Invokedynamic Bytecode in JDK 7

One of the most anticipated feature in the upcoming release of JDK 7 is the invokedynamic bytecode. This bytecode is suppose to make the JVM to be more dynamic language friendly by providing it with a flexible method call mechanism. As you know Java is a statically typed language; so when you invoke a method call, the compiler and ultimately the JVM will ensure that the method call has a valid method name, the exact parameter type(s) and also the return type if any.

The invokedynamic bytecode changes this by allowing late binding in method calls viz. a method call at a call site is not resolved until it is invoked at runtime. So for the first time you can intercept non existent method calls, and pass control to another method to execute in its place.

Lets take a look at a simple example. The Grails framework has this really nice persistence model call GROM. You use GROM to create your domain classes then you can dynamically run query against these classes; here is the cool part, the queries are non-existent method calls to the domain object. For example, say you have Book as your domain class with the usual author, title, ISBN, release dates, etc as fields. To perform a query on Book, you can do any one of the following

Book.findByTitle(“The Stand”)
Book.findByTitleLike(“Harry Pot%”)
Book.findByTitleLikeOrReleaseDateLessThan(“%Something%”, someDate)

The findBy is really a sort of SQL in English. When they are invoked, these method calls are intercepted by GROM (because the calls do not exists) and converted to the appropriate SQL. You can learn more about GROM’s dynamic query capabilities here.

So we want to do something similar in Java. I’ll show how to use InvokeDynamic to trap findBy method calls and adapt the call to another method. We have the following static method

public static ResultSet query(String query, Object[] params)

which will perform the actual query using JDBC. Whenever we do the following

InvokeDynamic.<ResultSet>findByTitleAndAuthor(“The Shining”, “Stephen King”)

we are actually invoking query() like so

query(“findByTitleAndAuthor”, new Object[]{ “The Shining”, “Stephen King”});

Notice that the original method call have been adapted to query(). Here are the steps you to do this

  1. Write the actual method(s) that will eventually handle the call. In the example about, this will be query(). query() has 2 parameters, one a String and the other an array of Object. It returns ResultSet.
  2. Prefix our method call that we want to intercept with  InvokeDynamic. Eg. InvokeDynamic.<String>foo(“fred”)
  3. Define a ‘bootstrap method’. The bootstrap method will intercept and adapt findByTitleAndAuthor() to query. Specifically it does this by calling query() with the method name (findByTitleAndAuthor) and it also packages the actual parameters into an array of Object. The bootstrap method is one called once for methods that are not linked.

The following code shows how this is done

import java.dyn.*;
public class Query {
   static {  
      //Bootstrap method
    Linkage.registerBootstrapMethod(“doBootstrap”);
   }

  public static ResultSet query(String queryString, Object… params) {
      //Performs query, return ResultSet
   }

   public static CallSite doBootstrap(Class caller, String methodName, MethodType type) {

      MethodHandles.Lookup lookup = MethodHandles.lookup();
      //Lookup the class that has the method that we will be linking to
      //In this case, query is in the same class

    Class me = lookup.lookupClass();
      //Lookup query method by matching the parameter type and return type
      MethodHandle rawQuery = lookup.findStatic(me, “query”
            , MethodType.methodType(ResultSet.class, String.class, Object[].class));
       //Set the method name as the first parameter to query()
      MethodHandle cookedQuery = MethodHandles.insertArguments(rawQuery, 0, methodName);
    //Return a CallSite object back to the JVM to continue with the call
      return (new CallSite(MethodHandles.collectArguments(cookedQuery, type)));
   }

   public static void main(String… args) throws Throwable {
    //Invoking this will result in doBootstrap() method being called
      ResultSet result = InvokeDynamic.<ResultSet>findByTitleAndAuthor(“The Shining”, “Stephen King”);
        
      val = InvokeDynamic.<String>findByTitleAndAuthor(“Lord of the Rings”, “JRR Tolkein”);
   }
}

The complete list of Invokedynamic Java API can be found here. To run this compile with JDK 7 which you can download here. Now you can run the program like so

java -XX:+UnlockExperimentalVMOptions -XX:+EnableInvokeDynamic Query

If you have any use cases do share them.

2 Responses to Invokedynamic Bytecode in JDK 7

  1. Igor says:

    You should use GORM instead of GROM

Leave a comment