Getting back into invokedynamic in JRuby
Charles Oliver Nutter
headius at headius.com
Mon Mar 15 19:37:39 PDT 2010
Hello all!
I'm finally getting back into invokedynamic/mlvm stuff in JRuby! I
have started updating our indy support and run into a few questions...
I was under the impression that JavaMethod handle would be a good way
to replace all the handle composition I was doing before. Is this
true?
I will explain...
Previously, when bootstrapping a call site, I used all MethodHandles.*
methods to compose a chain of direct method handles from the call site
all the way to the target method object, with no non-leaf Java code in
that call path. This was necessary, I believed, to allow inlining all
the way through the dynamic call site.
The structure was roughly like this:
Guard With Test
Test (leaf Java method
Success path
Various chained handles to unpack arguments (via leaf Java methods)
Actual target method
Fail path
Recache and invoke (non-leaf Java method
For the success path, it would then be all direct handles straight
through from caller to called method.
The logic for this version can be seen here:
http://github.com/jruby/jruby/blob/master/src/org/jruby/runtime/invokedynamic/InvokeDynamicSupport.java
This structure seemed to work well last fall, and on most
microbenchmarks it was as fast or faster than the trampolining version
in non-indy JRuby (where a CachingCallSite sits directly in the call
path). However, when I ran this code on current MLVM, the performance
was extremely slow...as much as ten times slower than it had been (and
ten times slower than my non-indy logic).
So today I did a rework using a Java method handle and all the
caching+call logic built directly into the handle I provide it. This
drastically reduced the complexity of my invokedynamic logic (since I
didn't have to do all that handle composition) and improved
performance, but it's still not as fast as last fall's MLVM plus the
composed handles.
You can see the new version here:
http://github.com/jruby/jruby/blob/indy/src/org/jruby/runtime/invokedynamic/InvokeDynamicSupport.java
I'm trying to find the right way to phrase my question to make sure I
get the right answer...
1. Do I need to use all direct method handles to get inlining from the
caller to the callee?
2. If I have a Java method handle that does a MethodHandle.invoke call
in its body, will that invoked handle get inlined all the way back for
all callers?
3. Does the body of the method pointed at by a JavaMethodHandle get
specialized for all call sites, so that it doesn't appear to be a
single body of code with a megamorphic invocation of a separate
handle?
Am I making my question clear enough?
Also, additional questions:
4. I still needed to bump up inlining budgets considerably to get
anything to inline across the dynamic call. Will that always be the
case, or is there still a plan to get dynamic call plumbing excluded
from that budget?
5. What can I do to investigate why current MLVM is, in all cases,
slower than what we had last fall?
I'm very interested in getting this stuff going again.
- Charlie
More information about the mlvm-dev
mailing list