LazyMethodGen enclosingMethod)
{
InstructionList body = enclosingMethod.getBody();
+ InstructionHandle ih = body.getStart();
+ if (ih.getInstruction() instanceof InvokeInstruction) {
+ InvokeInstruction ii = (InvokeInstruction)ih.getInstruction();
+ if (ii.getName(enclosingMethod.getEnclosingClass().getConstantPoolGen()).equals(NameMangler.AJC_CLINIT_NAME)) {
+ ih = ih.getNext();
+ }
+ }
BcelShadow s =
new BcelShadow(
world,
ShadowRange r = new ShadowRange(body);
r.associateWithShadow(s);
r.associateWithTargets(
- Range.genStart(body),
+ Range.genStart(body, ih),
Range.genEnd(body));
return s;
}
//???return TypeX.forName(getEnclosingClass().getClassName());
}
- public boolean hasRealTarget() {
+ public boolean isTargetDifferentFromThis() {
return hasTarget() && isExpressionKind();
}
if (!hasTarget()) {
throw new IllegalStateException("no target");
}
- initializeTargetVar();
- return targetVar;
- }
+ initializeTargetVar();
+ return targetVar;
+ }
public Var getArgVar(int i) {
initializeArgVars();
return argVars[i];
// reflective thisJoinPoint support
private BcelVar thisJoinPointVar = null;
- private BcelVar thisJoinPointStaticPartVar = null; //XXX should be field
- private BcelVar thisEnclosingJoinPointStaticPartVar = null; //XXX should be field
+ private BcelVar thisJoinPointStaticPartVar = null;
+ private BcelVar thisEnclosingJoinPointStaticPartVar = null;
public final Var getThisJoinPointVar() {
return getThisJoinPointBcelVar();
private void initializeThisVar() {
if (thisVar != null) return;
thisVar = new BcelVar(getThisType().resolve(world), 0);
+ thisVar.setPositionInAroundState(0);
}
public void initializeTargetVar() {
InstructionFactory fact = getFactory();
TypeX type = getTargetType();
targetVar = genTempVar(type, "ajc$target");
range.insert(targetVar.createStore(fact), Range.OutsideBefore);
+ targetVar.setPositionInAroundState(hasThis() ? 1 : 0);
}
- targetVar.setPositionInAroundState(0);
}
public void initializeArgVars() {
if (argVars != null) return;
InstructionFactory fact = getFactory();
int len = getArgCount();
argVars = new BcelVar[len];
+ int positionOffset = (hasTarget() ? 0 : 1) + (hasThis() ? 0 : 1);
if (getKind().argsOnStack()) {
// we move backwards because we're popping off the stack
BcelVar tmp = genTempVar(type, "ajc$arg" + i);
range.insert(tmp.createStore(getFactory()), Range.OutsideBefore);
int position = i;
- if (hasTarget()) position += 1;
+ if (hasTarget()) position += positionOffset;
tmp.setPositionInAroundState(position);
argVars[i] = tmp;
}
} else {
int index = 0;
if (hasThis()) index++;
+
for (int i = 0; i < len; i++) {
TypeX type = getArgType(i);
BcelVar tmp = genTempVar(type, "ajc$arg" + i);
range.insert(tmp.createCopyFrom(fact, index), Range.OutsideBefore);
argVars[i] = tmp;
int position = i;
- if (hasTarget()) position += 1;
+ if (hasTarget()) position += positionOffset;
tmp.setPositionInAroundState(position);
index += type.getSize();
}
public void initializeForAroundClosure() {
initializeArgVars();
if (hasTarget()) initializeTargetVar();
+ if (hasThis()) initializeThisVar();
}
}
public void weaveAfterThrowing(BcelAdvice munger, TypeX catchType) {
+ // a good optimization would be not to generate anything here
+ // if the shadow is GUARANTEED empty (i.e., there's NOTHING, not even
+ // a shadow, inside me).
+ if (getRange().getStart().getNext() == getRange().getEnd()) return;
InstructionFactory fact = getFactory();
InstructionList handler = new InstructionList();
BcelVar exceptionVar = genTempVar(catchType);
}
}
- // XXX only used for testing
+ // exposed for testing
InstructionList makeCallToCallback(LazyMethodGen callbackMethod) {
InstructionFactory fact = getFactory();
InstructionList callback = new InstructionList();
- if (targetVar != null) {
+ if (thisVar != null) {
+ callback.append(fact.ALOAD_0);
+ }
+ if (targetVar != null && targetVar != thisVar) {
callback.append(BcelRenderer.renderExpr(fact, world, targetVar));
}
callback.append(BcelRenderer.renderExprs(fact, world, argVars));
+ // remember to render tjps
+ if (thisJoinPointVar != null) {
+ callback.append(BcelRenderer.renderExpr(fact, world, thisJoinPointVar));
+ }
callback.append(Utility.createInvoke(fact, callbackMethod));
return callback;
}
BcelVar arrayVar = genTempVar(TypeX.OBJECTARRAY);
//final Type objectArrayType = new ArrayType(Type.OBJECT, 1);
final InstructionList il = new InstructionList();
- int alen = getArgCount() + (targetVar == null ? 0 : 1) + (thisJoinPointVar == null ? 0 : 1);
+ int alen = getArgCount() + (thisVar == null ? 0 : 1) +
+ ((targetVar != null && targetVar != thisVar) ? 1 : 0) +
+ (thisJoinPointVar == null ? 0 : 1);
il.append(Utility.createConstant(fact, alen));
il.append((Instruction)fact.createNewArray(Type.OBJECT, (short)1));
arrayVar.appendStore(il, fact);
int stateIndex = 0;
- if (targetVar != null) {
+ if (thisVar != null) {
+ arrayVar.appendConvertableArrayStore(il, fact, stateIndex, thisVar);
+ thisVar.setPositionInAroundState(stateIndex);
+ stateIndex++;
+ }
+ if (targetVar != null && targetVar != thisVar) {
arrayVar.appendConvertableArrayStore(il, fact, stateIndex, targetVar);
targetVar.setPositionInAroundState(stateIndex);
stateIndex++;
private IntMap makeRemap() {
IntMap ret = new IntMap(5);
int reti = 0;
- if (targetVar != null) {
+ if (thisVar != null) {
+ ret.put(0, reti++); // thisVar guaranteed to be 0
+ }
+ if (targetVar != null && targetVar != thisVar) {
ret.put(targetVar.getSlot(), reti++);
}
for (int i = 0, len = argVars.length; i < len; i++) {
// aliases, which we so helpfully put into temps at the beginning of this join
// point.
if (! getKind().argsOnStack()) {
- int index = 0;
- if (hasThis()) { ret.put(0, 0); index++; }
+ int oldi = 0;
+ 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; }
+ //assert targetVar == thisVar
for (int i = 0; i < getArgCount(); i++) {
TypeX type = getArgType(i);
- ret.put(index, index);
- index += type.getSize();
+ ret.put(oldi, newi);
+ oldi += type.getSize();
+ newi += type.getSize();
}
}
return ret;
}
/**
- * The new method is nonStatic iff we're from nonExpression advice
- * with an enclosing non-static method.
- * Otherwise, it's static
+ * The new method always static.
+ * It may take some extra arguments: this, target.
+ * If it's argsOnStack, then it must take both this/target
+ * If it's argsOnFrame, it shares this and target.
+ * ??? rewrite this to do less array munging, please
*/
private LazyMethodGen createMethodGen(String newMethodName) {
Type[] parameterTypes = world.makeBcelTypes(getSignature().getParameterTypes());
// modifiers |= Modifier.STRICT;
// }
modifiers |= Modifier.STATIC;
- if (hasTarget()) {
+ if (targetVar != null && targetVar != thisVar) {
TypeX targetType = getTargetType();
+ ResolvedMember resolvedMember = getSignature().resolve(world);
+ if (resolvedMember != null && Modifier.isProtected(resolvedMember.getModifiers()) &&
+ !samePackage(targetType.getPackageName(), getThisType().getPackageName()))
+ {
+ if (!targetType.isAssignableFrom(getThisType(), world)) {
+ throw new BCException("bad bytecode");
+ }
+ targetType = getThisType();
+ }
parameterTypes = addType(world.makeBcelType(targetType), parameterTypes);
}
+ if (thisVar != null) {
+ TypeX thisType = getThisType();
+ parameterTypes = addType(world.makeBcelType(thisType), parameterTypes);
+ }
// We always want to pass down thisJoinPoint in case we have already woven
// some advice in here. If we only have a single piece of around advice on a
// TypeX.getNames(getSignature().getExceptions(world)),
getEnclosingClass());
}
+
+ private boolean samePackage(String p1, String p2) {
+ if (p1 == null) return p2 == null;
+ if (p2 == null) return false;
+ return p1.equals(p2);
+ }
+
private Type[] addType(Type type, Type[] types) {
int len = types.length;