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