More performance explorations
John Rose
john.r.rose at oracle.com
Fri May 27 17:46:46 PDT 2011
On May 27, 2011, at 8:04 AM, Charles Oliver Nutter wrote:
> There's substantially more code here. I don't see any jumps that would
> short-circuit this logic. Am I reading right?
>
> Now the good news is that after the test is completed I don't see much
> additional logic on MLVM before it's back into the inlined recursive
> call. Both versions inline a single level of fib_ruby recursion and
> then callq the next level of recursion.
>
> So what's up with that logic leading up to test? I assume that's the
> new GWT logic, but am I getting that it's a lot more heavyweight than
> the old version? Or is some intermediate handle doing extra work?
OK, I think I understand the source of the sand in the gears.
It's not GWT. It's an intermediate handle. Those extra checks are checkcasts introduced by code like this:
static void doSomeRubyThing(org.jruby.runtime.builtin.IRubyObject x) { ... }
MethodHandle doSomeRubyThing = lookup().lookupStatic(..., methodType(void.class, IRubyObject.class));
MethodHandle gwrap = doSomeRubyThing.asType(doSomeRubyThing.type().generic());
Object x = gwrap.invokeExact((Object)y);
The invokeExact call takes an undifferentiated Object and casts it to IRubyObject before jumping into doSomeRubyThing. (It will also wait until the thing returns void and make a null to push toward x.)
Until recently, we specified that interface conversions in asType were no-ops. As you know, this is type-safe, and reflects the behavior of the JVM's verifier. But it does not reflect the rules of the Java language. The EG decided this was too surprising, so we made asType compatible with the Java language. This means you get lots of redundant "x instanceof IRubyObject" code. It adds no value. It is also poorly optimized (note the redundant tests in your sample code!).
The cure is simple: Get rid of the interface casts implied by your uses of asType. To do this, use MHs.explicitCastArguments, which does the more performance-friendly no-op retyping of interfaces. If you need to cast some arguments and safely widen others, do it in two steps: Pick a middle type that adjusts the interface arguments to Object, explicitCastArguments to that middle type, and then use asType the rest of the way. (The other order will work too. Don't know if there's a performance difference, but if there is I suspect the best order is eCA first them asType to finish.)
How badly does this bollix up your carefully constructed code?
Suggestion: Write an "eraseInterfaces(mh)" operator which will edit all the interfaces in mh.type(), and explicitCA to the edited type. The result can then be asTyped, and you'll get (I hope) much more similar machine code.
-- John
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.openjdk.java.net/pipermail/mlvm-dev/attachments/20110527/ee7370e4/attachment.html
More information about the mlvm-dev
mailing list