Monday, September 03, 2007

Bytecode incompatibility

Last post, I've blogged about using Soot to optimise class files. Soot is alright for me when I used it as a generator. But in the dynamic context, I've got some compiled classes from the different generator (say Groovyc), but I'd like to get them optimised with Soot and then re-define then with the Intromentation. This approach completely failed as Soot-compiled classes have different attributes compared with the original classes.

After this problem's kept me busy for a couple of days, I've came with a solution to use Javassist, another bytecode manipulation to help me re-mix two different versions of class.

I got the original class from Javassist class pool, removed the old target method. Then I loaded the Soot-optimised class from disk, using Javassist's ClassFile, and took only the optimised target method from it. After that I created a new MethodInfo for that method with constant pool of the original class and then I added it to the original class. I finally obtained its bytecode and give it to Intrumentation for class re-definition.

soot.Main.main( new String[]{
try {
String fname = "mydir/"+ className.replace('.', '/') +".class";
ClassPool cp = ClassPool.getDefault();
CtClass target = cp.get(className);
String mName = "main";
ClassFile srcClassFile =
new ClassFile(new DataInputStream(new FileInputStream(fname)));
MethodInfo srcMethodInfo =
getMethod(srcClassFile, mName, "([Ljava/lang/String;)V");
MethodInfo newMethodInfo =
new MethodInfo(target.getClassFile2().getConstPool(),
mName, srcMethodInfo, null);
target.removeMethod(target.getMethod(mName, "([Ljava/lang/String;)V"));
CtMethod newMethod = CtMethod.make(newMethodInfo, target);
Instrumentation i = Agent.getInstrumentation();
new ClassDefinition[]{
new ClassDefinition(Class.forName(className), target.toBytecode())
} catch (Exception e) {

Tell me, if you have a better idea !!

No comments: