Invokedynamic 101

how-to
Dec 16, 201423 mins

Oracle’s Java 7 release introduced a new invokedynamic bytecode instruction to the Java Virtual Machine (JVM) and a new java.lang.invoke API package to the standard class library. This post introduces you to this instruction and API.

The what and how of invokedynamic

Q: What is invokedynamic?

A: invokedynamic is a bytecode instruction that facilitates the implementation of dynamic languages (for the JVM) through dynamic method invocation. This instruction is described in the Java SE 7 Edition of the JVM Specification.

Q: How does invokedynamic facilitate dynamic language implementation?

A: In a dynamic language, type-checking typically occurs at runtime. Developers must pass appropriate types or risk runtime failures. It’s often the case that java.lang.Object is the most accurate type for a method argument. This situation complicates type checking, which impacts performance.

Another challenge is that dynamic languages typically offer the capability to add fields/methods to and remove them from existing classes. As a result, it’s necessary to defer class, method, and field resolution to runtime. Also, it’s often necessary to adapt a method invocation to a target that has a different signature.

These challenges have traditionally required ad hoc runtime support to be built on top of the JVM. This support includes wrapper type classes, using hash tables to provide dynamic symbol resolution, and so on. Bytecode is generated with entry points to the runtime in the form of method calls using any of the four method-invocation instructions:

  • invokestatic is used to invoke static methods.
  • invokevirtual is used to invoke public and protected non-static methods via dynamic dispatch.
  • invokeinterface is similar to invokevirtual except for the method dispatch being based on an interface type.
  • invokespecial is used to invoke instance initialization methods (constructors) as well as private methods and methods of a superclass of the current class.

This runtime support affects performance. Generated bytecode often requires several actual JVM method invocations for one dynamic language method invocation. Reflection is widely used and contributes to performance degradation. Also, the many different execution paths make it impossible for the JVM’s just-in-time (JIT) compiler to apply optimizations.

To address poor performance, the invokedynamic instruction does away with ad hoc runtime support. Instead, the first call bootstraps by invoking runtime logic that efficiently selects a target method, and subsequent calls typically invoke the target method without having to re-bootstrap.

invokedynamic also benefits dynamic language implementers by supporting dynamically changing call site targets — a call site, more specifically, a dynamic call site is an invokedynamic instruction. Furthermore, because the JVM internally supports invokedynamic, this instruction can be better optimized by the JIT compiler.

Method handles

Q: I understand that invokedynamic works with method handles to facilitate dynamic method invocation. What is a method handle?

A: A method handle is “a typed, directly executable reference to an underlying method, constructor, field, or similar low-level operation, with optional transformations of arguments or return values.” In other words, it’s similar to a C-style function pointer that points to executable code — a target — and which can be dereferenced to invoke this code. Method handles are described by the abstract java.lang.invoke.MethodHandle class.

Q: Can you provide a simple example of method handle creation and invocation?

A: Check out Listing 1.

Listing 1. MHD.java (version 1)

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;

public class MHD
{
   public static void main(String[] args) throws Throwable
   {
      MethodHandles.Lookup lookup = MethodHandles.lookup();
      MethodHandle mh = lookup.findStatic(MHD.class, "hello",
                                          MethodType.methodType(void.class));
      mh.invokeExact();
   }

   static void hello()
   {
      System.out.println("hello");
   }
}

Listing 1 describes a method handle demonstration program consisting of main() and hello() class methods. This program’s goal is to invoke hello() via a method handle.

main()‘s first task is to obtain a java.lang.invoke.MethodHandles.Lookup object. This object is a factory for creating method handles and is used to search for targets such as virtual methods, static methods, special methods, constructors, and field accessors. Furthermore, it’s dependent on a call site’s invocation context and enforces method handle access restrictions each time a method handle is created. In other words, a call site (such as Listing 1’s main() method acting as a call site) that obtains a lookup object can only access those targets that are accessible to the call site. The lookup object is obtained by invoking the java.lang.invoke.MethodHandles class’s MethodHandles.Lookup lookup() method.

