Trying to work newer indy into JRuby
Charles Oliver Nutter
charles.nutter at sun.com
Mon May 18 12:30:08 PDT 2009
John Rose wrote:
> The first two lines of GuardedRubyMethodHandle.invoke are your fast
> path; that's where we need to get the maximum amount of inlining. The
> JVM interpreter gets to those lines very quickly (without intervening
> bytecodes) when it executes an invokedynamic instruction. Christian
> Thalinger and I are working on making this true also in the compiled
> code.
Ok...and I'll state it one more way just to be absolutely clear: I
really, really want to avoid the situation that Cliff pointed out, and
I'm worried about my Java-based MethodHandle getting in the way. I think
I'm hearing that, but I obviously want to be certain :)
> The call to entry.typeOk looks like it might be megamorphic; if so
> that's a potential performance problem. There might be a way to
> refactor this with method handles to avoid the megamorphism; that's
> what guardWithTest is supposed to do. We'll get a better idea of what
> to work on when we look at the disassemblies of compiled code, but
> we'll need another round of compiler support to get this far.
typeOk is final/monomorphic and the methods it calls are all
final/monomorphic. Here they are:
http://gist.github.com/113687
This is the token check I told you about previously. So far we've been
able to guarantee that the token gets flipped if any related change
event fires, so this should be ok.
> The expression entry.method.call might also have a megamorphism (your
> nemesis, of course). I think it wants to be entry.mh.invoke, or even
> ((MethodHandle)entry).invoke, where entry is a JMH.
It most certainly is! There are several types of method (DynamicMethod,
see the CacheEntry code above), encapsulating interpreter logic, wrapped
methods (aliases) pre-compiled methods, and jit-compiled methods. And
even if it's all the same type, we generate our own "handles" specific
to the target method in many cases, in order to keep as much of the call
path monomorphic as possible.
In a totally free world, what I'd expect to do would be to have a
generated MethodHandle for every method as well, with code that would
only ever dispatch to that one DynamicMethod. Obviously that's
infeasible, so I really need to work with you all to find a way to
include our guard logic and invoke the eventual Ruby method objects, be
they interpreted, compiled, or otherwise, and still get things to inline
straight through.
Now the simple way I thought to do this was to simply have our existing
DynamicMethod supertype extend JavaMethodHandle. Is the implication that
if we have all MHs straight from the call site to the target body of
code, it can inline?
> Minor nits: I suggest making bootstrap in registerBootstrap be a
> private static final like DEFAULT. And you might consider naming
> those statics after their methods (modulo Java naming conventions):
> BOOTSTRAP, INVOKE.
Sure, good cleanup tips. I will spend some time the rest of the day
wiring up the other-arity call paths, probably as individual
GuardedMethodHandle subtypes (yes?) with their own invoke signatures.
I must also remark how similar this feels to LLVM's method invocation
APIs, where they toss "function" objects into the IR and it just
optimizes the calling logic. It seems to me that the new indy stuff
could be the underpinnings of a "JVM-LLVM" API that represents basic
blocks as concrete code bodies and transitions as method handle
invocations...
- Charlie
More information about the mlvm-dev
mailing list