return shadow.hasThis();
} else if (kind == AdviceKind.Around) {
if (shadow.getKind() == Shadow.PreInitialization) {
- world.showMessage(IMessage.WARNING,
+ world.showMessage(IMessage.ERROR,
"around on pre-initialization not supported (compiler limitation)",
getSourceLocation(), shadow.getSourceLocation());
return false;
+ } else if (shadow.getKind() == Shadow.Initialization) {
+ world.showMessage(IMessage.ERROR,
+ "around on initialization not supported (compiler limitation)",
+ getSourceLocation(), shadow.getSourceLocation());
+ return false;
} else {
if (!getSignature().getReturnType().isConvertableFrom(shadow.getReturnType(), world)) {
//System.err.println(this + ", " + sourceContext + ", " + start);
public abstract class Shadow {
private final Kind kind;
private final Member signature;
+ protected final Shadow enclosingShadow;
protected List mungers = new ArrayList(1);
// ----
-
- protected Shadow(Kind kind, Member signature) {
+ protected Shadow(Kind kind, Member signature, Shadow enclosingShadow) {
this.kind = kind;
this.signature = signature;
+ this.enclosingShadow = enclosingShadow;
}
// ----
public abstract World getIWorld();
+ /**
+ * could this(*) pcd ever match
+ */
+ public final boolean hasThis() {
+ if (getKind().neverHasThis()) {
+ return false;
+ } else if (getKind().isEnclosingKind()) {
+ return !getSignature().isStatic();
+ } else if (enclosingShadow == null) {
+ return false;
+ } else {
+ return enclosingShadow.hasThis();
+ }
+ }
+
+ /**
+ * the type of the this object here
+ *
+ * @throws IllegalStateException if there is no this here
+ */
+ public final TypeX getThisType() {
+ if (!hasThis()) throw new IllegalStateException("no this");
+ if (getKind().isEnclosingKind()) {
+ return getSignature().getDeclaringType();
+ } else {
+ return enclosingShadow.getThisType();
+ }
+ }
+
+ /**
+ * a var referencing this
+ *
+ * @throws IllegalStateException if there is no target here
+ */
+ public abstract Var getThisVar();
+
+
+
+ /**
+ * could target(*) pcd ever match
+ */
public final boolean hasTarget() {
- return !(getSignature().isStatic() || (getKind() == ConstructorCall)
- || (getKind() == PreInitialization));
+ if (getKind().neverHasTarget()) {
+ return false;
+ } else if (getKind().isTargetSameAsThis()) {
+ return hasThis();
+ } else {
+ return !getSignature().isStatic();
+ }
}
+ /**
+ * the type of the target object here
+ *
+ * @throws IllegalStateException if there is no target here
+ */
public final TypeX getTargetType() {
- if (!hasTarget()) return ResolvedTypeX.MISSING;
+ if (!hasTarget()) throw new IllegalStateException("no target");
return getSignature().getDeclaringType();
}
+ /**
+ * a var referencing the target
+ *
+ * @throws IllegalStateException if there is no target here
+ */
+ public abstract Var getTargetVar();
+
public TypeX[] getArgTypes() {
if (getKind() == FieldSet) return new TypeX[] { getSignature().getReturnType() };
return getSignature().getParameterTypes();
return getSignature()
.getParameterTypes().length;
}
-
- public abstract boolean hasThis();
- public abstract TypeX getThisType();
+
public abstract TypeX getEnclosingType();
- public abstract Var getThisVar();
- public abstract Var getTargetVar();
+
public abstract Var getArgVar(int i);
public abstract Var getThisJoinPointVar();
/** A type-safe enum representing the kind of shadows
*/
public static final class Kind extends TypeSafeEnum {
- private boolean argsOnStack;
+ private boolean argsOnStack; //XXX unused
public Kind(String name, int key, boolean argsOnStack) {
super(name, key);
}
public boolean argsOnStack() {
- return argsOnStack;
+ return !isTargetSameAsThis();
}
// !!! this is false for handlers!
return true;
}
+ // XXX revisit along with removal of priorities
+ public boolean hasHighPriorityExceptions() {
+ return !isTargetSameAsThis();
+ }
+
+
+ /**
+ * These are all the shadows that contains other shadows within them and
+ * are often directly associated with methods.
+ */
+ public boolean isEnclosingKind() {
+ return this == MethodExecution || this == ConstructorExecution ||
+ this == AdviceExecution || this == StaticInitialization
+ || this == Initialization;
+ }
+
+ public boolean isTargetSameAsThis() {
+ return this == MethodExecution
+ || this == ConstructorExecution
+ || this == StaticInitialization
+ || this == PreInitialization
+ || this == AdviceExecution
+ || this == Initialization;
+ }
+
+ public boolean neverHasTarget() {
+ return this == ConstructorCall
+ || this == ExceptionHandler
+ || this == PreInitialization
+ || this == StaticInitialization;
+ }
+
+ public boolean neverHasThis() {
+ return this == PreInitialization
+ || this == StaticInitialization;
+ }
+
+
public String getSimpleName() {
int dash = getName().lastIndexOf('-');
if (dash == -1) return getName();
+
+
+
// ---- type access methods
(InstructionHandle) srcToDest.get(oldRange.getEnd()));
shadowMap.put(oldRange, freshRange);
//recipient.matchedShadows.add(freshShadow);
+ // XXX should go through the NEW copied shadow and update
+ // the thisVar, targetVar, and argsVar
+ // ??? Might want to also go through at this time and add
+ // "extra" vars to the shadow.
}
}
}
enclosingShadow = BcelShadow.makeConstructorExecution(world, mg, superOrThisCall);
// walk the body
+ boolean beforeSuperOrThisCall = true;
if (shouldWeaveBody(mg)) { //!mg.isAjSynthetic()) {
for (InstructionHandle h = mg.getBody().getStart();
h != null;
h = h.getNext()) {
- if (h == superOrThisCall)
+ if (h == superOrThisCall) {
+ beforeSuperOrThisCall = false;
continue;
- match(mg, h, enclosingShadow, shadowAccumulator);
+ }
+ match(mg, h, beforeSuperOrThisCall ? null : enclosingShadow, shadowAccumulator);
}
match(enclosingShadow, shadowAccumulator);
}
private ShadowRange range;
private final BcelWorld world;
private final LazyMethodGen enclosingMethod;
- private final BcelShadow enclosingShadow;
-
- private boolean fallsThrough;
+ private boolean fallsThrough; //XXX not used anymore
// ---- initialization
LazyMethodGen enclosingMethod,
BcelShadow enclosingShadow)
{
- super(kind, signature);
+ super(kind, signature, enclosingShadow);
this.world = world;
this.enclosingMethod = enclosingMethod;
- this.enclosingShadow = enclosingShadow;
fallsThrough = kind.argsOnStack();
}
// overrides
public TypeX getEnclosingType() {
- return world.resolve(getEnclosingClass().getClassName());
+ return getEnclosingClass().getType();
}
public LazyClassGen getEnclosingClass() {
}
// ---- type access methods
-
- public boolean hasThis() {
- if (getKind() == PreInitialization) return false;
- return !getEnclosingCodeSignature().isStatic();
- //???return !enclosingMethod.isStatic();
- }
- public TypeX getThisType() {
- if (!hasThis()) return ResolvedTypeX.MISSING;
- return getEnclosingCodeSignature().getDeclaringType();
- //???return TypeX.forName(getEnclosingClass().getClassName());
- }
-
- public boolean isTargetDifferentFromThis() {
- return hasTarget() && isExpressionKind();
- }
-
-
private ObjectType getTargetBcelType() {
return (ObjectType) world.makeBcelType(getTargetType());
}
}
// ---- kinding
+
+ /**
+ * If the end of my range has no real instructions following then
+ * my context needs a return at the end.
+ */
+ public boolean terminatesWithReturn() {
+ return getRange().getRealNext() == null;
+ }
- public boolean isExpressionKind() {
- if (getKind() == PreInitialization) return true;
- return getKind().argsOnStack();
+ /**
+ * Is arg0 occupied with the value of this
+ */
+ public boolean arg0HoldsThis() {
+ if (getKind().isEnclosingKind()) {
+ return !getSignature().isStatic();
+ } else if (enclosingShadow == null) {
+ //XXX this is mostly right
+ // this doesn't do the right thing for calls in the pre part of introduced constructors.
+ return !enclosingMethod.isStatic();
+ } else {
+ return ((BcelShadow)enclosingShadow).arg0HoldsThis();
+ }
}
// ---- argument getting methods
// the enclosing of an execution is itself
return getThisJoinPointStaticPartBcelVar();
} else {
- return enclosingShadow.getThisJoinPointStaticPartBcelVar();
+ return ((BcelShadow)enclosingShadow).getThisJoinPointStaticPartBcelVar();
}
}
public void initializeTargetVar() {
InstructionFactory fact = getFactory();
if (targetVar != null) return;
- if (! isExpressionKind()) {
- initializeThisVar();
+ if (getKind().isTargetSameAsThis()) {
+ if (hasThis()) initializeThisVar();
targetVar = thisVar;
} else {
initializeArgVars(); // gotta pop off the args before we find the target
}
} else {
int index = 0;
- if (hasThis()) index++;
+ if (arg0HoldsThis()) index++;
for (int i = 0; i < len; i++) {
TypeX type = getArgType(i);
enclosingMethod.addExceptionHandler(range.getStart().getNext(), protectedEnd.getPrev(),
handlerStart, (ObjectType)BcelWorld.makeBcelType(catchType), //???Type.THROWABLE,
// high priority if our args are on the stack
- isExpressionKind());
+ getKind().hasHighPriorityExceptions());
}
enclosingMethod.addExceptionHandler(range.getStart().getNext(), protectedEnd.getPrev(),
handlerStart, (ObjectType)BcelWorld.makeBcelType(catchType),
// high priority if our args are on the stack
- isExpressionKind());
+ getKind().hasHighPriorityExceptions());
}
range.append(advice);
} else {
InstructionList callback = makeCallToCallback(extractedMethod);
- if (! isExpressionKind()) {
+ if (terminatesWithReturn()) {
callback.append(fact.createReturn(extractedMethod.getReturnType()));
} else {
advice.append(fact.createBranchInstruction(Constants.GOTO, range.getEnd()));
} else {
InstructionList callback = makeCallToCallback(callbackMethod);
InstructionList postCallback = new InstructionList();
- if (! isExpressionKind()) {
+ if (terminatesWithReturn()) {
callback.append(fact.createReturn(callbackMethod.getReturnType()));
} else {
advice.append(fact.createBranchInstruction(Constants.GOTO, postCallback.append(fact.NOP)));
int newi = 0;
// if we're passing in a this and we're not argsOnStack we're always
// passing in a target too
- if (hasThis()) { ret.put(0, 0); oldi++; newi+=1; }
+ if (arg0HoldsThis()) { ret.put(0, 0); oldi++; newi+=1; }
//assert targetVar == thisVar
for (int i = 0; i < getArgCount(); i++) {
TypeX type = getArgType(i);
newi += type.getSize();
}
}
+
+// System.err.println("making remap for : " + this);
+// if (targetVar != null) System.err.println("target slot : " + targetVar.getSlot());
+// if (thisVar != null) System.err.println(" this slot : " + thisVar.getSlot());
+// System.err.println(ret);
+
return ret;
}
TypeX targetType = getTargetType();
ResolvedMember resolvedMember = getSignature().resolve(world);
if (resolvedMember != null && Modifier.isProtected(resolvedMember.getModifiers()) &&
- !samePackage(targetType.getPackageName(), getThisType().getPackageName()))
+ !samePackage(targetType.getPackageName(), getEnclosingType().getPackageName()))
{
if (!targetType.isAssignableFrom(getThisType(), world)) {
throw new BCException("bad bytecode");
return new SourceLocation(new File(getEnclosingClass().getFileName()), getSourceLine());
}
- public BcelShadow getEnclosingShadow() {
+ public Shadow getEnclosingShadow() {
return enclosingShadow;
}
}
public boolean isFallsThrough() {
- return fallsThrough;
+ return !terminatesWithReturn(); //fallsThrough;
}
}
/**
* After this constructor is called, this range is not well situated unless
* {@link #associateWithTargets} is called
+ *
+ * XXX priority should be fixed
*/
public ExceptionRange(InstructionList body, TypeX exceptionType, int priority) {
super(body);
this.exceptionType = exceptionType;
this.priority = priority;
}
- public ExceptionRange(InstructionList body, TypeX exceptionType, boolean highPriority) {
- this(body, exceptionType, highPriority ? Integer.MAX_VALUE : -1);
+
+ /**
+ * @param insideExisting
+ */
+ public ExceptionRange(InstructionList body, TypeX exceptionType, boolean insideExisting) {
+ this(body, exceptionType, insideExisting ? Integer.MAX_VALUE : -1);
}
public void associateWithTargets(
InstructionHandle start,
return getRealEnd(end);
}
+ InstructionHandle getRealNext() {
+ return getRealStart(end);
+ }
+
static InstructionHandle getRealPrev(InstructionHandle ih) {
InstructionHandle ret = ih.getPrev();
while (isRangeHandle(ret)) {