MethodHandle vs invodynamic (performance-wise)

Rémi Forax forax at univ-mlv.fr
Sun Feb 13 11:38:35 PST 2011


On 02/13/2011 07:00 PM, forum at x9c.fr wrote:
> Le 13 févr. 2011 à 12:55, Rémi Forax a écrit :
>
>> On 02/13/2011 10:07 AM, forum at x9c.fr wrote:
>>> Dear list,
>>>
>>> In a previous thread (that I cannot find again), I read that better
>>> performances could be achieved via the "invokedynamic" instruction
>>> rather than by using "MethodHandle" instances.
>>> However, it is not clear to me whether this is true only for the
>>> current state of the implementation, or should remain true in the
>>> future (read "at the time of JDK7 release").
>> It's true for all implementations if the target of invokedynamic is stable
>> (don't change too often).
> Thanks for the information; is there a reasonable estimate of the different
> speeds (supposing that the target would indeed be constant). I mean, is
> the gap as huge as between reflection and handles?

No, the gap is not as huge. Theorically, if the method handle is stored
in a static final field, the difference is just a pointer check.

>
>>> If useful, here is a summary about the context: implementation
>>> of both an interpreter and a compiler supporting closures.
>> There are 2 different use cases, one is how to implement a
>> function/method call,
>> in that case you should use invokedynamic. The other is how to implement
>> a closure call,
>> in that case you should use MethodHandle.invoke{Exact|Generic}.
>>
>> It's a little bit more complex if a callsite can call a closure or a
>> method like by example
>> the method 'call' in Groovy. In that case, you can use an invokedynamic
>> and if the first parameter
>> is a MethodHandle and use the MHs.genericInvoker (or MHs.exactInvoker)
>> as target MethodHande.
>>
>> Anyway, as you see you should choose to use one mechanism or the other
>> depending
>> on the use case and not on some benchmark.
> Well, I do not fully understand your point. To some extend, it appears to me
> that both mechanisms can be used to achieve the very same effect. That's
> why I thought the "director's cut" should be performances.

if you know the method handle at link time, you should use invokedynamic,
if you don't know you should use MH.invokeExact.

>
>>> Please note that for interoperability reasons, it will not be possible
>>> to use built-in currification-like support provided by handles.
>>> Hence, all calls will be "total".M
>>>
>>> Thanks in advance for any insight.
>> In you case, you can:
>> - use MethodHandle instead of j.l.r.Method when doing native call.
> This is actually what is done in (unreleased) code.
> This resulted in a huge speed-up, but was wondering if I should use
> "invokedynamic" instead.
>
>
>> - use invokedynamic in the bytecode generated by Cafesterol and
>>    implement the corresponding bootstrap methods in Cadmium.
>>    AbstractNativeRunner.closures should be a list of method handles.
>> - change the implementation of Value or Block to store a MethodHandle
>>    in it and use it as a closure instead of using the Closure object.
> Well, this too has been rewritten, there is no more a list of closures but
> Value/Block is now a hierarchy of specialized classes (e. g. double,
> bare block, closure).

 From performance point of view is better to have unrelated final classes
instead of a hierarchy. double, closure etc. can be represented as
Double, MethodHandle (or a class that wraps MethodHandle) etc
and use Object as common super type.

>   There again, I wonder if the best is to do a
> "Method.invokeExact(-)" or to play with the "invokedynamic" instruction.
> The former has been implemented easily and is indeed quite fast.
> Is it a good investment to move to le latter, given that it will
> probably entail compile-time generation of one class per target in
> my case ?

Having one class per target is not a requirement at all.
invokedynamic is just a way to install a method handle at a callsite.
Let's take examples (sorry my Caml is a little rusty):

#  let rec fib n =
    if n<  1 then 1 else fib(n-1) + fib(n-2);;


here fib(n-1) and fib(n-2) should be encoded using invokedynamic.

#  p#get_x;;


p#get_x is also an invokedynamic.

#  let f = (function x ->  1);;


here f should be a MethodHandle so

#  f 1;;

is a call to MethodHandle.invokeExact()


>
> Thanks for the thorough information.
>
> Kind regards,
>
> Xavier Clerc

Rémi

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.openjdk.java.net/pipermail/mlvm-dev/attachments/20110213/78e996ec/attachment-0001.html 


More information about the mlvm-dev mailing list