Java News from Tuesday, May 20, 2008

Sun has posted the early draft review of JSR-292, Supporting Dynamically Typed Languages on the Java™ Platform, to the Java Community Process. According to the JSR,

This design introduces an invokedynamic instruction. Syntactically, it is a variation of the invokeinterface instruction. It carries a symbolic method name and just enough type information to accurately type the arguments on the JVM stack. It makes no requirements on its receiver argument, except that it be a non-null object reference. The machine-level semantics of this instruction are minimized, in that they defer as many decisions as possible to up-calls implemented in ordinary bytecodes.

In particular, the process of linking an invokedynamic instruction is completely defined by software, above the level of the JVM. Linking possibly includes decisions which take receiver or argument types into account, before deciding the outcome of an invocation. These decisions can possibly depend on changing method definitions and argument types, which means that linking is an ongoing process.

The linkage state of an invokedynamic instruction is an object called a target method (represented as a method handle, as defined below); it can also be the null reference. This linkage state starts out null and can be updated by the application.

Every call to an invokedynamic instruction directly invokes the call site&rquo;s target method, if it is not null. This target method can (in principle) be any method whose incoming argument types match the outgoing argument types from the invokedynamic instruction, and whose return type likewise matches the invocation. The method can be static or non-static (virtual or final), and can (in principle) be defined in any class. The dynamic language runtime can easily wrap adapter code around target methods to create new target methods to manage argument type mismatches and meet other requirements.

The first time an invokedynamic instruction is run, or whenever the target method is null, the JVM makes an up-call to a compiler-supplied routine called the bootstrap method. The bootstrap method receives the arguments to the call site. The arguments are boxed, varargs style, into an object array.

The bootstrap method also receives a reference to a CallSite object which reifies the particular invokedynamic instruction. The CallSite object reports static information about the call, including the method name and descriptor. It also provides a method for updating the target method of the call site. Because this object reference is specific to the call site but not to the current call, the dynamic language can save it away, or it can use it once and discard it.

The bootstrap method must execute the call directly. Optionally, it may install a target method for the call site to use next time. Whenever a non-null target method is installed, the application has (in effect) dynamically linked the call site to the desired target method.

The target method (or if there is none, the bootstrap method) is responsible for fulfilling the language-specific semantics of the call site. If the compiler of the call site requires dynamic typing, it must install any type specific target method (or methods) in a suitable adapter which will check argument types, maintain appropriate type history (if needed), invoke the type specific method, and perform relinking or error processing if an unexpected type is seen.

Here is a pseudo-code example, of the logic for dynamically invoking the name alpha on an untyped receiver, with two additional arguments (untyped reference and 32-bit integer):

// Running example of invokedynamic call site
class MyCaller {
    private static final CallSite site1 = (...);
    private static final MethodHandle bootstrapMethod = (...);
    Object myMethod(Object x, Object y, int z) {
        // x . invokedynamic["alpha",(Object,int)Object] (y, z)
        MethodHandle method1 = site1.target;
        if (method1 == null)
            return bootstrapMethod.invoke(site1, x, y, z);
   	return method1.invoke(x, y, z);
    }
}

A key feature of this design is that it does not distinguish between linking and execution phases of a call site. Linking (i.e., introduction of new target methods) is expected to be rare, but any method call has the potential to lead to further linking or unlinking activity, if the original call to the bootstrap method preserves the call site’s static context. This is appropriate to dynamically typed languages, since dynamic call linkage is always provisional.

Another key feature is that arbitrary methods can be target methods, and method calling sequences are the same as with the other call instructions (like invokevirtual), etc. This makes it easy for dynamic languages to link to static languages (like Java), and allows JVM optimizations (such as inlining) on standard invocation instructions to apply to the new instruction also. There is no need to package code in a particular type hierarchy (e.g., =java.util.concurrent.Callable=), or in a limited range of argument types (as with =java.lang.reflect.Method=). Put another way, this design is polymorphic across all method descriptors, and interoperates with method everywhere. This polymorphism is reflected in the API for method handles, which, though not completely orthogonal to the Java type system, strike a new angle relative to it.

This specification defines a number of details:

Other important questions deserve detailed treatment elsewhere, but cannot be specified here:

Extra-special kudos to the working groups for publishing the draft in HTML instead of pDF, even if they still make you click through an annoying, pointless license agreement t and download a zip file to read it.