Getting back into invokedynamic in JRuby

Charles Oliver Nutter headius at headius.com
Fri Mar 19 09:21:39 PDT 2010


On Tue, Mar 16, 2010 at 10:22 AM, Rémi Forax <forax at univ-mlv.fr> wrote:
> Le 16/03/2010 03:37, Charles Oliver Nutter a écrit :
>> 1. Do I need to use all direct method handles to get inlining from the
>> caller to the callee?
>>
>
> Yes.
>
>> 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?
>>
>
> Neither the backport nor the RI do that.
> It's a complex optimization involving to track method handle identity
> across method boundary.
> This is doable but not currently done.
> My hope is to come with an implementation doing that for the backport
> for the next JVM summit :)
>
> Currently if you want the best performance, it's better to avoid direct
> method handle invocation
> in the middle of an indy call.

Ok, so basically, nothing in either the backport nor the RI
(currently) can do anything if a piece of Java code (real Java!) in
the middle of a chain ends up doing polymorphic calls, even if those
polymorphic calls are directly into other handles. And you would like
to prototype specializing such cases.

This fits my assumption of the state of the world. I'll probably dump
this new indy branch and go back to all direct handles, plus some
cleanup as you suggest.

The specialization case is interesting for another reason, though:
closure conversion. The simple example is array.each {|x| puts x}
where you'd like both each and the block to inline into the caller.
Currently, since each will certainly receive many different closures,
the call from each to the closures is polymorphic, and so only each
itself can get inlined back. Given that so many of the new JVM
languages (all?) support (and encourage!) closures, this is going to
be a growing problem. The JRockit folks seemed to think it wouldn't be
hard to modify JRockit to handle this case, but they indicated it
would be easiest if it were a standard parameter type or call target
for the closure (like a MethodHandle, for example).

> I've taken a look to your code and think you could again simplify it.
> You don't use createGWT anymore and simulate it in all method invoke*
> of CacheHandle.
> In my opinion, this is not a good idea because:
> - the cached method handle should be stored in the GWT
>    (basicaly you don't need the object CacheEntry)
> - the fast path should not use any trampoline code (any of your method
> invoke*)
>   to be adapted to any signature.

So if I understand your suggestion, you think the new version of the
code could be used if the fast path itself was all direct handles as
before. I think that puts me pretty much back on the original code,
where the slow path used a pure-Java "fallback" trampoline and the
fast path was a straight-through chain of direct handles all the way
to the target.

>> 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?

FYI, Christian put me back on the right track. The inlining budgets
are definitely still coming into play, and indy performs as expected
(slightly faster than non-indy) if I additionally add
+MaxInlineSize=50 and +InlineSmallCode=2500. So the original code is
still OK.

- Charlie


More information about the mlvm-dev mailing list