Attached is an updated patch for the return-value conversion/coercion
optimization. It improves things significantly:
## before
Measure System.currentTimeMillis, int becoming Fixnum
6.092000 0.000000 6.092000 ( 6.091000)
5.929000 0.000000 5.929000 ( 5.929000)
5.878000 0.000000 5.878000 ( 5.878000)
6.282000 0.000000 6.282000 ( 6.282000)
5.912000 0.000000 5.912000 ( 5.911000)
Measure string.length, integer length to fixnum
0.606000 0.000000 0.606000 ( 0.606000)
0.486000 0.000000 0.486000 ( 0.486000)
0.494000 0.000000 0.494000 ( 0.494000)
0.495000 0.000000 0.495000 ( 0.495000)
0.498000 0.000000 0.498000 ( 0.498000)
## after
Measure System.currentTimeMillis, int becoming Fixnum
1.071000 0.000000 1.071000 ( 1.071000)
0.943000 0.000000 0.943000 ( 0.943000)
0.942000 0.000000 0.942000 ( 0.942000)
0.949000 0.000000 0.949000 ( 0.949000)
0.940000 0.000000 0.940000 ( 0.941000)
Measure string.length, integer length to fixnum
0.544000 0.000000 0.544000 ( 0.545000)
0.462000 0.000000 0.462000 ( 0.463000)
0.464000 0.000000 0.464000 ( 0.464000)
0.469000 0.000000 0.469000 ( 0.469000)
0.463000 0.000000 0.463000 ( 0.463000)
And it passes all tests...provided I disable testLowerJavaSupport.
"Lower" Java support was originally used to implement the
publicly-consumable "higher" Java support, and was also the source of
many of Java integration's performance problems. With the migration away
from Ruby-based "lower" support toward Java-based implementations of the
same features, performance has improved. And it may be the case that
"lower" java support features can simply go away.
So have a look at the contained patch. For the record, here's the
failure I get running testLowerJavaSupport with this change. In my mind,
the lack of consumers of "lower" support combined with the massive
performance improvement make it pretty much a no-brainer to abandon
"lower" support's APIs. And Dortch's work will make "lower" completely
irrelevant anyway.
Failure:
[junit] Testcase:
testLowerJavaSupport.rb(org.jruby.test.ScriptTestSuite$ScriptTest):
FAILED
[junit] test/testLowerJavaSupport.rb failed, complete failure list
follows:
[junit] EXCEPTION raised Low-level Java Support 77 --
[junit] Exception: undefined method `java_type' for
-1616413759:Fixnum
[junit] ./test/testLowerJavaSupport.rb:173
[junit] ./test/minirunit.rb:99:in `load'
[junit] ./test/minirunit.rb:99:in `test_load'
[junit] <script>:3
- Charlie
Index: test/test_index
===================================================================
--- test/test_index (revision 4100)
+++ test/test_index (working copy)
@@ -41,7 +41,7 @@
testLine_mixed_comment.rb
testLoad.rb
testLoops.rb
-testLowerJavaSupport.rb
+#testLowerJavaSupport.rb
testMarshal.rb
testMath.rb
testMethods.rb
Index: src/org/jruby/internal/runtime/FutureThread.java
===================================================================
--- src/org/jruby/internal/runtime/FutureThread.java (revision 4100)
+++ src/org/jruby/internal/runtime/FutureThread.java (working copy)
@@ -29,13 +29,13 @@
import org.jruby.RubyThread;
-import edu.emory.mathcs.backport.java.util.concurrent.ExecutionException;
-import edu.emory.mathcs.backport.java.util.concurrent.ExecutorService;
-import edu.emory.mathcs.backport.java.util.concurrent.Executors;
-import edu.emory.mathcs.backport.java.util.concurrent.Future;
-import edu.emory.mathcs.backport.java.util.concurrent.ThreadFactory;
-import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;
-import edu.emory.mathcs.backport.java.util.concurrent.TimeoutException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
/**
* @author cnutter
Index: src/org/jruby/internal/runtime/ThreadService.java
===================================================================
--- src/org/jruby/internal/runtime/ThreadService.java (revision 4100)
+++ src/org/jruby/internal/runtime/ThreadService.java (working copy)
@@ -30,7 +30,7 @@
***** END LICENSE BLOCK *****/
package org.jruby.internal.runtime;
-import edu.emory.mathcs.backport.java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.locks.ReentrantLock;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
Index: src/org/jruby/internal/runtime/GlobalVariables.java
===================================================================
--- src/org/jruby/internal/runtime/GlobalVariables.java (revision 4100)
+++ src/org/jruby/internal/runtime/GlobalVariables.java (working copy)
@@ -31,7 +31,7 @@
***** END LICENSE BLOCK *****/
package org.jruby.internal.runtime;
-import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.Iterator;
import java.util.Map;
Index: src/org/jruby/internal/runtime/ThreadLike.java
===================================================================
--- src/org/jruby/internal/runtime/ThreadLike.java (revision 4100)
+++ src/org/jruby/internal/runtime/ThreadLike.java (working copy)
@@ -27,8 +27,8 @@
***** END LICENSE BLOCK *****/
package org.jruby.internal.runtime;
-import edu.emory.mathcs.backport.java.util.concurrent.ExecutionException;
-import edu.emory.mathcs.backport.java.util.concurrent.TimeoutException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
public interface ThreadLike {
public void start();
Index: src/org/jruby/javasupport/JavaUtil.java
===================================================================
--- src/org/jruby/javasupport/JavaUtil.java (revision 4100)
+++ src/org/jruby/javasupport/JavaUtil.java (working copy)
@@ -36,10 +36,13 @@
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.BigInteger;
+import java.util.HashMap;
+import java.util.Map;
import org.jruby.Ruby;
import org.jruby.RubyBignum;
import org.jruby.RubyBoolean;
+import org.jruby.RubyFixnum;
import org.jruby.RubyFloat;
import org.jruby.RubyModule;
import org.jruby.RubyNumeric;
@@ -178,6 +181,112 @@
}
return rubyObjects;
}
+
+ public interface JavaConverter {
+ public IRubyObject convert(Ruby runtime, Object object);
+ }
+
+ public static final JavaConverter JAVA_DEFAULT_CONVERTER = new
JavaConverter() {
+ public IRubyObject convert(Ruby runtime, Object object) {
+ if (object == null) return runtime.getNil();
+ return convertJavaToRuby(runtime, object);
+ }
+ };
+
+ public static final JavaConverter JAVA_BOOLEAN_CONVERTER = new
JavaConverter() {
+ public IRubyObject convert(Ruby runtime, Object object) {
+ if (object == null) return runtime.getNil();
+ return RubyBoolean.newBoolean(runtime,
((Boolean)object).booleanValue());
+ }
+ };
+
+ public static final JavaConverter JAVA_FLOAT_CONVERTER = new
JavaConverter() {
+ public IRubyObject convert(Ruby runtime, Object object) {
+ if (object == null) return runtime.getNil();
+ return RubyFloat.newFloat(runtime, ((Float)object).doubleValue());
+ }
+ };
+
+ public static final JavaConverter JAVA_DOUBLE_CONVERTER = new
JavaConverter() {
+ public IRubyObject convert(Ruby runtime, Object object) {
+ if (object == null) return runtime.getNil();
+ return RubyFloat.newFloat(runtime, ((Double)object).doubleValue());
+ }
+ };
+
+ public static final JavaConverter JAVA_CHAR_CONVERTER = new
JavaConverter() {
+ public IRubyObject convert(Ruby runtime, Object object) {
+ if (object == null) return runtime.getNil();
+ return RubyFixnum.newFixnum(runtime,
((Character)object).charValue());
+ }
+ };
+
+ public static final JavaConverter JAVA_BYTE_CONVERTER = new
JavaConverter() {
+ public IRubyObject convert(Ruby runtime, Object object) {
+ if (object == null) return runtime.getNil();
+ return RubyFixnum.newFixnum(runtime, ((Byte)object).byteValue());
+ }
+ };
+
+ public static final JavaConverter JAVA_SHORT_CONVERTER = new
JavaConverter() {
+ public IRubyObject convert(Ruby runtime, Object object) {
+ if (object == null) return runtime.getNil();
+ return RubyFixnum.newFixnum(runtime, ((Short)object).shortValue());
+ }
+ };
+
+ public static final JavaConverter JAVA_INT_CONVERTER = new JavaConverter()
{
+ public IRubyObject convert(Ruby runtime, Object object) {
+ if (object == null) return runtime.getNil();
+ return RubyFixnum.newFixnum(runtime, ((Integer)object).intValue());
+ }
+ };
+
+ public static final JavaConverter JAVA_LONG_CONVERTER = new
JavaConverter() {
+ public IRubyObject convert(Ruby runtime, Object object) {
+ if (object == null) return runtime.getNil();
+ return RubyFixnum.newFixnum(runtime, ((Long)object).longValue());
+ }
+ };
+
+ public static final JavaConverter JAVA_STRING_CONVERTER = new
JavaConverter() {
+ public IRubyObject convert(Ruby runtime, Object object) {
+ if (object == null) return runtime.getNil();
+ return RubyString.newString(runtime, (String)object);
+ }
+ };
+
+ private static final Map JAVA_CONVERTERS = new HashMap();
+
+ static {
+ JAVA_CONVERTERS.put(Byte.class, JAVA_BYTE_CONVERTER);
+ JAVA_CONVERTERS.put(Byte.TYPE, JAVA_BYTE_CONVERTER);
+ JAVA_CONVERTERS.put(Short.class, JAVA_SHORT_CONVERTER);
+ JAVA_CONVERTERS.put(Short.TYPE, JAVA_SHORT_CONVERTER);
+ JAVA_CONVERTERS.put(Character.class, JAVA_CHAR_CONVERTER);
+ JAVA_CONVERTERS.put(Character.TYPE, JAVA_CHAR_CONVERTER);
+ JAVA_CONVERTERS.put(Integer.class, JAVA_INT_CONVERTER);
+ JAVA_CONVERTERS.put(Integer.TYPE, JAVA_INT_CONVERTER);
+ JAVA_CONVERTERS.put(Float.class, JAVA_FLOAT_CONVERTER);
+ JAVA_CONVERTERS.put(Float.TYPE, JAVA_FLOAT_CONVERTER);
+ JAVA_CONVERTERS.put(Double.class, JAVA_DOUBLE_CONVERTER);
+ JAVA_CONVERTERS.put(Double.TYPE, JAVA_DOUBLE_CONVERTER);
+ JAVA_CONVERTERS.put(Boolean.class, JAVA_BOOLEAN_CONVERTER);
+ JAVA_CONVERTERS.put(Boolean.TYPE, JAVA_BOOLEAN_CONVERTER);
+
+ JAVA_CONVERTERS.put(String.class, JAVA_STRING_CONVERTER);
+ }
+
+ public static JavaConverter getJavaConverter(Class clazz) {
+ JavaConverter converter = (JavaConverter)JAVA_CONVERTERS.get(clazz);
+
+ if (converter == null) {
+ converter = JAVA_DEFAULT_CONVERTER;
+ JAVA_CONVERTERS.put(clazz, converter);
+ }
+
+ return converter;
+ }
public static IRubyObject convertJavaToRuby(Ruby runtime, Object object) {
if (object == null) {
Index: src/org/jruby/javasupport/JavaMethod.java
===================================================================
--- src/org/jruby/javasupport/JavaMethod.java (revision 4100)
+++ src/org/jruby/javasupport/JavaMethod.java (working copy)
@@ -56,6 +56,7 @@
public class JavaMethod extends JavaCallable {
private final Method method;
private final Class[] parameterTypes;
+ private final JavaUtil.JavaConverter returnConverter;
public static RubyClass createJavaMethodClass(Ruby runtime, RubyModule
javaModule) {
// TODO: NOT_ALLOCATABLE_ALLOCATOR is probably ok here, since we don't
intend for people to monkey with
@@ -93,6 +94,8 @@
!Modifier.isPublic(method.getDeclaringClass().getModifiers())) {
accesibleObject().setAccessible(true);
}
+
+ returnConverter = JavaUtil.getJavaConverter(method.getReturnType());
}
public static JavaMethod create(Ruby runtime, Method method) {
@@ -194,7 +197,7 @@
private IRubyObject invokeWithExceptionHandling(Method method, Object
javaInvokee, Object[] arguments) {
try {
Object result = method.invoke(javaInvokee, arguments);
- return JavaObject.wrap(getRuntime(), result);
+ return returnConverter.convert(getRuntime(), result);
} catch (IllegalArgumentException iae) {
throw getRuntime().newTypeError("expected " +
argument_types().inspect() + "; got: "
+ dumpArgTypes(arguments)
Index: src/org/jruby/RubyObject.java
===================================================================
--- src/org/jruby/RubyObject.java (revision 4100)
+++ src/org/jruby/RubyObject.java (working copy)
@@ -37,7 +37,7 @@
***** END LICENSE BLOCK *****/
package org.jruby;
-import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicBoolean;
import org.jruby.evaluator.EvaluationState;
import org.jruby.exceptions.JumpException;
import org.jruby.internal.runtime.methods.DynamicMethod;
Index: src/org/jruby/RubyThread.java
===================================================================
--- src/org/jruby/RubyThread.java (revision 4100)
+++ src/org/jruby/RubyThread.java (working copy)
@@ -48,9 +48,9 @@
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
-import edu.emory.mathcs.backport.java.util.concurrent.ExecutionException;
-import edu.emory.mathcs.backport.java.util.concurrent.TimeoutException;
-import edu.emory.mathcs.backport.java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.locks.ReentrantLock;
import org.jruby.runtime.Arity;
import org.jruby.runtime.ObjectMarshal;
---------------------------------------------------------------------
To unsubscribe from this list please visit:
http://xircles.codehaus.org/manage_email