Load Time Structural Reflection in Java
Shigeru Chiba
Institute of Information Science and Electronics
University of Tsukuba
Introduction
• Reflection in java– Behavioral reflection– Structural reflection
• Javassist, a class library enabling structural reflection in java
Properties of Javassist
• Portable
• Provides source level abstraction
• Does byte code transformation at compile time
BCA
class Calendar implements Writable {public void write(PrintStream s) { ... }}class Calendar implements Printable {public void write(PrintStream s) { ... }public void print() { write(System.out); }}
• Implementation of BCA with behavioral reflection isnot straightforward
Javassist• Translates alterations by structural reflection into
equivalent bytecode• It is used with a user class loader class MyLoader extends ClassLoader {public Class loadClass(String name) {byte[] bytecode = readClassFile(name);return resolveClass(defineClass(bytecode));}private byte[] readClassFile(String name) {// read a class file from a resource.}}
Javassist API
• A CtClass object has to be created CtClass c = new CtClass(stream or string);
• To obtain bytecode of altered class byte[] bytecode = c.toBytecode();
• Javassist allows to dynamically define a new class CtClass c2 = new CtNewClass();
Introspection
• This part of Javassist is compatible with Java reflection API with the difference that Javassist does not provide methods for creating an instance or invoking a method because these are meaningless at load time
Alteration by Javassist
• Principles governing alteration in Javassist– Source level abstraction for programmers– Execution of structural reflection efficiently– Type safety while performing Structural
reflection
Adding a new member
void addMethod(CtMethod m, String name, ClassMap map)
void addWrapper(int modifiers, CtClass returnType, String name,CtClass[] parameters, CtClass[] exceptions,CtMethod body, ConstParameter constParam)
Replacing a Class name in the method body
public class XVector extends java.util.Vector {
public void add(X e) {super.addElement(e);}}
CtMethod m = /* method add() in XVector */;CtClass c = /* class StringVector */;ClassMap map = new ClassMap();map.put("X", "java.lang.String");c.addMethod(m, "addString", map);
public void addString(java.lang.String e) {super.addElement(e);}
Altering a Method body
void setBody(CtMethod m, ClassMap map)
void setWrapper(CtMethod m, ConstParameter param)
Reflective class loader
• Javassist provides a reflective class loader which can be used to self-reflectively modify the bytecode
Using Javassist with a Web server
for (;;) {
receive an http request from a web browser.
CtClass c = new CtClass(the requested class); do structural reflection on c if needed.
byte[] bytecode = c.toBytecode();
send the bytecode to the web browser.
}
Using Javassist Off line
CtClass c =newCtClass("Rectangle");
do structural reflection on c if needed.
c.compile(); writes bytecode on the original class file.
• Now the over written class file can be loaded in the JVM without user class loader
Comparison of OpenJava and Javassist
• Openjava needs source file of every processed class whereas Javassist needs just the class files of the classes
• Javassist is much faster as it can move compilation penalties to an earlier stage
Conclusion
• Javassist is portable
• Provides source level abstraction in a safe manner
• Does not need source code
• Can be extended to other object oriented languages with individually designed API for each language
Project overview
• Jalapeno is a JVM built by IBM Research (initiated in December 1997) It takes a compile-only approach to program execution• Three different compilers to provide translations: – A “baseline” compiler that makes it easier to mix
execution of un-optimized and optimized methods in the JVM
– A “quick” compiler for a low level of code optimization – An optimizing compiler for computationally intensive code
Motivation of the Project
• To deliver high performance and scalability ofJava applications on SMP server machines
• To support all Java features and semantics with respect to exceptions, garbage collection and threads
Jalapeno JVM• Jalapeno JVM includes the following subsystems: - Dynamic Class Loader - Dynamic Linker - Object Allocator - Garbage Collector - Thread Scheduler - Profiler - Three dynamic compilers
Jalapeno JVM
• All subsystems implemented in Java
• Self-bootstrapping
• Can dynamically self-optimize the JVM itself
Structure of Jalapeno Optimization system
• Unlike traditional JVMs, Jalapeno is adaptive
and dynamic
– Automatically select a set of methods to optimize
– Generate the best possible code for selected methods for a given compile-time budget
– Reduce synchronization and other thread primitive
Structure of Jalapeno adaptive Optimization system
• Jalapeno Adaptive Optimization System includes:
– On-Line Measurement (OLM) subsystem
– Controller subsystem
– Optimizing Compiler subsystem
Online Measurment
• OLM
– Collect application and hardware performance information
– Maintain Calling Context Graph (CCG) to keep track of context-sensitive information
– Continuously monitor the methods, including those previously “optimized”
Controller
• Controller
– Detect if certain performance threshold is reached
– Use information collected from OLM to build an optimization plan (e.g. which methods need to be compiled and the optimization levels)
Optimizing Compiler
• The Optimizing Compiler can be used either as a static or dynamic compiler.
• When used as a static compiler or a bytecode -to-bytecode optimizer, it generates file for later execution ,used to bootstrap Jalapeno JVM
Optimizing Compiler
• When used as a dynamic compiler, it
generates the best possible code given compile -time budget
• The Jalapeno Optimizing Compiler consists of an optimizer front-end and an optimizer backend
Intermediate Representation(IR)
• The Optimizing Compiler uses register-based intermediate representations
• IR consists of an operator and some number of operands
• Jalapeno uses 3 different types of IRs:
– HIR (High-Level IR)
– LIR (Low-Level IR)
– MIR (Machine-Specific IR)
IR
• Operators such as NULL_CHECK and BOUNDS_CHECK operators are used to facilitate optimization
• Control Flow Graph (CFG) and Basic Blocks (BB) are constructed as a by-product of BC2IR(Byte Code to Intermediate Representation)
Front end of Optimizing compiler
• The Front-End contains two parts:
– BC2IR algorithm to translate byte code to HIR and perform on the fly optimizations
– Additional optimization performed on the generated HIR
Back end of Optimizer Compiler• The Back-End of the compiler translates
– HIR to LIR
– LIR to MIR
– MIR to the final binary code• Different optimizations are performed during each
phase
HIR to LIR
• HIR is lowered to low-level IR (LIR)• LIR expands instructions into operations that are
specific to the Jalapeno JVM (such as object layouts or parameter-passing mechanism)
• The expanded LIR may expose more
opportunities for low-level optimizations
Final Assembly
• Emit the binary executable code into an
instruction array• Convert offsets in the IR to offsets in the
machine code• Store the instruction array (a Java array
reference) into a field of the object instance for that method
Inlining Method Calls
• During BC2IR phase:
– Static and final methods can be safely inlined.
– “Inlining plan” is based on static code size and depth heuristics
Implementation Status
• OLM is in prototype stage, and the controller is in design phase
• The Optimizing compiler can only be invoked as a static compiler or dynamically by the Jalapeno class loader to optimize all methods
Performance Benchmark Enviroments
• Four Java Environments:
– IBM JDK 1.1.6 w/o JIT
– IBM JDK 1.1.6 w IBM JIT v3.0
– Jalapeno Baseline – Use Jalapeno Baseline Compiler as a JIT for all classes dynamically loaded
– Jalapeno Optimizer – Use Jalapeno Optimizing as JIT for all classes dynamically loaded
Benchmark Programs
• Benchmark Programs:
– 9 “Micro-benchmark” Programs from Symantec
– 4 “Macro-benchmark” programs from SPECjvm98suite
Performance Results
• Micro-Benchmark:
– 3 of the 9 tests run faster with the Jalapeno Optimizing Compiler
– Remaining cases are within 1.6 times slower of the standard IBM JIT compiler
Performance Results
• Macro-Benchmark:
– 1.3 to 3.3 times slower than the “best” current commercial JVM"
– With further improvements, Jalapeno (a pure Java JVM) may achieve performance competitive to a state-of-the-art JVM implemented in C
Conclusion• First dynamic optimizing compiler for Java
that is being used in JVM with a compile –only approach to program execution
– Validated the “compile-only” approach to program execution
– Demonstrated that a JVM implemented in Java can deliver performance comparable to a standard JIT compiler