]> source.dussan.org Git - aspectj.git/commitdiff
296484:296501: annotationbinding
authoraclement <aclement>
Mon, 30 Nov 2009 21:04:11 +0000 (21:04 +0000)
committeraclement <aclement>
Mon, 30 Nov 2009 21:04:11 +0000 (21:04 +0000)
weaver/src/org/aspectj/weaver/bcel/AnnotationAccessFieldVar.java
weaver/src/org/aspectj/weaver/bcel/AnnotationAccessVar.java
weaver/src/org/aspectj/weaver/bcel/BcelShadow.java
weaver/src/org/aspectj/weaver/bcel/LazyClassGen.java

index c7d0e281e0b7afb150598958bd72815577b5764f..c96987f537d09ec64dc887b2030bbf22aff40db1 100644 (file)
@@ -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();
        }
index 60578ca10f04c055727e508b927d7f004b7c48b2..a083cca9836b9c23e9c2fdfd13b31ee3725abca2 100644 (file)
 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);
        }
index eaf8a8157404613818ba64f0ba09b7eddf6bb170..3738ebc3425241f8beb63eb83c1aca06c9735fbf 100644 (file)
@@ -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()));
                }
        }
 
index 6ae91ee69b70127880e49ca1090c798fab9ab2a1..fd0634ad5871638d4c5df2273e9ab8997492c1b1 100644 (file)
@@ -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??