Tuesday, August 21, 2007

Optimising Groovy bytecodes with Soot

I'm playing around Soot framework and get some optimised bytecodes after applying its default optimisation to Groovy-generated classes.
This does not help much for speed improvement, but I think it could help reduce the usage of PermGen space.

I've tested with a trivial class, and its file size after optimisation is 8.5% shrinker than the original. I'm expecting that this figure would be large if we optimise a whole application.

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.