Boxing, still a limit of invokedynamic?
Rémi Forax
forax at univ-mlv.fr
Sun May 13 10:55:08 PDT 2012
On 05/13/2012 07:21 PM, Charles Oliver Nutter wrote:
> On Sun, May 13, 2012 at 11:04 AM, Jochen Theodorou<blackdrag at gmx.org> wrote:
>> I wanted to ask you of your opinion. If I am going to compile something
>> like a+b-c and a,b,c are all primtives, but I won't know that the
>> results will be really the primtives too, then this means I will most
>> probably compile it like this:
>>
>> invokedynamic("minus", invokedynamic("plus",a,b), c)
>>
>> meaning the result of a+b will be an Object (since I won't know it is a
>> primitive) and then there will be one boxing for that, just to unbox
>> again for the minus and then box again for the result of the minus. If
>> now the result is not supposed to be a primitive, then there won't be
>> another unbox, till the next operation done with that value.
> You could also encode "a+b-c" as a single invokedynamic operation, but
> I guess you're looking for a general solution...
>
>> Now, even if the JIT is able to see through the one boxing and unboxing
>> fro the result of plus, what will stay is the boxing for the result of
>> the minus.... plus the many unboxing actions used when this result is
>> used. Isn't that a conceptual problem? And how do others deal with that?
> 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?
>
> 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.
>
> Of course this is all assuming that EA will be working across indy
> boundaries in the near future. Currently, it does not.
>
> In JRuby, where we have no static typing or type hints, we always do
> these invocations as all reference types. We're banking on JVM helping
> us out in the future, so my goal is to just use indy as efficiently as
> possible and keep call protocols simple.
>
> 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 think currently Groovy allows to replace + by a method
that will return everything you want.
But here, I think the spec of Groovy (if it means something)
should be changed to say that when your replace a method
by another, the return type must be a subtype of the
existing method.
>
>> 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?
>
> In my case, passing int instead of Fixnum where possible (usually only
> when a literal integer appears in the argument list) definitely helps;
> I don't have to construct a Fixnum or go to a cache to get it, and on
> the other side there's no type-checking required to make sure I really
> have a Fixnum. The int paths should be faster than the Integer paths.
>
> 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.
>
>> 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 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?
Object -> int is not equivalent to Object -> Integer -> int,
it can be Object -> Byte -> int by example.
You have to chain several calls to asType()
see slide 20 of my jvm summit talk last year,
http://wiki.jvmlangsummit.com/images/9/93/2011_Forax.pdf
>
> Bottom line here is that if you need a reference type on LHS, you'll
> have to create a reference type, and we need the JVM to figure out
> that it can brush that part away.
>
> - Charlie
Rémi
More information about the mlvm-dev
mailing list