Bug 234943 - Optimize code generation for annotation value binding
Summary: Optimize code generation for annotation value binding
Status: RESOLVED FIXED
Alias: None
Product: AspectJ
Classification: Tools
Component: Compiler (show other bugs)
Version: DEVELOPMENT   Edit
Hardware: PC Windows Vista
: P3 enhancement (vote)
Target Milestone: 1.6.1   Edit
Assignee: aspectj inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2008-05-30 17:13 EDT by Andrew Clement CLA
Modified: 2008-06-04 13:09 EDT (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Andrew Clement CLA 2008-05-30 17:13:23 EDT
Here is a typical scenario for using annotation matching:

// a trace level
enum Level { NONE,ONE,TWO,THREE; }

// a trace annotation
@interface Trace { Level value(); }

@Trace(Level.ONE)
public void c() { }

The annotation is being used to configure the trace level of the method.  The AspectJ code that binds this is as follows:

before(Trace t): execution(* *(..)) && @annotation(t) {
  callTrace(thisJoinPoint,t.value());
}

The advice only needed the enum value from the annotation and that was statically determinable.

The code generated for the above case right now is sub-optimal, there are a couple of reflection calls:

  Code:
   Stack=4, Locals=1, Args_size=1
   0:   invokestatic    #51; //Method X.aspectOf:()LX;
   3:   ldc     #1; //class Example
   5:   ldc     #54; //String c
   7:   iconst_0
   8:   anewarray       #56; //class java/lang/Class
   11:  invokevirtual   #60; //Method java/lang/Class.getDeclaredMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
   14:  ldc     #53; //class Trace
   16:  invokevirtual   #66; //Method java/lang/reflect/Method.getAnnotation:(Ljava/lang/Class;)Ljava/lang/annotation/Annotation;
   19:  checkcast       #53; //class Trace
   22:  invokevirtual   #70; //Method X.ajc$before$X$1$457fe24b:(LTrace;)V
   25:  return

Under this enhancement I'll improve that code generation for this scenario
Comment 1 Andrew Clement CLA 2008-06-04 13:09:58 EDT
Changes are in.  New syntax construct:

before(Trace t): execution(* *(..)) && @annotation(t) {
  callTrace(thisJoinPoint,t.value());
}

becomes:

before(Level lev): execution(* *(..)) && @annotation(Trace(lev)) {
  callTrace(thisJoinPoint,lev);
}

and the generated code becomes:

  Code:
   Stack=2, Locals=1, Args_size=1
   0:   invokestatic    #28; //Method X.aspectOf:()LX;
   3:   getstatic       #32; //Field Level.ONE:LLevel;
   6:   invokevirtual   #36; //Method X.ajc$before$X$1$4fa4f687:(LLevel;)V
   9:   return

rather more optimal and no reflection.

Now I could have modified the compiler to detect that only the Level within the annotation was being accessed within the advice and automatically changed the generated advice signature and code to do the same as the above.  But I wonder if that is too much magic?

Also this ONLY works for method-execution join points AND enumerated type values within annotations.  Optimizing for cases other than method-execution will, I think, cause problems with coupling as our advised locations are then tightly coupled to the annotation value.  For example, if a call joinpoint was optimized in this way and the annotation on the called entity was changed, the advised location would also need recompilation or it would not see the change.  We don't have this problem for method-execution as a change to the annotation value and rebuild will also cause the advised location to be  updated too.

So using this optimized syntax in the wrong way will currently produce 'compiler limitation' messages.  So, in fact, to implement this at all join points correctly (removing the method-execution restriction) would just mean inserting the same reflection code and an additional field access before calling the advice.

I would address supporting this syntax as other join points and for other annotation value types as and when use cases arise.