After obtaining the lookup object, this object’s MethodHandle findStatic(Class<?> refc, String name, MethodType type) method is called to obtain a method handle to the hello() method. The first argument passed to findStatic() is a reference to the class (MHD) from which the method (hello()) is accessed, and the second argument is the method’s name. The third argument is an example of a method type, which “represents the arguments and return type accepted and returned by a method handle, or the arguments and return type passed and expected by a method handle caller.” It’s represented by an instance of the java.lang.invoke.MethodType class, and obtained (in this example) by calling java.lang.invoke.MethodType‘s MethodType methodType(Class<?> rtype) method. This method is called because hello() only provides a return type, which happens to be void. This return type is made available to methodType() by passing void.class to this method.

The returned method handle is assigned to mh. This object is then used to call MethodHandle‘s Object invokeExact(Object... args) method, to invoke the method handle. In other words, invokeExact() results in hello() being called, and hello being written to the standard output stream. Because invokeExact() is declared to throw Throwable, I’ve appended throws Throwable to the main() method header.

Q: In your previous answer, you mentioned that the lookup object can only access those targets that are accessible to the call site. Can you provide an example that demonstrates trying to obtain a method handle to an inaccessible target?

A: Check out Listing 2.

Listing 2. MHD.java (version 2)

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;

class HW
{
   public void hello1()
   {
      System.out.println("hello from hello1");
   }

   private void hello2()
   {
      System.out.println("hello from hello2");
   }
}

public class MHD
{
   public static void main(String[] args) throws Throwable
   {
      HW hw = new HW();
      MethodHandles.Lookup lookup = MethodHandles.lookup();
      MethodHandle mh = lookup.findVirtual(HW.class, "hello1",
                                           MethodType.methodType(void.class));
      mh.invoke(hw);
      mh = lookup.findVirtual(HW.class, "hello2",
                              MethodType.methodType(void.class));
   }
}

Listing 2 declares HW (Hello, World) and MHD classes. HW declares a public hello1() instance method and a private hello2() instance method. MHD declares a main() method that will attempt to invoke these methods.

main()‘s first task is to instantiate HW in preparation for invoking hello1() and hello2(). Next, it obtains a lookup object and uses this object to obtain a method handle for invoking hello1(). This time, MethodHandles.Lookup‘s findVirtual() method is called and the first argument passed to this method is a Class object describing the HW class.

It turns out that findVirtual() will succeed, and the subsequent mh.invoke(hw); expression will invoke hello1(), resulting in hello from hello1 being output.

Because hello1() is public, it’s accessible to the main() method call site. In contrast, hello2() isn’t accessible. As a result, the second findVirtual() invocation will fail with an IllegalAccessException.

When you run this application, you should observe the following output:

hello from hello1
Exception in thread "main" java.lang.IllegalAccessException: member is private: HW.hello2()void, from MHD
	at java.lang.invoke.MemberName.makeAccessException(MemberName.java:507)
	at java.lang.invoke.MethodHandles$Lookup.checkAccess(MethodHandles.java:1172)
	at java.lang.invoke.MethodHandles$Lookup.checkMethod(MethodHandles.java:1152)
	at java.lang.invoke.MethodHandles$Lookup.accessVirtual(MethodHandles.java:648)
	at java.lang.invoke.MethodHandles$Lookup.findVirtual(MethodHandles.java:641)
	at MHD.main(MHD.java:27)

Q: Listings 1 and 2 use the invokeExact() and invoke() methods to execute a method handle. What’s the difference between these methods?

A: Although invokeExact() and invoke() are designed to execute a method handle (actually, the target code to which the method handle refers), they differ when it comes to performing type conversions on arguments and the return value. invokeExact() doesn’t perform automatic compatible-type conversion on arguments. Its arguments (or argument expressions) must be an exact type match to the method signature, with each argument provided separately, or all arguments provided together as an array. invoke() requires its arguments (or argument expressions) to be a type-compatible match to the method signature — automatic type conversions are performed, with each argument provided separately, or all arguments provided together as an array.

