]> source.dussan.org Git - aspectj.git/commitdiff
133770 'call and ltw': now able to complete ITD binding for binary types in LTW world
authoraclement <aclement>
Mon, 14 Aug 2006 14:21:38 +0000 (14:21 +0000)
committeraclement <aclement>
Mon, 14 Aug 2006 14:21:38 +0000 (14:21 +0000)
weaver/src/org/aspectj/weaver/World.java
weaver/src/org/aspectj/weaver/bcel/BcelWorld.java
weaver/src/org/aspectj/weaver/ltw/LTWWorld.java

index fb17ab9d32daf81530f6eec9356d30a40282caac..2112f3525138818893ba80490950a3c9d3cc88df 100644 (file)
@@ -109,6 +109,7 @@ public abstract class World implements Dump.INode {
     private boolean fastDelegateSupportEnabled = isASMAround;
        private boolean runMinimalMemory = false;
        private boolean shouldPipelineCompilation = true;
+       private boolean completeBinaryTypes = true;
        public boolean forDEBUG_structuralChangesCode = false;
        public boolean forDEBUG_bridgingCode = false;
        
@@ -267,6 +268,24 @@ public abstract class World implements Dump.INode {
             if (!allowMissing && ret.isMissing()) {
                 ret = handleRequiredMissingTypeDuringResolution(ty);
             }
+            
+            if (completeBinaryTypes && needsCompletion() && isLocallyDefined(ret.getName())) {
+               if (typeCompletionInProgress) {
+                       typesForCompletion.add(ret);
+               } else {                        
+                       try {
+                               typeCompletionInProgress=true;
+                               completeType(ret);
+                       } finally {
+                               typeCompletionInProgress=false;
+                       }
+                       while (typesForCompletion.size()!=0) {
+                               ResolvedType rt = (ResolvedType)typesForCompletion.get(0);
+                               completeType(rt);
+                               typesForCompletion.remove(0);
+                       }
+               }
+            }
         }        
   
                // Pulling in the type may have already put the right entry in the map
@@ -275,7 +294,42 @@ public abstract class World implements Dump.INode {
                }
         return ret;
     }
+    
+    // --- these methods are for supporting loadtime weaving with inter type declarations
+    // the idea is that when types are resolved, we give the world a chance to say whether
+    // it needs to 'finish them off' - ie. attach type mungers for ITDs.  These types won't
+    // actually get woven at this time, they will merely have type mungers attached to them
+    // for the purposes of answering questions like 'what is your supertype?' correctly.
+
+    /**
+     * return true if types need completing when getting resolved - overridden by subtypes.
+     */
+    protected boolean needsCompletion() {
+               return false;
+       }
+    
+       /**
+     * Called when a type is resolved - enables its type hierarchy to be finished off before we
+     * proceed
+     */
+    protected void completeType(ResolvedType ret) {}
+    
+    
+    /**
+     * Return true if the classloader relating to this world is definetly the one that will
+     * define the specified class.  Return false otherwise or we don't know for certain.
+     */
+    public boolean isLocallyDefined(String classname) {
+       return false;
+    }
 
+    // One type is completed at a time, if multiple need doing then they
+    // are queued up
+       private boolean typeCompletionInProgress = false;
+    private List/*ResolvedType*/typesForCompletion = new ArrayList();
+    
+    // ---
+    
     /**
      * We tried to resolve a type and couldn't find it...
      */
@@ -765,8 +819,10 @@ public abstract class World implements Dump.INode {
        public final static String xsetRUN_MINIMAL_MEMORY ="runMinimalMemory"; // default true
        public final static String xsetDEBUG_STRUCTURAL_CHANGES_CODE = "debugStructuralChangesCode"; // default false
        public final static String xsetDEBUG_BRIDGING = "debugBridging"; // default false
-       public final static String xsetPIPELINE_COMPILATION = "pipelineCompilation"; // default true
+       public final static String xsetPIPELINE_COMPILATION = "pipelineCompilation";
        public final static String xsetPIPELINE_COMPILATION_DEFAULT = "true"; 
+       public final static String xsetCOMPLETE_BINARY_TYPES = "completeBinaryTypes";
+       public final static String xsetCOMPLETE_BINARY_TYPES_DEFAULT = "true"; 
        
        public boolean isInJava5Mode() {
                return behaveInJava5Way;
@@ -1153,6 +1209,12 @@ public abstract class World implements Dump.INode {
                                
                                String s = p.getProperty(xsetPIPELINE_COMPILATION,xsetPIPELINE_COMPILATION_DEFAULT);
                                shouldPipelineCompilation = s.equalsIgnoreCase("true");
+
+                               s = p.getProperty(xsetCOMPLETE_BINARY_TYPES,xsetCOMPLETE_BINARY_TYPES_DEFAULT);
+                               completeBinaryTypes = s.equalsIgnoreCase("true");
+                               if (!completeBinaryTypes) {
+                                       getMessageHandler().handleMessage(MessageUtil.info("[completeBinaryTypes=false] Completion of binary types deactivated"));
+                               }
                                
                                s = p.getProperty(xsetRUN_MINIMAL_MEMORY,"false");
                        runMinimalMemory = s.equalsIgnoreCase("true");
@@ -1206,4 +1268,4 @@ public abstract class World implements Dump.INode {
            public boolean isASMAround() { 
                return isASMAround;
            }
-}
+}
\ No newline at end of file
index f7bd4d5f1955f2c2fa493c50fb398c80718ca847..b0d5ce96ac8a81bcae599456436d6096617c9584 100644 (file)
@@ -53,11 +53,14 @@ import org.aspectj.bridge.IMessageHandler;
 import org.aspectj.weaver.Advice;
 import org.aspectj.weaver.AdviceKind;
 import org.aspectj.weaver.AjAttribute;
+import org.aspectj.weaver.AnnotationOnTypeMunger;
+import org.aspectj.weaver.AnnotationX;
 import org.aspectj.weaver.BCException;
 import org.aspectj.weaver.ConcreteTypeMunger;
 import org.aspectj.weaver.ICrossReferenceHandler;
 import org.aspectj.weaver.Member;
 import org.aspectj.weaver.MemberImpl;
+import org.aspectj.weaver.NewParentTypeMunger;
 import org.aspectj.weaver.ReferenceType;
 import org.aspectj.weaver.ReferenceTypeDelegate;
 import org.aspectj.weaver.ResolvedMember;
@@ -68,6 +71,8 @@ import org.aspectj.weaver.UnresolvedType;
 import org.aspectj.weaver.World;
 import org.aspectj.weaver.AjAttribute.Aspect;
 import org.aspectj.weaver.asm.AsmDelegate;
+import org.aspectj.weaver.patterns.DeclareAnnotation;
+import org.aspectj.weaver.patterns.DeclareParents;
 import org.aspectj.weaver.patterns.FormalBinding;
 import org.aspectj.weaver.patterns.PerClause;
 import org.aspectj.weaver.patterns.Pointcut;
@@ -719,4 +724,127 @@ public class BcelWorld extends World implements Repository {
             return true;
         }
     }
+
+    /**
+        * Apply a single declare parents - return true if we change the type
+        */
+       private boolean applyDeclareParents(DeclareParents p, ResolvedType onType) {
+               boolean didSomething = false;
+               List newParents = p.findMatchingNewParents(onType,true);
+               if (!newParents.isEmpty()) {
+                       didSomething=true;
+                       BcelObjectType classType = BcelWorld.getBcelObjectType(onType);
+                       //System.err.println("need to do declare parents for: " + onType);
+                       for (Iterator j = newParents.iterator(); j.hasNext(); ) {
+                               ResolvedType newParent = (ResolvedType)j.next();
+                                                                       
+                               // We set it here so that the imminent matching for ITDs can succeed - we 
+                       // still haven't done the necessary changes to the class file itself 
+                       // (like transform super calls) - that is done in BcelTypeMunger.mungeNewParent()
+                               classType.addParent(newParent);
+                               ResolvedTypeMunger newParentMunger = new NewParentTypeMunger(newParent);
+                       newParentMunger.setSourceLocation(p.getSourceLocation());
+                               onType.addInterTypeMunger(new BcelTypeMunger(newParentMunger, getCrosscuttingMembersSet().findAspectDeclaringParents(p)));
+                       }
+               }
+               return didSomething;
+       }
+    
+       /**
+        * Apply a declare @type - return true if we change the type
+        */
+       private boolean applyDeclareAtType(DeclareAnnotation decA, ResolvedType onType,boolean reportProblems) {
+               boolean didSomething = false;
+               if (decA.matches(onType)) {
+                       
+                   if (onType.hasAnnotation(decA.getAnnotationX().getSignature())) {
+                     // already has it
+                     return false;
+                   }
+                       
+                       AnnotationX annoX = decA.getAnnotationX();
+                       
+                       // check the annotation is suitable for the target
+                       boolean isOK = checkTargetOK(decA,onType,annoX);
+
+                       if (isOK) {
+                               didSomething = true;
+                               ResolvedTypeMunger newAnnotationTM = new AnnotationOnTypeMunger(annoX);
+                               newAnnotationTM.setSourceLocation(decA.getSourceLocation());
+                               onType.addInterTypeMunger(new BcelTypeMunger(newAnnotationTM,decA.getAspect().resolve(this)));
+                               decA.copyAnnotationTo(onType);
+                       }
+               }
+               return didSomething;
+       }
+
+       /**
+        * Checks for an @target() on the annotation and if found ensures it allows the annotation
+        * to be attached to the target type that matched.
+        */
+       private boolean checkTargetOK(DeclareAnnotation decA, ResolvedType onType, AnnotationX annoX) {
+               if (annoX.specifiesTarget()) {
+                 if (  (onType.isAnnotation() && !annoX.allowedOnAnnotationType()) ||
+                               (!annoX.allowedOnRegularType())) {
+                         return false;
+                 }
+               }
+               return true;
+       }
+       
+       // Hmmm - very similar to the code in BcelWeaver.weaveParentTypeMungers - this code
+       // doesn't need to produce errors/warnings though as it won't really be weaving.
+       protected void weaveInterTypeDeclarations(ResolvedType onType) {
+               
+               List declareParentsList = getCrosscuttingMembersSet().getDeclareParents();
+               if (onType.isRawType()) onType = onType.getGenericType();
+               onType.clearInterTypeMungers(); 
+               
+               List decpToRepeat = new ArrayList();
+
+               boolean aParentChangeOccurred      = false;
+               boolean anAnnotationChangeOccurred = false;
+               // First pass - apply all decp mungers
+               for (Iterator i = declareParentsList.iterator(); i.hasNext(); ) {
+                       DeclareParents decp = (DeclareParents)i.next();
+                       boolean typeChanged = applyDeclareParents(decp,onType);
+                       if (typeChanged) {
+                               aParentChangeOccurred = true;
+                       } else { // Perhaps it would have matched if a 'dec @type' had modified the type
+                               if (!decp.getChild().isStarAnnotation()) decpToRepeat.add(decp);
+                       }
+               }
+
+               // Still first pass - apply all dec @type mungers
+               for (Iterator i = getCrosscuttingMembersSet().getDeclareAnnotationOnTypes().iterator();i.hasNext();) {
+                       DeclareAnnotation decA = (DeclareAnnotation)i.next();
+                       boolean typeChanged = applyDeclareAtType(decA,onType,true);
+                       if (typeChanged) {
+                               anAnnotationChangeOccurred = true;
+                       }
+               }
+               
+               while ((aParentChangeOccurred || anAnnotationChangeOccurred) && !decpToRepeat.isEmpty()) {
+                       anAnnotationChangeOccurred = aParentChangeOccurred = false;
+                       List decpToRepeatNextTime = new ArrayList();
+                       for (Iterator iter = decpToRepeat.iterator(); iter.hasNext();) {
+                               DeclareParents decp = (DeclareParents) iter.next();
+                               boolean typeChanged = applyDeclareParents(decp,onType);
+                               if (typeChanged) {
+                                       aParentChangeOccurred = true;
+                               } else {
+                                       decpToRepeatNextTime.add(decp);
+                               }
+                       }
+                       
+                       for (Iterator iter = getCrosscuttingMembersSet().getDeclareAnnotationOnTypes().iterator(); iter.hasNext();) {
+                               DeclareAnnotation decA = (DeclareAnnotation) iter.next();
+                               boolean typeChanged = applyDeclareAtType(decA,onType,false);
+                               if (typeChanged) {
+                                       anAnnotationChangeOccurred = true;
+                               }
+                       }
+                       decpToRepeat = decpToRepeatNextTime;
+               }
+    }
 }
