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