Q: Can you provide me with an example that shows how to invoke an instance field’s getter and setter?

A: Check out Listing 3.

Listing 3. MHD.java (version 3)

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;

class Point
{
   int x;
   int y;
}

public class MHD
{
   public static void main(String[] args) throws Throwable
   {
      MethodHandles.Lookup lookup = MethodHandles.lookup();

      Point point = new Point();

      // Set the x and y fields.

      MethodHandle mh = lookup.findSetter(Point.class, "x", 
                                          int.class);
      mh.invoke(point, 15);

      mh = lookup.findSetter(Point.class, "y", int.class);
      mh.invoke(point, 30);

      mh = lookup.findGetter(Point.class, "x", int.class);
      int x = (int) mh.invoke(point);
      System.out.printf("x = %d%n", x);

      mh = lookup.findGetter(Point.class, "y", int.class);
      int y = (int) mh.invoke(point);
      System.out.printf("y = %d%n", y);
   }
}

Listing 3 introduces a Point class with a pair of 32-bit integer instance fields named x and y. Each field’s setter and getter is accessed by calling MethodHandles.Lookup‘s findSetter() and findGetter() methods, and the resulting MethodHandle is returned. Each of findSetter() and findGetter() requires a Class argument that identifies the field’s class, the field’s name, and a Class object that identifies the field’s signature.

The invoke() method is used to execute a setter or getter– behind the scenes, the instance fields are accessed via the JVM’s putfield and getfield instructions. This method requires that a reference to the object whose field is being accessed be passed as the initial argument. For setter invocations, a second argument, consisting of the value being assigned to the field, also must be passed.

When you run this application, you should observe the following output:

x = 15
y = 30

Q: Your definition of method handle includes the phrase “with optional transformations of arguments or return values”. Can you provide an example of argument transformation?

A: I’ve created an example based on the Math class’s double pow(double a, double b) class method. In this example, I obtain a method handle to the pow() method, and transform this method handle so that the second argument passed to pow() is always 10. Check out Listing 4.

Listing 4. MHD.java (version 4)

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;

public class MHD
{
   public static void main(String[] args) throws Throwable
   {
      MethodHandles.Lookup lookup = MethodHandles.lookup();
      MethodHandle mh = lookup.findStatic(Math.class, "pow",
                                          MethodType.methodType(double.class,
                                                                double.class,
                                                                double.class));
      mh = MethodHandles.insertArguments(mh, 1, 10);
      System.out.printf("2^10 = %d%n", (int) (double) mh.invoke(2.0));
   }
}

Listing 4 uses a combinator (a method that combines or transforms a pre-existing method handle into a new method handle) to modify the method handle to the pow() method. In this case, the combinator is MethodHandles‘s MethodHandle insertArguments(MethodHandle target, int pos, Object... values) method, which inserts a bound argument (10) into the pre-existing method handle. When invoke() (or invokeExact()) is subsequently called on the new method handle, only a single argument is required.

Notice the double cast — (int) (double). invoke()‘s return value must be cast to double type to be compatible with the previously specified method type when the method handle was obtained (via the findStatic() method call). Because System.out.printf() requires an int value (because of %d), the double value must be cast to int.

Compile Listing 4 (javac MHD.java) and run the application (java MHD). You should observe the following output:

2^10 = 1024

Bootstrapping

Q: I understand that executing an invokedynamic instruction results in the execution of a method handle, which may be a chain of combinators. How does invokedynamic know which method handle to execute?

A: At runtime, an invokedynamic call site is bound to a method handle by way of a bootstrap method. This method is executed the first time the JVM encounters this call site during execution.

Q: How does invokedynamic locate the bootstrap method?

A: The invokedynamic instruction is followed by an operand that serves as an index into the classfile’s constant pool. The value in the constant pool at this index is a CONSTANT_InvokeDynamic structure. This structure includes an index into the classfile’s BootstrapMethods attribute, which ultimately identifies the bootstrap method.