\ No newline at end of file
index 2a9db1024569d08822285339b5ce6a8585bd2b70..49596ca51a30b916594d3dd6a2761f320791bf90 100644 (file)
@@ -24,6 +24,7 @@ import org.aspectj.weaver.ReferenceType;
 import org.aspectj.weaver.ReferenceTypeDelegate;
 import org.aspectj.weaver.ResolvedType;
 import org.aspectj.weaver.bcel.BcelWorld;
+import org.aspectj.weaver.loadtime.IWeavingContext;
 import org.aspectj.weaver.reflect.AnnotationFinder;
 import org.aspectj.weaver.reflect.IReflectionWorld;
 import org.aspectj.weaver.reflect.ReflectionBasedReferenceTypeDelegateFactory;
@@ -47,6 +48,7 @@ public class LTWWorld extends BcelWorld implements IReflectionWorld {
        
     private AnnotationFinder annotationFinder;
     private ClassLoader loader; // weavingContext?
+    private IWeavingContext weavingContext;
     
     protected final static Class concurrentMapClass = makeConcurrentMapClass();
     protected static Map/*<String, WeakReference<ReflectionBasedReferenceTypeDelegate>>*/ bootstrapTypes = makeConcurrentMap();
@@ -54,9 +56,10 @@ public class LTWWorld extends BcelWorld implements IReflectionWorld {
     /**
      * Build a World from a ClassLoader, for LTW support
      */
-    public LTWWorld(ClassLoader loader, IMessageHandler handler, ICrossReferenceHandler xrefHandler) {
+    public LTWWorld(ClassLoader loader, IWeavingContext weavingContext, IMessageHandler handler, ICrossReferenceHandler xrefHandler) {
         super(loader, handler, xrefHandler);
         this.loader = loader;
+        this.weavingContext = weavingContext;
         
         setBehaveInJava5Way(LangUtil.is15VMOrGreater());
         annotationFinder = ReflectionWorld.makeAnnotationFinderIfAny(loader, this);
@@ -184,4 +187,18 @@ public class LTWWorld extends BcelWorld implements IReflectionWorld {
             return true;
     }
     
+       protected void completeType(ResolvedType ret) {
+       getLint().typeNotExposedToWeaver.setSuppressed(true);
+       weaveInterTypeDeclarations(ret);
+       getLint().typeNotExposedToWeaver.setSuppressed(false);
+       }
+
+       protected boolean needsCompletion() {
+               return true;
+       }
+
+       public boolean isLocallyDefined(String classname) {
+               return weavingContext.isLocallyDefined(classname);
+       }
+    
 }