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