Devoxx France 2012 – Bytecode manipulation
Among libraries manipulating bytecode, there are EJB containers, terracota to distribute computations and hibernate. The eclipse plugin managing layout and display of Android screens also manipulates bytecode to instrument the real library used in Android.
Then, Julien and Frédéric present quickly the java bytecode : each primitive type is internally represented by a letter, class packages are represented with a slash instead of dots (example : java/lang/String)… The virtual machine whose goal is to run the bytecode is a pushdown automaton with an area containing constants (constant pool) and another containing code to execute (opcode). To illustrate that, they demonstrate execution of bytecode generated by compilation of a simple System.out.println to display the result of an addition. We can then see the stack and variables (processor registries) evolving.
ASM is one of the libraries allowing to manipulate bytecode. It has 2 APIs :
- An API based on an event model, structured around the visitor design pattern. It can be used to profile java code, by implementing the ClassFileTransformer interface.
- An API based on an object model, loading all the bytecode in memory as a syntax tree of the code (AST).
AspectJ is another library manipulating bytecode. This one allows to do aspect-oriented programming (AOP) to, for example, add logs (method calls…), security (verify access to some services) or validation (verify form fields) …
To illustrate that, Julien and Frédéric are doing 2 demonstrations around the computation of Fibonacci number, in a recursive way : the first one is very slow and does some computations multiple times, the second one is a lot faster because it uses AspectJ to implement a cache of already done computations.
Another possible use case is the modification of a class to add it the implementation of an interface not implemented before.
Byteman, another library manipulating bytecode, implements an agent modifying classes in a running JVM, to debug for example. It also provides a bytecode injector, to use in the setup of a JUnit test. It’s then possible, for example, to force File.mkdirs() to return false, allowing to improve test coverage.
To achieve its task, Byteman defines a language close to the bytecode, allowing to specify modifications to apply and the place to put them.
To end the presentation, Julien and Frédéric present us the beta version of a research project named JooFlux (it will be soon open sourced). This project uses Rémi Forax‘s work on the new bytecode named invokedynamic (introduced in Java 7). Byteman modifies completely a class, even if only one of its methods has changed (that forces the JIT compiler to optimize again all the methods). In contrast, JooFlux only modifies what is necessary, which will optimize the usage of JIT compiler. JooFlux also provides a Swing/JMX interface to manage bytecode injection. As an example of usage, you can replace all calls to invoke* by a call to invokedynamic.