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