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

Reply via email to