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