Spread problem with > 10 arguments
John Rose
John.Rose at Sun.COM
Mon Jul 6 17:17:05 PDT 2009
On Jul 6, 2009, at 7:40 AM, Fredrik Öhrström wrote:
> Because in the source code for JavaMethodHandle you will
> see an example of the combinatorial explosion of possible
> method types that I am flagging as a serious problem
> unless generic invocation is supported.
Hi Fredrik!
Yes, it is a serious problem. If you look at the Reference
Implementation code, you'll see places where bytecode generation is
stubbed out, and that is some cause for concern.
I should point out that the R.I. uses signature normalization in
several ways to mitigate the explosion you predict.
Many of the combinators (those with the word "Generic" in their class
names) either convert from or to an all-Object calling sequence. This
cuts the space of calling sequences to O(N) (where N is the maximum
argument list length).
The combinators which convert to and from arbitrary calling sequences
manage primitive values by first retyping them to long or int (with no
data change) and then managing boxing and value conversion with little
plugins. This would bring the space of "raw" calling sequences to
O(N**3), but further normalizations (sorting by kind, and then
lengthening all ints to long if there are any longs) makes the space
size O(N**2).
A final point about the explosion: It is almost certain to trail off
after 10 arguments, because of the relative scarcity of signatures
with N>10 in actual code. There is no plausible scenario (that I know
of) where we'll actually experience N**2 (or even linear) growth in
the complexity of argument signatures. Java programs are not that
complex.
This is still too many little classes, and in any case requires
dynamic bytecode weaving and/or some sort of fully polymorphic calling
mechanism. The solution I am proposing is to use the hardwired
"little classes" up to a few arguments (say N = 5 to 10) and back off
to full polymorphism using flyby adapters. This solution has no
effect on the public API, except perhaps exposing the flyby type
ArgumentList as an option (alternative to Object[]) with
spreadArguments, collectArguments, etc. At any rate, I'd like to
allow List where Object[] is allowed already for varargs processing.
As an internal implementation tactic, I think this is better for
HotSpot than using varargs Object arrays, because it puts less "magic"
in the JVM; you can implement the varargs mechanisms on top of it, but
the code complexity is lower (I think) than putting varargs processing
directly into the runtime.
> Even with the clever compression scheme already in place,
> it seems to me (please correct me if I am wrong) that
> JavaMethodHandle requires 180 methods to handle up to 5 arguments.
The most complex adapter module in the R.I. is ToGeneric, which builds
adapters that can take any calling sequence, and convert it to (non-
varargs) Object arguments and return value. There is one "little
class" per number of arguments; those classes A0..A5 extend JMH and
contain a total of 140 "invoke" methods.
> With up to 10 arguments it would have to implement 605 methods
> and with up to 20 arguments it would have to implement 2205 methods.
Yes A0..A10 contain 275 "invoke" methods. So your estimates are a
little high, but only by a small factor.
> I think this signifies more than just a tricky implementation matter.
> It is a clear indication that managing all possible signatures is
> something
> that should be inside the JVM and not implemented in bytecode.
Yes!
> Also, since the performance question for smaller JVMs is often
> mentioned,
> I would like to compare the situation with closures. Apparently a lot
> of people would like to see closures in the Java.
>
> It is indeed possible to compile a closuresq for loop as efficiently
> as a
> standard Java for loop. However the optimizations needed to do this
> are
> approximately: inlining, escape-analysis, object explosion.
>
> These are the same optimizations needed to optimize MethodHandle
> generic invocation efficiently!
At the JVM implementation level, this is really the same conversation
as closures. You are right that there is no significant difference
between method handles and closures. (At the *JVM* *level*! But
closures are essentially a language feature with a likely set of
implementation tactics, whereas method handles are not a language
feature, except for minimal punch-through in Java's type system.)
> But no one complains that closures should
> not be added to Java because non-optimizing JVMs will not execute
> them as
> efficiently.
Here's an alternate and more likely cause for that silence: No one
complains about this with closures because the people arguing about
closures are language and applications people, and they rarely think
in great detail about JVM implementation. This conversation right
here and now is likely to be a cutting edge conversation about JVM
implications of function pointers and the like.
> I think that any reasonable JVM that is interested in any sort of
> performance will have some sort of optimizer. Heck, even the JVM
> running
> inside the SIM card in a modern GSM/3G phone can now execute at a
> couple of
> hundred MHz and have 1 GB of memory! :-)
Good point. Counter-points: It is risky to declare a minimum size
for a JVM. Also, cycles on a small device drain power, which is the
real limited resource. So those 100's of MHz are only a peak rate.
Running more frequent GCs or a complex JIT could warm up your handset
more than the system designers will permit. As for deeply optimizing
background compilers (like HotSpot's), only on big power-guzzling
multi-core machines is there a concept of pre-paid cycles, which a JIT
can soak up almost "for free". I'm not familiar with the efficiency
characteristics of JRockit's eager JIT, but even if runs 1000
instructions to generate one instruction (which would be very good, if
combined with optimization), that's still a pretty big power spike to
start up an application.
-- John
More information about the mlvm-dev
mailing list