aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoraclement <aclement>2011-09-02 22:33:05 +0000
committeraclement <aclement>2011-09-02 22:33:05 +0000
commit481a2b0d10eea16364bb7edcd0bd3a214948f5e0 (patch)
tree06b510b0503ee16294df47176c0d848cfffa4136
parent11f0639de5913d78ef8a83421dd2afa06a6fd792 (diff)
downloadaspectj-481a2b0d10eea16364bb7edcd0bd3a214948f5e0.tar.gz
aspectj-481a2b0d10eea16364bb7edcd0bd3a214948f5e0.zip
356612
-rw-r--r--weaver/src/org/aspectj/weaver/bcel/AnnotationAccessVar.java53
-rw-r--r--weaver/src/org/aspectj/weaver/bcel/BcelShadow.java8
-rw-r--r--weaver/src/org/aspectj/weaver/bcel/LazyClassGen.java18
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);
}
}