Invokedynamic Deep Dive -W-

From JVMLangSummit
Jump to navigationJump to search

Issue: Invocation Modes

Shall MethodHandle support (a) an exactly typed invocation mode, (b) a freely converting invocation mode, or (c) both? (Default answer: (c).)


(a) Power users want exact mode so they can know that they are getting full optimization. (b) Most use cases, however, can benefit from generic invocation (MHs.convertArguments conversions) and tolerate the modest performance hit.

Current RI state:

We have MH.invoke as exact invocation, and MHs.invoke as generic. Note that the first is virtual and the second is static. The second has no signature specialization magic.

Desired Specification:

(As arrived at in the mlvm workshop yesterday.)

Two virtual-final methods: MH.invokeExact, MH.invokeGeneric. Both have special Java language support. Also add (non-magic) MH.invokeVarargs, for symmetry (was a static in MHs). Retire the name MH.invoke (reserve for future use, in case we ever get closures and/or a better exception story).

// Example code
abstract class MethodHandle {
    final MethodType type();  //pre-existing
    //@PolymorphicSignature <R,A> final R invoke(A... args);  // no longer present

    // JVM-specific invokers, a minimal but complete kit:
    @PolymorphicSignature <R,A> final R invokeExact(A... args) throws Throwable;
    @PolymorphicSignature <R,A> final R invokeGeneric(A... args) throws Throwable;
    abstract  Object invokeVarargs(Object/*...*/ x, Object... va) throws Throwable;

Also, probably: Add a couple more virtual methods to MH to make MH a "microkernel" type, from which (in principle) all other statics in MHs may be derived. (Though Hotspot probably won't do this.) As Fredrik Öhrström points out, spread, collect, and argument binding combinators are enough. With these, you can always (a) capture an arbitrary (wild) incoming argument list into a Object array, then (b) pass that in a pre-bound virtual call to an argument processor object of your choice, and finally (c) re-spread the argument list to another arbitrary outgoing argument list. This assumes certain JVM optimizations on varargs processing.

// Example code
abstract class MethodHandle {
    // And maybe, for a microkernel:
    abstract MethodHandle insertArgument(Object x);
    // And then, to complete the microkernel:
    abstract MethodHandle collectArguments(MethodType newType);
    abstract MethodHandle spreadArguments(MethodType newType);

Issue: Self-Bound Method Handles

The abstract super-class JavaMethodHandle lets you derive user-defined method handle types, as local and even anonymous inner classes.

This is easy to do given bound method handles, and they have proven extremely useful in practice.

Example: Look at the source for GuardWithTest in the Hotspot ref. impl. of JSR 292.

Hazard: Making these guys inlinable requires that the JVM inline target MH references through final non-static fields in the JMHs. (The Hotspot JVM does something like this already.)

Alternative: Wire things up using nameless combinators from MethodHandles; see current JRuby code.

Question: Are there plausible uses of method handle subtypes (not just class-based implementations)? E.g., a "settable method handle":

interface GetterSetter {
  MethodHandle getter();
  MethodHandle setter();
abstract class SettableMethodHandle extends JavaMethodHandle implements GetterSetter {
  MethodHandle getter() { return this; }