Q: What does the bootstrap method header look like?

A: A typical bootstrap header appears below:

public static CallSite bootstrap(Lookup lookup, String name, MethodType type)
   throws Throwable

The JVM invokes this method with the following arguments:

  • lookup: this lookup object is bound to those classes that are visible in the context of the call site (the invokedynamic instruction)
  • name: the (typically fictitious) name of a method to invoke — the bootstrap method determines the identity of the method handle being invoked
  • type: the type of the method being invoked, and which is expected by the call site

The bootstrap method can be called with up to an additional 251 static arguments taken from the constant pool. Also, it’s declared to throw a Throwable instance.

The bootstrap method returns a java.lang.invoke.CallSite subclass instance. The type of the call site’s target must be exactly equal to the type derived from the call site’s type, which is passed to the bootstrap method as the type argument. The CallSite instance is said to contain the method handle and becomes permanently linked to the call site (the invokedynamic instruction). Although the CallSite instance refers to the same program location (invokedynamic instruction) throughout its lifetime, it may allow its target method handle to be redefined, which lets you replace code during execution.

Q: Can you provide an example of a bootstrap method?

A: Check out Listing 5.

Listing 5. IDDL.java

import java.lang.invoke.CallSite;
import java.lang.invoke.ConstantCallSite;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;

public class IDDL
{
   private static MethodHandle hw;

   private static void hw() 
   {
      System.out.println("Hello, World!");
   }

   public static CallSite bootstrapDynamic(MethodHandles.Lookup caller, 
                                           String name, 
                                           MethodType type)
      throws IllegalAccessException, NoSuchMethodException
   {
      MethodHandles.Lookup lookup = MethodHandles.lookup();
      Class thisClass = lookup.lookupClass();
      hw = lookup.findStatic(thisClass, "hw", 
                             MethodType.methodType(void.class));
      if (!type.equals(hw.type()))
         hw = hw.asType(type);

      return new ConstantCallSite(hw);
   }
}

Listing 5 identifies an IDDL (InvokeDynamic Demo Linkage) class that reveals a target hw() method, and a bootstrapDynamic() method that creates a method handle to hw() and returns a java.lang.ConstantCallSite that wraps this method handle.

bootstrapDynamic() reveals that the bootstrap’s method name is changeable. It also shows that instead of specifying throws Throwable, you can list the exact exceptions being thrown via the throws clause.

The caller lookup object isn’t used by this bootstrap method because that object refers to the class in which the invokedynamic call occurs — you’ll see this class later. Instead, we need a lookup object that can find hw() in the IDDL class, which is the reason for MethodHandles.lookup().

MethodHandles.Lookup declares a Class<?> lookupClass() method that identifies the class performing the lookup. I pass this method’s return value to findStatic() as its first argument. Note that I could have passed IDDL.class instead (because IDDL.class is the Class object returned from lookupClass()), but chose to pass lookupClass()‘s return value to show more of the API.

findStatic() is also passed hw as the target method name and MethodType.methodType(void.class) to signify that this method has a void return type and no parameters.

It’s important that the method handle’s type match the call site’s expected type, and this is especially true when combinators are used. Essentially, you compare the type parameter value with the method handle’s type, which is obtained by invoking MethodHandle‘s MethodType type() method. If they differ, you invoke MethodHandle‘s MethodHandle asType(MethodType newType) method with the expected type (the type parameter value). This method returns an adapter method handle that adapts the type of the current method handle to the type passed to asType().

Finally, you must return an appropriate CallSite instance that wraps the target method handle. Because CallSite is abstract, you would use one of its subclasses, such as java.lang.invoke.ConstantCallSite, which is a CallSite whose target never changes.

Q: I would like to play with IDDL. Can you provide a class with an invokedynamic instruction that calls bootstrapDynamic()?

