Browse Source

rearchitect @decp

tags/POST_MEMORY_CHANGES
avasseur 18 years ago
parent
commit
2afe12a528

+ 2
- 2
aspectj5rt/java5-src/org/aspectj/lang/annotation/DeclareParents.java View File

@@ -27,7 +27,7 @@ public @interface DeclareParents {
* The target types expression
*/
String value();
/**
* Optional class defining default implementation
* of interface members (equivalent to defining
@@ -35,7 +35,7 @@ public @interface DeclareParents {
* public methods of the interface).
*/
Class defaultImpl() default DeclareParents.class;
// note - a default of "null" is not allowed,
// hence the strange default given above.
}

+ 4
- 3
tests/java5/ataspectj/ataspectj/DeclareParentsImplementsTest.java View File

@@ -50,10 +50,11 @@ public class DeclareParentsImplementsTest extends TestCase {
@Aspect
static class TestAspect {

@DeclareParents("ataspectj.DeclareParentsImplementsTest.Target")
public static Introduced i = new Implementation();//see here control of instantiation
@DeclareParents(value="ataspectj.DeclareParentsImplementsTest.Target",
defaultImpl=Implementation.class)
public static Introduced i;
// will lead to: class Target implements Introduced {
// void intro(args) { TestAspect.i.intro(args); }
// void intro(args) { delegate to some hidden field, lazy initialized here for now }
// }

@Before("execution(* ataspectj.DeclareParentsImplementsTest.Introduced.intro())")

+ 2
- 1
tests/java5/ataspectj/ataspectj/DeclareParentsInterfaceTest.java View File

@@ -15,6 +15,7 @@ import junit.framework.TestCase;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.DeclareImplements;
import org.aspectj.lang.annotation.DeclareParents;

import java.util.Arrays;

@@ -34,7 +35,7 @@ public class DeclareParentsInterfaceTest extends TestCase {
@Aspect
static class TestAspect {

@DeclareImplements("ataspectj.DeclareParentsInterfaceTest.Target")
@DeclareParents("ataspectj.DeclareParentsInterfaceTest.Target")
Marker introduce;

@Before("execution(* ataspectj.DeclareParentsInterfaceTest.Marker+.target())")

+ 1
- 1
tests/ltw/aop-abstractaspect.xml View File

@@ -5,4 +5,4 @@
<weaver options="-showWeaveInfo"/>
</aspectj>

+ 12
- 2
weaver/src/org/aspectj/weaver/AjcMemberMaker.java View File

@@ -499,8 +499,18 @@ public class AjcMemberMaker {
NameMangler.postIntroducedConstructor(aspectType, targetType),
UnresolvedType.insert(targetType, paramTypes));
}
public static ResolvedMember interConstructor(ResolvedType targetType, ResolvedMember constructor, UnresolvedType aspectType) {

public static ResolvedMember itdAtDeclareParentsField(ResolvedType targetType, UnresolvedType itdType, UnresolvedType aspectType) {
return new ResolvedMemberImpl(
Member.FIELD,
targetType,
Modifier.PRIVATE,
itdType,
NameMangler.itdAtDeclareParentsField(aspectType, itdType),
null);
}

public static ResolvedMember interConstructor(ResolvedType targetType, ResolvedMember constructor, UnresolvedType aspectType) {
//
// ResolvedType targetType,
// UnresolvedType[] argTypes,

+ 79
- 29
weaver/src/org/aspectj/weaver/MethodDelegateTypeMunger.java View File

@@ -28,10 +28,12 @@ import org.aspectj.weaver.patterns.TypePattern;
*/
public class MethodDelegateTypeMunger extends ResolvedTypeMunger {

private final UnresolvedType aspect;

/**
* The field in the aspect that hosts the mixin instance
* The mixin impl (no arg ctor)
*/
private final ResolvedMember aspectFieldDelegate;
private final String implClassName;

/**
* Type pattern this munger applies to
@@ -43,52 +45,42 @@ public class MethodDelegateTypeMunger extends ResolvedTypeMunger {
*
* @param signature
* @param aspect
* @param fieldName
* @param implClassName
* @param typePattern
*/
public MethodDelegateTypeMunger(ResolvedMember signature, ResolvedType aspect, String fieldName, TypePattern typePattern) {
public MethodDelegateTypeMunger(ResolvedMember signature, UnresolvedType aspect, String implClassName, TypePattern typePattern) {
super(MethodDelegate, signature);
this.aspect = aspect;
this.typePattern = typePattern;

ResolvedMember[] fields = aspect.getDeclaredFields();//note: will unpack attributes
ResolvedMember field = null;
for (int i = 0; i < fields.length; i++) {
if (fieldName.equals(fields[i].getName())) {
field = fields[i];
break;
}
}
if (field == null) {
throw new RuntimeException("Should not happen: aspect field not found for @DeclareParents delegate");
} else {
aspectFieldDelegate = field;
}
this.implClassName = implClassName;
}

private MethodDelegateTypeMunger(ResolvedMember signature, ResolvedMember fieldDelegate, TypePattern typePattern) {
super(MethodDelegate, signature);
this.aspectFieldDelegate = fieldDelegate;
this.typePattern = typePattern;
public ResolvedMember getDelegate(ResolvedType targetType) {
return AjcMemberMaker.itdAtDeclareParentsField(
targetType,
signature.getDeclaringType(),
aspect
);
}

public ResolvedMember getDelegate() {
return aspectFieldDelegate;
public String getImplClassName() {
return implClassName;
}

public void write(DataOutputStream s) throws IOException {
kind.write(s);
signature.write(s);
aspectFieldDelegate.write(s);
aspect.write(s);
s.writeUTF(implClassName);
typePattern.write(s);
}



public static ResolvedTypeMunger readMethod(VersionedDataInputStream s, ISourceContext context) throws IOException {
ResolvedMemberImpl signature = ResolvedMemberImpl.readResolvedMember(s, context);
ResolvedMemberImpl field = ResolvedMemberImpl.readResolvedMember(s, context);
UnresolvedType aspect = UnresolvedType.read(s);
String implClassName = s.readUTF();
TypePattern tp = TypePattern.read(s, context);
return new MethodDelegateTypeMunger(signature, field, tp);
return new MethodDelegateTypeMunger(signature, aspect, implClassName, tp);
}

/**
@@ -115,4 +107,62 @@ public class MethodDelegateTypeMunger extends ResolvedTypeMunger {
public boolean changesPublicSignature() {
return true;
}

public static class FieldHostTypeMunger extends ResolvedTypeMunger {

private UnresolvedType aspect;

/**
* Type pattern this munger applies to
*/
private final TypePattern typePattern;

/**
* Construct a new type munger for @AspectJ ITD
*
* @param field
* @param aspect
* @param typePattern
*/
public FieldHostTypeMunger(ResolvedMember field, UnresolvedType aspect, TypePattern typePattern) {
super(FieldHost, field);
this.aspect = aspect;
this.typePattern = typePattern;
}

public void write(DataOutputStream s) throws IOException {
kind.write(s);
signature.write(s);
aspect.write(s);
typePattern.write(s);
}

public static ResolvedTypeMunger readFieldHost(VersionedDataInputStream s, ISourceContext context) throws IOException {
ResolvedMemberImpl signature = ResolvedMemberImpl.readResolvedMember(s, context);
UnresolvedType aspect = UnresolvedType.read(s);
TypePattern tp = TypePattern.read(s, context);
return new FieldHostTypeMunger(signature, aspect, tp);
}

/**
* Match based on given type pattern, only classes can be matched
*
* @param matchType
* @param aspectType
* @return true if match
*/
public boolean matches(ResolvedType matchType, ResolvedType aspectType) {
// match only on class
if (matchType.isEnum() || matchType.isInterface() || matchType.isAnnotation()) {
return false;
}

return typePattern.matchesStatically(matchType);
}

public boolean changesPublicSignature() {
return false;
}

}
}

+ 7
- 6
weaver/src/org/aspectj/weaver/NameMangler.java View File

@@ -64,16 +64,17 @@ public class NameMangler {
// PTWIMPL method names that must include aspect type
public static String perTypeWithinFieldForTarget(UnresolvedType aspectType) {
String s = makeName(aspectType.getNameAsIdentifier(), "ptwAspectInstance");
return s;
return makeName(aspectType.getNameAsIdentifier(), "ptwAspectInstance");
}
public static String perTypeWithinLocalAspectOf(UnresolvedType aspectType) {
public static String perTypeWithinLocalAspectOf(UnresolvedType aspectType) {
return makeName(aspectType.getNameAsIdentifier(), "localAspectOf");
}
public static String itdAtDeclareParentsField(UnresolvedType aspectType, UnresolvedType itdType) {
return makeName(aspectType.getNameAsIdentifier(), itdType.getNameAsIdentifier());
}

public static String privilegedAccessMethodForMethod(String name, UnresolvedType objectType, UnresolvedType aspectType) {
return makeName("privMethod", aspectType.getNameAsIdentifier(),
objectType.getNameAsIdentifier(), name);

+ 5
- 0
weaver/src/org/aspectj/weaver/ResolvedTypeMunger.java View File

@@ -135,6 +135,8 @@ public abstract class ResolvedTypeMunger {
return NewConstructorTypeMunger.readConstructor(s, context);
} else if (kind == MethodDelegate) {
return MethodDelegateTypeMunger.readMethod(s, context);
} else if (kind == FieldHost) {
return MethodDelegateTypeMunger.FieldHostTypeMunger.readFieldHost(s, context);
} else {
throw new RuntimeException("unimplemented");
}
@@ -237,12 +239,14 @@ public abstract class ResolvedTypeMunger {
case 2: return Method;
case 5: return Constructor;
case 9: return MethodDelegate;
case 10: return FieldHost;
}
throw new BCException("bad kind: " + key);
}

public String toString() {
// we want MethodDelegate to appear as Method in WeaveInfo messages
//TODO we may want something for fieldhost ?
if (MethodDelegate.getName().equals(getName())) {
return Method.toString();
} else {
@@ -267,6 +271,7 @@ public abstract class ResolvedTypeMunger {
public static final Kind AnnotationOnType = new Kind("AnnotationOnType",8); // not serialized

public static final Kind MethodDelegate = new Kind("MethodDelegate", 9);// serialized, @AJ ITDs
public static final Kind FieldHost = new Kind("FieldHost", 10);// serialized, @AJ ITDs

public static final String SUPER_DISPATCH_NAME = "superDispatch";


+ 98
- 55
weaver/src/org/aspectj/weaver/bcel/AtAjAttributes.java View File

@@ -17,6 +17,7 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.lang.reflect.Modifier;

import org.aspectj.apache.bcel.Constants;
import org.aspectj.apache.bcel.classfile.Attribute;
@@ -31,6 +32,7 @@ import org.aspectj.apache.bcel.classfile.annotation.Annotation;
import org.aspectj.apache.bcel.classfile.annotation.ElementNameValuePair;
import org.aspectj.apache.bcel.classfile.annotation.RuntimeAnnotations;
import org.aspectj.apache.bcel.classfile.annotation.RuntimeVisibleAnnotations;
import org.aspectj.apache.bcel.classfile.annotation.ClassElementValue;
import org.aspectj.apache.bcel.generic.Type;
import org.aspectj.bridge.IMessage;
import org.aspectj.bridge.IMessageHandler;
@@ -50,6 +52,9 @@ import org.aspectj.weaver.ResolvedPointcutDefinition;
import org.aspectj.weaver.ResolvedType;
import org.aspectj.weaver.UnresolvedType;
import org.aspectj.weaver.WeaverMessages;
import org.aspectj.weaver.NewFieldTypeMunger;
import org.aspectj.weaver.ResolvedMemberImpl;
import org.aspectj.weaver.Member;
import org.aspectj.weaver.patterns.AndPointcut;
import org.aspectj.weaver.patterns.DeclareErrorOrWarning;
import org.aspectj.weaver.patterns.DeclareParents;
@@ -317,7 +322,6 @@ public class AtAjAttributes {
if (acceptAttribute(fattribute)) {
RuntimeAnnotations frvs = (RuntimeAnnotations) fattribute;
if (handleDeclareErrorOrWarningAnnotation(frvs, fstruct)
|| handleDeclareImplementsAnnotation(frvs, fstruct)
|| handleDeclareParentsAnnotation(frvs, fstruct)) {
// semantic check - must be in an @Aspect [remove if previous block bypassed in advance]
if (!type.isAnnotationStyleAspect()) {
@@ -338,7 +342,7 @@ public class AtAjAttributes {
}
struct.ajAttributes.addAll(fstruct.ajAttributes);
}
return struct.ajAttributes;
}

@@ -463,8 +467,8 @@ public class AtAjAttributes {
// Note: field annotation are for ITD and DEOW - processed at class level directly
return Collections.EMPTY_LIST;
}
/**
* Read @Aspect
*
@@ -518,12 +522,12 @@ public class AtAjAttributes {
struct.context,
bindings
);
// // we can't resolve here since the perclause typically refers to pointcuts
// // defined in the aspect that we haven't told the BcelObjectType about yet.
//
//
// perClause.resolve(binding);
// so we prepare to do it later...
aspectAttribute.setResolutionScope(binding);
return true;
@@ -607,47 +611,47 @@ public class AtAjAttributes {
return false;
}

/**
* Read @DeclareImplements
*
* @param runtimeAnnotations
* @param struct
* @return true if found
*/
private static boolean handleDeclareImplementsAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeFieldStruct struct) {//, ResolvedPointcutDefinition preResolvedPointcut) {
Annotation deci = getAnnotation(runtimeAnnotations, AjcMemberMaker.DECLAREIMPLEMENTS_ANNOTATION);
if (deci != null) {
ElementNameValuePair deciPatternNVP = getAnnotationElement(deci, VALUE);
String deciPattern = deciPatternNVP.getValue().stringifyValue();
if (deciPattern != null) {
TypePattern typePattern = parseTypePattern(deciPattern, struct);
ResolvedType fieldType = UnresolvedType.forSignature(struct.field.getSignature()).resolve(struct.enclosingType.getWorld());
if (fieldType.isPrimitiveType()) {
return false;
} else if (fieldType.isInterface()) {
TypePattern parent = new ExactTypePattern(UnresolvedType.forSignature(struct.field.getSignature()), false, false);
parent.resolve(struct.enclosingType.getWorld());
List parents = new ArrayList(1);
parents.add(parent);
//TODO kick ISourceLocation sl = struct.bField.getSourceLocation(); ??
struct.ajAttributes.add(
new AjAttribute.DeclareAttribute(
new DeclareParents(
typePattern,
parents,
false
)
)
);
return true;
} else {
reportError("@DeclareImplements: can only be used on field whose type is an interface", struct);
return false;
}
}
}
return false;
}
// /**
// * Read @DeclareImplements
// *
// * @param runtimeAnnotations
// * @param struct
// * @return true if found
// */
// private static boolean handleDeclareImplementsAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeFieldStruct struct) {//, ResolvedPointcutDefinition preResolvedPointcut) {
// Annotation deci = getAnnotation(runtimeAnnotations, AjcMemberMaker.DECLAREIMPLEMENTS_ANNOTATION);
// if (deci != null) {
// ElementNameValuePair deciPatternNVP = getAnnotationElement(deci, VALUE);
// String deciPattern = deciPatternNVP.getValue().stringifyValue();
// if (deciPattern != null) {
// TypePattern typePattern = parseTypePattern(deciPattern, struct);
// ResolvedType fieldType = UnresolvedType.forSignature(struct.field.getSignature()).resolve(struct.enclosingType.getWorld());
// if (fieldType.isPrimitiveType()) {
// return false;
// } else if (fieldType.isInterface()) {
// TypePattern parent = new ExactTypePattern(UnresolvedType.forSignature(struct.field.getSignature()), false, false);
// parent.resolve(struct.enclosingType.getWorld());
// List parents = new ArrayList(1);
// parents.add(parent);
// //TODO kick ISourceLocation sl = struct.bField.getSourceLocation(); ??
// struct.ajAttributes.add(
// new AjAttribute.DeclareAttribute(
// new DeclareParents(
// typePattern,
// parents,
// false
// )
// )
// );
// return true;
// } else {
// reportError("@DeclareImplements: can only be used on field whose type is an interface", struct);
// return false;
// }
// }
// }
// return false;
// }

/**
* Read @DeclareParents
@@ -664,9 +668,7 @@ public class AtAjAttributes {
if (decpPattern != null) {
TypePattern typePattern = parseTypePattern(decpPattern, struct);
ResolvedType fieldType = UnresolvedType.forSignature(struct.field.getSignature()).resolve(struct.enclosingType.getWorld());
if (fieldType.isPrimitiveType()) {
return false;
} else if (fieldType.isInterface() && (struct.field.isPublic() && struct.field.isStatic())) {
if (fieldType.isInterface()) {
TypePattern parent = new ExactTypePattern(UnresolvedType.forSignature(struct.field.getSignature()), false, false);
parent.resolve(struct.enclosingType.getWorld());
//TODO kick ISourceLocation sl = struct.bField.getSourceLocation(); ??
@@ -681,25 +683,66 @@ public class AtAjAttributes {
)
)
);


// do we have a defaultImpl=xxx.class (ie implementation)
String defaultImplClassName = null;
ElementNameValuePair defaultImplNVP = getAnnotationElement(decp, "defaultImpl");
if (defaultImplNVP != null) {
ClassElementValue defaultImpl = (ClassElementValue) defaultImplNVP.getValue();
defaultImplClassName = UnresolvedType.forSignature(defaultImpl.getClassString()).getName();
if (defaultImplClassName.equals("org.aspectj.lang.annotation.DeclareParents")) {
defaultImplClassName = null;
}
//TODO check public no arg ctor
}

// then iterate on field interface hierarchy (not object)
for (Iterator it = fieldType.getMethods(); it.hasNext();) {
ResolvedMember method = (ResolvedMember)it.next();
boolean hasAtLeastOneMethod = false;
ResolvedMember[] methods = (ResolvedMember[])fieldType.getMethodsWithoutIterator(true, false).toArray(new ResolvedMember[0]);
for (int i = 0; i < methods.length; i++) {
ResolvedMember method = (ResolvedMember)methods[i];
if (method.isAbstract()) {
if (defaultImplClassName == null) {
// non marker interface with no default impl provided
reportError("@DeclareParents: used with a non marker interface and no defaultImpl=\"...\" provided", struct);
return false;
}
hasAtLeastOneMethod = true;
struct.ajAttributes.add(
new AjAttribute.TypeMunger(
new MethodDelegateTypeMunger(
method,
struct.enclosingType,
struct.field.getName(),
defaultImplClassName,
typePattern
)
)
);
}
}
// successfull so far, we thus need a bcel type munger to have
// a field hosting the mixin in the target type
if (hasAtLeastOneMethod) {
struct.ajAttributes.add(
new AjAttribute.TypeMunger(
new MethodDelegateTypeMunger.FieldHostTypeMunger(
AjcMemberMaker.itdAtDeclareParentsField(
null,//prototyped
fieldType,
struct.enclosingType
),
struct.enclosingType,
typePattern
)
)
);
}

return true;
} else {
reportError("@DeclareParents: can only be used on a public static field whose type is an interface", struct);
reportError("@DeclareParents: can only be used on a field whose type is an interface", struct);
return false;
}
}

+ 42
- 7
weaver/src/org/aspectj/weaver/bcel/BcelTypeMunger.java View File

@@ -29,6 +29,7 @@ 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.Type;
import org.aspectj.apache.bcel.generic.BranchInstruction;
import org.aspectj.apache.bcel.generic.annotation.AnnotationGen;
import org.aspectj.bridge.IMessage;
import org.aspectj.bridge.ISourceLocation;
@@ -63,7 +64,7 @@ import org.aspectj.weaver.WeaverStateInfo;
import org.aspectj.weaver.World;
import org.aspectj.weaver.patterns.DeclareAnnotation;
import org.aspectj.weaver.patterns.Pointcut;
import org.aspectj.lang.Signature;

//XXX addLazyMethodGen is probably bad everywhere
public class BcelTypeMunger extends ConcreteTypeMunger {
@@ -87,6 +88,8 @@ public class BcelTypeMunger extends ConcreteTypeMunger {
changed = mungeNewMethod(weaver, (NewMethodTypeMunger)munger);
} else if (munger.getKind() == ResolvedTypeMunger.MethodDelegate) {
changed = mungeMethodDelegate(weaver, (MethodDelegateTypeMunger)munger);
} else if (munger.getKind() == ResolvedTypeMunger.FieldHost) {
changed = mungeFieldHost(weaver, (MethodDelegateTypeMunger.FieldHostTypeMunger)munger);
} else if (munger.getKind() == ResolvedTypeMunger.PerObjectInterface) {
changed = mungePerObjectInterface(weaver, (PerObjectInterfaceTypeMunger)munger);
worthReporting = false;
@@ -147,7 +150,9 @@ public class BcelTypeMunger extends ConcreteTypeMunger {
// reportDeclareParentsMessage(WeaveMessage.WEAVEMESSAGE_DECLAREPARENTSEXTENDS,sourceType,parent);
}
} else {
} else if (munger.getKind().equals(ResolvedTypeMunger.FieldHost)) {
;//hidden
} else {
ResolvedMember declaredSig = munger.getDeclaredSignature();
if (declaredSig==null) declaredSig= munger.getSignature();
weaver.getWorld().getMessageHandler().handleMessage(WeaveMessage.constructWeavingMessage(WeaveMessage.WEAVEMESSAGE_ITD,
@@ -1103,11 +1108,23 @@ public class BcelTypeMunger extends ConcreteTypeMunger {
InstructionList body = new InstructionList();
InstructionFactory fact = gen.getFactory();

// getstatic field from aspect
body.append(Utility.createGet(fact, munger.getDelegate()));

// getfield
body.append(InstructionConstants.ALOAD_0);
body.append(Utility.createGet(fact, munger.getDelegate(weaver.getLazyClassGen().getType())));
BranchInstruction ifNonNull = InstructionFactory.createBranchInstruction(Constants.IFNULL, null);
body.append(ifNonNull);
InstructionHandle ifNonNullElse = body.append(InstructionConstants.ALOAD_0);
body.append(fact.createNew(munger.getImplClassName()));
body.append(InstructionConstants.DUP);
body.append(fact.createInvoke(munger.getImplClassName(), "<init>", Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL));
body.append(Utility.createSet(fact, munger.getDelegate(weaver.getLazyClassGen().getType())));
ifNonNull.setTarget(ifNonNullElse);
body.append(InstructionConstants.ALOAD_0);
body.append(Utility.createGet(fact, munger.getDelegate(weaver.getLazyClassGen().getType())));

//args
int pos = 0;
if (!introduced.isStatic()) { // skip 'this'
if (!introduced.isStatic()) { // skip 'this' (?? can this really happen)
//body.append(InstructionFactory.createThis());
pos++;
}
@@ -1133,7 +1150,25 @@ public class BcelTypeMunger extends ConcreteTypeMunger {
return false;
}

private ResolvedMember getRealMemberForITDFromAspect(ResolvedType aspectType,ResolvedMember lookingFor,boolean isCtorRelated) {
private boolean mungeFieldHost(BcelClassWeaver weaver, MethodDelegateTypeMunger.FieldHostTypeMunger munger) {
LazyClassGen gen = weaver.getLazyClassGen();
if (gen.getType().isAnnotation() || gen.getType().isEnum()) {
// don't signal error as it could be a consequence of a wild type pattern
return false;
}
boolean shouldApply = munger.matches(weaver.getLazyClassGen().getType(), aspectType);
ResolvedMember host = AjcMemberMaker.itdAtDeclareParentsField(
weaver.getLazyClassGen().getType(),
munger.getSignature().getType(),
aspectType);
weaver.getLazyClassGen().addField(makeFieldGen(
weaver.getLazyClassGen(),
host).getField(), null);
return true;
}


private ResolvedMember getRealMemberForITDFromAspect(ResolvedType aspectType,ResolvedMember lookingFor,boolean isCtorRelated) {
World world = aspectType.getWorld();
boolean debug = false;
if (debug) {

Loading…
Cancel
Save