import java.util.List;
import org.aspectj.apache.bcel.classfile.annotation.AnnotationGen;
-import org.aspectj.apache.bcel.classfile.annotation.NameValuePair;
import org.aspectj.apache.bcel.classfile.annotation.EnumElementValue;
+import org.aspectj.apache.bcel.classfile.annotation.NameValuePair;
+import org.aspectj.apache.bcel.classfile.annotation.SimpleElementValue;
import org.aspectj.apache.bcel.generic.InstructionFactory;
import org.aspectj.apache.bcel.generic.InstructionList;
import org.aspectj.apache.bcel.generic.Type;
this.annoFieldOfInterest = annoFieldOfInterest;
}
+ @Override
public void appendLoadAndConvert(InstructionList il, InstructionFactory fact, ResolvedType toType) {
// Only possible to do annotation field value extraction at
// MethodExecution
boolean doneAndDusted = false;
for (Iterator iterator = vals.iterator(); iterator.hasNext();) {
NameValuePair object = (NameValuePair) iterator.next();
- EnumElementValue v = (EnumElementValue) object.getValue();
- String s = v.getEnumTypeString();
- ResolvedType rt = toType.getWorld().resolve(UnresolvedType.forSignature(s));
- if (rt.equals(toType)) {
- il.append(fact.createGetStatic(rt.getName(), v.getEnumValueString(), Type.getType(rt.getSignature())));
+ Object o = object.getValue();
+ if (o instanceof EnumElementValue) {
+ EnumElementValue v = (EnumElementValue) object.getValue();
+ String s = v.getEnumTypeString();
+ ResolvedType rt = toType.getWorld().resolve(UnresolvedType.forSignature(s));
+ if (rt.equals(toType)) {
+ il.append(fact.createGetStatic(rt.getName(), v.getEnumValueString(), Type.getType(rt.getSignature())));
+ doneAndDusted = true;
+ }
+ } else if (o instanceof SimpleElementValue) {
+ // FIXASC types other than String will go bang bang at runtime
+ SimpleElementValue v = (SimpleElementValue) object.getValue();
+ il.append(fact.createConstant(v.getValueString()));
doneAndDusted = true;
+ // String s = v.getEnumTypeString();
+ // ResolvedType rt = toType.getWorld().resolve(UnresolvedType.forSignature(s));
+ // if (rt.equals(toType)) {
+ // il.append(fact.createGetStatic(rt.getName(), v.getEnumValueString(), Type.getType(rt.getSignature())));
+ // doneAndDusted = true;
+ // }
+ int stop = 1;
}
}
if (!doneAndDusted) {
}
}
+ @Override
public void insertLoad(InstructionList il, InstructionFactory fact) {
// Only possible to do annotation field value extraction at
// MethodExecution
appendLoadAndConvert(il, fact, annoFieldOfInterest);
}
+ @Override
public String toString() {
return super.toString();
}
package org.aspectj.weaver.bcel;
import org.aspectj.apache.bcel.Constants;
+import org.aspectj.apache.bcel.classfile.Field;
import org.aspectj.apache.bcel.generic.Instruction;
+import org.aspectj.apache.bcel.generic.InstructionBranch;
import org.aspectj.apache.bcel.generic.InstructionConstants;
import org.aspectj.apache.bcel.generic.InstructionFactory;
+import org.aspectj.apache.bcel.generic.InstructionHandle;
import org.aspectj.apache.bcel.generic.InstructionList;
import org.aspectj.apache.bcel.generic.ObjectType;
import org.aspectj.apache.bcel.generic.Type;
*/
public class AnnotationAccessVar extends BcelVar {
+ private BcelShadow shadow;
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)
- public AnnotationAccessVar(Kind kind, ResolvedType annotationType, UnresolvedType theTargetIsStoredHere, Member sig) {
+ public AnnotationAccessVar(BcelShadow shadow, Kind kind, ResolvedType annotationType, UnresolvedType theTargetIsStoredHere,
+ Member sig) {
super(annotationType, 0);
+ this.shadow = shadow;
this.kind = kind;
this.containingType = theTargetIsStoredHere;
this.member = sig;
return kind;
}
+ @Override
public String toString() {
return "AnnotationAccessVar(" + getType() + ")";
}
+ @Override
public Instruction createLoad(InstructionFactory fact) {
throw new IllegalStateException("unimplemented");
}
+ @Override
public Instruction createStore(InstructionFactory fact) {
throw new IllegalStateException("unimplemented");
}
+ @Override
public InstructionList createCopyFrom(InstructionFactory fact, int oldSlot) {
throw new IllegalStateException("unimplemented");
}
+ @Override
public void appendLoad(InstructionList il, InstructionFactory fact) {
il.append(createLoadInstructions(getType(), fact));
}
+ @Override
public void appendLoadAndConvert(InstructionList il, InstructionFactory fact, ResolvedType toType) {
il.append(createLoadInstructions(toType, fact));
}
+ @Override
public void insertLoad(InstructionList il, InstructionFactory fact) {
il.insert(createLoadInstructions(getType(), fact));
}
((kind == Shadow.FieldGet || kind == Shadow.FieldSet) && member.getKind() == Member.METHOD)) {
Type jlrMethod = BcelWorld.makeBcelType(UnresolvedType.forSignature("Ljava/lang/reflect/Method;"));
+ Type jlAnnotation = BcelWorld.makeBcelType(UnresolvedType.forSignature("Ljava/lang/annotation/Annotation;"));
Type[] paramTypes = BcelWorld.makeBcelTypes(member.getParameterTypes());
- il.append(fact.createConstant(BcelWorld.makeBcelType(containingType)));
+ // il.append(fact.createConstant(BcelWorld.makeBcelType(containingType)));
if (kind == Shadow.MethodCall
|| kind == Shadow.MethodExecution
((kind == Shadow.FieldGet || kind == Shadow.FieldSet) && member.getKind() == Member.METHOD)
|| ((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);
+
+ // 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));
+ il.append(InstructionConstants.DUP);
+ InstructionBranch ifNonNull = InstructionFactory.createBranchInstruction(Constants.IFNONNULL, null);
+ il.append(ifNonNull);
+ il.append(InstructionConstants.POP);
+ il.append(fact.createConstant(BcelWorld.makeBcelType(containingType)));
+
il.append(fact.createConstant(member.getName()));
buildArray(il, fact, jlClass, paramTypes, 1);
- // OPTIMIZE cache result of getDeclaredMethod and getAnnotation? Might be able to use it again if someone else needs
- // the same annotations?
+ // OPTIMIZE cache result of getDeclaredMethod?
il.append(fact.createInvoke("java/lang/Class", "getDeclaredMethod", jlrMethod,
new Type[] { jlString, jlClassArray }, Constants.INVOKEVIRTUAL));
il.append(pushConstant);// fact.createConstant(new ObjectType(toType.getName())));
il.append(fact.createInvoke("java/lang/reflect/Method", "getAnnotation", jlaAnnotation, new Type[] { jlClass },
Constants.INVOKEVIRTUAL));
+ il.append(InstructionConstants.DUP);
+ il.append(fact
+ .createPutStatic(shadow.getEnclosingClass().getName(), annotationCachingField.getName(), jlAnnotation));
+ InstructionHandle ifNullElse = il.append(InstructionConstants.NOP);
+ ifNonNull.setTarget(ifNullElse);
+
} else { // init/preinit/ctor-call/ctor-exec
+ il.append(fact.createConstant(BcelWorld.makeBcelType(containingType)));
buildArray(il, fact, jlClass, paramTypes, 1);
Type jlrCtor = BcelWorld.makeBcelType(UnresolvedType.JAVA_LANG_REFLECT_CONSTRUCTOR);
// OPTIMIZE cache result of getDeclaredConstructor and getAnnotation? Might be able to use it again if someone else
* @param valueType The type from the annotation that is of interest
* @return a variable that represents access to that annotation value
*/
+ @Override
public Var getAccessorForValue(ResolvedType valueType) {
return new AnnotationAccessFieldVar(this, valueType);
}
}
for (ResolvedType annotationType : annotations) {
- AnnotationAccessVar accessVar = new AnnotationAccessVar(getKind(), annotationType.resolve(world), relevantType,
+ AnnotationAccessVar accessVar = new AnnotationAccessVar(this, getKind(), annotationType.resolve(world), relevantType,
annotationHolder);
kindedAnnotationVars.put(annotationType, accessVar);
}
for (int i = 0; i < annotations.length; i++) {
ResolvedType ann = annotations[i];
Kind k = Shadow.StaticInitialization;
- withinAnnotationVars.put(ann, new AnnotationAccessVar(k, ann, getEnclosingType(), null));
+ withinAnnotationVars.put(ann, new AnnotationAccessVar(this, k, ann, getEnclosingType(), null));
}
}
ResolvedType ann = annotations[i];
Kind k = (getEnclosingMethod().getMemberView().getKind() == Member.CONSTRUCTOR ? Shadow.ConstructorExecution
: Shadow.MethodExecution);
- withincodeAnnotationVars.put(ann, new AnnotationAccessVar(k, ann, getEnclosingType(), getEnclosingCodeSignature()));
+ withincodeAnnotationVars.put(ann,
+ new AnnotationAccessVar(this, k, ann, getEnclosingType(), getEnclosingCodeSignature()));
}
}
ResolvedMember[] fields = type.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
ResolvedMember field = fields[i];
- if (field.getName().equals("serialVersionUID") && Modifier.isStatic(field.getModifiers()) && field.getType().equals(ResolvedType.LONG)) {
+ if (field.getName().equals("serialVersionUID") && Modifier.isStatic(field.getModifiers())
+ && field.getType().equals(ResolvedType.LONG)) {
return true;
}
}
// reflective thisJoinPoint support
private Map<BcelShadow, Field> tjpFields = new HashMap<BcelShadow, Field>();
+ Map<CacheKey, Field> annotationCachingFieldCache = new HashMap<CacheKey, Field>();
private int tjpFieldsCounter = -1; // -1 means not yet initialized
+ private int annoFieldsCounter = 0;
public static final ObjectType proceedingTjpType = new ObjectType("org.aspectj.lang.ProceedingJoinPoint");
public static final ObjectType tjpType = new ObjectType("org.aspectj.lang.JoinPoint");
public static final ObjectType staticTjpType = new ObjectType("org.aspectj.lang.JoinPoint$StaticPart");
+ public static final ObjectType typeForAnnotation = new ObjectType("java.lang.annotation.Annotation");
public static final ObjectType enclosingStaticTjpType = new ObjectType("org.aspectj.lang.JoinPoint$EnclosingStaticPart");
private static final ObjectType sigType = new ObjectType("org.aspectj.lang.Signature");
// private static final ObjectType slType =
tjpFieldsCounter = 0;
} else {
tjpFieldsCounter = Integer.parseInt(lastField.getName().substring(8)) + 1;
- //System.out.println("tjp counter starting at " + tjpFieldsCounter);
+ // System.out.println("tjp counter starting at " + tjpFieldsCounter);
}
}
}
return tjpField;
}
+ /**
+ * Create a field in the type containing the shadow where the annotation retrieved during binding can be stored - for later fast
+ * access.
+ *
+ * @param shadow the shadow at which the @annotation result is being cached
+ * @return a field
+ */
+ public Field getAnnotationCachingField(BcelShadow shadow, ResolvedType toType) {
+ // Multiple annotation types at a shadow. A different field would be required for each
+ CacheKey cacheKey = new CacheKey(shadow, toType);
+ Field field = annotationCachingFieldCache.get(cacheKey);
+ if (field == null) {
+ // private static Annotation ajc$anno$<nnn>
+ StringBuilder sb = new StringBuilder();
+ sb.append(NameMangler.ANNOTATION_CACHE_FIELD_NAME);
+ sb.append(annoFieldsCounter++);
+ FieldGen annotationCacheField = new FieldGen(Modifier.PRIVATE | Modifier.STATIC, typeForAnnotation, sb.toString(), cp);
+ addField(annotationCacheField);
+ field = annotationCacheField.getField();
+ annotationCachingFieldCache.put(cacheKey, field);
+ }
+ return field;
+ }
+
+ static class CacheKey {
+ private BcelShadow shadow;
+ private ResolvedType annotationType;
+
+ CacheKey(BcelShadow shadow, ResolvedType annotationType) {
+ this.shadow = shadow;
+ this.annotationType = annotationType;
+ }
+
+ @Override
+ public int hashCode() {
+ return shadow.hashCode() * 37 + annotationType.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof CacheKey)) {
+ return false;
+ }
+ CacheKey oCacheKey = (CacheKey) other;
+ return shadow.equals(oCacheKey.shadow) && annotationType.equals(oCacheKey.annotationType);
+ }
+ }
+
// FIXME ATAJ needed only for slow Aspects.aspectOf - keep or remove
// private void addAjClassField() {
// // Andy: Why build it again??