Lazy Method Handle update
john.r.rose at oracle.com
Wed May 9 12:34:58 PDT 2012
Lazy Method Handles is a project to defer code generation for method handle behavior, and minimize requirements for support from hand-written assembly code.
The idea is to make all method handle behavior visible to the JVM compiler, so that it can be optimized properly. Assembly code cannot be optimized.
In JDK 7 FCS a method handle is represented as a chain of argument transformation blocks, ending in a pointer to a methodOop. The argument transformations are assembly coded and work in the interpreter stack. The reason this is not outrageously slow is that we vigorously inline method handle calls whenever we can. But there is a performance cliff you can drop off of, when you are working with non-constant MHs. (BTW, invokedynamic almost always inlines its target.) Project Lambda needs us not to drop off of this cliff.
To fix this, we are now representing the argument transformations using a simple AST-like IR, called a LambdaForm. This form can be easily rendered down to bytecodes. (Eventually it maybe directly rendered to native code.) The form is *also* interpretable by a Java-coded AST walker. This allows the system to be lazy, and to work hardest on optimizing those method handles that are actually called frequently. The laziness also helps simplify bootstrapping. The remaining assembly code is much smaller, and can be mirrored in the JIT IR and optimized.
Here's an update on where we are. Christian Thalinger, Michel Haupt, and I are currently working on the following tasks:
A. clean out the compiled method calling path, for non-constant method handles
B. flatten the BMH layout (no boxing, linked lists, or arrays)
C. make the handling of MethodType checking visible to the compiler (removing more assembly code)
D. tuning reuse and compilation of LambdaForm instances
E. profiling MH.LambdaForm values at MH call sites
F. tuning optimization of call sites involving LFs
For A. the remaining snag is getting the argument register assignments correct for the call to the target method. There is also an issue with representing non-nominal calls in the backend.
For B. we are currently working on bootstrap issues. The idea here is that, while we can do escape analysis, etc., a cleaner data structure will make the compiler succeed more often.
For C. we have a refactoring in process for moving the MT value out of the methodOop.
Chris, Michael, and I are working on A, B, C, respectively. We think a first cut of lazy MHs needs the first three items in order to be reasonably faster than the all-assembly implementation of JDK 7.
In order to address the infamous NoClassDefFound error, we are minimizing nominal information in MH adapter code (LambdaForms and their bytecode). Only names on the BCP will be in adapter code. Part C. is an important part of this, since it allows the system to internally "flatten" calls like MH.invokeExact((MyFunnyType)x) to MH.invokeExact((Object)x). The new internal MH methods (invokeBasic, invokeStatic, etc.) all use "denominalized" types, which is to say that all reference types are represented as java.lang.Object.
More information about the mlvm-dev