From 6abc8f8488c57bf668ff826b678926a3f8c100d7 Mon Sep 17 00:00:00 2001 From: aclement Date: Mon, 30 Nov 2009 21:04:11 +0000 Subject: [PATCH] 296484:296501: annotationbinding --- .../weaver/bcel/AnnotationAccessFieldVar.java | 31 ++++++++-- .../weaver/bcel/AnnotationAccessVar.java | 41 ++++++++++++-- .../org/aspectj/weaver/bcel/BcelShadow.java | 7 ++- .../org/aspectj/weaver/bcel/LazyClassGen.java | 56 ++++++++++++++++++- 4 files changed, 120 insertions(+), 15 deletions(-) diff --git a/weaver/src/org/aspectj/weaver/bcel/AnnotationAccessFieldVar.java b/weaver/src/org/aspectj/weaver/bcel/AnnotationAccessFieldVar.java index c7d0e281e..c96987f53 100644 --- a/weaver/src/org/aspectj/weaver/bcel/AnnotationAccessFieldVar.java +++ b/weaver/src/org/aspectj/weaver/bcel/AnnotationAccessFieldVar.java @@ -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(); } diff --git a/weaver/src/org/aspectj/weaver/bcel/AnnotationAccessVar.java b/weaver/src/org/aspectj/weaver/bcel/AnnotationAccessVar.java index 60578ca10..a083cca98 100644 --- a/weaver/src/org/aspectj/weaver/bcel/AnnotationAccessVar.java +++ b/weaver/src/org/aspectj/weaver/bcel/AnnotationAccessVar.java @@ -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); } diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java b/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java index eaf8a8157..3738ebc34 100644 --- a/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java +++ b/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java @@ -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())); } } diff --git a/weaver/src/org/aspectj/weaver/bcel/LazyClassGen.java b/weaver/src/org/aspectj/weaver/bcel/LazyClassGen.java index 6ae91ee69..fd0634ad5 100644 --- a/weaver/src/org/aspectj/weaver/bcel/LazyClassGen.java +++ b/weaver/src/org/aspectj/weaver/bcel/LazyClassGen.java @@ -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 tjpFields = new HashMap(); + Map annotationCachingFieldCache = new HashMap(); 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$ + 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?? -- 2.39.5