Flyby adapters, anyone?

John Rose John.Rose at Sun.COM
Mon Jul 6 12:14:16 PDT 2009


On Jul 5, 2009, at 4:38 PM, Rémi Forax wrote:

>> Obviously avoiding arg boxing is key to
>> performance, so call paths will need to support a large number of
>> unboxed arguments to allow passing call protocols along cleanly.
>
> One nice goal will be to be able to express call protocol with only  
> one
> object

I'm making progress on the Last Adapter, which I call the "flyby  
adapter".  I think (and please help me figure this out) that it  
provides a reasonable way to manage very complex argument lists with  
little or no boxing effort.

A flyby adapter is typed (as usual) and contains two method handles,  
"probe" and "target".  The "probe" is of type (ArgumentList)void, and  
the "target" is of the same type as the adapter itself.  The flyby  
adapter packages up the incoming argument lists into an ArgumentList  
object, and runs the probe.  After the probe returns, control is  
transferred to the target.

The probe is free to side-effect ArgumentList object, though it cannot  
change the types of any arguments.  Any changes made by the probe are  
seen by the target.

Note that the flyby, the probe, and the target all see the same  
arguments; this may seem to be a limitation but it is not.  In  
general, if it is useful for them to see somewhat different argument  
lists, this can be done by inserting and dropping arguments at various  
points.

Expressed using varargs, the flyby pattern looks something like this:

class FlyBy extends JavaMethodHandle {
   final MethodHandle probe, target;
   Object invoke(Object... argList) {
     probe.<void>invoke(argList);
     return MethodHandles.invoke(target, argList);
   }
}

The opaque interface type ArgumentList provides access to the same  
information as a varargs Object[] array would, plus the static type of  
the arguments.  In fact, some platforms (those with very good unboxing  
optimizations) may implement it on top of varargs arrays.

The interface type is a subtype of List, and provides additional  
accessors:
   MethodType type()
   Object get/setReference(i)  // non-prims only
   int get/setRawInt(i)  // all prims except long, double
   long get/setRawLong(i)   // long, double prims

The List get/set accessors DTRT with respect to the static type, and  
bottom out in the above accessors.

The ArgumentList object is allocated on the heap, but is only a few  
words in size, and contains a pointer straight into the stacked  
argument list.  The JVM takes care to null out the stack reference  
when the frame is taken down.

By using flyby adapters, we can write generic code that can process  
any argument list.  We can do this without ever spinning bytecodes at  
runtime.  This is why the current implementation throws NYI wherever  
bytecodes would have to be generated:  If this works, I plan to use  
flybys instead of generated classes.

As noted above, flybys are probably most useful in conjunction with  
some argument adding and dropping.  Particularly useful, probably, is  
the ability to insert zero-valued arguments before the adapter, thus  
giving the ArgumentList some scratch variables to work with; these  
values (amended to values computed by the probe) are then passed to  
the target.

Another useful transformation, probably, is dropping some of the  
original arguments just before calling the target (presumably they  
were only useful to the probe).  These two transformation could be  
encoded (for example) as a trailing set of zero values to append just  
before calling the probe, and a leading sequence of arguments to drop  
just before calling the target.

The flyby is the only JVM-primitive adapter that is not completely  
tail-recursive, because it must push a stack frame while the probe  
executes.  But it will guarantee that the call to the target is a tail  
call.  This will provide a hook for building state machines and other  
low-level patterns.

Other adapters defined by JSR 292 which currently seem to need  
bytecode generation will be implemented on top of flybys.  For  
example, collectArguments can be built on a flyby which performs all  
the boxing and stores it into a trailing argument.

A completely non-allocating version of the flyby adapter is useful;  
this would avoid creating the ArgumentList, and pass the whole  
argument list (spread out as usual) to the probe.  The probe would in  
turn return a new value to be appended to the argument list.  This is  
quite powerful if the first argument is a method handle; what you get  
is a continuation-passing state machine, where the rest of the  
arguments are "along for the ride"; they might be a pointer to an  
abstract machine state which itself is mutable.  This suggests that  
flybys have two inherent degrees of freedom (beyond their method  
type):  Whether the arguments are collected or not going into the  
probe, and whether a return value from the probe is inserted or not  
into the target arguments.  The add-zero/drop degrees of freedom  
mentioned above are not inherent to the pattern.

One last point:  A key motivation for flybys is running method handles  
on very small platforms where dynamic bytecode generation is difficult  
or impossible.

-- John

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.openjdk.java.net/pipermail/mlvm-dev/attachments/20090706/6f583d63/attachment.html 


More information about the mlvm-dev mailing list