Discussion and Execution Times
As an experiment, we have compared the execution times for dummy aspects implemented both with AspectJ and Spoon-AOP:
AspectJ version:
public aspect Empty {
before() : execution(* ToBeAdvised.*(..)) {}
}
public aspect JoinPointAccess {
before() : execution(* ToBeAdvised.*(..)) {
if(thisJoinPoint.getArgs().length>0) {} else {}
}}
public aspect StaticJoinPointAccess {
int getNumParameters(JoinPoint.StaticPart tjpsp) {
Signature sig = tjpsp.getSignature();
if (sig instanceof CodeSignature) {
return ((CodeSignature) sig).getParameterTypes().length;
} else {
return 0;
}
}
before() : execution(* ToBeAdvised.*(..)) {
if (getNumParameters(thisJoinPointStaticPart) > 0) {} else {}
}
}}
Spoon-AOP equivalent version:
public class Empty extends Aspect {
@Before(side=Side.EXECUTION) void before() {
if(_targetClass_==ToBeAdvised.class) {}
}
}
public class JoinPointAccess extends Aspect {
@Before(side=Side.EXECUTION) void before() {
if(_targetClass_==ToBeAdvised.class) {
if(_argumentCount_>0) {} else {}
}
}
}
The execution times (reference time for the pure Java program without aspects is 83 ms):
See the main test program and the advised class here. Also, you will find the full Spoon-AOP version of the tests performed here in the Spoon CVS.
| Spoon-AOP | AspectJ | Why? | |
|---|---|---|---|
| Empty aspect | 83 ms | 193 ms | AspectJ, like most of the classical AOP weavers, introduces an intermediate call between the client and the advised method. This "stub" multiplies the execution time by about two. With Spoon AOP, the aspect code is inlined, which induces no overhead compared to regular Java code. |
| JoinPointAccess aspect | 83 ms | 8570 ms | With AspectJ (or any other classical AOP weavers), when generic data on the joinpoint are accessed at runtime, it has disastrous impacts on performances (up to more than times 100!). With Spoon-AOP, the joinpoint data are statically available and the woven code is partially evaluated, which removes all useless code (here the test is removed). |
| StaticJoinPointAccess aspect | 83 ms | 787 ms | With AspectJ, some joinpoint data can be accessed statically by using thisJoinPointStaticPart. However, this can lead to complex code and tricks (see StaticJoinPointAccess) whereas Spoon-AOP version remains the same. In general, AspectJ provides the possibility to write more efficient code, but it is not as straightforward as using Spoon-AOP, and still largely less efficient. |
Note that in order to avoid this problem with AspectJ, you can also use pointcuts and bind the parameters with advice variables. However, in my opinion, this has a bad effect on aspect reusability. Also, it makes it harder to factorize common advice code. In order to illustrate this, we show the following example, where we access the first parameters of the method and need to implement specific code depending on their types (int or String).
AspectJ version:
public aspect AccessFirstArg {
before(String s) : execution(* ToBeAdvised.*(String,..)) && args(s) {
String tmp=s;
}
before(int i) : execution(* ToBeAdvised.*(int,..)) && args(i) {
int tmp=i;
}
}
Spoon-AOP equivalent version:
public class TestAspect extends Aspect {
@Before(side=EXECUTION) void m() {
if(_targetClass_==ToBeAdvised.class && _argumentCount_>0)
if(_arguments_[0] instanceof String) {
String tmp=(String)_arguments_[0];
} if(_arguments_[0] instanceof Integer) {
int tmp=(Integer)_arguments_[0];
}
}
}
Find the full Spoon-AOP version of the tests performed here in the Spoon CVS.
| Spoon-AOP (TestAspect) | AspectJ (AccessFirstArg) | Why? |
|---|---|---|
| 84 ms | 248 ms | Even though AspectJ accesses all the information in a static way, there is still a context change between the advised code and the advice, which explains the overhead (note that the assignment is hardly noticeable). |
As we can see in this example, not only the performance of Spoon is better, but the code is more straightforward for Java programmers (it is pure Java!). Also, the aspect code is more reusable since it does not need any tricky and specialized pointcut definitions, which artificially separate the optimized advice into two different sub-advices... Note that the Spoon version is as well typed as the AspectJ version since the casts used here are not runtime casts. They are evaluated at compile-time and are removed in the final woven code (since they are not needed here).

