Bug 296484

Summary: [annotations] performance problem with @annotation(x) context extraction.
Product: [Tools] AspectJ Reporter: Simone Gianni <simoneg>
Component: CompilerAssignee: aspectj inbox <aspectj-inbox>
Status: RESOLVED FIXED QA Contact:
Severity: normal    
Priority: P3 CC: aclement
Version: unspecified   
Target Milestone: 1.6.7   
Hardware: PC   
OS: Linux   
Whiteboard:
Attachments:
Description Flags
Sample project, provided by Oliver Hoff, demonstrating the performance problem none

Description Simone Gianni CLA 2009-11-30 10:34:01 EST
User-Agent:       Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.5) Gecko/2009010218 Gentoo Firefox/3.0.5
Build Identifier: 20090619-0625 AspectJ 1.6.6

Thanks to Oliver Hoff for reporting this.

When @annotation(x) is used to extract an annotation in a pointcut, AspectJ weaves the following code :

   49:  ldc     #1; //class tests/SampleProgram
   51:  ldc     #92; //String calc
   53:  iconst_0
   54:  anewarray       #74; //class java/lang/Class
   57:  invokevirtual   #78; //Method java/lang/Class.getDeclaredMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
   60:  ldc     #71; //class tests/Log
   62:  invokevirtual   #84; //Method java/lang/reflect/Method.getAnnotation:(Ljava/lang/Class;)Ljava/lang/annotation/Annotation;
   65:  checkcast       #71; //class tests/Log
   68:  invokevirtual   #91; //Method tests/Intercept.ajc$afterReturning$tests_Intercept$2$74fc38c9:(Ltests/Log;)V

Which uses getDeclaredMethod to find the current method. 

If however the @annotation(x) is not used, and the annotation is extracted inside the advice using 

Log log = (Log) ((MethodSignature) thisJoinPointStaticPart.getSignature()).getMethod().getAnnotation(Log.class);           

this is 10 times faster than the code produced by AspectJ.

This makes using @annotation a performance problem, while it could probably be optimized in two ways :
- Use thisJoinPointStaticPart to make it a performance-equivalent
- Annotation could even be cached and reused, without calling getAnnotation every time, to make it even more efficient.


Reproducible: Always

Steps to Reproduce:
1. See attached sample project
2. Comment/uncomment the two advices in Intercept.aj
Comment 1 Simone Gianni CLA 2009-11-30 10:36:13 EST
Created attachment 153350 [details]
Sample project, provided by Oliver Hoff, demonstrating the performance problem
Comment 2 Andrew Clement CLA 2009-11-30 12:21:26 EST
Yes, when I looked at the generated code last night I came to the same conclusion as Simone.  This stuff hasn't been reviewed since first being added in 1.5.0.

Caching the annotation seems the best option for now.
Comment 3 Andrew Clement CLA 2009-11-30 12:39:49 EST
Just found this tag in the AspectJ source :D

// OPTIMIZE cache result of getDeclaredMethod and getAnnotation?
Comment 4 Simone Gianni CLA 2009-11-30 13:01:22 EST
:D
Comment 5 Andrew Clement CLA 2009-11-30 16:03:43 EST
Changes are in to cache, it is quicker, but it is not as quick as the syntax for binding the string directly (see bug 296501).

Numbers for 1,000,000 iterations:

Manually fetching annotation with getAnnotation(): 645ms
Binding annotation with @annotation(Marker): 445ms (was > 20seconds)
Binding annotation value with @annotation(Marker(message)): 3ms
Comment 6 Andrew Clement CLA 2009-12-01 15:33:45 EST
fixed