A: I’ve created an IDD (InvokeDynamic Demo) class whose main() method executes the invokedynamic instruction. Furthermore, this instruction links to IDDL‘s bootstrapDynamic() method.

Because the Java 7 compiler doesn’t emit the invokedynamic instruction, IDD must be created programmatically. One way to accomplish this task is to use a bytecode manipulation framework, such as ASM, to create an application that generates IDD.class. Alternatively, you could use Listing 6.

Listing 6. IDDG.java

import java.io.FileOutputStream;
import java.io.IOException;

public class IDDG // InvokeDynamic Demo Generator
{
   static short[] _bytes =
   {
      0xCA, 0xFE, 0xBA, 0xBE, 0x00, 0x00, 0x00, 0x33,
      0x00, 0x17, 0x01, 0x00, 0x03, 0x49, 0x44, 0x44,
      0x07, 0x00, 0x01, 0x01, 0x00, 0x10, 0x6A, 0x61,
      0x76, 0x61, 0x2F, 0x6C, 0x61, 0x6E, 0x67, 0x2F,
      0x4F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x07, 0x00,
      0x03, 0x01, 0x00, 0x06, 0x3C, 0x69, 0x6E, 0x69,
      0x74, 0x3E, 0x01, 0x00, 0x03, 0x28, 0x29, 0x56,
      0x0C, 0x00, 0x05, 0x00, 0x06, 0x0A, 0x00, 0x04,
      0x00, 0x07, 0x01, 0x00, 0x04, 0x6D, 0x61, 0x69,
      0x6E, 0x01, 0x00, 0x16, 0x28, 0x5B, 0x4C, 0x6A,
      0x61, 0x76, 0x61, 0x2F, 0x6C, 0x61, 0x6E, 0x67,
      0x2F, 0x53, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x3B,
      0x29, 0x56, 0x01, 0x00, 0x04, 0x49, 0x44, 0x44,
      0x4C, 0x07, 0x00, 0x0B, 0x01, 0x00, 0x10, 0x62,
      0x6F, 0x6F, 0x74, 0x73, 0x74, 0x72, 0x61, 0x70,
      0x44, 0x79, 0x6E, 0x61, 0x6D, 0x69, 0x63, 0x01,
      0x00, 0x73, 0x28, 0x4C, 0x6A, 0x61, 0x76, 0x61,
      0x2F, 0x6C, 0x61, 0x6E, 0x67, 0x2F, 0x69, 0x6E,
      0x76, 0x6F, 0x6B, 0x65, 0x2F, 0x4D, 0x65, 0x74,
      0x68, 0x6F, 0x64, 0x48, 0x61, 0x6E, 0x64, 0x6C,
      0x65, 0x73, 0x24, 0x4C, 0x6F, 0x6F, 0x6B, 0x75,
      0x70, 0x3B, 0x4C, 0x6A, 0x61, 0x76, 0x61, 0x2F,
      0x6C, 0x61, 0x6E, 0x67, 0x2F, 0x53, 0x74, 0x72,
      0x69, 0x6E, 0x67, 0x3B, 0x4C, 0x6A, 0x61, 0x76,
      0x61, 0x2F, 0x6C, 0x61, 0x6E, 0x67, 0x2F, 0x69,
      0x6E, 0x76, 0x6F, 0x6B, 0x65, 0x2F, 0x4D, 0x65,
      0x74, 0x68, 0x6F, 0x64, 0x54, 0x79, 0x70, 0x65,
      0x3B, 0x29, 0x4C, 0x6A, 0x61, 0x76, 0x61, 0x2F,
      0x6C, 0x61, 0x6E, 0x67, 0x2F, 0x69, 0x6E, 0x76,
      0x6F, 0x6B, 0x65, 0x2F, 0x43, 0x61, 0x6C, 0x6C,
      0x53, 0x69, 0x74, 0x65, 0x3B, 0x0C, 0x00, 0x0D,
      0x00, 0x0E, 0x0A, 0x00, 0x0C, 0x00, 0x0F, 0x0F,
      0x06, 0x00, 0x10, 0x01, 0x00, 0x03, 0x66, 0x6F,
      0x6F, 0x0C, 0x00, 0x12, 0x00, 0x06, 0x12, 0x00,
      0x00, 0x00, 0x13, 0x01, 0x00, 0x04, 0x43, 0x6F,
      0x64, 0x65, 0x01, 0x00, 0x10, 0x42, 0x6F, 0x6F,
      0x74, 0x73, 0x74, 0x72, 0x61, 0x70, 0x4D, 0x65,
      0x74, 0x68, 0x6F, 0x64, 0x73, 0x00, 0x21, 0x00,
      0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x02, 0x00, 0x01, 0x00, 0x05, 0x00, 0x06, 0x00,
      0x01, 0x00, 0x15, 0x00, 0x00, 0x00, 0x11, 0x00,
      0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x2A,
      0xB7, 0x00, 0x08, 0xB1, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x09, 0x00, 0x09, 0x00, 0x0A, 0x00, 0x01,
      0x00, 0x15, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00,
      0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0xBA, 0x00,
      0x14, 0x00, 0x00, 0xB1, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x01, 0x00, 0x16, 0x00, 0x00, 0x00, 0x06,
      0x00, 0x01, 0x00, 0x11, 0x00, 0x00
   };

