package org.aspectj.weaver.bcel;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.Set;
import org.aspectj.apache.bcel.Constants;
import org.aspectj.apache.bcel.classfile.BootstrapMethods;
import org.aspectj.apache.bcel.classfile.ConstantPool;
import org.aspectj.apache.bcel.classfile.Method;
import org.aspectj.apache.bcel.classfile.annotation.AnnotationGen;
import org.aspectj.apache.bcel.generic.FieldGen;
import org.aspectj.apache.bcel.generic.FieldInstruction;
import org.aspectj.apache.bcel.generic.Instruction;
import org.aspectj.apache.bcel.generic.InstructionBranch;
import org.aspectj.apache.bcel.generic.InstructionCP;
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.InstructionLV;
import org.aspectj.apache.bcel.generic.InstructionList;
import org.aspectj.apache.bcel.generic.InstructionSelect;
import org.aspectj.apache.bcel.generic.InstructionTargeter;
import org.aspectj.apache.bcel.generic.InvokeInstruction;
import org.aspectj.apache.bcel.generic.LineNumberTag;
import org.aspectj.apache.bcel.generic.LocalVariableTag;
import org.aspectj.apache.bcel.generic.MULTIANEWARRAY;
import org.aspectj.apache.bcel.generic.MethodGen;
import org.aspectj.apache.bcel.generic.ObjectType;
import org.aspectj.apache.bcel.generic.RET;
import org.aspectj.apache.bcel.generic.Tag;
import org.aspectj.apache.bcel.generic.Type;
import org.aspectj.asm.AsmManager;
import org.aspectj.bridge.IMessage;
import org.aspectj.bridge.ISourceLocation;
import org.aspectj.bridge.Message;
import org.aspectj.bridge.MessageUtil;
import org.aspectj.bridge.WeaveMessage;
import org.aspectj.bridge.context.CompilationAndWeavingContext;
import org.aspectj.bridge.context.ContextToken;
import org.aspectj.util.PartialOrder;
import org.aspectj.weaver.AjAttribute;
import org.aspectj.weaver.AjcMemberMaker;
import org.aspectj.weaver.AnnotationAJ;
import org.aspectj.weaver.BCException;
import org.aspectj.weaver.ConcreteTypeMunger;
import org.aspectj.weaver.IClassWeaver;
import org.aspectj.weaver.IntMap;
import org.aspectj.weaver.Member;
import org.aspectj.weaver.MissingResolvedTypeWithKnownSignature;
import org.aspectj.weaver.NameMangler;
import org.aspectj.weaver.NewConstructorTypeMunger;
import org.aspectj.weaver.NewFieldTypeMunger;
import org.aspectj.weaver.NewMethodTypeMunger;
import org.aspectj.weaver.ResolvedMember;
import org.aspectj.weaver.ResolvedMemberImpl;
import org.aspectj.weaver.ResolvedType;
import org.aspectj.weaver.ResolvedTypeMunger;
import org.aspectj.weaver.Shadow;
import org.aspectj.weaver.ShadowMunger;
import org.aspectj.weaver.UnresolvedType;
import org.aspectj.weaver.UnresolvedTypeVariableReferenceType;
import org.aspectj.weaver.WeaverStateInfo;
import org.aspectj.weaver.World;
import org.aspectj.weaver.model.AsmRelationshipProvider;
import org.aspectj.weaver.patterns.DeclareAnnotation;
import org.aspectj.weaver.patterns.ExactTypePattern;
import org.aspectj.weaver.tools.Trace;
import org.aspectj.weaver.tools.TraceFactory;
class BcelClassWeaver implements IClassWeaver {
private static Trace trace = TraceFactory.getTraceFactory().getTrace(BcelClassWeaver.class);
private static final String SWITCH_TABLE_SYNTHETIC_METHOD_PREFIX = "$SWITCH_TABLE$";
public static boolean weave(BcelWorld world, LazyClassGen clazz, List<ShadowMunger> shadowMungers,
List<ConcreteTypeMunger> typeMungers, List<ConcreteTypeMunger> lateTypeMungers, boolean inReweavableMode) {
BcelClassWeaver classWeaver = new BcelClassWeaver(world, clazz, shadowMungers, typeMungers, lateTypeMungers);
classWeaver.setReweavableMode(inReweavableMode);
boolean b = classWeaver.weave();
return b;
}
private final LazyClassGen clazz;
private final List<ShadowMunger> shadowMungers;
private final List<ConcreteTypeMunger> typeMungers;
private final List<ConcreteTypeMunger> lateTypeMungers;
private List<ShadowMunger>[] indexedShadowMungers;
private boolean canMatchBodyShadows = false;
private final BcelObjectType ty;
private final BcelWorld world;
private final ConstantPool cpg;
private final InstructionFactory fact;
private final List<LazyMethodGen> addedLazyMethodGens = new ArrayList<LazyMethodGen>();
private final Set<ResolvedMember> addedDispatchTargets = new HashSet<ResolvedMember>();
private boolean inReweavableMode = false;
private List<IfaceInitList> addedSuperInitializersAsList = null;
private final Map<ResolvedType, IfaceInitList> addedSuperInitializers = new HashMap<ResolvedType, IfaceInitList>();
private final List<ConcreteTypeMunger> addedThisInitializers = new ArrayList<ConcreteTypeMunger>();
private final List<ConcreteTypeMunger> addedClassInitializers = new ArrayList<ConcreteTypeMunger>();
private final Map<ResolvedMember, ResolvedMember> mapToAnnotationHolder = new HashMap<ResolvedMember, ResolvedMember>();
private final List<BcelShadow> initializationShadows = new ArrayList<BcelShadow>();
private BcelClassWeaver(BcelWorld world, LazyClassGen clazz, List<ShadowMunger> shadowMungers,
List<ConcreteTypeMunger> typeMungers, List<ConcreteTypeMunger> lateTypeMungers) {
super();
this.world = world;
this.clazz = clazz;
this.shadowMungers = shadowMungers;
this.typeMungers = typeMungers;
this.lateTypeMungers = lateTypeMungers;
this.ty = clazz.getBcelObjectType();
this.cpg = clazz.getConstantPool();
this.fact = clazz.getFactory();
indexShadowMungers();
initializeSuperInitializerMap(ty.getResolvedTypeX());
if (!checkedXsetForLowLevelContextCapturing) {
Properties p = world.getExtraConfiguration();
if (p != null) {
String s = p.getProperty(World.xsetCAPTURE_ALL_CONTEXT, "false");
captureLowLevelContext = s.equalsIgnoreCase("true");
if (captureLowLevelContext) {
world.getMessageHandler().handleMessage(
MessageUtil.info("[" + World.xsetCAPTURE_ALL_CONTEXT
+ "=true] Enabling collection of low level context for debug/crash messages"));
}
}
checkedXsetForLowLevelContextCapturing = true;
}
}
private boolean canMatch(Shadow.Kind kind) {
return indexedShadowMungers[kind.getKey()] != null;
}
private void initializeSuperInitializerMap(ResolvedType child) {
ResolvedType[] superInterfaces = child.getDeclaredInterfaces();
for (int i = 0, len = superInterfaces.length; i < len; i++) {
if (ty.getResolvedTypeX().isTopmostImplementor(superInterfaces[i])) {
if (addSuperInitializer(superInterfaces[i])) {
initializeSuperInitializerMap(superInterfaces[i]);
}
}
}
}
private void indexShadowMungers() {
indexedShadowMungers = new List[Shadow.MAX_SHADOW_KIND + 1];
for (ShadowMunger shadowMunger : shadowMungers) {
int couldMatchKinds = shadowMunger.getPointcut().couldMatchKinds();
for (Shadow.Kind kind : Shadow.SHADOW_KINDS) {
if (kind.isSet(couldMatchKinds)) {
byte k = kind.getKey();
if (indexedShadowMungers[k] == null) {
indexedShadowMungers[k] = new ArrayList<ShadowMunger>();
if (!kind.isEnclosingKind()) {
canMatchBodyShadows = true;
}
}
indexedShadowMungers[k].add(shadowMunger);
}
}
}
}
private boolean addSuperInitializer(ResolvedType onType) {
if (onType.isRawType() || onType.isParameterizedType()) {
onType = onType.getGenericType();
}
IfaceInitList l = addedSuperInitializers.get(onType);
if (l != null) {
return false;
}
l = new IfaceInitList(onType);
addedSuperInitializers.put(onType, l);
return true;
}
public void addInitializer(ConcreteTypeMunger cm) {
NewFieldTypeMunger m = (NewFieldTypeMunger) cm.getMunger();
ResolvedType onType = m.getSignature().getDeclaringType().resolve(world);
if (onType.isRawType()) {
onType = onType.getGenericType();
}
if (Modifier.isStatic(m.getSignature().getModifiers())) {
addedClassInitializers.add(cm);
} else {
if (onType == ty.getResolvedTypeX()) {
addedThisInitializers.add(cm);
} else {
IfaceInitList l = addedSuperInitializers.get(onType);
l.list.add(cm);
}
}
}
private static class IfaceInitList implements PartialOrder.PartialComparable {
final ResolvedType onType;
List<ConcreteTypeMunger> list = new ArrayList<ConcreteTypeMunger>();
IfaceInitList(ResolvedType onType) {
this.onType = onType;
}
public int compareTo(Object other) {
IfaceInitList o = (IfaceInitList) other;
if (onType.isAssignableFrom(o.onType)) {
return +1;
} else if (o.onType.isAssignableFrom(onType)) {
return -1;
} else {
return 0;
}
}
public int fallbackCompareTo(Object other) {
return 0;
}
}
public boolean addDispatchTarget(ResolvedMember m) {
return addedDispatchTargets.add(m);
}
public void addLazyMethodGen(LazyMethodGen gen) {
addedLazyMethodGens.add(gen);
}
public void addOrReplaceLazyMethodGen(LazyMethodGen mg) {
if (alreadyDefined(clazz, mg)) {
return;
}
for (Iterator<LazyMethodGen> i = addedLazyMethodGens.iterator(); i.hasNext();) {
LazyMethodGen existing = i.next();
if (signaturesMatch(mg, existing)) {
if (existing.definingType == null) {
return;
} else if (mg.definingType.isAssignableFrom(existing.definingType)) {
return;
} else if (existing.definingType.isAssignableFrom(mg.definingType)) {
i.remove();
addedLazyMethodGens.add(mg);
return;
} else {
throw new BCException("conflict between: " + mg + " and " + existing);
}
}
}
addedLazyMethodGens.add(mg);
}
private boolean alreadyDefined(LazyClassGen clazz, LazyMethodGen mg) {
for (Iterator<LazyMethodGen> i = clazz.getMethodGens().iterator(); i.hasNext();) {
LazyMethodGen existing = i.next();
if (signaturesMatch(mg, existing)) {
if (!mg.isAbstract() && existing.isAbstract()) {
i.remove();
return false;
}
return true;
}
}
return false;
}
private boolean signaturesMatch(LazyMethodGen mg, LazyMethodGen existing) {
return mg.getName().equals(existing.getName()) && mg.getSignature().equals(existing.getSignature());
}
protected static LazyMethodGen makeBridgeMethod(LazyClassGen gen, ResolvedMember member) {
int mods = member.getModifiers();
if (Modifier.isAbstract(mods)) {
mods = mods - Modifier.ABSTRACT;
}
LazyMethodGen ret = new LazyMethodGen(mods, BcelWorld.makeBcelType(member.getReturnType()), member.getName(),
BcelWorld.makeBcelTypes(member.getParameterTypes()), UnresolvedType.getNames(member.getExceptions()), gen);
return ret;
}
private static void createBridgeMethod(BcelWorld world, LazyMethodGen whatToBridgeToMethodGen, LazyClassGen clazz, ResolvedMember theBridgeMethod) {
InstructionList body;
InstructionFactory fact;
int pos = 0;
ResolvedMember whatToBridgeTo = whatToBridgeToMethodGen.getMemberView();
if (whatToBridgeTo == null) {
whatToBridgeTo = new ResolvedMemberImpl(Member.METHOD, whatToBridgeToMethodGen.getEnclosingClass().getType(),
whatToBridgeToMethodGen.getAccessFlags(), whatToBridgeToMethodGen.getName(),
whatToBridgeToMethodGen.getSignature());
}
LazyMethodGen bridgeMethod = makeBridgeMethod(clazz, theBridgeMethod);
int newflags = bridgeMethod.getAccessFlags() | Constants.ACC_BRIDGE | Constants.ACC_SYNTHETIC ;
if ((newflags & 0x00000100) != 0) {
newflags = newflags - 0x100;
}
bridgeMethod.setAccessFlags(newflags);
Type returnType = BcelWorld.makeBcelType(theBridgeMethod.getReturnType());
Type[] paramTypes = BcelWorld.makeBcelTypes(theBridgeMethod.getParameterTypes());
Type[] newParamTypes = whatToBridgeToMethodGen.getArgumentTypes();
body = bridgeMethod.getBody();
fact = clazz.getFactory();
if (!whatToBridgeToMethodGen.isStatic()) {
body.append(InstructionFactory.createThis());
pos++;
}
for (int i = 0, len = paramTypes.length; i < len; i++) {
Type paramType = paramTypes[i];
body.append(InstructionFactory.createLoad(paramType, pos));
if (!newParamTypes[i].equals(paramTypes[i])) {
if (world.forDEBUG_bridgingCode) {
System.err.println("Bridging: Cast " + newParamTypes[i] + " from " + paramTypes[i]);
}
body.append(fact.createCast(paramTypes[i], newParamTypes[i]));
}
pos += paramType.getSize();
}
body.append(Utility.createInvoke(fact, world, whatToBridgeTo));
body.append(InstructionFactory.createReturn(returnType));
clazz.addMethodGen(bridgeMethod);
}
public boolean weave() {
if (clazz.isWoven() && !clazz.isReweavable()) {
if (world.getLint().nonReweavableTypeEncountered.isEnabled()) {
world.getLint().nonReweavableTypeEncountered.signal(clazz.getType().getName(), ty.getSourceLocation());
}
return false;
}
Set<String> aspectsAffectingType = null;
if (inReweavableMode || clazz.getType().isAspect()) {
aspectsAffectingType = new HashSet<String>();
}
boolean isChanged = false;
if (clazz.getType().isAspect()) {
isChanged = true;
}
WeaverStateInfo typeWeaverState = (world.isOverWeaving() ? getLazyClassGen().getType().getWeaverState() : null);
for (ConcreteTypeMunger o : typeMungers) {
if (!(o instanceof BcelTypeMunger)) {
continue;
}
BcelTypeMunger munger = (BcelTypeMunger) o;
if (typeWeaverState != null && typeWeaverState.isAspectAlreadyApplied(munger.getAspectType())) {
continue;
}
boolean typeMungerAffectedType = munger.munge(this);
if (typeMungerAffectedType) {
isChanged = true;
if (inReweavableMode || clazz.getType().isAspect()) {
aspectsAffectingType.add(munger.getAspectType().getSignature());
}
}
}
isChanged = weaveDeclareAtMethodCtor(clazz) || isChanged;
isChanged = weaveDeclareAtField(clazz) || isChanged;
addedSuperInitializersAsList = new ArrayList<IfaceInitList>(addedSuperInitializers.values());
addedSuperInitializersAsList = PartialOrder.sort(addedSuperInitializersAsList);
if (addedSuperInitializersAsList == null) {
throw new BCException("circularity in inter-types");
}
LazyMethodGen staticInit = clazz.getStaticInitializer();
staticInit.getBody().insert(genInitInstructions(addedClassInitializers, true));
List<LazyMethodGen> methodGens = new ArrayList<LazyMethodGen>(clazz.getMethodGens());
for (LazyMethodGen member : methodGens) {
if (!member.hasBody()) {
continue;
}
if (world.isJoinpointSynchronizationEnabled() && world.areSynchronizationPointcutsInUse()
&& member.getMethod().isSynchronized()) {
transformSynchronizedMethod(member);
}
boolean shadowMungerMatched = match(member);
if (shadowMungerMatched) {
if (inReweavableMode || clazz.getType().isAspect()) {
aspectsAffectingType.addAll(findAspectsForMungers(member));
}
isChanged = true;
}
}
for (LazyMethodGen methodGen : methodGens) {
if (!methodGen.hasBody()) {
continue;
}
implement(methodGen);
}
if (!initializationShadows.isEmpty()) {
List<LazyMethodGen> recursiveCtors = new ArrayList<LazyMethodGen>();
while (inlineSelfConstructors(methodGens, recursiveCtors)) {
}
positionAndImplement(initializationShadows);
}
if (lateTypeMungers != null) {
for (Iterator<ConcreteTypeMunger> i = lateTypeMungers.iterator(); i.hasNext();) {
BcelTypeMunger munger = (BcelTypeMunger) i.next();
if (munger.matches(clazz.getType())) {
boolean typeMungerAffectedType = munger.munge(this);
if (typeMungerAffectedType) {
isChanged = true;
if (inReweavableMode || clazz.getType().isAspect()) {
aspectsAffectingType.add(munger.getAspectType().getSignature());
}
}
}
}
}
if (isChanged) {
clazz.getOrCreateWeaverStateInfo(inReweavableMode);
weaveInAddedMethods();
}
if (inReweavableMode) {
WeaverStateInfo wsi = clazz.getOrCreateWeaverStateInfo(true);
wsi.addAspectsAffectingType(aspectsAffectingType);
if (!world.isOverWeaving()) {
wsi.setUnwovenClassFileData(ty.getJavaClass().getBytes());
wsi.setReweavable(true);
} else {
wsi.markOverweavingInUse();
}
} else {
clazz.getOrCreateWeaverStateInfo(false).setReweavable(false);
}
for (LazyMethodGen mg : methodGens) {
BcelMethod method = mg.getMemberView();
if (method != null) {
method.wipeJoinpointSignatures();
}
}
return isChanged;
}
private static ResolvedMember isOverriding(ResolvedType typeToCheck, ResolvedMember methodThatMightBeGettingOverridden,
String mname, String mrettype, int mmods, boolean inSamePackage, UnresolvedType[] methodParamsArray) {
if (Modifier.isStatic(methodThatMightBeGettingOverridden.getModifiers())) {
return null;
}
if (Modifier.isPrivate(methodThatMightBeGettingOverridden.getModifiers())) {
return null;
}
if (!methodThatMightBeGettingOverridden.getName().equals(mname)) {
return null;
}
if (methodThatMightBeGettingOverridden.getParameterTypes().length != methodParamsArray.length) {
return null;
}
if (!isVisibilityOverride(mmods, methodThatMightBeGettingOverridden, inSamePackage)) {
return null;
}
if (typeToCheck.getWorld().forDEBUG_bridgingCode) {
System.err.println(" Bridging:seriously considering this might be getting overridden '"
+ methodThatMightBeGettingOverridden + "'");
}
World w = typeToCheck.getWorld();
boolean sameParams = true;
for (int p = 0, max = methodThatMightBeGettingOverridden.getParameterTypes().length; p < max; p++) {
UnresolvedType mtmbgoParameter = methodThatMightBeGettingOverridden.getParameterTypes()[p];
UnresolvedType ptype = methodParamsArray[p];
if (mtmbgoParameter.isTypeVariableReference()) {
if (!mtmbgoParameter.resolve(w).isAssignableFrom(ptype.resolve(w))) {
sameParams = false;
}
} else {
boolean b = !methodThatMightBeGettingOverridden.getParameterTypes()[p].getErasureSignature().equals(
methodParamsArray[p].getErasureSignature());
UnresolvedType parameterType = methodThatMightBeGettingOverridden.getParameterTypes()[p];
if (parameterType instanceof UnresolvedTypeVariableReferenceType) {
parameterType = ((UnresolvedTypeVariableReferenceType) parameterType).getTypeVariable().getFirstBound();
}
if (b) {
sameParams = false;
}
}
}
if (sameParams) {
if (typeToCheck.isParameterizedType()) {
return methodThatMightBeGettingOverridden.getBackingGenericMember();
} else if (!methodThatMightBeGettingOverridden.getReturnType().getErasureSignature().equals(mrettype)) {
ResolvedType superReturn = typeToCheck.getWorld().resolve(
UnresolvedType.forSignature(methodThatMightBeGettingOverridden.getReturnType().getErasureSignature()));
ResolvedType subReturn = typeToCheck.getWorld().resolve(UnresolvedType.forSignature(mrettype));
if (superReturn.isAssignableFrom(subReturn)) {
return methodThatMightBeGettingOverridden;
}
} else {
return methodThatMightBeGettingOverridden;
}
}
return null;
}
static boolean isVisibilityOverride(int methodMods, ResolvedMember inheritedMethod, boolean inSamePackage) {
int inheritedModifiers = inheritedMethod.getModifiers();
if (Modifier.isStatic(inheritedModifiers)) {
return false;
}
if (methodMods == inheritedModifiers) {
return true;
}
if (Modifier.isPrivate(inheritedModifiers)) {
return false;
}
boolean isPackageVisible = !Modifier.isPrivate(inheritedModifiers) && !Modifier.isProtected(inheritedModifiers)
&& !Modifier.isPublic(inheritedModifiers);
if (isPackageVisible && !inSamePackage) {
return false;
}
return true;
}
public static void checkForOverride(ResolvedType typeToCheck, String mname, String mparams, String mrettype,
int mmods, String mpkg, UnresolvedType[] methodParamsArray, List<ResolvedMember> overriddenMethodsCollector) {
if (typeToCheck == null) {
return;
}
if (typeToCheck instanceof MissingResolvedTypeWithKnownSignature) {
return;
}
if (typeToCheck.getWorld().forDEBUG_bridgingCode) {
System.err.println(" Bridging:checking for override of " + mname + " in " + typeToCheck);
}
String packageName = typeToCheck.getPackageName();
if (packageName == null) {
packageName = "";
}
boolean inSamePackage = packageName.equals(mpkg);
ResolvedMember[] methods = typeToCheck.getDeclaredMethods();
for (int ii = 0; ii < methods.length; ii++) {
ResolvedMember methodThatMightBeGettingOverridden = methods[ii];
ResolvedMember isOverriding = isOverriding(typeToCheck, methodThatMightBeGettingOverridden, mname, mrettype, mmods,
inSamePackage, methodParamsArray);
if (isOverriding != null) {
overriddenMethodsCollector.add(isOverriding);
}
}
List<ConcreteTypeMunger> l = (typeToCheck.isRawType() ? typeToCheck.getGenericType().getInterTypeMungers() : typeToCheck
.getInterTypeMungers());
for (Iterator<ConcreteTypeMunger> iterator = l.iterator(); iterator.hasNext();) {
ConcreteTypeMunger o = iterator.next();
if (o instanceof BcelTypeMunger) {
BcelTypeMunger element = (BcelTypeMunger) o;
if (element.getMunger() instanceof NewMethodTypeMunger) {
if (typeToCheck.getWorld().forDEBUG_bridgingCode) {
System.err.println("Possible ITD candidate " + element);
}
ResolvedMember aMethod = element.getSignature();
ResolvedMember isOverriding = isOverriding(typeToCheck, aMethod, mname, mrettype, mmods, inSamePackage,
methodParamsArray);
if (isOverriding != null) {
overriddenMethodsCollector.add(isOverriding);
}
}
}
}
if (typeToCheck.equals(UnresolvedType.OBJECT)) {
return;
}
ResolvedType superclass = typeToCheck.getSuperclass();
checkForOverride(superclass, mname, mparams, mrettype, mmods, mpkg, methodParamsArray,overriddenMethodsCollector);
ResolvedType[] interfaces = typeToCheck.getDeclaredInterfaces();
for (int i = 0; i < interfaces.length; i++) {
ResolvedType anInterface = interfaces[i];
checkForOverride(anInterface, mname, mparams, mrettype, mmods, mpkg, methodParamsArray,overriddenMethodsCollector);
}
}
public static boolean calculateAnyRequiredBridgeMethods(BcelWorld world, LazyClassGen clazz) {
world.ensureAdvancedConfigurationProcessed();
if (!world.isInJava5Mode()) {
return false;
}
if (clazz.isInterface()) {
return false;
}
boolean didSomething = false;
List<LazyMethodGen> methods = clazz.getMethodGens();
Set<String> methodsSet = new HashSet<String>();
for (int i = 0; i < methods.size(); i++) {
LazyMethodGen aMethod = methods.get(i);
StringBuilder sb = new StringBuilder(aMethod.getName());
sb.append(aMethod.getSignature());
methodsSet.add(sb.toString());
}
for (int i = 0; i < methods.size(); i++) {
LazyMethodGen bridgeToCandidate = methods.get(i);
if (bridgeToCandidate.isBridgeMethod()) {
continue;
}
String name = bridgeToCandidate.getName();
String psig = bridgeToCandidate.getParameterSignature();
String rsig = bridgeToCandidate.getReturnType().getSignature();
if (bridgeToCandidate.isStatic()) {
continue;
}
if (name.endsWith("init>")) {
continue;
}
if (world.forDEBUG_bridgingCode) {
System.err.println("Bridging: Determining if we have to bridge to " + clazz.getName() + "." + name + "" + bridgeToCandidate.getSignature());
}
ResolvedType theSuperclass = clazz.getSuperClass();
if (world.forDEBUG_bridgingCode) {
System.err.println("Bridging: Checking supertype " + theSuperclass);
}
String pkgName = clazz.getPackageName();
UnresolvedType[] bm = BcelWorld.fromBcel(bridgeToCandidate.getArgumentTypes());
List<ResolvedMember> overriddenMethodsCollector = new ArrayList<ResolvedMember>();
checkForOverride(theSuperclass, name, psig, rsig, bridgeToCandidate.getAccessFlags(), pkgName, bm, overriddenMethodsCollector);
if (overriddenMethodsCollector.size() != 0) {
for (ResolvedMember overriddenMethod: overriddenMethodsCollector) {
String key = new StringBuilder(overriddenMethod.getName()).append(overriddenMethod.getSignatureErased()).toString();
boolean alreadyHaveABridgeMethod = methodsSet.contains(key);
if (!alreadyHaveABridgeMethod) {
if (world.forDEBUG_bridgingCode) {
System.err.println("Bridging:bridging to '" + overriddenMethod + "'");
}
createBridgeMethod(world, bridgeToCandidate, clazz, overriddenMethod);
methodsSet.add(key);
didSomething = true;
}
}
}
String[] interfaces = clazz.getInterfaceNames();
for (int j = 0; j < interfaces.length; j++) {
if (world.forDEBUG_bridgingCode) {
System.err.println("Bridging:checking superinterface " + interfaces[j]);
}
ResolvedType interfaceType = world.resolve(interfaces[j]);
overriddenMethodsCollector.clear();
checkForOverride(interfaceType, name, psig, rsig, bridgeToCandidate.getAccessFlags(),
clazz.getPackageName(), bm, overriddenMethodsCollector);
for (ResolvedMember overriddenMethod: overriddenMethodsCollector) {
String key = new StringBuffer().append(overriddenMethod.getName()).append(overriddenMethod.getSignatureErased()).toString();
boolean alreadyHaveABridgeMethod = methodsSet.contains(key);
if (!alreadyHaveABridgeMethod) {
createBridgeMethod(world, bridgeToCandidate, clazz, overriddenMethod);
methodsSet.add(key);
didSomething = true;
if (world.forDEBUG_bridgingCode) {
System.err.println("Bridging:bridging to " + overriddenMethod);
}
}
}
}
}
return didSomething;
}
private boolean weaveDeclareAtMethodCtor(LazyClassGen clazz) {
List<Integer> reportedProblems = new ArrayList<Integer>();
List<DeclareAnnotation> allDecams = world.getDeclareAnnotationOnMethods();
if (allDecams.isEmpty()) {
return false;
}
boolean isChanged = false;
List<ConcreteTypeMunger> itdMethodsCtors = getITDSubset(clazz, ResolvedTypeMunger.Method);
itdMethodsCtors.addAll(getITDSubset(clazz, ResolvedTypeMunger.Constructor));
if (!itdMethodsCtors.isEmpty()) {
isChanged = weaveAtMethodOnITDSRepeatedly(allDecams, itdMethodsCtors, reportedProblems);
}
List<DeclareAnnotation> decaMs = getMatchingSubset(allDecams, clazz.getType());
if (decaMs.isEmpty()) {
return false;
}
Set<DeclareAnnotation> unusedDecams = new HashSet<DeclareAnnotation>();
unusedDecams.addAll(decaMs);
if (addedLazyMethodGens!=null) {
for (LazyMethodGen method: addedLazyMethodGens) {
ResolvedMember resolvedmember =
new ResolvedMemberImpl(ResolvedMember.METHOD,method.getEnclosingClass().getType(),method.getAccessFlags(),
BcelWorld.fromBcel(method.getReturnType()),method.getName(),
BcelWorld.fromBcel(method.getArgumentTypes()),UnresolvedType.forNames(method.getDeclaredExceptions()));
resolvedmember.setAnnotationTypes(method.getAnnotationTypes());
resolvedmember.setAnnotations(method.getAnnotations());
List<DeclareAnnotation> worthRetrying = new ArrayList<DeclareAnnotation>();
boolean modificationOccured = false;
for (DeclareAnnotation decam: decaMs) {
if (decam.matches(resolvedmember, world)) {
if (doesAlreadyHaveAnnotation(resolvedmember, decam, reportedProblems,false)) {
unusedDecams.remove(decam);
continue;
}
AnnotationGen a = ((BcelAnnotation) decam.getAnnotation()).getBcelAnnotation();
AnnotationAJ aj = new BcelAnnotation(new AnnotationGen(a, clazz.getConstantPool(), true),world);
method.addAnnotation(aj);
resolvedmember.addAnnotation(decam.getAnnotation());
AsmRelationshipProvider.addDeclareAnnotationMethodRelationship(decam.getSourceLocation(),
clazz.getName(), resolvedmember, world.getModelAsAsmManager());
reportMethodCtorWeavingMessage(clazz, resolvedmember, decam, method.getDeclarationLineNumber());
isChanged = true;
modificationOccured = true;
unusedDecams.remove(decam);
} else if (!decam.isStarredAnnotationPattern()) {
worthRetrying.add(decam);
}
}
while (!worthRetrying.isEmpty() && modificationOccured) {
modificationOccured = false;
List<DeclareAnnotation> forRemoval = new ArrayList<DeclareAnnotation>();
for (DeclareAnnotation decam : worthRetrying) {
if (decam.matches(resolvedmember, world)) {
if (doesAlreadyHaveAnnotation(resolvedmember, decam, reportedProblems,false)) {
unusedDecams.remove(decam);
continue;
}
AnnotationGen a = ((BcelAnnotation) decam.getAnnotation()).getBcelAnnotation();
AnnotationAJ aj = new BcelAnnotation(new AnnotationGen(a, clazz.getConstantPool(), true),world);
method.addAnnotation(aj);
resolvedmember.addAnnotation(decam.getAnnotation());
AsmRelationshipProvider.addDeclareAnnotationMethodRelationship(decam.getSourceLocation(),
clazz.getName(), resolvedmember, world.getModelAsAsmManager());
isChanged = true;
modificationOccured = true;
forRemoval.add(decam);
unusedDecams.remove(decam);
}
}
worthRetrying.removeAll(forRemoval);
}
}
}
List<LazyMethodGen> members = clazz.getMethodGens();
if (!members.isEmpty()) {
for (int memberCounter = 0; memberCounter < members.size(); memberCounter++) {
LazyMethodGen mg = members.get(memberCounter);
if (!mg.getName().startsWith(NameMangler.PREFIX)) {
List<DeclareAnnotation> worthRetrying = new ArrayList<DeclareAnnotation>();
boolean modificationOccured = false;
List<AnnotationGen> annotationsToAdd = null;
for (DeclareAnnotation decaM : decaMs) {
if (decaM.matches(mg.getMemberView(), world)) {
if (doesAlreadyHaveAnnotation(mg.getMemberView(), decaM, reportedProblems,true)) {
unusedDecams.remove(decaM);
continue;
}
if (annotationsToAdd == null) {
annotationsToAdd = new ArrayList<AnnotationGen>();
}
AnnotationGen a = ((BcelAnnotation) decaM.getAnnotation()).getBcelAnnotation();
AnnotationGen ag = new AnnotationGen(a, clazz.getConstantPool(), true);
annotationsToAdd.add(ag);
mg.addAnnotation(decaM.getAnnotation());
AsmRelationshipProvider.addDeclareAnnotationMethodRelationship(decaM.getSourceLocation(),
clazz.getName(), mg.getMemberView(), world.getModelAsAsmManager());
reportMethodCtorWeavingMessage(clazz, mg.getMemberView(), decaM, mg.getDeclarationLineNumber());
isChanged = true;
modificationOccured = true;
unusedDecams.remove(decaM);
} else {
if (!decaM.isStarredAnnotationPattern()) {
worthRetrying.add(decaM);
}
}
}
while (!worthRetrying.isEmpty() && modificationOccured) {
modificationOccured = false;
List<DeclareAnnotation> forRemoval = new ArrayList<DeclareAnnotation>();
for (DeclareAnnotation decaM : worthRetrying) {
if (decaM.matches(mg.getMemberView(), world)) {
if (doesAlreadyHaveAnnotation(mg.getMemberView(), decaM, reportedProblems,true)) {
unusedDecams.remove(decaM);
continue;
}
if (annotationsToAdd == null) {
annotationsToAdd = new ArrayList<AnnotationGen>();
}
AnnotationGen a = ((BcelAnnotation) decaM.getAnnotation()).getBcelAnnotation();
AnnotationGen ag = new AnnotationGen(a, clazz.getConstantPool(), true);
annotationsToAdd.add(ag);
mg.addAnnotation(decaM.getAnnotation());
AsmRelationshipProvider.addDeclareAnnotationMethodRelationship(decaM.getSourceLocation(),
clazz.getName(), mg.getMemberView(), world.getModelAsAsmManager());
isChanged = true;
modificationOccured = true;
forRemoval.add(decaM);
unusedDecams.remove(decaM);
}
}
worthRetrying.removeAll(forRemoval);
}
if (annotationsToAdd != null) {
Method oldMethod = mg.getMethod();
MethodGen myGen = new MethodGen(oldMethod, clazz.getClassName(), clazz.getConstantPool(), false);
for (AnnotationGen a : annotationsToAdd) {
myGen.addAnnotation(a);
}
Method newMethod = myGen.getMethod();
members.set(memberCounter, new LazyMethodGen(newMethod, clazz));
}
}
}
checkUnusedDeclareAts(unusedDecams, false);
}
return isChanged;
}
private void reportMethodCtorWeavingMessage(LazyClassGen clazz, ResolvedMember member, DeclareAnnotation decaM,
int memberLineNumber) {
if (!getWorld().getMessageHandler().isIgnoring(IMessage.WEAVEINFO)) {
StringBuffer parmString = new StringBuffer("(");
UnresolvedType[] paramTypes = member.getParameterTypes();
for (int i = 0; i < paramTypes.length; i++) {
UnresolvedType type = paramTypes[i];
String s = org.aspectj.apache.bcel.classfile.Utility.signatureToString(type.getSignature());
if (s.lastIndexOf('.') != -1) {
s = s.substring(s.lastIndexOf('.') + 1);
}
parmString.append(s);
if ((i + 1) < paramTypes.length) {
parmString.append(",");
}
}
parmString.append(")");
String methodName = member.getName();
StringBuffer sig = new StringBuffer();
sig.append(org.aspectj.apache.bcel.classfile.Utility.accessToString(member.getModifiers()));
sig.append(" ");
sig.append(member.getReturnType().toString());
sig.append(" ");
sig.append(member.getDeclaringType().toString());
sig.append(".");
sig.append(methodName.equals("<init>") ? "new" : methodName);
sig.append(parmString);
StringBuffer loc = new StringBuffer();
if (clazz.getFileName() == null) {
loc.append("no debug info available");
} else {
loc.append(clazz.getFileName());
if (memberLineNumber != -1) {
loc.append(":" + memberLineNumber);
}
}
getWorld().getMessageHandler().handleMessage(
WeaveMessage.constructWeavingMessage(
WeaveMessage.WEAVEMESSAGE_ANNOTATES,
new String[] { sig.toString(), loc.toString(), decaM.getAnnotationString(),
methodName.startsWith("<init>") ? "constructor" : "method", decaM.getAspect().toString(),
Utility.beautifyLocation(decaM.getSourceLocation()) }));
}
}
private List<DeclareAnnotation> getMatchingSubset(List<DeclareAnnotation> declareAnnotations, ResolvedType type) {
List<DeclareAnnotation> subset = new ArrayList<DeclareAnnotation>();
for (DeclareAnnotation da : declareAnnotations) {
if (da.couldEverMatch(type)) {
subset.add(da);
}
}
return subset;
}
private List<ConcreteTypeMunger> getITDSubset(LazyClassGen clazz, ResolvedTypeMunger.Kind wantedKind) {
List<ConcreteTypeMunger> subset = new ArrayList<ConcreteTypeMunger>();
for (ConcreteTypeMunger typeMunger : clazz.getBcelObjectType().getTypeMungers()) {
if (typeMunger.getMunger().getKind() == wantedKind) {
subset.add(typeMunger);
}
}
return subset;
}
public LazyMethodGen locateAnnotationHolderForFieldMunger(LazyClassGen clazz, ConcreteTypeMunger fieldMunger) {
NewFieldTypeMunger newFieldMunger = (NewFieldTypeMunger) fieldMunger.getMunger();
ResolvedMember lookingFor = AjcMemberMaker.interFieldInitializer(newFieldMunger.getSignature(), clazz.getType());
for (LazyMethodGen method : clazz.getMethodGens()) {
if (method.getName().equals(lookingFor.getName())) {
return method;
}
}
return null;
}
public LazyMethodGen locateAnnotationHolderForMethodCtorMunger(LazyClassGen clazz, ConcreteTypeMunger methodCtorMunger) {
ResolvedTypeMunger rtMunger = methodCtorMunger.getMunger();
ResolvedMember lookingFor = null;
if (rtMunger instanceof NewMethodTypeMunger) {
NewMethodTypeMunger nftm = (NewMethodTypeMunger) rtMunger;
lookingFor = AjcMemberMaker.interMethodDispatcher(nftm.getSignature(), methodCtorMunger.getAspectType());
} else if (rtMunger instanceof NewConstructorTypeMunger) {
NewConstructorTypeMunger nftm = (NewConstructorTypeMunger) rtMunger;
lookingFor = AjcMemberMaker.postIntroducedConstructor(methodCtorMunger.getAspectType(), nftm.getSignature()
.getDeclaringType(), nftm.getSignature().getParameterTypes());
} else {
throw new BCException("Not sure what this is: " + methodCtorMunger);
}
String name = lookingFor.getName();
String paramSignature = lookingFor.getParameterSignature();
for (LazyMethodGen member : clazz.getMethodGens()) {
if (member.getName().equals(name) && member.getParameterSignature().equals(paramSignature)) {
return member;
}
}
return null;
}
private boolean weaveAtFieldRepeatedly(List<DeclareAnnotation> decaFs, List<ConcreteTypeMunger> itdFields,
List<Integer> reportedErrors) {
boolean isChanged = false;
for (Iterator<ConcreteTypeMunger> iter = itdFields.iterator(); iter.hasNext();) {
BcelTypeMunger fieldMunger = (BcelTypeMunger) iter.next();
ResolvedMember itdIsActually = fieldMunger.getSignature();
Set<DeclareAnnotation> worthRetrying = new LinkedHashSet<DeclareAnnotation>();
boolean modificationOccured = false;
for (Iterator<DeclareAnnotation> iter2 = decaFs.iterator(); iter2.hasNext();) {
DeclareAnnotation decaF = iter2.next();
if (decaF.matches(itdIsActually, world)) {
if (decaF.isRemover()) {
LazyMethodGen annotationHolder = locateAnnotationHolderForFieldMunger(clazz, fieldMunger);
if (annotationHolder.hasAnnotation(decaF.getAnnotationType())) {
isChanged = true;
annotationHolder.removeAnnotation(decaF.getAnnotationType());
AsmRelationshipProvider.addDeclareAnnotationRelationship(world.getModelAsAsmManager(),
decaF.getSourceLocation(), itdIsActually.getSourceLocation(), true);
} else {
worthRetrying.add(decaF);
}
} else {
LazyMethodGen annotationHolder = locateAnnotationHolderForFieldMunger(clazz, fieldMunger);
if (doesAlreadyHaveAnnotation(annotationHolder, itdIsActually, decaF, reportedErrors)) {
continue;
}
annotationHolder.addAnnotation(decaF.getAnnotation());
AsmRelationshipProvider.addDeclareAnnotationRelationship(world.getModelAsAsmManager(),
decaF.getSourceLocation(), itdIsActually.getSourceLocation(), false);
isChanged = true;
modificationOccured = true;
}
} else {
if (!decaF.isStarredAnnotationPattern()) {
worthRetrying.add(decaF);
}
}
}
while (!worthRetrying.isEmpty() && modificationOccured) {
modificationOccured = false;
List<DeclareAnnotation> forRemoval = new ArrayList<DeclareAnnotation>();
for (Iterator<DeclareAnnotation> iter2 = worthRetrying.iterator(); iter2.hasNext();) {
DeclareAnnotation decaF = iter2.next();
if (decaF.matches(itdIsActually, world)) {
if (decaF.isRemover()) {
LazyMethodGen annotationHolder = locateAnnotationHolderForFieldMunger(clazz, fieldMunger);
if (annotationHolder.hasAnnotation(decaF.getAnnotationType())) {
isChanged = true;
annotationHolder.removeAnnotation(decaF.getAnnotationType());
AsmRelationshipProvider.addDeclareAnnotationRelationship(world.getModelAsAsmManager(),
decaF.getSourceLocation(), itdIsActually.getSourceLocation(), true);
forRemoval.add(decaF);
}
} else {
LazyMethodGen annotationHolder = locateAnnotationHolderForFieldMunger(clazz, fieldMunger);
if (doesAlreadyHaveAnnotation(annotationHolder, itdIsActually, decaF, reportedErrors)) {
continue;
}
annotationHolder.addAnnotation(decaF.getAnnotation());
AsmRelationshipProvider.addDeclareAnnotationRelationship(world.getModelAsAsmManager(),
decaF.getSourceLocation(), itdIsActually.getSourceLocation(), false);
isChanged = true;
modificationOccured = true;
forRemoval.add(decaF);
}
}
}
worthRetrying.removeAll(forRemoval);
}
}
return isChanged;
}
private boolean weaveAtMethodOnITDSRepeatedly(List<DeclareAnnotation> decaMCs,
List<ConcreteTypeMunger> itdsForMethodAndConstructor, List<Integer> reportedErrors) {
boolean isChanged = false;
AsmManager asmManager = world.getModelAsAsmManager();
for (ConcreteTypeMunger methodctorMunger : itdsForMethodAndConstructor) {
ResolvedMember unMangledInterMethod = methodctorMunger.getSignature();
List<DeclareAnnotation> worthRetrying = new ArrayList<DeclareAnnotation>();
boolean modificationOccured = false;
for (Iterator<DeclareAnnotation> iter2 = decaMCs.iterator(); iter2.hasNext();) {
DeclareAnnotation decaMC = iter2.next();
if (decaMC.matches(unMangledInterMethod, world)) {
LazyMethodGen annotationHolder = locateAnnotationHolderForMethodCtorMunger(clazz, methodctorMunger);
if (annotationHolder == null
|| doesAlreadyHaveAnnotation(annotationHolder, unMangledInterMethod, decaMC, reportedErrors)) {
continue;
}
annotationHolder.addAnnotation(decaMC.getAnnotation());
isChanged = true;
AsmRelationshipProvider.addDeclareAnnotationRelationship(asmManager, decaMC.getSourceLocation(),
unMangledInterMethod.getSourceLocation(), false);
reportMethodCtorWeavingMessage(clazz, unMangledInterMethod, decaMC, -1);
modificationOccured = true;
} else {
if (!decaMC.isStarredAnnotationPattern()) {
worthRetrying.add(decaMC);
}
}
}
while (!worthRetrying.isEmpty() && modificationOccured) {
modificationOccured = false;
List<DeclareAnnotation> forRemoval = new ArrayList<DeclareAnnotation>();
for (Iterator<DeclareAnnotation> iter2 = worthRetrying.iterator(); iter2.hasNext();) {
DeclareAnnotation decaMC = iter2.next();
if (decaMC.matches(unMangledInterMethod, world)) {
LazyMethodGen annotationHolder = locateAnnotationHolderForFieldMunger(clazz, methodctorMunger);
if (doesAlreadyHaveAnnotation(annotationHolder, unMangledInterMethod, decaMC, reportedErrors)) {
continue;
}
annotationHolder.addAnnotation(decaMC.getAnnotation());
unMangledInterMethod.addAnnotation(decaMC.getAnnotation());
AsmRelationshipProvider.addDeclareAnnotationRelationship(asmManager, decaMC.getSourceLocation(),
unMangledInterMethod.getSourceLocation(), false);
isChanged = true;
modificationOccured = true;
forRemoval.add(decaMC);
}
worthRetrying.removeAll(forRemoval);
}
}
}
return isChanged;
}
private boolean dontAddTwice(DeclareAnnotation decaF, AnnotationAJ[] dontAddMeTwice) {
for (AnnotationAJ ann : dontAddMeTwice) {
if (ann != null && decaF.getAnnotation().getTypeName().equals(ann.getTypeName())) {
return true;
}
}
return false;
}
private AnnotationAJ[] removeFromAnnotationsArray(AnnotationAJ[] annotations,AnnotationAJ annotation) {
for (int i=0;i<annotations.length;i++) {
if (annotations[i] != null && annotation.getTypeName().equals(annotations[i].getTypeName())) {
AnnotationAJ[] newArray = new AnnotationAJ[annotations.length-1];
int index=0;
for (int j=0;j<annotations.length;j++) {
if (j!=i) {
newArray[index++]=annotations[j];
}
}
return newArray;
}
}
return annotations;
}
private boolean weaveDeclareAtField(LazyClassGen clazz) {
List<Integer> reportedProblems = new ArrayList<Integer>();
List<DeclareAnnotation> allDecafs = world.getDeclareAnnotationOnFields();
if (allDecafs.isEmpty()) {
return false;
}
boolean typeIsChanged = false;
List<ConcreteTypeMunger> relevantItdFields = getITDSubset(clazz, ResolvedTypeMunger.Field);
if (relevantItdFields != null) {
typeIsChanged = weaveAtFieldRepeatedly(allDecafs, relevantItdFields, reportedProblems);
}
List<DeclareAnnotation> decafs = getMatchingSubset(allDecafs, clazz.getType());
if (decafs.isEmpty()) {
return typeIsChanged;
}
List<BcelField> fields = clazz.getFieldGens();
if (fields != null) {
Set<DeclareAnnotation> unusedDecafs = new HashSet<DeclareAnnotation>();
unusedDecafs.addAll(decafs);
for (BcelField field : fields) {
if (!field.getName().startsWith(NameMangler.PREFIX)) {
Set<DeclareAnnotation> worthRetrying = new LinkedHashSet<DeclareAnnotation>();
boolean modificationOccured = false;
AnnotationAJ[] dontAddMeTwice = field.getAnnotations();
for (DeclareAnnotation decaf : decafs) {
if (decaf.getAnnotation() == null) {
return false;
}
if (decaf.matches(field, world)) {
if (decaf.isRemover()) {
AnnotationAJ annotation = decaf.getAnnotation();
if (field.hasAnnotation(annotation.getType())) {
typeIsChanged = true;
field.removeAnnotation(annotation);
AsmRelationshipProvider.addDeclareAnnotationFieldRelationship(world.getModelAsAsmManager(),
decaf.getSourceLocation(), clazz.getName(), field, true);
reportFieldAnnotationWeavingMessage(clazz, field, decaf, true);
dontAddMeTwice = removeFromAnnotationsArray(dontAddMeTwice, annotation);
} else {
worthRetrying.add(decaf);
}
unusedDecafs.remove(decaf);
} else {
if (!dontAddTwice(decaf, dontAddMeTwice)) {
if (doesAlreadyHaveAnnotation(field, decaf, reportedProblems,true )) {
unusedDecafs.remove(decaf);
continue;
}
field.addAnnotation(decaf.getAnnotation());
}
AsmRelationshipProvider.addDeclareAnnotationFieldRelationship(world.getModelAsAsmManager(),
decaf.getSourceLocation(), clazz.getName(), field, false);
reportFieldAnnotationWeavingMessage(clazz, field, decaf, false);
typeIsChanged = true;
modificationOccured = true;
unusedDecafs.remove(decaf);
}
} else if (!decaf.isStarredAnnotationPattern() || decaf.isRemover()) {
worthRetrying.add(decaf);
}
}
while (!worthRetrying.isEmpty() && modificationOccured) {
modificationOccured = false;
List<DeclareAnnotation> forRemoval = new ArrayList<DeclareAnnotation>();
for (Iterator<DeclareAnnotation> iter = worthRetrying.iterator(); iter.hasNext();) {
DeclareAnnotation decaF = iter.next();
if (decaF.matches(field, world)) {
if (decaF.isRemover()) {
AnnotationAJ annotation = decaF.getAnnotation();
if (field.hasAnnotation(annotation.getType())) {
typeIsChanged = modificationOccured = true;
forRemoval.add(decaF);
field.removeAnnotation(annotation);
AsmRelationshipProvider.addDeclareAnnotationFieldRelationship(world.getModelAsAsmManager(),
decaF.getSourceLocation(), clazz.getName(), field, true);
reportFieldAnnotationWeavingMessage(clazz, field, decaF, true);
}
} else {
unusedDecafs.remove(decaF);
if (doesAlreadyHaveAnnotation(field, decaF, reportedProblems,true)) {
continue;
}
field.addAnnotation(decaF.getAnnotation());
AsmRelationshipProvider.addDeclareAnnotationFieldRelationship(world.getModelAsAsmManager(),
decaF.getSourceLocation(), clazz.getName(), field, false);
typeIsChanged = modificationOccured = true;
forRemoval.add(decaF);
}
}
}
worthRetrying.removeAll(forRemoval);
}
}
}
checkUnusedDeclareAts(unusedDecafs, true);
}
return typeIsChanged;
}
private void checkUnusedDeclareAts(Set<DeclareAnnotation> unusedDecaTs, boolean isDeclareAtField) {
for (DeclareAnnotation declA : unusedDecaTs) {
boolean shouldCheck = declA.isExactPattern() || declA.getSignaturePattern().getExactDeclaringTypes().size() != 0;
if (shouldCheck && declA.getKind() != DeclareAnnotation.AT_CONSTRUCTOR) {
if (declA.getSignaturePattern().isMatchOnAnyName()) {
shouldCheck = false;
} else {
List<ExactTypePattern> declaringTypePatterns = declA.getSignaturePattern().getExactDeclaringTypes();
if (declaringTypePatterns.size() == 0) {
shouldCheck = false;
} else {
for (ExactTypePattern exactTypePattern : declaringTypePatterns) {
if (exactTypePattern.isIncludeSubtypes()) {
shouldCheck = false;
break;
}
}
}
}
}
if (shouldCheck) {
boolean itdMatch = false;
List<ConcreteTypeMunger> lst = clazz.getType().getInterTypeMungers();
for (Iterator<ConcreteTypeMunger> iterator = lst.iterator(); iterator.hasNext() && !itdMatch;) {
ConcreteTypeMunger element = iterator.next();
if (element.getMunger() instanceof NewFieldTypeMunger) {
NewFieldTypeMunger nftm = (NewFieldTypeMunger) element.getMunger();
itdMatch = declA.matches(nftm.getSignature(), world);
} else if (element.getMunger() instanceof NewMethodTypeMunger) {
NewMethodTypeMunger nmtm = (NewMethodTypeMunger) element.getMunger();
itdMatch = declA.matches(nmtm.getSignature(), world);
} else if (element.getMunger() instanceof NewConstructorTypeMunger) {
NewConstructorTypeMunger nctm = (NewConstructorTypeMunger) element.getMunger();
itdMatch = declA.matches(nctm.getSignature(), world);
}
}
if (!itdMatch) {
IMessage message = null;
if (isDeclareAtField) {
message = new Message("The field '" + declA.getSignaturePattern().toString() + "' does not exist",
declA.getSourceLocation(), true);
} else {
message = new Message("The method '" + declA.getSignaturePattern().toString() + "' does not exist",
declA.getSourceLocation(), true);
}
world.getMessageHandler().handleMessage(message);
}
}
}
}
private void reportFieldAnnotationWeavingMessage(LazyClassGen clazz, BcelField theField, DeclareAnnotation decaf,
boolean isRemove) {
if (!getWorld().getMessageHandler().isIgnoring(IMessage.WEAVEINFO)) {
world.getMessageHandler().handleMessage(
WeaveMessage.constructWeavingMessage(
isRemove ? WeaveMessage.WEAVEMESSAGE_REMOVES_ANNOTATION : WeaveMessage.WEAVEMESSAGE_ANNOTATES,
new String[] { theField.getFieldAsIs().toString() + "' of type '" + clazz.getName(),
clazz.getFileName(), decaf.getAnnotationString(), "field", decaf.getAspect().toString(),
Utility.beautifyLocation(decaf.getSourceLocation()) }));
}
}
private boolean doesAlreadyHaveAnnotation(ResolvedMember rm, DeclareAnnotation deca, List<Integer> reportedProblems, boolean reportError) {
if (rm.hasAnnotation(deca.getAnnotationType())) {
if (reportError && world.getLint().elementAlreadyAnnotated.isEnabled()) {
Integer uniqueID = new Integer(rm.hashCode() * deca.hashCode());
if (!reportedProblems.contains(uniqueID)) {
reportedProblems.add(uniqueID);
world.getLint().elementAlreadyAnnotated.signal(new String[] { rm.toString(),
deca.getAnnotationType().toString() }, rm.getSourceLocation(),
new ISourceLocation[] { deca.getSourceLocation() });
}
}
return true;
}
return false;
}
private boolean doesAlreadyHaveAnnotation(LazyMethodGen rm, ResolvedMember itdfieldsig, DeclareAnnotation deca,
List<Integer> reportedProblems) {
if (rm != null && rm.hasAnnotation(deca.getAnnotationType())) {
if (world.getLint().elementAlreadyAnnotated.isEnabled()) {
Integer uniqueID = new Integer(rm.hashCode() * deca.hashCode());
if (!reportedProblems.contains(uniqueID)) {
reportedProblems.add(uniqueID);
reportedProblems.add(new Integer(itdfieldsig.hashCode() * deca.hashCode()));
world.getLint().elementAlreadyAnnotated.signal(new String[] { itdfieldsig.toString(),
deca.getAnnotationType().toString() }, rm.getSourceLocation(),
new ISourceLocation[] { deca.getSourceLocation() });
}
}
return true;
}
return false;
}
private Set<String> findAspectsForMungers(LazyMethodGen mg) {
Set<String> aspectsAffectingType = new HashSet<String>();
for (BcelShadow shadow : mg.matchedShadows) {
for (ShadowMunger munger : shadow.getMungers()) {
if (munger instanceof BcelAdvice) {
BcelAdvice bcelAdvice = (BcelAdvice) munger;
if (bcelAdvice.getConcreteAspect() != null) {
aspectsAffectingType.add(bcelAdvice.getConcreteAspect().getSignature());
}
} else {
}
}
}
return aspectsAffectingType;
}
private boolean inlineSelfConstructors(List<LazyMethodGen> methodGens, List<LazyMethodGen> recursiveCtors) {
boolean inlinedSomething = false;
List<LazyMethodGen> newRecursiveCtors = new ArrayList<LazyMethodGen>();
for (LazyMethodGen methodGen : methodGens) {
if (!methodGen.getName().equals("<init>")) {
continue;
}
InstructionHandle ih = findSuperOrThisCall(methodGen);
if (ih != null && isThisCall(ih)) {
LazyMethodGen donor = getCalledMethod(ih);
if (donor.equals(methodGen)) {
newRecursiveCtors.add(donor);
} else {
if (!recursiveCtors.contains(donor)) {
inlineMethod(donor, methodGen, ih);
inlinedSomething = true;
}
}
}
}
recursiveCtors.addAll(newRecursiveCtors);
return inlinedSomething;
}
private void positionAndImplement(List<BcelShadow> initializationShadows) {
for (BcelShadow s : initializationShadows) {
positionInitializationShadow(s);
s.implement();
}
}
private void positionInitializationShadow(BcelShadow s) {
LazyMethodGen mg = s.getEnclosingMethod();
InstructionHandle call = findSuperOrThisCall(mg);
InstructionList body = mg.getBody();
ShadowRange r = new ShadowRange(body);
r.associateWithShadow(s);
if (s.getKind() == Shadow.PreInitialization) {
r.associateWithTargets(Range.genStart(body, body.getStart().getNext()), Range.genEnd(body, call.getPrev()));
} else {
r.associateWithTargets(Range.genStart(body, call.getNext()), Range.genEnd(body));
}
}
private boolean isThisCall(InstructionHandle ih) {
InvokeInstruction inst = (InvokeInstruction) ih.getInstruction();
return inst.getClassName(cpg).equals(clazz.getName());
}
public static void inlineMethod(LazyMethodGen donor, LazyMethodGen recipient, InstructionHandle call) {
final InstructionFactory fact = recipient.getEnclosingClass().getFactory();
IntMap frameEnv = new IntMap();
InstructionList argumentStores = genArgumentStores(donor, recipient, frameEnv, fact);
InstructionList inlineInstructions = genInlineInstructions(donor, recipient, frameEnv, fact, false);
inlineInstructions.insert(argumentStores);
recipient.getBody().append(call, inlineInstructions);
Utility.deleteInstruction(call, recipient);
}
public static void transformSynchronizedMethod(LazyMethodGen synchronizedMethod) {
if (trace.isTraceEnabled()) {
trace.enter("transformSynchronizedMethod", synchronizedMethod);
}
final InstructionFactory fact = synchronizedMethod.getEnclosingClass().getFactory();
InstructionList body = synchronizedMethod.getBody();
InstructionList prepend = new InstructionList();
Type enclosingClassType = BcelWorld.makeBcelType(synchronizedMethod.getEnclosingClass().getType());
if (synchronizedMethod.isStatic()) {
if (synchronizedMethod.getEnclosingClass().isAtLeastJava5()) {
int slotForLockObject = synchronizedMethod.allocateLocal(enclosingClassType);
prepend.append(fact.createConstant(enclosingClassType));
prepend.append(InstructionFactory.createDup(1));
prepend.append(InstructionFactory.createStore(enclosingClassType, slotForLockObject));
prepend.append(InstructionFactory.MONITORENTER);
InstructionList finallyBlock = new InstructionList();
finallyBlock.append(InstructionFactory.createLoad(Type.getType(java.lang.Class.class), slotForLockObject));
finallyBlock.append(InstructionConstants.MONITOREXIT);
finallyBlock.append(InstructionConstants.ATHROW);
InstructionHandle walker = body.getStart();
List<InstructionHandle> rets = new ArrayList<InstructionHandle>();
while (walker != null) {
if (walker.getInstruction().isReturnInstruction()) {
rets.add(walker);
}
walker = walker.getNext();
}
if (!rets.isEmpty()) {
for (Iterator<InstructionHandle> iter = rets.iterator(); iter.hasNext();) {
InstructionHandle element = iter.next();
InstructionList monitorExitBlock = new InstructionList();
monitorExitBlock.append(InstructionFactory.createLoad(enclosingClassType, slotForLockObject));
monitorExitBlock.append(InstructionConstants.MONITOREXIT);
InstructionHandle monitorExitBlockStart = body.insert(element, monitorExitBlock);
for (InstructionTargeter targeter : element.getTargetersCopy()) {
if (targeter instanceof LocalVariableTag) {
} else if (targeter instanceof LineNumberTag) {
} else if (targeter instanceof InstructionBranch) {
targeter.updateTarget(element, monitorExitBlockStart);
} else {
throw new BCException("Unexpected targeter encountered during transform: " + targeter);
}
}
}
}
InstructionHandle finallyStart = finallyBlock.getStart();
InstructionHandle tryPosition = body.getStart();
InstructionHandle catchPosition = body.getEnd();
body.insert(body.getStart(), prepend);
synchronizedMethod.getBody().append(finallyBlock);
synchronizedMethod.addExceptionHandler(tryPosition, catchPosition, finallyStart, null, false);
synchronizedMethod.addExceptionHandler(finallyStart, finallyStart.getNext(), finallyStart, null, false);
} else {
Type classType = BcelWorld.makeBcelType(synchronizedMethod.getEnclosingClass().getType());
Type clazzType = Type.getType(Class.class);
InstructionList parttwo = new InstructionList();
parttwo.append(InstructionFactory.createDup(1));
int slotForThis = synchronizedMethod.allocateLocal(classType);
parttwo.append(InstructionFactory.createStore(clazzType, slotForThis));
parttwo.append(InstructionFactory.MONITORENTER);
String fieldname = synchronizedMethod.getEnclosingClass().allocateField("class$");
FieldGen f = new FieldGen(Modifier.STATIC | Modifier.PRIVATE, Type.getType(Class.class), fieldname,
synchronizedMethod.getEnclosingClass().getConstantPool());
synchronizedMethod.getEnclosingClass().addField(f, null);
String name = synchronizedMethod.getEnclosingClass().getName();
prepend.append(fact.createGetStatic(name, fieldname, Type.getType(Class.class)));
prepend.append(InstructionFactory.createDup(1));
prepend.append(InstructionFactory.createBranchInstruction(Constants.IFNONNULL, parttwo.getStart()));
prepend.append(InstructionFactory.POP);
prepend.append(fact.createConstant(name));
InstructionHandle tryInstruction = prepend.getEnd();
prepend.append(fact.createInvoke("java.lang.Class", "forName", clazzType,
new Type[] { Type.getType(String.class) }, Constants.INVOKESTATIC));
InstructionHandle catchInstruction = prepend.getEnd();
prepend.append(InstructionFactory.createDup(1));
prepend.append(fact.createPutStatic(synchronizedMethod.getEnclosingClass().getType().getName(), fieldname,
Type.getType(Class.class)));
prepend.append(InstructionFactory.createBranchInstruction(Constants.GOTO, parttwo.getStart()));
InstructionList catchBlockForLiteralLoadingFail = new InstructionList();
catchBlockForLiteralLoadingFail.append(fact.createNew((ObjectType) Type.getType(NoClassDefFoundError.class)));
catchBlockForLiteralLoadingFail.append(InstructionFactory.createDup_1(1));
catchBlockForLiteralLoadingFail.append(InstructionFactory.SWAP);
catchBlockForLiteralLoadingFail.append(fact.createInvoke("java.lang.Throwable", "getMessage",
Type.getType(String.class), new Type[] {}, Constants.INVOKEVIRTUAL));
catchBlockForLiteralLoadingFail.append(fact.createInvoke("java.lang.NoClassDefFoundError", "<init>", Type.VOID,
new Type[] { Type.getType(String.class) }, Constants.INVOKESPECIAL));
catchBlockForLiteralLoadingFail.append(InstructionFactory.ATHROW);
InstructionHandle catchBlockStart = catchBlockForLiteralLoadingFail.getStart();
prepend.append(catchBlockForLiteralLoadingFail);
prepend.append(parttwo);
InstructionList finallyBlock = new InstructionList();
finallyBlock.append(InstructionFactory.createLoad(Type.getType(java.lang.Class.class), slotForThis));
finallyBlock.append(InstructionConstants.MONITOREXIT);
finallyBlock.append(InstructionConstants.ATHROW);
InstructionHandle walker = body.getStart();
List<InstructionHandle> rets = new ArrayList<InstructionHandle>();
while (walker != null) {
if (walker.getInstruction().isReturnInstruction()) {
rets.add(walker);
}
walker = walker.getNext();
}
if (rets.size() > 0) {
for (InstructionHandle ret : rets) {
InstructionList monitorExitBlock = new InstructionList();
monitorExitBlock.append(InstructionFactory.createLoad(classType, slotForThis));
monitorExitBlock.append(InstructionConstants.MONITOREXIT);
InstructionHandle monitorExitBlockStart = body.insert(ret, monitorExitBlock);
for (InstructionTargeter targeter : ret.getTargetersCopy()) {
if (targeter instanceof LocalVariableTag) {
} else if (targeter instanceof LineNumberTag) {
} else if (targeter instanceof InstructionBranch) {
targeter.updateTarget(ret, monitorExitBlockStart);
} else {
throw new BCException("Unexpected targeter encountered during transform: " + targeter);
}
}
}
}
InstructionHandle finallyStart = finallyBlock.getStart();
InstructionHandle tryPosition = body.getStart();
InstructionHandle catchPosition = body.getEnd();
body.insert(body.getStart(), prepend);
synchronizedMethod.getBody().append(finallyBlock);
synchronizedMethod.addExceptionHandler(tryPosition, catchPosition, finallyStart, null, false);
synchronizedMethod.addExceptionHandler(tryInstruction, catchInstruction, catchBlockStart,
(ObjectType) Type.getType(ClassNotFoundException.class), true);
synchronizedMethod.addExceptionHandler(finallyStart, finallyStart.getNext(), finallyStart, null, false);
}
} else {
Type classType = BcelWorld.makeBcelType(synchronizedMethod.getEnclosingClass().getType());
prepend.append(InstructionFactory.createLoad(classType, 0));
prepend.append(InstructionFactory.createDup(1));
int slotForThis = synchronizedMethod.allocateLocal(classType);
prepend.append(InstructionFactory.createStore(classType, slotForThis));
prepend.append(InstructionFactory.MONITORENTER);
InstructionList finallyBlock = new InstructionList();
finallyBlock.append(InstructionFactory.createLoad(classType, slotForThis));
finallyBlock.append(InstructionConstants.MONITOREXIT);
finallyBlock.append(InstructionConstants.ATHROW);
InstructionHandle walker = body.getStart();
List<InstructionHandle> rets = new ArrayList<InstructionHandle>();
while (walker != null) {
if (walker.getInstruction().isReturnInstruction()) {
rets.add(walker);
}
walker = walker.getNext();
}
if (!rets.isEmpty()) {
for (Iterator<InstructionHandle> iter = rets.iterator(); iter.hasNext();) {
InstructionHandle element = iter.next();
InstructionList monitorExitBlock = new InstructionList();
monitorExitBlock.append(InstructionFactory.createLoad(classType, slotForThis));
monitorExitBlock.append(InstructionConstants.MONITOREXIT);
InstructionHandle monitorExitBlockStart = body.insert(element, monitorExitBlock);
for (InstructionTargeter targeter : element.getTargetersCopy()) {
if (targeter instanceof LocalVariableTag) {
} else if (targeter instanceof LineNumberTag) {
} else if (targeter instanceof InstructionBranch) {
targeter.updateTarget(element, monitorExitBlockStart);
} else {
throw new BCException("Unexpected targeter encountered during transform: " + targeter);
}
}
}
}
InstructionHandle finallyStart = finallyBlock.getStart();
InstructionHandle tryPosition = body.getStart();
InstructionHandle catchPosition = body.getEnd();
body.insert(body.getStart(), prepend);
synchronizedMethod.getBody().append(finallyBlock);
synchronizedMethod.addExceptionHandler(tryPosition, catchPosition, finallyStart, null, false);
synchronizedMethod.addExceptionHandler(finallyStart, finallyStart.getNext(), finallyStart, null, false);
}
if (trace.isTraceEnabled()) {
trace.exit("transformSynchronizedMethod");
}
}
static InstructionList genInlineInstructions(LazyMethodGen donor, LazyMethodGen recipient, IntMap frameEnv,
InstructionFactory fact, boolean keepReturns) {
InstructionList footer = new InstructionList();
InstructionHandle end = footer.append(InstructionConstants.NOP);
InstructionList ret = new InstructionList();
InstructionList sourceList = donor.getBody();
Map<InstructionHandle, InstructionHandle> srcToDest = new HashMap<InstructionHandle, InstructionHandle>();
ConstantPool donorCpg = donor.getEnclosingClass().getConstantPool();
ConstantPool recipientCpg = recipient.getEnclosingClass().getConstantPool();
boolean isAcrossClass = donorCpg != recipientCpg;
BootstrapMethods bootstrapMethods = null;
for (InstructionHandle src = sourceList.getStart(); src != null; src = src.getNext()) {
Instruction fresh = Utility.copyInstruction(src.getInstruction());
InstructionHandle dest;
if (fresh.isConstantPoolInstruction()) {
if (isAcrossClass) {
InstructionCP cpi = (InstructionCP) fresh;
cpi.setIndex(recipientCpg.addConstant(donorCpg.getConstant(cpi.getIndex()), donorCpg));
}
}
if (src.getInstruction() == Range.RANGEINSTRUCTION) {
dest = ret.append(Range.RANGEINSTRUCTION);
} else if (fresh.isReturnInstruction()) {
if (keepReturns) {
dest = ret.append(fresh);
} else {
dest = ret.append(InstructionFactory.createBranchInstruction(Constants.GOTO, end));
}
} else if (fresh instanceof InstructionBranch) {
dest = ret.append((InstructionBranch) fresh);
} else if (fresh.isLocalVariableInstruction() || fresh instanceof RET) {
int oldIndex = fresh.getIndex();
int freshIndex;
if (!frameEnv.hasKey(oldIndex)) {
freshIndex = recipient.allocateLocal(2);
frameEnv.put(oldIndex, freshIndex);
} else {
freshIndex = frameEnv.get(oldIndex);
}
if (fresh instanceof RET) {
fresh.setIndex(freshIndex);
} else {
fresh = ((InstructionLV) fresh).setIndexAndCopyIfNecessary(freshIndex);
}
dest = ret.append(fresh);
} else {
dest = ret.append(fresh);
}
srcToDest.put(src, dest);
}
Map<Tag, Tag> tagMap = new HashMap<Tag, Tag>();
Map<BcelShadow, BcelShadow> shadowMap = new HashMap<BcelShadow, BcelShadow>();
for (InstructionHandle dest = ret.getStart(), src = sourceList.getStart(); dest != null; dest = dest.getNext(), src = src
.getNext()) {
Instruction inst = dest.getInstruction();
if (inst instanceof InstructionBranch) {
InstructionBranch branch = (InstructionBranch) inst;
InstructionHandle oldTarget = branch.getTarget();
InstructionHandle newTarget = srcToDest.get(oldTarget);
if (newTarget == null) {
} else {
branch.setTarget(newTarget);
if (branch instanceof InstructionSelect) {
InstructionSelect select = (InstructionSelect) branch;
InstructionHandle[] oldTargets = select.getTargets();
for (int k = oldTargets.length - 1; k >= 0; k--) {
select.setTarget(k, srcToDest.get(oldTargets[k]));
}
}
}
}
Iterator<InstructionTargeter> tIter = src.getTargeters().iterator();
while (tIter.hasNext()) {
InstructionTargeter old = tIter.next();
if (old instanceof Tag) {
Tag oldTag = (Tag) old;
Tag fresh = tagMap.get(oldTag);
if (fresh == null) {
fresh = oldTag.copy();
if (old instanceof LocalVariableTag) {
LocalVariableTag lvTag = (LocalVariableTag) old;
LocalVariableTag lvTagFresh = (LocalVariableTag) fresh;
if (lvTag.getSlot() == 0) {
fresh = new LocalVariableTag(lvTag.getRealType().getSignature(), "ajc$aspectInstance",
frameEnv.get(lvTag.getSlot()), 0);
} else {
lvTagFresh.updateSlot(frameEnv.get(lvTag.getSlot()));
}
}
tagMap.put(oldTag, fresh);
}
dest.addTargeter(fresh);
} else if (old instanceof ExceptionRange) {
ExceptionRange er = (ExceptionRange) old;
if (er.getStart() == src) {
ExceptionRange freshEr = new ExceptionRange(recipient.getBody(), er.getCatchType(), er.getPriority());
freshEr.associateWithTargets(dest, srcToDest.get(er.getEnd()), srcToDest.get(er.getHandler()));
}
} else if (old instanceof ShadowRange) {
ShadowRange oldRange = (ShadowRange) old;
if (oldRange.getStart() == src) {
BcelShadow oldShadow = oldRange.getShadow();
BcelShadow freshEnclosing = oldShadow.getEnclosingShadow() == null ? null : (BcelShadow) shadowMap
.get(oldShadow.getEnclosingShadow());
BcelShadow freshShadow = oldShadow.copyInto(recipient, freshEnclosing);
ShadowRange freshRange = new ShadowRange(recipient.getBody());
freshRange.associateWithShadow(freshShadow);
freshRange.associateWithTargets(dest, srcToDest.get(oldRange.getEnd()));
shadowMap.put(oldShadow, freshShadow);
}
}
}
}
if (!keepReturns) {
ret.append(footer);
}
return ret;
}
private static InstructionList genArgumentStores(LazyMethodGen donor, LazyMethodGen recipient, IntMap frameEnv,
InstructionFactory fact) {
InstructionList ret = new InstructionList();
int donorFramePos = 0;
if (!donor.isStatic()) {
int targetSlot = recipient.allocateLocal(Type.OBJECT);
ret.insert(InstructionFactory.createStore(Type.OBJECT, targetSlot));
frameEnv.put(donorFramePos, targetSlot);
donorFramePos += 1;
}
Type[] argTypes = donor.getArgumentTypes();
for (int i = 0, len = argTypes.length; i < len; i++) {
Type argType = argTypes[i];
int argSlot = recipient.allocateLocal(argType);
ret.insert(InstructionFactory.createStore(argType, argSlot));
frameEnv.put(donorFramePos, argSlot);
donorFramePos += argType.getSize();
}
return ret;
}
private LazyMethodGen getCalledMethod(InstructionHandle ih) {
InvokeInstruction inst = (InvokeInstruction) ih.getInstruction();
String methodName = inst.getName(cpg);
String signature = inst.getSignature(cpg);
return clazz.getLazyMethodGen(methodName, signature);
}
private void weaveInAddedMethods() {
Collections.sort(addedLazyMethodGens, new Comparator<LazyMethodGen>() {
public int compare(LazyMethodGen aa, LazyMethodGen bb) {
int i = aa.getName().compareTo(bb.getName());
if (i != 0) {
return i;
}
return aa.getSignature().compareTo(bb.getSignature());
}
});
for (LazyMethodGen addedMember : addedLazyMethodGens) {
clazz.addMethodGen(addedMember);
}
}
private InstructionHandle findSuperOrThisCall(LazyMethodGen mg) {
int depth = 1;
InstructionHandle start = mg.getBody().getStart();
while (true) {
if (start == null) {
return null;
}
Instruction inst = start.getInstruction();
if (inst.opcode == Constants.INVOKESPECIAL && ((InvokeInstruction) inst).getName(cpg).equals("<init>")) {
depth--;
if (depth == 0) {
return start;
}
} else if (inst.opcode == Constants.NEW) {
depth++;
}
start = start.getNext();
}
}
private boolean match(LazyMethodGen mg) {
BcelShadow enclosingShadow;
List<BcelShadow> shadowAccumulator = new ArrayList<BcelShadow>();
boolean isOverweaving = world.isOverWeaving();
boolean startsAngly = mg.getName().charAt(0) == '<';
if (startsAngly && mg.getName().equals("<init>")) {
return matchInit(mg, shadowAccumulator);
} else if (!shouldWeaveBody(mg)) {
return false;
} else {
if (startsAngly && mg.getName().equals("<clinit>")) {
enclosingShadow = BcelShadow.makeStaticInitialization(world, mg);
} else if (mg.isAdviceMethod()) {
enclosingShadow = BcelShadow.makeAdviceExecution(world, mg);
} else {
AjAttribute.EffectiveSignatureAttribute effective = mg.getEffectiveSignature();
if (effective == null) {
if (isOverweaving && mg.getName().startsWith(NameMangler.PREFIX)) {
return false;
}
if (mg.getName().startsWith(SWITCH_TABLE_SYNTHETIC_METHOD_PREFIX)
&& Objects.equals(mg.getReturnType().getSignature(), "[I")) {
return false;
}
enclosingShadow = BcelShadow.makeMethodExecution(world, mg, !canMatchBodyShadows);
} else if (effective.isWeaveBody()) {
ResolvedMember rm = effective.getEffectiveSignature();
fixParameterNamesForResolvedMember(rm, mg.getMemberView());
fixAnnotationsForResolvedMember(rm, mg.getMemberView());
enclosingShadow = BcelShadow.makeShadowForMethod(world, mg, effective.getShadowKind(), rm);
} else {
return false;
}
}
if (canMatchBodyShadows) {
for (InstructionHandle h = mg.getBody().getStart(); h != null; h = h.getNext()) {
match(mg, h, enclosingShadow, shadowAccumulator);
}
}
if (canMatch(enclosingShadow.getKind())
&& !(mg.getName().charAt(0) == 'a' && mg.getName().startsWith("ajc$interFieldInit"))) {
if (match(enclosingShadow, shadowAccumulator)) {
enclosingShadow.init();
}
}
mg.matchedShadows = shadowAccumulator;
return !shadowAccumulator.isEmpty();
}
}
private boolean matchInit(LazyMethodGen mg, List<BcelShadow> shadowAccumulator) {
BcelShadow enclosingShadow;
InstructionHandle superOrThisCall = findSuperOrThisCall(mg);
if (superOrThisCall == null) {
return false;
}
enclosingShadow = BcelShadow.makeConstructorExecution(world, mg, superOrThisCall);
if (mg.getEffectiveSignature() != null) {
enclosingShadow.setMatchingSignature(mg.getEffectiveSignature().getEffectiveSignature());
}
boolean beforeSuperOrThisCall = true;
if (shouldWeaveBody(mg)) {
if (canMatchBodyShadows) {
for (InstructionHandle h = mg.getBody().getStart(); h != null; h = h.getNext()) {
if (h == superOrThisCall) {
beforeSuperOrThisCall = false;
continue;
}
match(mg, h, beforeSuperOrThisCall ? null : enclosingShadow, shadowAccumulator);
}
}
if (canMatch(Shadow.ConstructorExecution)) {
match(enclosingShadow, shadowAccumulator);
}
}
if (!isThisCall(superOrThisCall)) {
InstructionHandle curr = enclosingShadow.getRange().getStart();
for (Iterator<IfaceInitList> i = addedSuperInitializersAsList.iterator(); i.hasNext();) {
IfaceInitList l = i.next();
Member ifaceInitSig = AjcMemberMaker.interfaceConstructor(l.onType);
BcelShadow initShadow = BcelShadow.makeIfaceInitialization(world, mg, ifaceInitSig);
InstructionList inits = genInitInstructions(l.list, false);
if (match(initShadow, shadowAccumulator) || !inits.isEmpty()) {
initShadow.initIfaceInitializer(curr);
initShadow.getRange().insert(inits, Range.OutsideBefore);
}
}
InstructionList inits = genInitInstructions(addedThisInitializers, false);
enclosingShadow.getRange().insert(inits, Range.OutsideBefore);
}
boolean addedInitialization = match(BcelShadow.makeUnfinishedInitialization(world, mg), initializationShadows);
addedInitialization |= match(BcelShadow.makeUnfinishedPreinitialization(world, mg), initializationShadows);
mg.matchedShadows = shadowAccumulator;
return addedInitialization || !shadowAccumulator.isEmpty();
}
private boolean shouldWeaveBody(LazyMethodGen mg) {
if (mg.isBridgeMethod()) {
return false;
}
if (mg.isAjSynthetic()) {
return mg.getName().equals("<clinit>");
}
AjAttribute.EffectiveSignatureAttribute a = mg.getEffectiveSignature();
if (a != null) {
return a.isWeaveBody();
}
return true;
}
private InstructionList genInitInstructions(List<ConcreteTypeMunger> list, boolean isStatic) {
list = PartialOrder.sort(list);
if (list == null) {
throw new BCException("circularity in inter-types");
}
InstructionList ret = new InstructionList();
for (ConcreteTypeMunger cmunger : list) {
NewFieldTypeMunger munger = (NewFieldTypeMunger) cmunger.getMunger();
ResolvedMember initMethod = munger.getInitMethod(cmunger.getAspectType());
if (!isStatic) {
ret.append(InstructionConstants.ALOAD_0);
}
ret.append(Utility.createInvoke(fact, world, initMethod));
}
return ret;
}
private void match(LazyMethodGen mg, InstructionHandle ih, BcelShadow enclosingShadow, List<BcelShadow> shadowAccumulator) {
Instruction i = ih.getInstruction();
if (canMatch(Shadow.ExceptionHandler) && !Range.isRangeHandle(ih)) {
Set<InstructionTargeter> targeters = ih.getTargetersCopy();
for (InstructionTargeter t : targeters) {
if (t instanceof ExceptionRange) {
ExceptionRange er = (ExceptionRange) t;
if (er.getCatchType() == null) {
continue;
}
if (isInitFailureHandler(ih)) {
return;
}
if (!ih.getInstruction().isStoreInstruction() && ih.getInstruction().getOpcode() != Constants.NOP) {
mg.getBody().insert(ih, InstructionConstants.NOP);
InstructionHandle newNOP = ih.getPrev();
er.updateTarget(ih, newNOP, mg.getBody());
for (InstructionTargeter t2 : targeters) {
newNOP.addTargeter(t2);
}
ih.removeAllTargeters();
match(BcelShadow.makeExceptionHandler(world, er, mg, newNOP, enclosingShadow), shadowAccumulator);
} else {
match(BcelShadow.makeExceptionHandler(world, er, mg, ih, enclosingShadow), shadowAccumulator);
}
}
}
}
if ((i instanceof FieldInstruction) && (canMatch(Shadow.FieldGet) || canMatch(Shadow.FieldSet))) {
FieldInstruction fi = (FieldInstruction) i;
if (fi.opcode == Constants.PUTFIELD || fi.opcode == Constants.PUTSTATIC) {
InstructionHandle prevHandle = ih.getPrev();
Instruction prevI = prevHandle.getInstruction();
if (Utility.isConstantPushInstruction(prevI)) {
Member field = BcelWorld.makeFieldJoinPointSignature(clazz, (FieldInstruction) i);
ResolvedMember resolvedField = field.resolve(world);
if (resolvedField == null) {
} else if (Modifier.isFinal(resolvedField.getModifiers())) {
} else {
if (canMatch(Shadow.FieldSet)) {
matchSetInstruction(mg, ih, enclosingShadow, shadowAccumulator);
}
}
} else {
if (canMatch(Shadow.FieldSet)) {
matchSetInstruction(mg, ih, enclosingShadow, shadowAccumulator);
}
}
} else {
if (canMatch(Shadow.FieldGet)) {
matchGetInstruction(mg, ih, enclosingShadow, shadowAccumulator);
}
}
} else if (i instanceof InvokeInstruction) {
InvokeInstruction ii = (InvokeInstruction) i;
if (ii.getMethodName(clazz.getConstantPool()).equals("<init>")) {
if (canMatch(Shadow.ConstructorCall)) {
match(BcelShadow.makeConstructorCall(world, mg, ih, enclosingShadow), shadowAccumulator);
}
} else if (ii.opcode == Constants.INVOKESPECIAL) {
String onTypeName = ii.getClassName(cpg);
if (onTypeName.equals(mg.getEnclosingClass().getName())) {
matchInvokeInstruction(mg, ih, ii, enclosingShadow, shadowAccumulator);
} else {
}
} else {
if (ii.getOpcode()!=Constants.INVOKEDYNAMIC) {
matchInvokeInstruction(mg, ih, ii, enclosingShadow, shadowAccumulator);
}
}
} else if (world.isJoinpointArrayConstructionEnabled() && i.isArrayCreationInstruction()) {
if (canMatch(Shadow.ConstructorCall)) {
if (i.opcode == Constants.ANEWARRAY) {
BcelShadow ctorCallShadow = BcelShadow.makeArrayConstructorCall(world, mg, ih, enclosingShadow);
match(ctorCallShadow, shadowAccumulator);
} else if (i.opcode == Constants.NEWARRAY) {
BcelShadow ctorCallShadow = BcelShadow.makeArrayConstructorCall(world, mg, ih, enclosingShadow);
match(ctorCallShadow, shadowAccumulator);
} else if (i instanceof MULTIANEWARRAY) {
BcelShadow ctorCallShadow = BcelShadow.makeArrayConstructorCall(world, mg, ih, enclosingShadow);
match(ctorCallShadow, shadowAccumulator);
}
}
} else if (world.isJoinpointSynchronizationEnabled()
&& ((i.getOpcode() == Constants.MONITORENTER) || (i.getOpcode() == Constants.MONITOREXIT))) {
if (i.getOpcode() == Constants.MONITORENTER) {
BcelShadow monitorEntryShadow = BcelShadow.makeMonitorEnter(world, mg, ih, enclosingShadow);
match(monitorEntryShadow, shadowAccumulator);
} else {
BcelShadow monitorExitShadow = BcelShadow.makeMonitorExit(world, mg, ih, enclosingShadow);
match(monitorExitShadow, shadowAccumulator);
}
}
}
private boolean isInitFailureHandler(InstructionHandle ih) {
InstructionHandle twoInstructionsAway = ih.getNext().getNext();
if (twoInstructionsAway.getInstruction().opcode == Constants.PUTSTATIC) {
String name = ((FieldInstruction) twoInstructionsAway.getInstruction()).getFieldName(cpg);
if (name.equals(NameMangler.INITFAILURECAUSE_FIELD_NAME)) {
return true;
}
}
return false;
}
private void matchSetInstruction(LazyMethodGen mg, InstructionHandle ih, BcelShadow enclosingShadow,
List<BcelShadow> shadowAccumulator) {
FieldInstruction fi = (FieldInstruction) ih.getInstruction();
Member field = BcelWorld.makeFieldJoinPointSignature(clazz, fi);
if (field.getName().startsWith(NameMangler.PREFIX)) {
return;
}
ResolvedMember resolvedField = field.resolve(world);
if (resolvedField == null) {
return;
} else if (Modifier.isFinal(resolvedField.getModifiers())
&& Utility.isConstantPushInstruction(ih.getPrev().getInstruction())) {
return;
} else if (resolvedField.isSynthetic()) {
return;
} else {
BcelShadow bs = BcelShadow.makeFieldSet(world, resolvedField, mg, ih, enclosingShadow);
String cname = fi.getClassName(cpg);
if (!resolvedField.getDeclaringType().getName().equals(cname)) {
bs.setActualTargetType(cname);
}
match(bs, shadowAccumulator);
}
}
private void matchGetInstruction(LazyMethodGen mg, InstructionHandle ih, BcelShadow enclosingShadow,
List<BcelShadow> shadowAccumulator) {
FieldInstruction fi = (FieldInstruction) ih.getInstruction();
Member field = BcelWorld.makeFieldJoinPointSignature(clazz, fi);
if (field.getName().startsWith(NameMangler.PREFIX)) {
return;
}
ResolvedMember resolvedField = field.resolve(world);
if (resolvedField == null) {
return;
} else if (resolvedField.isSynthetic()) {
return;
} else {
BcelShadow bs = BcelShadow.makeFieldGet(world, resolvedField, mg, ih, enclosingShadow);
String cname = fi.getClassName(cpg);
if (!resolvedField.getDeclaringType().getName().equals(cname)) {
bs.setActualTargetType(cname);
}
match(bs, shadowAccumulator);
}
}
private ResolvedMember findResolvedMemberNamed(ResolvedType type, String methodName) {
ResolvedMember[] allMethods = type.getDeclaredMethods();
for (int i = 0; i < allMethods.length; i++) {
ResolvedMember member = allMethods[i];
if (member.getName().equals(methodName)) {
return member;
}
}
return null;
}
private ResolvedMember findResolvedMemberNamed(ResolvedType type, String methodName, UnresolvedType[] params) {
ResolvedMember[] allMethods = type.getDeclaredMethods();
List<ResolvedMember> candidates = new ArrayList<ResolvedMember>();
for (int i = 0; i < allMethods.length; i++) {
ResolvedMember candidate = allMethods[i];
if (candidate.getName().equals(methodName)) {
if (candidate.getArity() == params.length) {
candidates.add(candidate);
}
}
}
if (candidates.size() == 0) {
return null;
} else if (candidates.size() == 1) {
return candidates.get(0);
} else {
for (ResolvedMember candidate : candidates) {
boolean allOK = true;
UnresolvedType[] candidateParams = candidate.getParameterTypes();
for (int p = 0; p < candidateParams.length; p++) {
if (!candidateParams[p].getErasureSignature().equals(params[p].getErasureSignature())) {
allOK = false;
break;
}
}
if (allOK) {
return candidate;
}
}
}
return null;
}
private void fixParameterNamesForResolvedMember(ResolvedMember rm, ResolvedMember declaredSig) {
UnresolvedType memberHostType = declaredSig.getDeclaringType();
String methodName = declaredSig.getName();
String[] pnames = null;
if (rm.getKind() == Member.METHOD && !rm.isAbstract()) {
if (methodName.startsWith("ajc$inlineAccessMethod") || methodName.startsWith("ajc$superDispatch")) {
ResolvedMember resolvedDooberry = world.resolve(declaredSig);
pnames = resolvedDooberry.getParameterNames();
} else {
ResolvedMember realthing = AjcMemberMaker.interMethodDispatcher(rm.resolve(world), memberHostType).resolve(world);
ResolvedMember theRealMember = findResolvedMemberNamed(memberHostType.resolve(world), realthing.getName());
if (theRealMember != null) {
pnames = theRealMember.getParameterNames();
if (pnames.length > 0 && pnames[0].equals("ajc$this_")) {
String[] pnames2 = new String[pnames.length - 1];
System.arraycopy(pnames, 1, pnames2, 0, pnames2.length);
pnames = pnames2;
}
}
}
}
rm.setParameterNames(pnames);
}
private void fixAnnotationsForResolvedMember(ResolvedMember rm, ResolvedMember declaredSig) {
try {
UnresolvedType memberHostType = declaredSig.getDeclaringType();
boolean containsKey = mapToAnnotationHolder.containsKey(rm);
ResolvedMember realAnnotationHolder = mapToAnnotationHolder.get(rm);
String methodName = declaredSig.getName();
if (!containsKey) {
if (rm.getKind() == Member.FIELD) {
if (methodName.startsWith("ajc$inlineAccessField")) {
realAnnotationHolder = world.resolve(rm);
} else {
ResolvedMember realthing = AjcMemberMaker.interFieldInitializer(rm, memberHostType);
realAnnotationHolder = world.resolve(realthing);
}
} else if (rm.getKind() == Member.METHOD && !rm.isAbstract()) {
if (methodName.startsWith("ajc$inlineAccessMethod") || methodName.startsWith("ajc$superDispatch")) {
realAnnotationHolder = world.resolve(declaredSig);
} else {
ResolvedMember realthing = AjcMemberMaker.interMethodDispatcher(rm.resolve(world), memberHostType).resolve(world);
realAnnotationHolder = findResolvedMemberNamed(memberHostType.resolve(world), realthing.getName(),realthing.getParameterTypes());
if (realAnnotationHolder == null) {
throw new UnsupportedOperationException(
"Known limitation in M4 - can't find ITD members when type variable is used as an argument and has upper bound specified");
}
}
} else if (rm.getKind() == Member.CONSTRUCTOR) {
ResolvedMember realThing = AjcMemberMaker.postIntroducedConstructor(memberHostType.resolve(world),rm.getDeclaringType(), rm.getParameterTypes());
realAnnotationHolder = world.resolve(realThing);
if (realAnnotationHolder == null) {
throw new UnsupportedOperationException("Known limitation in M4 - can't find ITD members when type variable is used as an argument and has upper bound specified");
}
}
mapToAnnotationHolder.put(rm, realAnnotationHolder);
}
ResolvedType[] annotationTypes;
AnnotationAJ[] annotations;
if (realAnnotationHolder!=null) {
annotationTypes = realAnnotationHolder.getAnnotationTypes();
annotations = realAnnotationHolder.getAnnotations();
if (annotationTypes==null) {
annotationTypes = ResolvedType.EMPTY_ARRAY;
}
if (annotations==null) {
annotations = AnnotationAJ.EMPTY_ARRAY;
}
} else {
annotations = AnnotationAJ.EMPTY_ARRAY;
annotationTypes = ResolvedType.EMPTY_ARRAY;
}
rm.setAnnotations(annotations);
rm.setAnnotationTypes(annotationTypes);
} catch (UnsupportedOperationException ex) {
throw ex;
} catch (Throwable t) {
throw new BCException("Unexpectedly went bang when searching for annotations on " + rm, t);
}
}
private void matchInvokeInstruction(LazyMethodGen mg, InstructionHandle ih, InvokeInstruction invoke,
BcelShadow enclosingShadow, List<BcelShadow> shadowAccumulator) {
String methodName = invoke.getName(cpg);
if (methodName.startsWith(NameMangler.PREFIX)) {
Member jpSig = world.makeJoinPointSignatureForMethodInvocation(clazz, invoke);
ResolvedMember declaredSig = jpSig.resolve(world);
if (declaredSig == null) {
return;
}
if (declaredSig.getKind() == Member.FIELD) {
Shadow.Kind kind;
if (jpSig.getReturnType().equals(UnresolvedType.VOID)) {
kind = Shadow.FieldSet;
} else {
kind = Shadow.FieldGet;
}
if (canMatch(Shadow.FieldGet) || canMatch(Shadow.FieldSet)) {
match(BcelShadow.makeShadowForMethodCall(world, mg, ih, enclosingShadow, kind, declaredSig), shadowAccumulator);
}
} else if (!declaredSig.getName().startsWith(NameMangler.PREFIX)) {
if (canMatch(Shadow.MethodCall)) {
match(BcelShadow.makeShadowForMethodCall(world, mg, ih, enclosingShadow, Shadow.MethodCall, declaredSig),
shadowAccumulator);
}
} else {
AjAttribute.EffectiveSignatureAttribute effectiveSig = declaredSig.getEffectiveSignature();
if (effectiveSig == null) {
return;
}
if (effectiveSig.isWeaveBody()) {
return;
}
ResolvedMember rm = effectiveSig.getEffectiveSignature();
fixParameterNamesForResolvedMember(rm, declaredSig);
fixAnnotationsForResolvedMember(rm, declaredSig);
if (canMatch(effectiveSig.getShadowKind())) {
match(BcelShadow.makeShadowForMethodCall(world, mg, ih, enclosingShadow, effectiveSig.getShadowKind(), rm),
shadowAccumulator);
}
}
} else {
if (canMatch(Shadow.MethodCall)) {
boolean proceed = true;
if (world.isOverWeaving()) {
String s = invoke.getClassName(mg.getConstantPool());
if (s.length() > 4
&& s.charAt(4) == 'a'
&& (s.equals("org.aspectj.runtime.internal.CFlowCounter")
|| s.equals("org.aspectj.runtime.internal.CFlowStack") || s
.equals("org.aspectj.runtime.reflect.Factory"))) {
proceed = false;
} else {
if (methodName.equals("aspectOf")) {
proceed = false;
}
}
}
if (methodName.startsWith(SWITCH_TABLE_SYNTHETIC_METHOD_PREFIX)) {
proceed = false;
}
if (proceed) {
match(BcelShadow.makeMethodCall(world, mg, ih, enclosingShadow), shadowAccumulator);
}
}
}
}
private static boolean checkedXsetForLowLevelContextCapturing = false;
private static boolean captureLowLevelContext = false;
private boolean match(BcelShadow shadow, List<BcelShadow> shadowAccumulator) {
if (captureLowLevelContext) {
ContextToken shadowMatchToken = CompilationAndWeavingContext.enteringPhase(
CompilationAndWeavingContext.MATCHING_SHADOW, shadow);
boolean isMatched = false;
Shadow.Kind shadowKind = shadow.getKind();
List<ShadowMunger> candidateMungers = indexedShadowMungers[shadowKind.getKey()];
if (candidateMungers != null) {
for (ShadowMunger munger : candidateMungers) {
ContextToken mungerMatchToken = CompilationAndWeavingContext.enteringPhase(
CompilationAndWeavingContext.MATCHING_POINTCUT, munger.getPointcut());
if (munger.match(shadow, world)) {
shadow.addMunger(munger);
isMatched = true;
if (shadow.getKind() == Shadow.StaticInitialization) {
clazz.warnOnAddedStaticInitializer(shadow, munger.getSourceLocation());
}
}
CompilationAndWeavingContext.leavingPhase(mungerMatchToken);
}
if (isMatched) {
shadowAccumulator.add(shadow);
}
}
CompilationAndWeavingContext.leavingPhase(shadowMatchToken);
return isMatched;
} else {
boolean isMatched = false;
Shadow.Kind shadowKind = shadow.getKind();
List<ShadowMunger> candidateMungers = indexedShadowMungers[shadowKind.getKey()];
if (candidateMungers != null) {
for (ShadowMunger munger : candidateMungers) {
if (munger.match(shadow, world)) {
shadow.addMunger(munger);
isMatched = true;
if (shadow.getKind() == Shadow.StaticInitialization) {
clazz.warnOnAddedStaticInitializer(shadow, munger.getSourceLocation());
}
}
}
if (isMatched) {
shadowAccumulator.add(shadow);
}
}
return isMatched;
}
}
private void implement(LazyMethodGen mg) {
List<BcelShadow> shadows = mg.matchedShadows;
if (shadows == null) {
return;
}
for (BcelShadow shadow : shadows) {
ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.IMPLEMENTING_ON_SHADOW,
shadow);
shadow.implement();
CompilationAndWeavingContext.leavingPhase(tok);
}
mg.getMaxLocals();
mg.matchedShadows = null;
}
public LazyClassGen getLazyClassGen() {
return clazz;
}
public BcelWorld getWorld() {
return world;
}
public void setReweavableMode(boolean mode) {
inReweavableMode = mode;
}
public boolean getReweavableMode() {
return inReweavableMode;
}
@Override
public String toString() {
return "BcelClassWeaver instance for : " + clazz;
}
}