* If the body of the advice can be determined to not alter the stack, or if this shadow doesn't care about the stack, i.e.
* method-execution, then the new method for the advice can also be re-lined. We are not doing that presently.
*/
public void weaveAroundInline(BcelAdvice munger, boolean hasDynamicTest) {
// !!! THIS BLOCK OF CODE SHOULD BE IN A METHOD CALLED weaveAround(...);
Member mungerSig = munger.getSignature();
// Member originalSig = mungerSig; // If mungerSig is on a parameterized type, originalSig is the member on the generic type
if (mungerSig instanceof ResolvedMember) {
ResolvedMember rm = (ResolvedMember) mungerSig;
if (rm.hasBackingGenericMember()) {
mungerSig = rm.getBackingGenericMember();
}
}
ResolvedType declaringAspectType = world.resolve(mungerSig.getDeclaringType(), true);
if (declaringAspectType.isMissing()) {
world.getLint().cantFindType.signal(
new String[] { WeaverMessages.format(WeaverMessages.CANT_FIND_TYPE_DURING_AROUND_WEAVE,
declaringAspectType.getClassName()) }, getSourceLocation(),
new ISourceLocation[] { munger.getSourceLocation() });
}
// ??? might want some checks here to give better errors
ResolvedType rt = (declaringAspectType.isParameterizedType() ? declaringAspectType.getGenericType() : declaringAspectType);
BcelObjectType ot = BcelWorld.getBcelObjectType(rt);
LazyMethodGen adviceMethod = ot.getLazyClassGen().getLazyMethodGen(mungerSig);
if (!adviceMethod.getCanInline()) {
weaveAroundClosure(munger, hasDynamicTest);
return;
}
// specific test for @AJ proceedInInners
if (isAnnotationStylePassingProceedingJoinPointOutOfAdvice(munger, hasDynamicTest, adviceMethod)) {
return;
}
// We can't inline around methods if they have around advice on them, this
// is because the weaving will extract the body and hence the proceed call.
// TODO should consider optimizations to recognize simple cases that don't require body extraction
enclosingMethod.setCanInline(false);
LazyClassGen shadowClass = getEnclosingClass();
// Extract the shadow into a new method. For example:
// "private static final void method_aroundBody0(M, M, String, org.aspectj.lang.JoinPoint)"
// Parameters are: this if there is one, target if there is one and its different to this, then original arguments
// at the shadow, then tjp
String extractedShadowMethodName = NameMangler.aroundShadowMethodName(getSignature(), shadowClass.getNewGeneratedNameTag());
List<String> parameterNames = new ArrayList<String>();
LazyMethodGen extractedShadowMethod = extractShadowInstructionsIntoNewMethod(extractedShadowMethodName, Modifier.PRIVATE,
munger.getSourceLocation(), parameterNames);
List<BcelVar> argsToCallLocalAdviceMethodWith = new ArrayList<BcelVar>();
List<BcelVar> proceedVarList = new ArrayList<BcelVar>();
int extraParamOffset = 0;
// Create the extra parameters that are needed for passing to proceed
// This code is very similar to that found in makeCallToCallback and should
// be rationalized in the future
if (thisVar != null) {
argsToCallLocalAdviceMethodWith.add(thisVar);
proceedVarList.add(new BcelVar(thisVar.getType(), extraParamOffset));
extraParamOffset += thisVar.getType().getSize();
}
if (targetVar != null && targetVar != thisVar) {
argsToCallLocalAdviceMethodWith.add(targetVar);
proceedVarList.add(new BcelVar(targetVar.getType(), extraParamOffset));
extraParamOffset += targetVar.getType().getSize();
}
int idx = 0;
for (int i = 0, len = getArgCount(); i < len; i++) {
argsToCallLocalAdviceMethodWith.add(argVars[i]);
proceedVarList.add(new BcelVar(argVars[i].getType(), extraParamOffset));
extraParamOffset += argVars[i].getType().getSize();
}
if (thisJoinPointVar != null) {
argsToCallLocalAdviceMethodWith.add(thisJoinPointVar);
proceedVarList.add(new BcelVar(thisJoinPointVar.getType(), extraParamOffset));
extraParamOffset += thisJoinPointVar.getType().getSize();
}
// We use the munger signature here because it allows for any parameterization of the mungers pointcut that
// may have occurred ie. if the pointcut is p(T t) in the super aspect and that has become p(Foo t) in the sub aspect
// then here the munger signature will have 'Foo' as an argument in it whilst the adviceMethod argument type will be
// 'Object' - since it represents the advice method in the superaspect which uses the erasure of the type variable p(Object
// t) - see pr174449.
Type[] adviceParameterTypes = BcelWorld.makeBcelTypes(munger.getSignature().getParameterTypes());
// forces initialization ... dont like this but seems to be required for some tests to pass, I think that means there
// is a LazyMethodGen method that is not correctly setup to call initialize() when it is invoked - but I dont have
// time right now to discover which
adviceMethod.getArgumentTypes();
Type[] extractedMethodParameterTypes = extractedShadowMethod.getArgumentTypes();
Type[] parameterTypes = new Type[extractedMethodParameterTypes.length + adviceParameterTypes.length + 1];
int parameterIndex = 0;
System.arraycopy(extractedMethodParameterTypes, 0, parameterTypes, parameterIndex, extractedMethodParameterTypes.length);
parameterIndex += extractedMethodParameterTypes.length;
parameterTypes[parameterIndex++] = BcelWorld.makeBcelType(adviceMethod.getEnclosingClass().getType());
System.arraycopy(adviceParameterTypes, 0, parameterTypes, parameterIndex, adviceParameterTypes.length);
// Extract the advice into a new method. This will go in the same type as the shadow
// name will be something like foo_aroundBody1$advice
String localAdviceMethodName = NameMangler.aroundAdviceMethodName(getSignature(), shadowClass.getNewGeneratedNameTag());
LazyMethodGen localAdviceMethod = new LazyMethodGen(Modifier.PRIVATE | (world.useFinal() ? Modifier.FINAL : 0)
| Modifier.STATIC, BcelWorld.makeBcelType(mungerSig.getReturnType()), localAdviceMethodName, parameterTypes,
NoDeclaredExceptions, shadowClass);
// Doesnt work properly, so leave it out:
// String aspectFilename = adviceMethod.getEnclosingClass().getInternalFileName();
// String shadowFilename = shadowClass.getInternalFileName();
// if (!aspectFilename.equals(shadowFilename)) {
// localAdviceMethod.fromFilename = aspectFilename;
// shadowClass.addInlinedSourceFileInfo(aspectFilename, adviceMethod.highestLineNumber);
// }
shadowClass.addMethodGen(localAdviceMethod);
// create a map that will move all slots in advice method forward by extraParamOffset
// in order to make room for the new proceed-required arguments that are added at
// the beginning of the parameter list
int nVars = adviceMethod.getMaxLocals() + extraParamOffset;
IntMap varMap = IntMap.idMap(nVars);
for (int i = extraParamOffset; i < nVars; i++) {
varMap.put(i - extraParamOffset, i);
}
final InstructionFactory fact = getFactory();
localAdviceMethod.getBody().insert(
BcelClassWeaver.genInlineInstructions(adviceMethod, localAdviceMethod, varMap, fact, true));
localAdviceMethod.setMaxLocals(nVars);
// the shadow is now empty. First, create a correct call
// to the around advice. This includes both the call (which may involve
// value conversion of the advice arguments) and the return
// (which may involve value conversion of the return value). Right now
// we push a null for the unused closure. It's sad, but there it is.
InstructionList advice = new InstructionList();
// InstructionHandle adviceMethodInvocation;
{
for (Iterator<BcelVar> i = argsToCallLocalAdviceMethodWith.iterator(); i.hasNext();) {
BcelVar var = i.next();
var.appendLoad(advice, fact);
}
// ??? we don't actually need to push NULL for the closure if we take care
boolean isAnnoStyleConcreteAspect = munger.getConcreteAspect().isAnnotationStyleAspect();
boolean isAnnoStyleDeclaringAspect = munger.getDeclaringAspect() != null ? munger.getDeclaringAspect().resolve(world)
.isAnnotationStyleAspect() : false;
InstructionList iList = null;
if (isAnnoStyleConcreteAspect && isAnnoStyleDeclaringAspect) {
iList = this.loadThisJoinPoint();
iList.append(Utility.createConversion(getFactory(), LazyClassGen.tjpType, LazyClassGen.proceedingTjpType));
} else {
iList = new InstructionList(InstructionConstants.ACONST_NULL);
}
advice.append(munger.getAdviceArgSetup(this, null, iList));
// adviceMethodInvocation =
advice.append(Utility.createInvoke(fact, localAdviceMethod)); // (fact, getWorld(), munger.getSignature()));
advice.append(Utility.createConversion(getFactory(), BcelWorld.makeBcelType(mungerSig.getReturnType()),
extractedShadowMethod.getReturnType(), world.isInJava5Mode()));
if (!isFallsThrough()) {
advice.append(InstructionFactory.createReturn(extractedShadowMethod.getReturnType()));
}
}