]> source.dussan.org Git - aspectj.git/commitdiff
356612
authoraclement <aclement>
Fri, 2 Sep 2011 22:33:05 +0000 (22:33 +0000)
committeraclement <aclement>
Fri, 2 Sep 2011 22:33:05 +0000 (22:33 +0000)
weaver/src/org/aspectj/weaver/bcel/AnnotationAccessVar.java
weaver/src/org/aspectj/weaver/bcel/BcelShadow.java
weaver/src/org/aspectj/weaver/bcel/LazyClassGen.java

index 54b6361de6c0a2c9f4c9d5cbcc0ce5b5da8c2bfb..88a67d666ff08556a2c3c00fb46a9cf6a234aff6 100644 (file)
@@ -39,14 +39,16 @@ public class AnnotationAccessVar extends BcelVar {
        private Kind kind; // What kind of shadow are we at?
        private UnresolvedType containingType; // The type upon which we want to ask for 'member'
        private Member member; // Holds the member that has the annotations (for method/field join points)
+       private boolean isWithin; // implies @within() or @withincode(). If false, that implies @annotation()
 
        public AnnotationAccessVar(BcelShadow shadow, Kind kind, ResolvedType annotationType, UnresolvedType theTargetIsStoredHere,
-                       Member sig) {
+                       Member sig, boolean isWithin) {
                super(annotationType, 0);
                this.shadow = shadow;
                this.kind = kind;
                this.containingType = theTargetIsStoredHere;
                this.member = sig;
+               this.isWithin = isWithin;
        }
 
        public Kind getKind() {
@@ -120,7 +122,7 @@ public class AnnotationAccessVar extends BcelVar {
                                        || ((kind == Shadow.ConstructorCall || kind == Shadow.ConstructorExecution) && member.getKind() == Member.METHOD)) {
 
                                // Need to look at the cached annotation before going to fetch it again
-                               Field annotationCachingField = shadow.getEnclosingClass().getAnnotationCachingField(shadow, toType);
+                               Field annotationCachingField = shadow.getEnclosingClass().getAnnotationCachingField(shadow, toType, isWithin);
 
                                // Basic idea here is to check if the cached field is null, if it is then initialize it, otherwise use it
                                il.append(fact.createGetStatic(shadow.getEnclosingClass().getName(), annotationCachingField.getName(), jlAnnotation));
@@ -156,14 +158,7 @@ public class AnnotationAccessVar extends BcelVar {
                                                new Type[] { jlClass }, Constants.INVOKEVIRTUAL));
                        }
                } else if (kind == Shadow.FieldSet || kind == Shadow.FieldGet) {
-                       Type jlrField = BcelWorld.makeBcelType(UnresolvedType.JAVA_LANG_REFLECT_FIELD);
-                       il.append(fact.createConstant(BcelWorld.makeBcelType(containingType))); // Stick the target on the stack
-                       il.append(fact.createConstant(member.getName())); // Stick what we are after on the stack
-                       il.append(fact.createInvoke("java/lang/Class", "getDeclaredField", jlrField, new Type[] { jlString },
-                                       Constants.INVOKEVIRTUAL));
-                       il.append(pushConstant);
-                       il.append(fact.createInvoke("java/lang/reflect/Field", "getAnnotation", jlaAnnotation, new Type[] { jlClass },
-                                       Constants.INVOKEVIRTUAL));
+                       generateBytecodeToAccessAnnotationAtFieldGetSetShadow(toType, fact, il, pushConstant);
                } else if (kind == Shadow.StaticInitialization || kind == Shadow.ExceptionHandler) {
                        il.append(fact.createConstant(BcelWorld.makeBcelType(containingType)));
                        il.append(pushConstant);
@@ -176,6 +171,44 @@ public class AnnotationAccessVar extends BcelVar {
                return il;
        }
 
+       /**
+        * At a FieldGet or FieldSet shadow, generate the bytecode to access the annotation for that field. The annotation is cached so
+        * the code checks that cached value before proceeding.
+        */
+       private void generateBytecodeToAccessAnnotationAtFieldGetSetShadow(ResolvedType toType, InstructionFactory fact,
+                       InstructionList il, Instruction pushConstantAnnotationType) {
+               Type jlClass = BcelWorld.makeBcelType(UnresolvedType.JL_CLASS);
+               Type jlString = BcelWorld.makeBcelType(UnresolvedType.JL_STRING);
+               Type jlaAnnotation = BcelWorld.makeBcelType(UnresolvedType.JAVA_LANG_ANNOTATION);
+               Type jlrField = BcelWorld.makeBcelType(UnresolvedType.JAVA_LANG_REFLECT_FIELD);
+
+               LazyClassGen shadowEnclosingClass = shadow.getEnclosingClass();
+
+               // The annotation for the field of interest is cached, check cached value before fetching it
+               Field annotationCachingField = shadowEnclosingClass.getAnnotationCachingField(shadow, toType, isWithin);
+               String annotationCachingFieldName = annotationCachingField.getName();
+
+               // Basic idea here is to check if the cached field is null, if it is then initialize it, otherwise use it
+               il.append(fact.createGetStatic(shadowEnclosingClass.getName(), annotationCachingFieldName, jlaAnnotation));
+               il.appendDUP();
+               InstructionBranch ifNonNull = new InstructionBranch(Constants.IFNONNULL, null);
+               il.append(ifNonNull);
+               il.appendPOP();
+
+               // get the field of interest
+               il.append(fact.createConstant(BcelWorld.makeBcelType(containingType)));
+               il.append(fact.createConstant(member.getName()));
+               il.append(fact.createInvoke("java/lang/Class", "getDeclaredField", jlrField, new Type[] { jlString },
+                               Constants.INVOKEVIRTUAL));
+               il.append(pushConstantAnnotationType);
+               il.append(fact.createInvoke("java/lang/reflect/Field", "getAnnotation", jlaAnnotation, new Type[] { jlClass },
+                               Constants.INVOKEVIRTUAL));
+               il.appendDUP();
+               il.append(fact.createPutStatic(shadowEnclosingClass.getName(), annotationCachingFieldName, jlaAnnotation));
+               InstructionHandle ifNullElse = il.appendNOP();
+               ifNonNull.setTarget(ifNullElse);
+       }
+
        private void buildArray(InstructionList il, InstructionFactory fact, Type arrayElementType, Type[] arrayEntries, int dim) {
                il.append(fact.createConstant(Integer.valueOf(arrayEntries == null ? 0 : arrayEntries.length)));
                il.append(fact.createNewArray(arrayElementType, (short) dim));
index 8972776996d4d84d51eb5146485b9b4e163a302e..8c51e0f4909b10a3b863c0ded298841d7d266146 100644 (file)
@@ -1612,7 +1612,7 @@ public class BcelShadow extends Shadow {
 
                for (ResolvedType annotationType : annotations) {
                        AnnotationAccessVar accessVar = new AnnotationAccessVar(this, getKind(), annotationType.resolve(world), relevantType,
-                                       annotationHolder);
+                                       annotationHolder, false);
                        kindedAnnotationVars.put(annotationType, accessVar);
                }
        }
@@ -1659,7 +1659,7 @@ public class BcelShadow extends Shadow {
                for (int i = 0; i < annotations.length; i++) {
                        ResolvedType ann = annotations[i];
                        Kind k = Shadow.StaticInitialization;
-                       withinAnnotationVars.put(ann, new AnnotationAccessVar(this, k, ann, getEnclosingType(), null));
+                       withinAnnotationVars.put(ann, new AnnotationAccessVar(this, k, ann, getEnclosingType(), null, true));
                }
        }
 
@@ -1675,8 +1675,8 @@ public class BcelShadow extends Shadow {
                        ResolvedType ann = annotations[i];
                        Kind k = (getEnclosingMethod().getMemberView().getKind() == Member.CONSTRUCTOR ? Shadow.ConstructorExecution
                                        : Shadow.MethodExecution);
-                       withincodeAnnotationVars.put(ann,
-                                       new AnnotationAccessVar(this, k, ann, getEnclosingType(), getEnclosingCodeSignature()));
+                       withincodeAnnotationVars.put(ann, new AnnotationAccessVar(this, k, ann, getEnclosingType(),
+                                       getEnclosingCodeSignature(), true));
                }
        }
 
