Friday, September 07, 2007

Xfire plugin for Grails 0.6 released

Nothing's fancy. I've just released my latest Xfire plugin for Grails 0.6.
It's now available from Grails plugins repository.

This command:

$ grails install-plugin xfire


is enough to give it a go.

A few note here, it uses Xerces 2.8.1, where Grails ships with 2.6.2. Just in case for any incompatibility.

Tuesday, September 04, 2007

Dynamic Recompiling a Groovy Class

After we identified an invariant dynamic call, the call replacement technique could be applied to the caller method. The following describes an early version of the algorithm to do so:


1. find an invocation statement to ScriptBytecodeAdapter
2. determine a number of parameters that the statement needs.
2.1 if the number of parameters = 3, this invocation has no argument.
2.2 if the number of parameters = 4, this invocation has a set of arguments.
3. statically unwrap the last parameter passed to this statement
(note that Groovy's using Object[]
to wrap a set of method arguments,
and we need to unwrap and pass them
to the new invocation statement)
3.1 in this step, we can also clean up unneeded the Object[] variable
and its assignment statements.
4. construct the new invocation statement,
using information gathered from the profiler.
(we can not infer the target class using
any information provided by the statement,
because the real call will be chosen by Groovy meta-class).
5. fix object casting, this can be done by traversing backwardly
to the statement prior to the invocation.
Then change casting type from GroovyObject
to the correct type (also get this value from the profiler)



The result so far:

$r19_2 = $r19;
goto label7;
label6:
$r19_2 = org.codehaus.groovy.aop.tests.Target.class$groovy$lang$GroovyObject;
label7:
$r20 = ScriptBytecodeAdapter.castToType(r0, $r19_2);
$r21 = (org.codehaus.groovy.aop.tests.Target) $r20;
$r23 = $r21.method2("test");
$r18[$i0] = $r23;
$r24 = ScriptBytecodeAdapter.invokeMethodOnCurrentN(r2, $r16, $r17, $r18);
return $r24;

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[]{
"-d",
"mydir",
"-via-shimple",
className
});
try {
String fname = "mydir/"+ className.replace('.', '/') +".class";
ClassPool cp = ClassPool.getDefault();
CtClass target = cp.get(className);
target.defrost();
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);
target.addMethod(newMethod);
Instrumentation i = Agent.getInstrumentation();
i.redefineClasses(
new ClassDefinition[]{
new ClassDefinition(Class.forName(className), target.toBytecode())
});
} catch (Exception e) {
e.printStackTrace();
}



Tell me, if you have a better idea !!

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.