   public static void main(String[] args)
   {
      try (FileOutputStream fos = new FileOutputStream("IDD.class"))
      {
         for (short _byte: _bytes)
            fos.write(_byte);
      }
      catch (IOException ioe)
      {
         ioe.printStackTrace();
      }
   }
}

Listing 6 presents the source code to a simple application that generates IDD.class. Compile the source code (javac IDDG.java) and run IDDG.class (java IDDG). You should observe an IDD.class file in the current directory.

You can explore the contents of IDD.class by using the javap tool with its -c (disassemble the code) and -v (print additional information — verbose) options. For example, executing javap -c -v IDD.class results in this output:

Classfile /C:/cpw/javaqa/article12/code/IDD/IDD.class
  Last modified 6-Dec-2014; size 390 bytes
  MD5 checksum ee1ec44a736cc0d446337023ec1a8ba6
public class IDD
  BootstrapMethods:
    0: #17 invokestatic IDDL.bootstrapDynamic:
              (Ljava/lang/invoke/MethodHandles$Lookup;
               Ljava/lang/String;Ljava/lang/invoke/MethodType;)
              Ljava/lang/invoke/CallSite;
      Method arguments:
  minor version: 0
  major version: 51
  flags: ACC_PUBLIC, ACC_SUPER

Constant pool:
   #1 = Utf8               IDD
   #2 = Class              #1             //  IDD
   #3 = Utf8               java/lang/Object
   #4 = Class              #3             //  java/lang/Object
   #5 = Utf8               <init>
   #6 = Utf8               ()V
   #7 = NameAndType        #5:#6          //  "<init>":()V
   #8 = Methodref          #4.#7          //  java/lang/Object."<init>":()V
   #9 = Utf8               main
  #10 = Utf8               ([Ljava/lang/String;)V
  #11 = Utf8               IDDL
  #12 = Class              #11            //  IDDL
  #13 = Utf8               bootstrapDynamic
  #14 = Utf8               (Ljava/lang/invoke/MethodHandles$Lookup;
                            Ljava/lang/String;
                            Ljava/lang/invoke/MethodType;)
                           Ljava/lang/invoke/CallSite;
  #15 = NameAndType        #13:#14        //  bootstrapDynamic:
                                          //     (Ljava/lang/invoke/MethodHandles$Lookup;
                                          //      Ljava/lang/String;
                                          //      Ljava/lang/invoke/MethodType;)
                                          //     Ljava/lang/invoke/CallSite;
  #16 = Methodref          #12.#15        //  IDDL.bootstrapDynamic:
                                          //     (Ljava/lang/invoke/MethodHandles$Lookup;
                                          //      Ljava/lang/String;
                                          //      Ljava/lang/invoke/MethodType;)
                                          //     Ljava/lang/invoke/CallSite;
  #17 = MethodHandle       #6:#16         //  invokestatic IDDL.bootstrapDynamic:
                                          //     (Ljava/lang/invoke/MethodHandles$Lookup;
                                          //      Ljava/lang/String;
                                          //      Ljava/lang/invoke/MethodType;)
                                          //     Ljava/lang/invoke/CallSite;
  #18 = Utf8               foo
  #19 = NameAndType        #18:#6         //  foo:()V
  #20 = InvokeDynamic      #0:#19         //  #0:foo:()V
  #21 = Utf8               Code
  #22 = Utf8               BootstrapMethods
{
  public IDD();
    flags: ACC_PUBLIC

    Code:
      stack=1, locals=1, args_size=1
         0: aload_0       
         1: invokespecial #8                  // Method java/lang/Object."<init>":()V
         4: return        

  public static void main(java.lang.String[]);
    flags: ACC_PUBLIC, ACC_STATIC

    Code:
      stack=0, locals=1, args_size=1
         0: invokedynamic #20,  0             // InvokeDynamic #0:foo:()V
         5: return        
}

