@@ -15,8 +15,9 @@ import java.util.Iterator; | |||
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; | |||
@@ -44,6 +45,7 @@ class AnnotationAccessFieldVar extends BcelVar { | |||
this.annoFieldOfInterest = annoFieldOfInterest; | |||
} | |||
@Override | |||
public void appendLoadAndConvert(InstructionList il, InstructionFactory fact, ResolvedType toType) { | |||
// Only possible to do annotation field value extraction at | |||
// MethodExecution | |||
@@ -62,12 +64,27 @@ class AnnotationAccessFieldVar extends BcelVar { | |||
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) { | |||
@@ -91,6 +108,7 @@ class AnnotationAccessFieldVar extends BcelVar { | |||
} | |||
} | |||
@Override | |||
public void insertLoad(InstructionList il, InstructionFactory fact) { | |||
// Only possible to do annotation field value extraction at | |||
// MethodExecution | |||
@@ -100,6 +118,7 @@ class AnnotationAccessFieldVar extends BcelVar { | |||
appendLoadAndConvert(il, fact, annoFieldOfInterest); | |||
} | |||
@Override | |||
public String toString() { | |||
return super.toString(); | |||
} |
@@ -13,9 +13,12 @@ | |||
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; | |||
@@ -32,12 +35,15 @@ import org.aspectj.weaver.ast.Var; | |||
*/ | |||
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; | |||
@@ -47,30 +53,37 @@ public class AnnotationAccessVar extends BcelVar { | |||
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)); | |||
} | |||
@@ -93,9 +106,10 @@ public class AnnotationAccessVar extends BcelVar { | |||
((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 | |||
@@ -105,16 +119,34 @@ public class AnnotationAccessVar extends BcelVar { | |||
((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 | |||
@@ -201,6 +233,7 @@ public class AnnotationAccessVar extends BcelVar { | |||
* @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); | |||
} |
@@ -1592,7 +1592,7 @@ public class BcelShadow extends Shadow { | |||
} | |||
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); | |||
} | |||
@@ -1640,7 +1640,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(k, ann, getEnclosingType(), null)); | |||
withinAnnotationVars.put(ann, new AnnotationAccessVar(this, k, ann, getEnclosingType(), null)); | |||
} | |||
} | |||
@@ -1656,7 +1656,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(k, ann, getEnclosingType(), getEnclosingCodeSignature())); | |||
withincodeAnnotationVars.put(ann, | |||
new AnnotationAccessVar(this, k, ann, getEnclosingType(), getEnclosingCodeSignature())); | |||
} | |||
} | |||
@@ -320,7 +320,8 @@ public final class LazyClassGen { | |||
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; | |||
} | |||
} | |||
@@ -926,10 +927,13 @@ public final class LazyClassGen { | |||
// 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 = | |||
@@ -991,7 +995,7 @@ public final class LazyClassGen { | |||
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); | |||
} | |||
} | |||
} | |||
@@ -1003,6 +1007,54 @@ public final class LazyClassGen { | |||
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?? |