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
_______________________________________________
mlvm-dev mailing list
mlvm-dev@openjdk.java.net
http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev

Reply via email to