Boxing, still a limit of invokedynamic?

Jochen Theodorou blackdrag at gmx.org
Sun May 13 13:14:40 PDT 2012


Am 13.05.2012 19:21, schrieb Charles Oliver Nutter:
[...]
> You could also encode "a+b-c" as a single invokedynamic operation, but
> I guess you're looking for a general solution...

yes, I am looking for a general solution. I was thinking of making the 
whole expression as a MethodHandle combination, which then has a,b,c as 
input arguments... but that's a pretty big step to do. I don't want to 
spend months in changing the compiler just to find it doesn't give me 
the performance I am looking for. Plus this approach has its own 
problems with evaluation order and such.

[...]
> First of all...how are you expecting that JIT will see through the
> first boxing? If the return result is going to be Object, it's going
> to go into an Integer. Perhaps you are hoping for escape analysis to
> get rid of it?

I don't know what part it does, but I assume EA is right.

> If that's the case, why wouldn't the same expectation apply to the
> second call? If (a+b) returns an Integer that's immediately passed
> into (tmp-c) and both calls inline, in theory EA should have enough to
> eliminate the intermediate. If the result of (tmp-c) is never used as
> an object and never escapes, then EA should be able to get rid of that
> too.

well.. in my example the result of tmp-c is returned, so it escapes. But 
even if I only store it in a bytecode slot... I mean I wouldn't EA 
expect to even optimize these cases.... on further thought though it 
might be possible.

> Of course this is all assuming that EA will be working across indy
> boundaries in the near future. Currently, it does not.

Indeed, I was kind of assuming that. You telling me it does not makes 
some results much clearer to me. The question then is... should I wait 
for EA working across indy boundaries? And when would that be available?

[...]
> A confusing point for me: in your case, where you know they're all
> ints, how do you not know that + and - also return int? Can't you
> determine statically that this whole expression will return a
> primitive int?

I may not have written that part clearly enough. We don't know that + 
and - return int. You may vagualy remember my JVM talk 2 years ago in 
which I explained how I plan to make a primitive optimization path. In 
this path the compiler will indeed assume that a+b will return an int 
and will then emit iadd instead of using static method calls or any 
other helpers. This optimized path has basically the same performance as 
Java in the best case, but it is guarded, which reduces the performance 
to half of Java speed in the best case. The problem is that prim opts 
cannot handle more complex cases and it is really easy to turn them 
off... That plus the problem of almost doubling the method bytecode make 
them a sub optimal solution. But it is one indy has to compete with.


>> I am asking because I was experimenting with method signatures and for
>> such plus and minus methods and got mixed results. I was expecting the
>> primtive versions would achieve the best results, but that was not the
>> case. a plus(int, int) had worse performance than a plus(int,Integer) or
>> plus(Integer,int) in some cases and sometimes it looked like
>> plus(Integer,Integer) is worse, in other cases not. Well, this is
>> causing me some problems. Why do I get such strange results? I would
>> assume it depends on the JIT and the boxing logic it is able to
>> recognize and not.
>
> What does the assembly look like?

you mean the compiled code? I will try to give examples of this later. 
But if

> And again remember...I don't think the JIT in u4- does anything with
> the boxing coming out of these calls. It might do something on the
> other side, but not across the invokedynamic call.

is right, then it is no wonder, that one time this and another time that 
is faster. But I suspect it is worse. It is not only across indy calls, 
that the JIT does nothing with boxing, I assume it is even across 
MethodHandles in the same indy call. To be more exact with my suspecion, 
I expect a constant int boxed by an MethodHandle and then unboxed by 
another one in the same indy call to be slower, than just returning the 
int itself.

If I have a+1, then the ideal plus is one that takes int,int and returns 
Integer, because that way everything can happen inside the 
invokeddynamic part. if I have a=a+1 (a being an int) then 
plus(int,int):int is probably better, but using the one from before and 
unboxing the Integer to int is not. And depending from where your 
results are coming from you get better performance by using 
plus(Integer,int) plus(int,Integer) and plus(Integer,Integer)... with 
different return types probably as well.

>> One more thing I noticed is, that if I have a = b+c, with all of them
>> being int and b+c returning object, then letting the MethodHandle do the
>> conversion from Object to int is actually much worse performance wise,
>> than a cast to integer and calling valueOf. Shouldn't that be at least
>> equal, if not as fast considering that the result of b+c was first boxed
>> and then is unboxed?
>
> Perhaps doing it in the handles makes the code more opaque? Do the
> non-handle way and the handle way have exactly the same logic?

the non handle way means to calculate b+c using a handle and then unbox 
the result using a library function from Groovy... afaik. The handle way 
uses the abilities of MethodHandles to convert the Integer into an int. 
I don't know for sure what that part is doing in the end, but normally 
it shouldn't be slower.

bye Jochen



More information about the mlvm-dev mailing list