Boxing, still a limit of invokedynamic?
Charles Oliver Nutter
headius at headius.com
Sun May 13 10:21:11 PDT 2012
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 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?
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
More information about the mlvm-dev
mailing list