Thursday, October 20, 2005

JRockit powered AOP prototype available

(imported from http://blogs.codehaus.org/people/avasseur, read comments there)

It's there !


I am very pleased to announce the prototype version of JRockit that includes our AOP API is available. It will drive you far far away from current bytecode instrumentation techniques to a world of plain Java API, complete runtime control for hot deployment and undeployment, agnostic from the programming model you like for your aspects.


If you are involved in the AOP field, bytecode instrumentation field, APM field, and did not heard from us recently, please drop me an email and I 'll consider your participation in evaluating this technology to help us drive it to reality.


You can read the official announcement and some background information in our BEA dev2dev dedicated forum.

Monday, October 10, 2005

Synchronized block join points (v2)

(imported from http://blogs.codehaus.org/people/avasseur, read comments there)

Back in July Jonas suggested some semantics for a synchronized block join point. The discussion was interesting but I am wondering if we actually came up with the right question.


What if we simply think in terms of "is this type listening to locking events ?" instead of trying to come up with a pointcut expression that defines the semantics of a synchronized block - as done in Jonas discusion?


Lets draft some code:


Consider the program:

class Bar {
synchronized void foo() {
..
}

static synchronized void statfoo() {
..
}

void stuff() {
..
synchronized(bar) {
..
}
}
}


So the deal is to listen to lock events - mainly:


  • waiting the lock

  • just acquired the lock

  • just released the lock (or perhaps about to release it - but this does not matter much for this discussion)



I argue that instead of defining semantics, the issue should be narrowed to a type pattern ie something as simple as Bar (or more fancy variations based on type hierarchy or annotation - you bet it).


Given that we can define this interface:

interface Lockable {
void waiting();
void acquired();
void released();
}


As a user you can then implement this interface on your own types, use some sort of AOP or proxy to have it introduced where you want, etc.


So what should happen to make that work?


First based on the type pattern, we simply introduce Lockable to Bar. This can be done manually, by the mean of AOP if f.e. I was writing @Distributed class Bar { .. } and so on - depends on the use case.


Second the interface must then be implemented by Bar.
The user can provide one if implemented manually, or the system (AOP f.e.) can provide an empty one ie something like (depends on the AOP system but you get the idea)

@Introduce("Bar")
class LockableNOOP implements Lockable {
void waiting() {}
void acquired() {}
void released() {}
}


Last we need to transform the program so that the synchronized block or the Bar' synchronized method are triggering event to that.
This is not that hard since we just need to look at the type hierarchy for non static synchronized method and given that an instance synchronized method can be rewritten (by the system) as a synchronized(this) block we end up to something like that:

Replace all synchronized blocks like that:

Given

synchronized(stuff) {
..
}

to

if (stuff instanceof Lockable) {
Lockable lockable = (Lockable)stuff;
lockable.waiting();
synchronized(stuff) {
lockable.acquired();
..// unchanged body
}
lockable.released();
} else {
synchronized(stuff) {
..// unchanged body
}
}

Fairly easy.


So far, nothing will happen, as we have a LockableNOOP implementation, unless the user (you) explicitly provided some implementation.


Last part: configure the system so that it advises Lockable' methods, so that you can add your behavior there (f.e. distribute lock, or trace them for some application performance system). There, usual AOP stuff can be used.

You can now access the enclosing static join point information if you need - which gives you if you really need it, the rich semantics Jonas was looking for:

call(Lockable.waiting()) && withincode(....) && target(t) && cflow(...) .....
// t is the locked object


There are two interesting things to solve now:


  • What if I want to kick out the synchronized() block ?(f.e. for distributed lock). I think a small variation of Lockable can solve that - f.e. boolean shouldUseJavaLocks(), and a tiny change for the transformed program.

  • What about the static synchronized statfoo() {..} in Bar? For that one, the transformation would have to be a bit more compex so that we f.e. lock on an introduced static field. That said, the Lockable interface is not handy anymore. Any suggestion for that one? Should we define three methods like static void lockable_waiting() that ones would implement or introduce to adress this use case?



On a more high level perspective, this send us back to a recurrent set of problems in the AOP / bytecode transformation space:


  • to achieve API transparency, we have a very intrusive transformation engine (though the one described here can be quite fast)

  • by changing the bytecode we break the visibility another system may require to work properly (as f.e. we add if blocks, change synchronized method into synchronized blocks etc).



There is thus a set of open questions:


  • So should that belongs to the JVM directly, and in which form?
    (as f.e. JVMTI already provides monitor entry / exit events, that should be fairly easy).

  • Should those 3 Lockable' methods (or 6 if we include the static versions) belong to java.lang.Object direclty?

  • Would an hybrid system that changes the synchronize blocks using bytecode transformation but then relies on JVM level support for AOP such as we do in JRockit be enough to listen for lock events?

  • Is the cost of the introduced instanceof acceptable?



Happy thinking!

Wednesday, September 28, 2005

How will nextgen AOP looks like?

(imported from http://blogs.codehaus.org/people/avasseur, read comments there)

This last days I have been thinking some about how next gen AOP implementations may look like in say 4 years from now in the Java landscape.

As you may known, 5 years ago AspectJ was not based on bytecode manipulation but was based on source code transformation.
As of today, full blown AOP like AspectJ and JBoss AOP are usually build on top of really heavy bytecode manipulation, while more lightweight approach like Spring AOP are build on top of proxy (which under the hood can use bytecode generation technology ie JDK or CGlib proxy).

In the next few days we will start spreading the prototype implementation of AOP support in JRockit JVM which allows to implement all of the AOP interceptions features without even touching the bytecode but with a more abstracted subscription based API. If you missed the dev2dev series you can read more about it there.

This technology is definitely a breakthrough in the field, but does not address the introduction/mixin features ie capability to add method / field / annotation / change the object hierarchy of the object model in a crosscutting manner.
This means that f.e. to implement AspectJ as it is on top of the new JVM based technology we need to wether

  • remove the feature from AspectJ - this is dumb as introduction are an important part of AOP

  • do that in the VM - well, perhaps but unlikely from my perspective as it would mean changing the Java language itself else ones would not be able to call the introduced members from regular code

  • use an hybrid bytecode / VM based AOP approach - why not but it looks a lot like going back to the old bytecode based implementation complexity

  • do it in another way!



My thoughts on that is that we will likely do it in another way - and perhaps going back to source code transformation. This year Sun' folks presented the Jackpot project at JavaOne - which is sort of a rule driven source transformation engine. If that ones goes mainstream somewhere with Java 7, ones will have a fairly great technology set to rethink the way we implement AOP in Java, mixing nextgen APT (that will expose the full AST), Jackpot and JVM weaving.

Wednesday, August 10, 2005

AOP weavers - are we doing it wrong?

(imported from http://blogs.codehaus.org/people/avasseur, read comments there)

These last days I have been prototyping around an interesting idea.


As you know we have been working on an API to add JVM support for AOP in JRockit. The prototype will be available any time soon.


The nice thing about it is that you don't manipulate the bytecode anymore and that you are using only well known java.lang.reflect.* API to tell the JVM if your pointcut is matching or not. This is somehow similar to what ones can do with Spring AOP - as this one is proxy based (see f.e. MethodMatcher API in Spring).


The immediate benefit of it is that first there is no need to have another in-memory representation of classes beeing weaved (before they get loaded) that is backed by some expensive (both memory and CPU) bytecode analysis.
This advantage is detailled in our JVM support for AOP part1 article.


As a consequence it is really easy to query the method annotation, generics properties, and such - something that is extremely complex to achieve with acceptable overhead in regular bytecode based weaver such as AspectJ or AspectWerkz (actually more complex than changing some bytecode instruction).


So what is that idea I had ?


Having AOP support in JRockit is nice, but it will take some time before that gets mainstream (with eventually a JSR etc). In this transition period, there must be a way to implement a better bytecode based weaver that will perform way better than current weavers (both AspectJ and AspectWerkz), that will be easier to implement, and whose only requirement is Java 5 (well off course, it won't be as good as JRockit JVM support for AOP - so it is still a transition technology).


I have thus been sketching on an hybrid system that makes extensive use of the hotswap API, and whose actual weaver relies only on pointcut matching backed by the java.lang.reflect.* API ie does not build any kind of equivalent structure backed by bytecode analysis.


As such the memory overhead is zero, and the CPU overhead is way less than current AspectJ and AspectWerkz.


The overall idea is quite simple and consists in 2 phases:


Phase 1


A first weaver is changing the bytecode in some stable way - such that all classes are transformed (lets say prepared) the same way - while not introducing any dependancies on any kind of AOP, and while not adding any kind of performance overhead (ie no changes in the execution flow such as introduced by wrappers method and such usually used when implementing instrumentation needed for around advice).


All classes thus get loaded as expected with a very limited time overhead and no memory overhead at all (thanks to the excellent ASM performance).


Phase 2

Then when an actual class gets loaded (as per regular application behavior) I get a small callback invoked when this class has just been loaded and just before anything else happens (ie the class static initializer invoked by the JVM). Current load time weavers do things "just before the class gets loaded" and as such cannot access the java.lang.reflect representation of what they weave.


This callback can then perform the actual weaving by relying entirely on the java.lang.reflect.* API to match the pointcuts. It then constructs the instrumented version of the class and hotswap it thanks to the Java 5 API. The JVM eats this one and goes on.


The first prepare phase is needed as the hotswap API does forbids change in the schema (ie cannot add or remove methods or fields).


A nice extra side effect is that at any point in time any class can be exposed to the AOP layer thru a simple API. This can be handy for some cases where there are some circular references in the dependancies (f.e. the instrumentation needs the java.lang.reflect.Method class to match against the pointcuts so if I want to add aspects to the Method class, I cannot do it until I have a representation of this class ie there 's no way to have it working by simply invoking the callback from the prepared Method class itself).


This might seems like gory details, especially when compared to what we do in the JRockit JVM support for AOP, but I am sure there are some concepts worth digging there - as memory usage and weaving overhead as been reported more than once as a major problem (see f.e. use case with AspectJ reported by Ron Bodkin where the system takes 4 minutes to start instead of less than a minute without any weaver here)


This makes it also very easy to add aspects even to java.* classes (though it's not generally a good idea unless you know what you are doing).


This sample is an actual code snip of the actual AOP transformation (part of phase 2). As you can see it relies on the java.lang.reflect API.



public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
if (!filter(access, name)) {//fast filter for f.e. clinit method as we look for method execution join points
// see if we get a match for this join point
// only java.lang.reflect.* API is used here
Member method = ReflectQuery.getMethod(m_klass, name, desc);
Class thisClass = m_klass;
Class targetClass = null;
Member withinCode = null;
//do matching
if (match(method, thisClass, targetClass, withinCode)) {
//change the bytecode but don't change the schema for hotswap purpose
} else {
return super.visitMethod(access, name, desc, signature, exceptions);
}
}
}


Finally I must say this idea is not 100% new as I wrote a paper on it for AOSD 2004 (read my paper here). At that time though I was not doing the pointcut matching based on the java.lang.reflect API - as the purpose was to enable dynamic AOP in AspectWerkz 1.0) ie I was not solving the problem of the memory and CPU overhead of the actual weaver.


What do you think? Are those ideas worth digging more?

Tuesday, August 2, 2005

JVM support for AOP in BEA JRockit

(imported from http://blogs.codehaus.org/people/avasseur, read comments there)

We have plublished a follow-up to our JavaOne 2005 session that describes with some more details the JVM support for AOP that is beeing designed within the BEA JRockit JVM.


This first article introduces the problems that usually happen with current weavers (in the Java land) and briefly described the proposed solution.

The next part to appear in the following weeks will give more details and code samples.


Read the article





JRockit JVM Support For AOP, Part 1 by Jonas Bonér and Alexandre Vasseur, Joakim Dahlstedt -- AOP is all the rage, but how do you implement it? In this article, Jonas, Alexandre, and Joakim show that the current approaches to implementing AOP suffer from many problems, making scalability an issue. Moreover, they indicate that the traditional approach to aspect weaving duplicates efforts that the JVM already performs.


We are currently working on making the prototype implementation available for further evaluation.


If you could not attend JavaOne 2005, the slides are available from the JavaOne web site, and they are also available here


The full webcast of the JavaOne session is also available on dev2dev.