public static final Kind AdviceExecution = new Kind(JoinPoint.ADVICE_EXECUTION, 9, false);
public static final Kind Initialization = new Kind(JoinPoint.INITIALIZATION, 10, false);
public static final Kind ExceptionHandler = new Kind(JoinPoint.EXCEPTION_HANDLER, 11, true);
+
+ public static final int MAX_SHADOW_KIND = 11;
+ public static final Kind[] SHADOW_KINDS = new Kind[] {
+ MethodCall, ConstructorCall, MethodExecution, ConstructorExecution,
+ FieldGet, FieldSet, StaticInitialization, PreInitialization,
+ AdviceExecution, Initialization, ExceptionHandler,
+ };
/** A type-safe enum representing the kind of shadows
import org.aspectj.weaver.ResolvedTypeX;
import org.aspectj.weaver.Shadow;
import org.aspectj.weaver.ShadowMunger;
+import org.aspectj.weaver.Shadow.Kind;
+import org.aspectj.weaver.patterns.FastMatchInfo;
class BcelClassWeaver implements IClassWeaver {
this.ty = clazz.getBcelObjectType();
this.cpg = clazz.getConstantPoolGen();
this.fact = clazz.getFactory();
+
+ fastMatchShadowMungers(shadowMungers);
+
initializeSuperInitializerMap(ty.getResolvedTypeX());
}
- // --------------------------------------------
-
- private void initializeSuperInitializerMap(ResolvedTypeX child) {
+ private List[] perKindShadowMungers;
+ private boolean canMatchBodyShadows = false;
+ private boolean canMatchInitialization = false;
+ private void fastMatchShadowMungers(List shadowMungers) {
+ perKindShadowMungers = new List[Shadow.MAX_SHADOW_KIND+1];
+ for (int i = 0; i < Shadow.SHADOW_KINDS.length; i++) {
+ Shadow.Kind kind = Shadow.SHADOW_KINDS[i];
+ ArrayList mungers = new ArrayList(0);
+ perKindShadowMungers[kind.getKey()] = mungers;
+ fastMatchShadowMungers(shadowMungers, mungers, kind);
+ if (mungers.isEmpty()) {
+ perKindShadowMungers[kind.getKey()] = null;
+ } else {
+ if (kind == Shadow.Initialization) {
+ canMatchInitialization = true;
+ } else if (!kind.isEnclosingKind()) {
+ canMatchBodyShadows = true;
+ }
+ }
+ }
+ }
+
+ private boolean canMatch(Shadow.Kind kind) {
+ return perKindShadowMungers[kind.getKey()] != null;
+ }
+
+ private void fastMatchShadowMungers(List shadowMungers, ArrayList mungers, Kind kind) {
+ FastMatchInfo info = new FastMatchInfo(clazz.getType(), kind);
+ for (Iterator i = shadowMungers.iterator(); i.hasNext();) {
+ ShadowMunger munger = (ShadowMunger) i.next();
+ if (munger.getPointcut().fastMatch(info).maybeTrue()) mungers.add(munger);
+ }
+ }
+
+
+ private void initializeSuperInitializerMap(ResolvedTypeX child) {
ResolvedTypeX[] superInterfaces = child.getDeclaredInterfaces();
for (int i=0, len=superInterfaces.length; i < len; i++) {
if (ty.getResolvedTypeX().isTopmostImplementor(superInterfaces[i])) {
List methodGens = new ArrayList(clazz.getMethodGens());
for (Iterator i = methodGens.iterator(); i.hasNext();) {
LazyMethodGen mg = (LazyMethodGen)i.next();
+ //mg.getBody();
if (! mg.hasBody()) continue;
isChanged |= match(mg);
}
} else {
AjAttribute.EffectiveSignatureAttribute effective = mg.getEffectiveSignature();
if (effective == null) {
- enclosingShadow = BcelShadow.makeMethodExecution(world, mg);
+ enclosingShadow = BcelShadow.makeMethodExecution(world, mg, !canMatchBodyShadows);
} else if (effective.isWeaveBody()) {
enclosingShadow =
BcelShadow.makeShadowForMethod(
}
}
- for (InstructionHandle h = mg.getBody().getStart();
- h != null;
- h = h.getNext()) {
- match(mg, h, enclosingShadow, shadowAccumulator);
+ if (canMatchBodyShadows) {
+ for (InstructionHandle h = mg.getBody().getStart();
+ h != null;
+ h = h.getNext()) {
+ match(mg, h, enclosingShadow, shadowAccumulator);
+ }
+ }
+ if (match(enclosingShadow, shadowAccumulator)) {
+ enclosingShadow.init();
}
- match(enclosingShadow, shadowAccumulator);
mg.matchedShadows = shadowAccumulator;
return !shadowAccumulator.isEmpty();
}
}
- private boolean shouldWeaveBody(LazyMethodGen mg) {
+ private boolean shouldWeaveBody(LazyMethodGen mg) {
if (mg.isAjSynthetic()) return mg.getName().equals("<clinit>");
AjAttribute.EffectiveSignatureAttribute a = mg.getEffectiveSignature();
if (a != null) return a.isWeaveBody();
}
+ public static BcelShadow makeMethodExecution(
+ BcelWorld world,
+ LazyMethodGen enclosingMethod,
+ boolean lazyInit)
+ {
+ if (!lazyInit) return makeMethodExecution(world, enclosingMethod);
+
+ BcelShadow s =
+ new BcelShadow(
+ world,
+ MethodExecution,
+ enclosingMethod.getMemberView(),
+ enclosingMethod,
+ null);
+
+ return s;
+ }
+
+
+ public void init() {
+ if (range != null) return;
+
+ final InstructionList body = enclosingMethod.getBody();
+ ShadowRange r = new ShadowRange(body);
+ r.associateWithShadow(this);
+ r.associateWithTargets(
+ Range.genStart(body),
+ Range.genEnd(body));
+ }
+
public static BcelShadow makeMethodExecution(
BcelWorld world,
LazyMethodGen enclosingMethod)
{
return makeShadowForMethod(world, enclosingMethod, MethodExecution,
- world.makeMethodSignature(enclosingMethod));
+ enclosingMethod.getMemberView()); //world.makeMethodSignature(enclosingMethod));
}
import org.aspectj.weaver.ShadowMunger;
import org.aspectj.weaver.TypeX;
import org.aspectj.weaver.patterns.DeclareParents;
+import org.aspectj.weaver.patterns.FastMatchInfo;
public class BcelWeaver implements IWeaver {
private BcelWorld world;
}
} catch (RuntimeException re) {
System.err.println("trouble in: ");
- clazz.print(System.err);
+ //XXXclazz.print(System.err);
throw re;
} catch (Error re) {
System.err.println("trouble in: ");
private List fastMatch(List list, ResolvedTypeX type) {
if (list == null) return Collections.EMPTY_LIST;
+ // here we do the coarsest grained fast match with no kind constraints
+ // this will remove all obvious non-matches and see if we need to do any weaving
+ FastMatchInfo info = new FastMatchInfo(type, null);
+
List result = new ArrayList();
Iterator iter = list.iterator();
while (iter.hasNext()) {
ShadowMunger munger = (ShadowMunger)iter.next();
- if (munger.getPointcut().fastMatch(type).maybeTrue()) {
+ if (munger.getPointcut().fastMatch(info).maybeTrue()) {
result.add(munger);
}
}
import org.aspectj.weaver.ISourceContext;
import org.aspectj.weaver.Member;
import org.aspectj.weaver.ResolvedTypeX;
+import org.aspectj.weaver.TypeX;
/**
public final class LazyMethodGen {
private int accessFlags;
- private final Type returnType;
+ private Type returnType;
private final String name;
- private final Type[] argumentTypes;
+ private Type[] argumentTypes;
//private final String[] argumentNames;
- private final String[] declaredExceptions;
- private final InstructionList body; // leaving null for abstracts
- private final Attribute[] attributes;
+ private String[] declaredExceptions;
+ private InstructionList body; // leaving null for abstracts
+ private Attribute[] attributes;
/* private */ final LazyClassGen enclosingClass;
private final BcelMethod memberView;
int highestLineNumber = 0;
String[] declaredExceptions,
LazyClassGen enclosingClass)
{
+ //System.err.println("raw create of: " + name + ", " + enclosingClass.getName() + ", " + returnType);
this.memberView = null; // ??? should be okay, since constructed ones aren't woven into
this.accessFlags = accessFlags;
this.returnType = returnType;
return ret;
}
- // build from an existing method
+ private Method savedMethod = null;
+ // build from an existing method, lazy build saves most work for initialization
public LazyMethodGen(Method m, LazyClassGen enclosingClass) {
+ savedMethod = m;
+
this.enclosingClass = enclosingClass;
if (!(m.isAbstract() || m.isNative()) && m.getCode() == null) {
throw new RuntimeException("bad non-abstract method with no code: " + m + " on " + enclosingClass);
if ((m.isAbstract() || m.isNative()) && m.getCode() != null) {
throw new RuntimeException("bad abstract method with code: " + m + " on " + enclosingClass);
}
- MethodGen gen = new MethodGen(m, enclosingClass.getName(), enclosingClass.getConstantPoolGen());
this.memberView = new BcelMethod(enclosingClass.getBcelObjectType(), m);
- this.accessFlags = gen.getAccessFlags();
- this.returnType = gen.getReturnType();
- this.name = gen.getName();
- this.argumentTypes = gen.getArgumentTypes();
- //this.argumentNames = gen.getArgumentNames();
- this.declaredExceptions = gen.getExceptions();
- this.attributes = gen.getAttributes();
- this.maxLocals = gen.getMaxLocals();
+
+ this.accessFlags = m.getAccessFlags();
+ this.name = m.getName();
+ }
+
+ private void initialize() {
+ if (returnType != null) return;
+
+ //System.err.println("initializing: " + getName() + ", " + enclosingClass.getName() + ", " + returnType + ", " + savedMethod);
+
+ MethodGen gen = new MethodGen(savedMethod, enclosingClass.getName(), enclosingClass.getConstantPoolGen());
+
+ this.returnType = gen.getReturnType();
+ this.argumentTypes = gen.getArgumentTypes();
+
+ this.declaredExceptions = gen.getExceptions();
+ this.attributes = gen.getAttributes();
+ this.maxLocals = gen.getMaxLocals();
+
+// this.returnType = BcelWorld.makeBcelType(memberView.getReturnType());
+// this.argumentTypes = BcelWorld.makeBcelTypes(memberView.getParameterTypes());
+//
+// this.declaredExceptions = TypeX.getNames(memberView.getExceptions()); //gen.getExceptions();
+// this.attributes = new Attribute[0]; //gen.getAttributes();
+// this.maxLocals = savedMethod.getCode().getMaxLocals();
+
+
if (gen.isAbstract() || gen.isNative()) {
body = null;
} else {
+ //body = new InstructionList(savedMethod.getCode().getCode());
body = gen.getInstructionList();
+
unpackHandlers(gen);
unpackLineNumbers(gen);
unpackLocals(gen);
}
assertGoodBody();
+
+ //System.err.println("initialized: " + this.getClassName() + "." + this.getName());
}
// XXX we're relying on the javac promise I've just made up that we won't have an early exception
}
public Method getMethod() {
+ if (savedMethod != null) return savedMethod; //??? this relies on gentle treatment of constant pool
+
try {
MethodGen gen = pack();
return gen.getMethod();
this.getMemberView() == null ? null : this.getMemberView().getSourceLocation(), null);
throw e;
}
-
+ }
+
+ public void markAsChanged() {
+ initialize();
+ savedMethod = null;
}
// =============================
}
public Type[] getArgumentTypes() {
+ initialize();
return argumentTypes;
}
-// public String[] getArgumentNames() {
-// return argumentNames;
-// }
-
public LazyClassGen getEnclosingClass() {
return enclosingClass;
}
}
public Type getReturnType() {
+ initialize();
return returnType;
}
}
public InstructionList getBody() {
+ markAsChanged();
return body;
}
- public boolean hasBody() { return body != null; }
-
+ public boolean hasBody() {
+ if (savedMethod != null) return savedMethod.getCode() != null;
+ return body != null;
+ }
public Attribute[] getAttributes() {
return attributes;
// }
// }
l.add(0, fresh);
- }
-
+ }
public boolean isPrivate() {
*/
public void assertGoodBody() {
- // XXX this is REALLY slow since we get the string first...
- assertGoodBody(getBody(), toString());
+ if (true) return; // only enable for debugging, consider using cheaper toString()
+ assertGoodBody(getBody(), toString()); //definingType.getNameAsIdentifier() + "." + getName()); //toString());
}
- // XXX we might not want to release with any calls to this incredibly inefficient method.
public static void assertGoodBody(InstructionList il, String from) {
- if (true) return;
+ if (true) return; // only to be enabled for debugging
if (il == null) return;
Set body = new HashSet();
Stack ranges = new Stack();
}
public String getSignature() {
- return Member.typesToSignature(BcelWorld.fromBcel(getReturnType()),
- BcelWorld.fromBcel(getArgumentTypes()));
+ return memberView.getSignature();
+// return Member.typesToSignature(BcelWorld.fromBcel(getReturnType()),
+// BcelWorld.fromBcel(getArgumentTypes()));
}
public BcelMethod getMemberView() {
}
public void forcePublic() {
+ markAsChanged();
accessFlags = Utility.makePublic(accessFlags);
}
public void setCanInline(boolean canInline) {
this.canInline = canInline;
}
- public boolean hasExceptionHandlers() {
- return hasExceptionHandlers;
- }
-
}
setLocation(left.getSourceContext(), left.getStart(), right.getEnd());
}
- public FuzzyBoolean fastMatch(ResolvedTypeX type) {
+ public FuzzyBoolean fastMatch(FastMatchInfo type) {
return left.fastMatch(type).and(right.fastMatch(type));
}
this.arguments = arguments;
}
- public FuzzyBoolean fastMatch(ResolvedTypeX type) {
+ public FuzzyBoolean fastMatch(FastMatchInfo type) {
return FuzzyBoolean.MAYBE;
}
this.freeVars = freeVars;
}
- public FuzzyBoolean fastMatch(ResolvedTypeX type) {
+ public FuzzyBoolean fastMatch(FastMatchInfo type) {
return FuzzyBoolean.MAYBE;
}
this.slots = slots;
}
- public FuzzyBoolean fastMatch(ResolvedTypeX type) {
+ public FuzzyBoolean fastMatch(FastMatchInfo type) {
return FuzzyBoolean.MAYBE;
}
--- /dev/null
+/* *******************************************************************
+ * Copyright (c) 2004 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Jim Hugunin initial implementation
+ * ******************************************************************/
+
+
+package org.aspectj.weaver.patterns;
+
+import org.aspectj.weaver.ResolvedTypeX;
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.Shadow.Kind;
+
+
+public class FastMatchInfo {
+ private Kind kind;
+ private ResolvedTypeX type;
+
+ public FastMatchInfo(ResolvedTypeX type, Shadow.Kind kind) {
+ this.type = type;
+ this.kind = kind;
+ }
+
+ /**
+ * kind can be null to indicate that all kinds should be considered.
+ * This is usually done as a first pass
+ * @return
+ */
+ public Kind getKind() {
+ return kind;
+ }
+
+ public ResolvedTypeX getType() {
+ return type;
+ }
+
+}
this.exceptionType = exceptionType;
}
- public FuzzyBoolean fastMatch(ResolvedTypeX type) {
+ public FuzzyBoolean fastMatch(FastMatchInfo type) {
//??? should be able to do better by finding all referenced types in type
return FuzzyBoolean.MAYBE;
}
this.extraParameterFlags = extraParameterFlags;
}
- public FuzzyBoolean fastMatch(ResolvedTypeX type) {
+ public FuzzyBoolean fastMatch(FastMatchInfo type) {
return FuzzyBoolean.MAYBE;
}
this.munger = munger;
}
- public FuzzyBoolean fastMatch(ResolvedTypeX type) {
+ public FuzzyBoolean fastMatch(FastMatchInfo info) {
+ if (info.getKind() != null) {
+ if (info.getKind() != kind) return FuzzyBoolean.NO;
+ }
+
return FuzzyBoolean.MAYBE;
}
+
public FuzzyBoolean match(Shadow shadow) {
if (shadow.getKind() != kind) return FuzzyBoolean.NO;
if(kind == Shadow.MethodCall) {
warnOnConfusingSig(shadow);
}
- return FuzzyBoolean.NO;
+ return FuzzyBoolean.NO;
}
- return FuzzyBoolean.YES;
+ return FuzzyBoolean.YES;
}
private void warnOnConfusingSig(Shadow shadow) {
}
- public FuzzyBoolean fastMatch(ResolvedTypeX type) {
+ public FuzzyBoolean fastMatch(FastMatchInfo type) {
return body.fastMatch(type).not();
}
}
- public FuzzyBoolean fastMatch(ResolvedTypeX type) {
+ public FuzzyBoolean fastMatch(FastMatchInfo type) {
return left.fastMatch(type).or(right.fastMatch(type));
}
// -----
- public FuzzyBoolean fastMatch(ResolvedTypeX type) {
+ public FuzzyBoolean fastMatch(FastMatchInfo type) {
return FuzzyBoolean.MAYBE;
}
this.kind = kind;
}
- public FuzzyBoolean fastMatch(ResolvedTypeX type) {
+ public FuzzyBoolean fastMatch(FastMatchInfo type) {
throw new RuntimeException("unimplemented");
}
}
// -----
- public FuzzyBoolean fastMatch(ResolvedTypeX type) {
+ public FuzzyBoolean fastMatch(FastMatchInfo type) {
return FuzzyBoolean.MAYBE;
}
public PerSingleton() {
}
- public FuzzyBoolean fastMatch(ResolvedTypeX type) {
+ public FuzzyBoolean fastMatch(FastMatchInfo type) {
return FuzzyBoolean.YES;
}
/**
* Could I match any shadows in the code defined within this type?
*/
- public abstract FuzzyBoolean fastMatch(ResolvedTypeX type);
+ public abstract FuzzyBoolean fastMatch(FastMatchInfo info);
/**
* Do I really match this shadow?
return Literal.FALSE; // can only get here if an earlier error occurred
}
- public FuzzyBoolean fastMatch(ResolvedTypeX type) {
+ public FuzzyBoolean fastMatch(FastMatchInfo type) {
return FuzzyBoolean.NO;
}
//??? do either of these match methods make any sense???
- public FuzzyBoolean fastMatch(ResolvedTypeX type) {
+ public FuzzyBoolean fastMatch(FastMatchInfo type) {
return FuzzyBoolean.MAYBE;
}
this.type = type;
}
- public FuzzyBoolean fastMatch(ResolvedTypeX type) {
+ public FuzzyBoolean fastMatch(FastMatchInfo type) {
return FuzzyBoolean.MAYBE;
}
return FuzzyBoolean.NO;
}
- public FuzzyBoolean fastMatch(ResolvedTypeX type) {
- return isWithinType(type);
+ public FuzzyBoolean fastMatch(FastMatchInfo info) {
+ return isWithinType(info.getType());
}
public FuzzyBoolean match(Shadow shadow) {
this.signature = signature;
}
- public FuzzyBoolean fastMatch(ResolvedTypeX type) {
+ public FuzzyBoolean fastMatch(FastMatchInfo type) {
return FuzzyBoolean.MAYBE;
}