a modest tool for writing JSR 292 code

An earlier version of JSR 292 included some syntax support in the Java language for issuing invokedynamic instructions. This is no longer the case in JDK 7. Such support, if it shows up at all, will be dependent on Project Lambda, and that is after JDK 7.

(By the way, for a larger example of the syntax support in action, check out this hand-transformed benchmark code for Rhino. This was part of the exploratory work described in my JavaOne talk.)

Well, that’s the bad news. But here’s a bit of good news: I have hacked together a classfile transformer, named “indify”, which is able to pattern-match some byte-compiled Java programs, and transform them into equivalent programs which use JSR 292 bytecode features. It can be used to generate invokedynamic instructions, including those with the new bootstrap method argument format. The transformer can also generate “ldc” instructions for MethodHandle and MethodType constants. (Such constants are a little-known feature of JSR 292.)

The code for “indify” is in a Mercurial repository on Kenai.com. It is all in a single file of less than 1500 lines. (Update: More recent versions are slightly larger.)

Of course, the creation of semantics-preserving program transformations is often difficult. And in this case, the transformation is slightly uphill, more like a decompiler than a compiler. Lower-level expressions are turned into simpler, higher-level JSR 292 operations.

To make the project workable and small, I cut corners. The tool transforms only a limited set of Java programs. In order to make it work for you, you have to prepare stylized, stereotyped Java programs, which make it very clear where you are expecting to perform the transformations.

The javadoc in the source code gives some rules for preparing your code. There is also a small example file. The basic trick works like this. Suppose you have a method that you want to create a method handle constant on, like this one:

public static Integer adder(Integer x, Integer y) { return x + y; }
Getting the method handle requires an expression that looks like this:
lookup().findStatic(Example.class, "adder",
  fromMethodDescriptorString("(Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Integer;", null));
Suppose you want to transform that expression into a simple method handle constant. Perhaps in Java with closures you'll be able to write #adder but for now, put the noxious expression into a small private method like this one:
private static MethodHandle MH_adder() throws NoAccessException {
  return lookup().findStatic(Example.class, "adder",
    fromMethodDescriptorString("(Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Integer;", null));
}
The name must begin with the string MH_; the rest of the name is arbitrary. Call the function whereever you like (within the same file). Compile the Java code, and run “indify” on the resulting class file. The constant implied by MH_adder will be appended to the class file constant pool, and all such calls to the method will be transformed into ldc instructions.

The pattern for invokedynamic is more complex, and builds on top of simpler method handle and method type constant expressions. Here is an example:

private static MethodHandle INDY_tester() throws Throwable {
  CallSite cs = (CallSite) MH_mybsm().invokeWithArguments(lookup(), "myindyname",
    fromMethodDescriptorString("(Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Integer;", null));
  return cs.dynamicInvoker();
}
This code assumes that your bootstrap method is provided by a private constant method MH_mybsm. The factored method INDY_tester calls the bootstrap method on the standard arguments (class scope, name, and type), obtains the call site, and returns the site’s invoker method handle. (This is a late-bound alias for the target, which follows the call site target as it changes.) The caller of INDY_tester is required to immediately invoke the result, like this:
System.out.println((Integer) INDY_tester().invokeExact((Integer)40,(Integer)2));
That invokeExact call is part of the built-in semantics of invokedynamic. The “indify&rdquo tool tranforms the two calls INDY_tester and invokeExact into a single invokedynamic instruction. The static linkage information for this instruction (which is obtained by inspecting the contents of INDY_tester) is appended to the class file constant pool, as in the previous example.

Here is a pre-built distribution. For now, you should throw the switch “--transitionalJSR292”, to make it emit the older format (tag 17) of CONSTANT_InvokeDynamic. (The newer format, tag 18, is not widely available yet.) [12/23 Update: Build b123 of OpenJDK 7 supports tag 18, and contains a version of indify.] To find out about the bytecode instructions, you can always look here.

For large scale use, this tool is a non-starter. For medium sized projects, it is at best a dead end. Real language implementations will need to use a real bytecode backend, like ASM. A small tool like “indify&rdquo is not robust or user-friendly enough for medium to large jobs. And, I’m not planning on supporting it, or developing it much further. Actually, I would be sad to see it get much bigger or more complex.

But “indify” may be useful for small inputs, in cases where the result of the transformation is easy to verify. For example, if you are experimenting with small bytecode examples, or writing or teaching about them, this is a way to make your work be readable as Java code, instead of pseudocode or bytecode assembly language.

Comments:

Interesting. What tool or combination of tools would you recommend to learn the internals of JVM ? ( e.g ) What can I do to look at the constant pool ?

Posted by Mohan Radhakrishnan on November 17, 2010 at 06:01 PM PST #

Post a Comment:
  • HTML Syntax: NOT allowed
About

John R. Rose

Java maven, HotSpot developer, Mac user, Scheme refugee.

Once Sun and present Oracle engineer.

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today