This output reveals a default constructor and a main() method. main() executes the invokedynamic followed by return JVM instructions.

invokedynamic is called with argument #20, which refers to the 20th entry in the constant pool. This entry provides a symbolic reference to a call site specifier in the form of an InvokeDynamic structure.

The InvokeDynamic structure presents a pair of values:

  • #0 is an index into the BootstrapMethods table, which provides linkage between the invokedynamic call site and the target method. Linkage is described by an index to a MethodHandle structure in the constant pool. In this case, the index is #17. The MethodHandle structure identifies a static bootstrapDynamic() method in an IDDL class.
  • #19 is an index to a NameAndType structure in the constant pool that identifies a fictitious void foo() method. This method is a placeholder for the method that gets called after the linkage is complete.

Compile Listing 5 (javac IDDL.java) and run IDD.class (java IDD). You should observe the following output, which reveals the result of invokedynamic working in partnership with java.lang.invoke:

Hello, World!

Invokedynamic and Java 8

Q: Does the Java 8 compiler emit invokedynamic instructions?

A: The Java 8 compiler emits invokedynamic instructions in lambda expression contexts. For example, consider Listing 7.

Listing 7. LD.java

public class LD // Lambda demo
{
   public static void main(String[] args)
   {
      Runnable r = () -> System.out.println("Hello");
      r.run();
   }
}

Listing 7 reveals a very simple lambda expression that equates to the java.lang.Runnable type. After creating this expression, main() invokes Runnable‘s run() method to run the lambda body.

Compile Listing 7 (javac LD.java) and run the resulting classfile (java LD). You should observe the following output:

Hello

Now that you know that the source code is correct and that the application runs successfully, run the javap tool with the -c option to view main()‘s bytecode (javap -c LD.class). You should observe the following output, which reveals the presence of invokedynamic:

Compiled from "LD.java"
public class LD {
  public LD();
    Code:
       0: aload_0       
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return        

  public static void main(java.lang.String[]);
    Code:
       0: invokedynamic #2,  0              // InvokeDynamic #0:run:()Ljava/lang/Runnable;
       5: astore_1      
       6: aload_1       
       7: invokeinterface #3,  1            // InterfaceMethod java/lang/Runnable.run:()V
      12: return        
}

If you would like to observe the constant pool along with the bootstrap methods table, include the -v option when executing javap.

What’s next?

This post offers only a brief introduction to invokedynamic. To learn more about this useful instruction and its companion java.lang.invoke package, check out the following resources:

download
Get the source code for this post’s applications. Created by Jeff Friesen for JavaWorld

The following software was used to develop the post’s code:

  • 64-bit JDK 7u6
  • 64-bit JDK 8 (build 132)

The post’s code was tested on the following platform(s):

  • JVM on 64-bit Windows 7 SP1