Wednesday, August 08, 2007

Possible JIT for Groovy with JVMTI

Nothing involves Groovy bytecode analysis at the moment, but I show you here the possible way to re-define a Java class with a Java 6 JVMTI agent. Yes, I say Java 6 as Java 5 does not support class re-definition through java.lang.instrument package.

As you might know, several AOP systems, that enable load-time weaving, use class transformation at load-time to weave aspects to the existing programs. They use a java JVMTI agent to achieve this.

Now in Java 6, you can do a bit more further as it offers method

Instrumentation.redefineClasses(ClassDefinition[] defs);




I'm experimenting this technique with a normal class, here:

package org.groovy.git.test;

public class TestClass {

public void myMethod(){
System.out.println("a");
}
}



The re-definition process is performed just to change a TestClass object from printing "a" to printing "b".


package org.groovy.git.test;

import java.lang.instrument.ClassDefinition;
import java.lang.instrument.Instrumentation;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;

import org.groovy.git.Agent;

public class AgentTest {

public static void main(String[] args) throws Exception {
// get an instrumentation from the agent
Instrumentation i = Agent.getInstrumentation();

// here, print "a"
TestClass t1 = new TestClass();
t1.myMethod();

// doing bytecode manipulation,
// replace a new method body for "myMethod"

CtClass ct = ClassPool.getDefault().get(TestClass.class.getName());
CtMethod m = ct.getDeclaredMethod("myMethod");
m.setBody("{ System.out.println(\"b\");}"); // make it printing "b"
byte[] bytes = ct.toBytecode();

// prepare a new class definition
ClassDefinition[] def=new ClassDefinition[1];
def[0] = new ClassDefinition(TestClass.class, bytes);
i.redefineClasses(def);

// this shows "b"
TestClass t2 = new TestClass();
t2.myMethod();
}

}



You might see that the above code get instrumentation from the Agent class, which is in a jar loaded by -javaagent:jarfile. In this experiment, I use Javassist for bytecode manipulation.

As you expected, the above code will show:

a
b


as the TestClass has been re-defined and its method, myMethod, body's been replaced.

2 comments:

IPorsut said...

เปลี่ยนอย่างนี้ก็ได้ด้วย

chanwit said...

Yep, but one limitation is that the object "t1" is still using the old code (it always prints "a") where object "t2" will be instantiated from the new class.

All things need to compile this is in Groovy AOP SVN. Just in case you want to play it.