As Published In
Oracle Magazine
May/June 2010

TECHNOLOGY: Java


Dynamic Language Support on the Java Virtual Machine

By Ed Ort and Janice J. Heiss

A new bytecode and a new linkage mechanism offer better support for dynamically typed languages.

Java Development Kit (JDK) 7 is a prototype of what could be in the next release of Java Platform, Standard Edition (Java SE). JDK 7 introduces several key features to improve the performance, usability, and security of the Java platform. Of particular interest to Java developers is the addition of support for Java Specification Request (JSR) 292. The addition of a new Java bytecode, invokedynamic, for method invocation, and an accompanying linkage mechanism that makes use of a new construct called a method handle, will enable implementers of compilers for dynamically typed languages such as JRuby and Jython to generate bytecode that runs extremely fast in the Java virtual machine (JVM).

As a result, you should see more of your favorite dynamically typed languages available in the Java ecosystem, along with a performance boost in code generated by dynamically typed language compilers that run in the JVM. This article will help you take advantage of the new invokedynamic Java bytecode instruction for the JVM and the new method handle linkage mechanism.

Dynamically Typed Languages and the JVM

If you said that the JVM is a program that executes Java programs translated into machine-independent bytecode, your statement would be correct but incomplete. The JVM does execute Java programs translated into bytecode, but it is not limited to handling translated Java programs. Increasingly, JVM implementations of dynamic languages are becoming available. These include JRuby, an implementation of the Ruby programming language; Jython, an implementation of the Python programming language; the Groovy scripting language; and Rhino, an implementation of JavaScript.

This is great news for application developers. The flexibility offered by dynamic languages, especially scripting languages, makes these languages particularly attractive for application prototyping and experimentation as well as for applications that evolve rapidly. This flexibility stems from dynamic typing. A language that is dynamically typed verifies at runtime that the values in an application conform to expected types. By comparison, a statically typed language such as the Java programming language does most of its type checking at compile time, checking the types of variables but not of values. The Java language also allows some dynamic type checking of values, especially receivers of virtual or interface method calls. But even these calls require a static type for the receiver.

It is easier to write code in dynamically typed languages than in statically typed languages, because the former have more-permissive type matching rules and can perform many type conversions automatically. Dynamic typing is also more flexible than static typing, because it enables programs to generate or configure types based on runtime data. These behaviors can help you create applications more quickly than you would when coding them in a statically typed language.

A Problem for Dynamically Typed Languages

The first step in bringing dynamic languages to the JVM was JSR 223: Scripting for the Java Platform, a specification that defined an API for accessing Java code from code written in dynamic scripting languages. JSR 223 also specified a framework for hosting scripting engines in Java applications. A scripting engine is a program that executes scripting code, either by compiling or interpreting it. This specification and its implementation made it much easier to create applications that include both Java code and scripting code. Although support for JSR 223 has stimulated the development of scripting engines for the JVM, developers of these scripting engines have faced a troublesome obstacle.

When developers write engines that compile dynamically typed languages to run in the JVM, they have to satisfy the requirements of the Java bytecode the JVM executes. Until now, that bytecode has been designed exclusively for statically typed languages, especially in its treatment of method invocation. This design has been a pain point for script engine developers generating bytecodes for method invocation.

Bytecode Requirements for Method Invocation

A statically typed language does its type checking before execution, at compile time. What this means for a method invocation is that the compiler, in addition to the bytecode it generates, needs to know the type of the value returned by the method as well as the types of any receiver or parameters specified in the call.

Consider the following Java code snippet:

 

 
   String s = “Hello World”;
   System.out.println(s);


Note that the type of parameter for the method is known. It’s a String. The println() method doesn’t return a value, but if the code example did call a method that does return a value, the type of the return value would need to be specified. The receiver of the call, System.out, also has a statically known type, java.io.PrintStream.

Armed with the needed type information, the javac compiler can generate the appropriate bytecode instructions:

 

 
ldc #2   
   // String “Hello World”
astore_1
getstatic #3 
   // Field System.out
aload_1
invokevirtual #4   
   // Method PrintStream.println


If you’re not familiar with bytecode, the important thing to understand is that a lot of the bytecode execution in the JVM involves operations on values in an operand stack. The operand stack is the virtual machine equivalent of the hardware registers in a real machine. Most of the bytecode instructs the JVM to push a value in a local value onto the operand stack, pop a value off the stack into a local variable, duplicate a value in the stack, swap values in the stack, or execute operations that produce or consume values on the stack.

