diff options
author | aclement <aclement> | 2011-09-02 22:33:05 +0000 |
---|---|---|
committer | aclement <aclement> | 2011-09-02 22:33:05 +0000 |
commit | 481a2b0d10eea16364bb7edcd0bd3a214948f5e0 (patch) | |
tree | 06b510b0503ee16294df47176c0d848cfffa4136 | |
parent | 11f0639de5913d78ef8a83421dd2afa06a6fd792 (diff) | |
download | aspectj-481a2b0d10eea16364bb7edcd0bd3a214948f5e0.tar.gz aspectj-481a2b0d10eea16364bb7edcd0bd3a214948f5e0.zip |
356612
-rw-r--r-- | weaver/src/org/aspectj/weaver/bcel/AnnotationAccessVar.java | 53 | ||||
-rw-r--r-- | weaver/src/org/aspectj/weaver/bcel/BcelShadow.java | 8 | ||||
-rw-r--r-- | weaver/src/org/aspectj/weaver/bcel/LazyClassGen.java | 18 |
3 files changed, 58 insertions, 21 deletions
diff --git a/weaver/src/org/aspectj/weaver/bcel/AnnotationAccessVar.java b/weaver/src/org/aspectj/weaver/bcel/AnnotationAccessVar.java index 54b6361de..88a67d666 100644 --- a/weaver/src/org/aspectj/weaver/bcel/AnnotationAccessVar.java +++ b/weaver/src/org/aspectj/weaver/bcel/AnnotationAccessVar.java @@ -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)); diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java b/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java index 897277699..8c51e0f49 100644 --- a/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java +++ b/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java @@ -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)); } } diff --git a/weaver/src/org/aspectj/weaver/bcel/LazyClassGen.java b/weaver/src/org/aspectj/weaver/bcel/LazyClassGen.java index e87b92a51..6a41e410d 100644 --- a/weaver/src/org/aspectj/weaver/bcel/LazyClassGen.java +++ b/weaver/src/org/aspectj/weaver/bcel/LazyClassGen.java @@ -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); } } |