index e87b92a51060c094efd353d77f8bb11a630190dd..6a41e410d27aa3b14f3708f22123565b864ec2da 100644 (file)
@@ -1048,10 +1048,11 @@ public final class LazyClassGen {
         * @param shadow the shadow at which the @annotation result is being cached
         * @return a field
         */
-       public Field getAnnotationCachingField(BcelShadow shadow, ResolvedType toType) {
+       public Field getAnnotationCachingField(BcelShadow shadow, ResolvedType toType, boolean isWithin) {
                // Multiple annotation types at a shadow. A different field would be required for each
-               CacheKey cacheKey = new CacheKey(shadow, toType);
+               CacheKey cacheKey = new CacheKey(shadow, toType, isWithin);
                Field field = annotationCachingFieldCache.get(cacheKey);
+               // System.out.println(field + " for shadow " + shadow);
                if (field == null) {
                        // private static Annotation ajc$anno$<nnn>
                        StringBuilder sb = new StringBuilder();
@@ -1066,17 +1067,20 @@ public final class LazyClassGen {
        }
 
        static class CacheKey {
-               private BcelShadow shadow;
+               private Object key;
                private ResolvedType annotationType;
 
-               CacheKey(BcelShadow shadow, ResolvedType annotationType) {
-                       this.shadow = shadow;
+               // If the annotation is being accessed via @annotation on a shadow then we can use the shadows toString() (so two shadows
+               // the same share a variable), but if it is @withincode() or @within() we can't share them (as the shadows may look the same
+               // but be occurring 'within' different things). In the within cases we continue to use the shadow itself as the key.
+               CacheKey(BcelShadow shadow, ResolvedType annotationType, boolean isWithin) {
+                       this.key = isWithin ? shadow : shadow.toString();
                        this.annotationType = annotationType;
                }
 
                @Override
                public int hashCode() {
-                       return shadow.hashCode() * 37 + annotationType.hashCode();
+                       return key.hashCode() * 37 + annotationType.hashCode();
                }
 
                @Override
@@ -1085,7 +1089,7 @@ public final class LazyClassGen {
                                return false;
                        }
                        CacheKey oCacheKey = (CacheKey) other;
-                       return shadow.equals(oCacheKey.shadow) && annotationType.equals(oCacheKey.annotationType);
+                       return key.equals(oCacheKey.key) && annotationType.equals(oCacheKey.annotationType);
                }
        }