Trying to work newer indy into JRuby

Rémi Forax forax at univ-mlv.fr
Mon May 18 14:18:17 PDT 2009


Charles Oliver Nutter a écrit :
> 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 don't think you need different subtypes.
A JavaMethodHandle takes a MethodHandle as parameters so
you can have more than one variant of invoke() in GuardedMethodHandle
and select the good one depending on the type() of the CallSite.
 
> 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
>   
Rémi



More information about the mlvm-dev mailing list