aboutsummaryrefslogtreecommitdiffstats
path: root/weaver
diff options
context:
space:
mode:
authoraclement <aclement>2006-08-14 14:21:38 +0000
committeraclement <aclement>2006-08-14 14:21:38 +0000
commit2d33e8d998fde7f5d695e8be56b2d197622e7cfc (patch)
tree4906fe65937d62647d3f3b18c89c8d45df4c207d /weaver
parent67bbaac0301bf2007c16ab5b6ad0e62664a99fbd (diff)
downloadaspectj-2d33e8d998fde7f5d695e8be56b2d197622e7cfc.tar.gz
aspectj-2d33e8d998fde7f5d695e8be56b2d197622e7cfc.zip
133770 'call and ltw': now able to complete ITD binding for binary types in LTW world
Diffstat (limited to 'weaver')
-rw-r--r--weaver/src/org/aspectj/weaver/World.java66
-rw-r--r--weaver/src/org/aspectj/weaver/bcel/BcelWorld.java128
-rw-r--r--weaver/src/org/aspectj/weaver/ltw/LTWWorld.java19
3 files changed, 210 insertions, 3 deletions
diff --git a/weaver/src/org/aspectj/weaver/World.java b/weaver/src/org/aspectj/weaver/World.java
index fb17ab9d3..2112f3525 100644
--- a/weaver/src/org/aspectj/weaver/World.java
+++ b/weaver/src/org/aspectj/weaver/World.java
@@ -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
diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelWorld.java b/weaver/src/org/aspectj/weaver/bcel/BcelWorld.java
index f7bd4d5f1..b0d5ce96a 100644
--- a/weaver/src/org/aspectj/weaver/bcel/BcelWorld.java
+++ b/weaver/src/org/aspectj/weaver/bcel/BcelWorld.java
@@ -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
diff --git a/weaver/src/org/aspectj/weaver/ltw/LTWWorld.java b/weaver/src/org/aspectj/weaver/ltw/LTWWorld.java
index 2a9db1024..49596ca51 100644
--- a/weaver/src/org/aspectj/weaver/ltw/LTWWorld.java
+++ b/weaver/src/org/aspectj/weaver/ltw/LTWWorld.java
@@ -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);
+ }
+
}