<html><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><div><div>On Jul 5, 2009, at 4:38 PM, Rémi Forax wrote:</div><br class="Apple-interchange-newline"><blockquote type="cite"><span class="Apple-style-span" style="border-collapse: separate; color: rgb(0, 0, 0); font-family: Helvetica; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; "><blockquote type="cite">Obviously avoiding arg boxing is key to<br></blockquote><blockquote type="cite">performance, so call paths will need to support a large number of<br></blockquote><blockquote type="cite">unboxed arguments to allow passing call protocols along cleanly.<br></blockquote><font class="Apple-style-span" color="#006312"><br></font>One nice goal will be to be able to express call protocol with only one<span class="Apple-converted-space">&nbsp;</span><br>object<br></span></blockquote></div><br><div>I'm making progress on the Last Adapter, which I call the "flyby adapter". &nbsp;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.</div><div><br></div><div>A flyby adapter is typed (as usual) and contains two method handles, "probe" and "target". &nbsp;The "probe" is of type (ArgumentList)void, and the "target" is of the same type as the adapter itself. &nbsp;The flyby adapter packages up the incoming argument lists into an ArgumentList object, and runs the probe. &nbsp;After the&nbsp;probe&nbsp;returns, control is transferred to the target.</div><div><br></div><div>The&nbsp;probe&nbsp;is free to side-effect ArgumentList object, though it cannot change the types of any arguments. &nbsp;Any changes made by the&nbsp;probe&nbsp;are seen by the target.</div><div><br></div><div>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. &nbsp;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.</div><div><br></div><div>Expressed using varargs, the flyby pattern looks something like this:</div><div><br></div><div>class FlyBy extends JavaMethodHandle {</div><div>&nbsp;&nbsp;final MethodHandle probe, target;</div><div>&nbsp;&nbsp;Object invoke(Object... argList) {</div><div>&nbsp;&nbsp; &nbsp;probe.&lt;void&gt;invoke(argList);</div><div>&nbsp;&nbsp; &nbsp;return MethodHandles.invoke(target, argList);</div><div>&nbsp;&nbsp;}</div><div>}</div><div><br></div><div><div>The opaque interface type ArgumentList provides access to the same information as a varargs Object[] array would, plus the static type of the arguments. &nbsp;In fact, some&nbsp;platforms (those with very good unboxing optimizations) may implement it on top of varargs arrays.</div><div><br></div><div>The interface type is a subtype of List, and provides additional accessors:</div><div>&nbsp;&nbsp;MethodType type()</div><div>&nbsp;&nbsp;Object get/setReference(i) &nbsp;// non-prims only</div><div>&nbsp;&nbsp;int get/setRawInt(i) &nbsp;// all prims except long, double</div><div>&nbsp;&nbsp;long get/setRawLong(i) &nbsp; // long, double prims</div><div><br></div><div>The List get/set accessors DTRT with respect to the static type, and bottom out in the above accessors.</div><div><br></div><div>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. &nbsp;The JVM takes care to null out the stack reference when the frame is taken down.</div><div><br></div><div>By using flyby adapters, we can write generic code that can process any argument list. &nbsp;We can do this without ever spinning bytecodes at runtime. &nbsp;This is why the current implementation throws NYI wherever bytecodes would have to be generated: &nbsp;If this works, I plan to use flybys instead of generated classes.</div><div><br></div><div>As noted above, flybys are probably most useful in conjunction with some argument adding and dropping. &nbsp;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.</div><div><br></div><div>Another useful transformation, probably, is dropping some of the original arguments just before calling the target (presumably they were only useful to the probe). &nbsp;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.</div><div><br></div><div>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. &nbsp;But it will guarantee that the call to the target is a tail call. &nbsp;This will provide a hook for building state machines and other low-level patterns.</div><div><br></div><div>Other adapters defined by JSR 292 which currently seem to need bytecode generation will be implemented on top of flybys. &nbsp;For example, collectArguments can be built on a flyby which performs all the boxing and stores it into a trailing argument.</div><div><br></div><div>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. &nbsp;The probe would in turn return a new value to be appended to the argument list. &nbsp;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. &nbsp;This suggests that flybys have two inherent degrees of freedom (beyond their method type): &nbsp;Whether the arguments are collected or not going into&nbsp;the probe, and whether a return value from the probe is inserted or not into the target arguments. &nbsp;The add-zero/drop degrees of freedom mentioned above are not inherent to the pattern.</div><div><br></div><div>One last point: &nbsp;A key motivation for flybys is running method handles on very small platforms where dynamic bytecode generation&nbsp;is&nbsp;difficult or impossible.</div><div><br></div><div>-- John</div><div><br></div></div></body></html>