Monday, September 10, 2007

How does Groovy AOP relate to GIT?

GIT is the name of Groovy just-in-time compiler, which is being developed. I'm using it as an underlying layer for Groovy AOP.

MetaClassImpl, the default meta-class of Groovy, picks a call for each invocation, which is a joinpoint in AOP theory.

GIT is trying to optimise this invocation process by checking the change of a MetaClass of each class. It replaces the meta-call with the real call, which is returned by the MetaClass. Weaving process in Groovy AOP will take the similar approach. But when MetaClass picks a real call, it would return "WovenMetaMethod" that contains also "before", "after", and "around" information. The runtime weaver then uses this information to generate an equivalent list of bytecode instructions and use them to replace the meta-call.

This is how GIT relates to Groovy AOP.

Saturday, September 08, 2007

An ERP built with Grails

I've setup the project called Geogia at Google Code for developing an ERP system using Grails. All domain classes are being re-written based on UML diagrams of project Neogia. Gentleware AG kindly sponsored Poseidon UML CE edition for this project. Thank you :).

This project is being developed using version 0.6 of Grails.

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 !!