guardWithTest
John Rose
John.Rose at Sun.COM
Mon May 25 18:47:55 PDT 2009
Nice blog entry, Fredrik. Neal Gafter was also asking me at Lang.NET
for a slow path like the one you suggest.
If the user has a specific signature in mind, guardWithTest is
interchangeable with a hand-written JMH containing the if/then/else
logic. But the general API needs to be signature-polymorphic. And
this needs to happen without simulation overheads sometimes associated
with boxing, varargs, and other artifacts of the Core Reflection API.
For JVMs like JRockit that do a good job of escape analysis and can
scalarize and unbox varargs calling sequences, the simulation
overheads are not a big problem. For them, the right answer may be to
implement the signature-polymorphic aspects of JSR 292 using varargs
internally, along the lines of Fredrik's sketches.
For smaller JVMs, I still think we need the calling sequence
transformers. There is one class of transformer which I call a
"flyby" which is able to do if/then/else and even loops. It can be
implemented efficiently on small JVMs without advanced optimizations.
The way it works is:
class Flyby extends MethodHandle<(A...)=>R> {
MethodHandle<(A...)=>T> combiner;
MethodHandle<(T,A...)=>R> target;
R invoke(A... a...) {
T t = combiner.invoke(a...); //"fly by" the argument list
return target.invoke(t, a...); //now call the target
}
}
Because of the polymorphism over A... and the other types, this cannot
be implemented as a JMH. But it can be implemented either with
varargs and boxing (as Fredrik points out). It can be implemented
very simply in an interpreter-only system by a small amount of
assembly code, which copies the argument list, pushes the original
copy out of the way with a marker to identify it correctly for stack
walkers (like the GC), recursively runs the combiner, and then
restacks the arguments and jumps to the target.
Note that the combiner and/or target may need to drop or permute
arguments, depending on the use case. Assuming that simple argument
motion is reasonably cheap, this flyby combinator is able to
efficiently perform arbitrary intermediate computations on argument
lists, even in a JVM without special handling of boxing or varargs.
This combinator is flexible; it can be used to peform any recursive
call to a method handle, and fold in the returned result into the
target.
It can collect a varargs list, if T is Object[], combiner is new
Object[]{...}, and target drops all but the array.
It can implement guardWithTest, if T is MethodHandle, combiner calls
the test and selects one of target or fallback, and the flyby target
is MethodHandle.invoke.
Using that pattern, a flyby combinator can implement any sort of
control flow. The arguments a... serve as immutable "register" values
shared by the control flow elements, and the combiner computes the
next block to call (a "PC" or continuation) to call, in the form of a
method handle.
We knew we needed guardWithTest very early, at least as a use case of
a more general facility. The real problem is to come up with a
facility that is universal enough, and can be implemented efficiently
on a range of JVMs. The flyby plays a role in such a design. That's
it is in the current prototype, unde the name "combineArguments".
-- John
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.openjdk.java.net/pipermail/mlvm-dev/attachments/20090525/b3ba6c0c/attachment.html
More information about the mlvm-dev
mailing list