Charles Oliver Nutter wrote:
The odd thing about this is that there should be very little challenge in making return values quickly rubify to an appropriate type. We know the return value from a given method isn't going to change, and we know exactly how to box it or wrap it. So what's the deal?

Using this logic I made a small modification to JavaMethod. Basically, at construction time, it creates a type-specific ReturnConverter that it uses to convert values for all future invocations. I theorized that the performance hit we see was largely due to all the stacked conditionals in JavaUtil.convertJavaToRuby.

And I was right:

Measure System.currentTimeMillis, int becoming Fixnum
  0.688000   0.000000   0.688000 (  0.688000)
  0.607000   0.000000   0.607000 (  0.607000)
  0.589000   0.000000   0.589000 (  0.589000)
  0.606000   0.000000   0.606000 (  0.606000)
  0.602000   0.000000   0.602000 (  0.602000)
Measure string.length, integer length to fixnum
  0.470000   0.000000   0.470000 (  0.470000)
  0.462000   0.000000   0.462000 (  0.461000)
  0.460000   0.000000   0.460000 (  0.460000)
  0.459000   0.000000   0.459000 (  0.459000)
  0.459000   0.000000   0.459000 (  0.458000)

Now we're starting to look a little more reasonable. The remaining performance difference is likely due to Java reflection being used in JI, rather than direct STI invocation in String#length.

It's probably safe to assume that almost all of the core types we autoconvert are suffering from this performance hit right now, because they all rely on a generic piece of code with a bunch of stacked object comparisons to do conversion. And the change I made would just as easily apply to parameters being passed into Java code...we'd just have an array of converters for the incoming parameters that would only focus on conversion to a single type...the type we want for the call.

Seems like a good change to look at making in the general case, yes?

How's your JI work coming, Bill?

- Charlie
Index: src/org/jruby/javasupport/JavaMethod.java
===================================================================
--- src/org/jruby/javasupport/JavaMethod.java   (revision 4037)
+++ src/org/jruby/javasupport/JavaMethod.java   (working copy)
@@ -56,6 +56,11 @@
 public class JavaMethod extends JavaCallable {
     private final Method method;
     private final Class[] parameterTypes;
+    private final ReturnConverter returnConverter;
+    
+    private static abstract class ReturnConverter {
+        public abstract IRubyObject convert(Object javaValue);
+    }
 
     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
@@ -80,7 +85,7 @@
         return result;
     }
 
-    public JavaMethod(Ruby runtime, Method method) {
+    public JavaMethod(final Ruby runtime, Method method) {
         super(runtime, (RubyClass) 
runtime.getModule("Java").getClass("JavaMethod"));
         this.method = method;
         this.parameterTypes = method.getParameterTypes();
@@ -93,6 +98,17 @@
             !Modifier.isPublic(method.getDeclaringClass().getModifiers())) {
             accesibleObject().setAccessible(true);
         }
+        
+        if (method.getReturnType() == Long.TYPE) {
+            returnConverter = new ReturnConverter() {
+                public IRubyObject convert(Object javaValue) {
+                    return runtime.newFixnum(((Number) javaValue).longValue());
+                }
+            };
+        } else {
+            returnConverter = null;
+        }
+        
     }
 
     public static JavaMethod create(Ruby runtime, Method method) {
@@ -194,6 +210,9 @@
     private IRubyObject invokeWithExceptionHandling(Method method, Object 
javaInvokee, Object[] arguments) {
         try {
             Object result = method.invoke(javaInvokee, arguments);
+            if (returnConverter != null) {
+                return returnConverter.convert(result);
+            }
             return JavaObject.wrap(getRuntime(), result);
         } catch (IllegalArgumentException iae) {
             throw getRuntime().newTypeError("expected " + 
argument_types().inspect() + "; got: "

---------------------------------------------------------------------
To unsubscribe from this list please visit:

    http://xircles.codehaus.org/manage_email

Reply via email to