For example, here’s a commented version of the bytecode:

 

 
ldc #2   
   // Push the String “Hello World”   
   onto the stack
astore_1     
   // Pop it and store it in local 
   variable #1
getstatic #3 
   // Push the static field System
   .out
aload_1 
   // Push the String referenced   
   from local variable #1
invokevirtual #4 
   // Pop the String and PrintStream, 
   call println. 


Clearly the invokevirtual bytecode instruction is different from the other bytecode instructions in the example. It invokes a method in addition to manipulating the operand stack. The full information for the invokevirtual bytecode instruction (noted in the code simply as #4) includes the method’s class, name, and signature, as follows:

• The receiver class providing the method: java.io.PrintStream
• The method name: println
• The number (1) and type (reference to String) of the method argument
• The method’s return type: V for void (that is, no return value is pushed onto the stack)

The signature is encoded as the constant string (Ljava/lang/String;)V, whose format describes the effects of the invocation on the operand stack.

In response to the invokevirtual bytecode instruction, the JVM looks for a method with the supplied name and signature—in this case, println:(Ljava/lang/String;)V in the java.io.PrintStream class. If the method isn’t in that class, the JVM will search up the chain of the class’ superclasses. Note that as a matter of static typing, the receiver class (PrintStream) must match the type of the operand pushed onto the stack (System.out). If the code had attempted to load any other kind of object for the receiver, the JVM would have rejected the code as unverifiable.

Awkward Attempts at Meeting Dynamic Requirements

Because dynamically typed languages don’t provide type information until runtime, implementers must try various approaches to meet the bytecode verification requirements for method invocation, none of which is optimal. For example, suppose the following code snippet exists in a hypothetical dynamically typed language:

 

function max (x,y) {
   if x.lessThan(y) then y else x
}


Note that no type is specified for the receiver or the arguments—after all, dynamically typed languages do not provide type information until runtime. As a result, the code does not meet the verification rules for method invocation, which require that types be known in advance. The code can’t be directly compiled into bytecode on the Java platform.

You might solve this problem by creating language-specific Java types for the return value and the method arguments, especially those that act as method call receivers. For example, a dynamically typed language implementation might change the previous code snippet to

 

MyObject function max 
   (MyObject x,MyObject y) {
   if x.lessThan(y) then y else x
}


The language-specific base type MyObject must contain the method isLessThan and any other methods a dynamic language might want to use, in order to meet the bytecode requirements for the method invocation.

You might also solve the problem of receiver typing through reflected invocation. This approach uses a java.lang.reflect.Method object to invoke the method. Using a Method object to do the method invocation circumvents having to directly invoke the method and, as a result, bypasses the requirement of having to specify the type of the returned value or the types of any parameters.

A third approach you might try is to avoid bytecode altogether and create a language-specific interpreter for method invocation to run on top of the JVM.

Let’s take a look at each option.

Creating a language-specific base type meets the requirements of the Java bytecode, but it is limited by the need to statically type each receiver to a prescribed base type. One problem with this technique is that a language implementer must think up a list of all methods in advance to put into the base type. Future methods, such as those defined by an end user, must be simulated less directly with a catchall method—often called invoke or apply. Also, JVM system types such as String and Integer cannot serve directly as receivers of language-specific method calls.

The reflected invocation approach has restrictions of its own. For example, a java.lang.reflect.Method object provides access to a method on a class or an interface—just what an implementer of a dynamic language needs—but the method must come from a specific Java type available at runtime. Although dynamic languages can provide type information at runtime, not all of them can provide normal Java types for reflection. This is particularly true for dynamic languages such as JRuby or Rhino, which have interpreters. This problem can be overcome if the language defines its own notion of method (a “RubyMethod,” say), but then another problem arises: simulation overhead. The JVM’s native calling sequence (which, as we saw, uses an operand stack) must be simulated by a slow and clumsy alternative such as explicit argument arrays. In the end, the simulation overheads inherent in reflected method objects slow down dynamic code at every language-specific method call.

Finally, running an interpreter on top of the JVM to handle method invocations is relatively slow, certainly slower than having the JVM directly handle the processing.

JSR 292: The Next Step in Dynamic Language Support

JSR 292 aims to solve the problems inherent in trying to fit a square peg (method invocation in a dynamically typed language) into a round hole (the statically based Java bytecode requirements). It does this by introducing the new invokedynamic Java bytecode instruction for the JVM and the new method handle linkage mechanism.

Bytecode Instructions for Method Invocation

Since its inception, the JVM specification has specified four bytecodes for method invocation:

• invokevirtual. Invokes a method on a class. This is the typical type of method invocation.
• invokeinterface. Similar to invokevirtual but invokes a method on an interface.
• invokestatic. Invokes a static method on a class. This is the only kind of invocation that lacks a receiver argument.
• invokespecial. Invokes a method without reference to the type of the receiver. (This kind of invocation is restricted to constructors, superclass methods, or private methods.)

Let’s examine two of these bytecodes: invokevirtual, because it’s the most typical type of method invocation, and invokeinterface, because it’s similar in format to the new invokedynamic instruction.

The invokevirtual instruction. Recall the invokevirtual bytecode instruction that was shown in the earlier bytecode example. Here it is again, with a slightly more detailed presentation:

 

invokevirtual #4 
   //Method java/io/PrintStream
   .println:(Ljava/lang/String;)V


The invokevirtual part of the instruction is the 1-byte operation code. The remainder of the instruction, #4, is the 2-byte operand, which provides information about the method call in an abstract way. The operand refers to an entry in a pool of constants, the structure of which need not concern us here. The entry contains a symbolic reference that bundles together information pertinent to the method invocation. The information includes the receiver class that contains the method, the method name, and the method signature. The method signature specifies the method’s return type and the types of its arguments.

Thus, the syntax of the invokevirtual bytecode instruction consists of an opcode and a constant pool index as follows:

 

invokevirtual <method-specification>


The invokeinterface instruction. An invokeinterface bytecode instruction for a Java program might look like this:

 

invokeinterface #9, 2 
   //InterfaceMethod java/util/
   List.add:(Ljava/lang/Object;)Z


The syntax for the invokeinterface bytecode instruction is as follows:

 

invokeinterface <method-
   specification> <n>


Just as with invokevirtual, the <method-specification> is a 2-byte constant pool index specifying an interface name, a method name, and a signature. Also, <n> is a 2-byte operand that specifies the number of arguments.

As is the case for invokevirtual, the signature specifies the method’s argument types as well as the method’s return type. In this example, the <method-specification> specifies that the interface is java.util.List and the method is add. The type signature specifies that the method takes arguments of type java.lang.Object, represented by Ljava/lang/Object, and returns a Boolean result, represented by the Z code.

The <n> value in the example is 2, indicating that the method takes two arguments, including the receiver. This extra count could be determined from the signature.

The invokedynamic instruction. The syntax of the new invokedynamic bytecode instruction is similar to that of the invokeinterface instruction.

 

invokedynamic <method-specification>
   <n>


However, unlike the invokeinterface instruction, the <method-specification> needs to specify only a method name and a signature. There is no mention of a receiver class. In this case, the 2-byte number <n> must be 0. Some JVMs may use this internally to link the instruction to runtime structures.

An invokedynamic bytecode instruction might look like this:

 

invokedynamic #10 
   //NameAndType lessThan:
   (Ljava/lang/Object;Ljava/lang/
   Object;)Z


Significantly, the invokedynamic bytecode instruction enables an implementer of a dynamic language to translate a method invocation into bytecode without having to specify a target type that contains the method. The method specification in this case is a simplified constant pool reference that specifies only a method name and a type signature. The signature specifies the return type of the call and the types of method arguments. As with invokestatic, none of the arguments is singled out as a receiver.

But wait. How does the JVM find the method if the receiver type isn’t supplied? After all, the JVM needs to link to and invoke a real method on a real type. The answer to that question is that JSR 292 also includes a new linkage mechanism for dynamically typed languages. When the JVM sees an invokedynamic instruction, it uses this new linkage mechanism to get to the method it needs. This mechanism works through what are called method handles.

A New Dynamic Linkage Mechanism: Method Handles

JDK 7 includes a new package, java.dyn, that contains the classes associated with dynamic language support in the Java platform. One of the classes in the package is MethodHandle. A method handle is a simple object of type java.dyn.MethodHandle that anonymously encapsulates a reference to a JVM method. A method handle is callable, just like a named reference to a method. Like regular methods, method handles are typed, so there is no possibility of popping the wrong number or wrong types of arguments from the operand stack.

Method handles are unique because they are accessed via a pointer structure rather than via a linked name. And unlike reflective methods (which are also anonymous encapsulations of Java methods), method handles can be “bound” to language-specific data. (The details of the binding process, called “partial application,” are explained in the technical paper cited at the end of this article.) The point here is that method handles are designed to provide a flexible way to answer the question, “What does my invokedynamic instruction actually invoke?”

As with the other invoke instructions, the first time an invokedynamic instruction is executed, it is linked. When this linking happens, a method handle is assigned to the individual invokedynamic instruction as its particular target. Each time that particular instruction is executed, the JVM invokes the target method handle. Interestingly, the target of any given invokedynamic instruction can change over time in response to changes in the dynamic language program.

Another part of this new linkage mechanism is the bootstrap method. A bootstrap method is a method handle that is called once for each invokedynamic instruction when the instruction is linked. The bootstrap method specifies which target method to assign initially to the instruction. Each class that contains at least one invokedynamic instruction must also specify a bootstrap method.

Next Steps


READ more about
support for dynamically typed languages in Java SE 7
the technical theory behind invokedynamic
the JDK 7 release
the JDK 7 project
JSR 292: Supporting Dynamically Typed Languages on the Java Platform



 LEARN about
the Da Vinci Machine Project



 WATCH
The TechCast Show: Mark Reinhold’s JDK 7 Roundup



 DOWNLOAD
the JDK 7 Early Access

The bootstrap mechanism provides a way for a language runtime to participate in method dispatching at runtime, but the approach also enables the JVM to bypass the language runtime if the method dispatch decision doesn’t change. When the JVM must link an invokedynamic instruction, it calls a bootstrap method. A call into a language-supplied method like this is termed an up-call, but normally a linked invokedynamic instruction performs no up-call but, rather, directly invokes the instruction’s own target method.

A method handle is quite simple. All it contains is a type token of class java.dyn.MethodType that describes a specific type, corresponding to the fixed type signatures of the invoke instructions. (Naturally, the target of an invokedynamic instruction must agree exactly with the static signature of the instruction itself.) Also, a method handle implicitly has invocation methods associated with it. To call a method handle, you call its invocation method in much the same way as you call object methods such as List.add. In this case, the call is always of the form MethodHandle.invokeExact(. . .), where the signature is arbitrary but must always match the called method handle’s own type.

Because each method handle has its own type, it will accept only an invoke call of that type. If the type of the call doesn’t match the type of the method handle, the method handle will throw an exception. There is also a method called invokeGeneric, which instructs the JVM to attempt minor argument conversions such as casting and boxing.

Here, for example, is a snippet of bytecode that calls a method handle:

 

getfield #678 
   //MyClass.myMH
ldc #999 
   //123456
invokevirtual #44 
   //Method java/dyn/
   MethodHandle.invokeExact(I)I
   istore 5


In this example, the call is to a method handle named myMH with a single int argument. The call also expects an int type to be returned. The method handle has to accept that signature type. Before allowing the call, the JVM will verify (each time) that the method handle includes a type token that matches the call’s signature—in this case, (I)I. In response, the method handle directs the JVM to the appropriate target function. Method handles are unique in that they appear to contain an infinite number of methods named invokeExact, one such method for each possible signature. But any given individual method handle can only respond to exactly one such method call, which matches its own method type. This feature is called “signature polymorphism.”

An Easier Life for Java Developers

Over the years, the JVM has been host to a growing number of languages, including implementations of dynamically typed languages such as Ruby and Python. Support for dynamically typed languages in the JVM is very attractive to application developers who build applications in these languages. That’s because dynamic typing gives developers a lot of flexibility and the JVM delivers a lot of execution efficiency. However, implementers of compilers for dynamically typed languages have found it difficult to meet the JVM bytecode requirements for method invocation. JSR 292 addresses that problem by providing a new bytecode, invokedynamic, and a new linkage mechanism based on method handles. It is one of several revisions to the Java SE platform that can make your life as a Java developer easier. 


Ed Ort is a former Sun staff writer. Janice J. Heiss is a Java acquisitions editor at Oracle.

Send us your comments