/**************************************************************************************
* Copyright (c) Jonas Bon�r, Alexandre Vasseur. All rights reserved. *
* http://aspectwerkz.codehaus.org *
* ---------------------------------------------------------------------------------- *
* The software in this package is published under the terms of the LGPL license *
* a copy of which has been included with this distribution in the license.txt file. *
**************************************************************************************/
package org.codehaus.aspectwerkz.transform.inlining.compiler;
import org.codehaus.aspectwerkz.DeploymentModel;
import org.codehaus.aspectwerkz.aspect.AdviceInfo;
import org.codehaus.aspectwerkz.aspect.container.AspectFactoryManager;
import org.codehaus.aspectwerkz.definition.AspectDefinition;
import org.codehaus.aspectwerkz.joinpoint.management.AdviceInfoContainer;
import org.codehaus.aspectwerkz.joinpoint.management.JoinPointType;
import org.codehaus.aspectwerkz.reflect.ClassInfo;
import org.codehaus.aspectwerkz.transform.AspectWerkzPreProcessor;
import org.codehaus.aspectwerkz.transform.JoinPointCompiler;
import org.codehaus.aspectwerkz.transform.TransformationConstants;
import org.codehaus.aspectwerkz.transform.inlining.AdviceMethodInfo;
import org.codehaus.aspectwerkz.transform.inlining.AsmHelper;
import org.codehaus.aspectwerkz.transform.inlining.AspectInfo;
import org.codehaus.aspectwerkz.transform.inlining.AspectModelManager;
import org.codehaus.aspectwerkz.transform.inlining.EmittedJoinPoint;
import org.codehaus.aspectwerkz.transform.inlining.spi.AspectModel;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.Type;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Abstract base class for the different join point compiler implementations.
* <p/>
* Compiles/generates a class that represents a specific join point, a class which invokes the advices
* and the target join point statically.
* <p/>
* FIXME: depending on hotswap needs, remove the implements StaticJP or JP decision
*
* @author <a href="mailto:jboner@codehaus.org">Jonas Bon�r </a>
* @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur </a>
* @author <a href="mailto:the_mindstorm@evolva.ro">Alex Popescu</a>
*/
public abstract class AbstractJoinPointCompiler implements JoinPointCompiler, TransformationConstants {
public static final boolean DUMP_JIT_CLASSES = AspectWerkzPreProcessor.DUMP_AFTER;
protected final String m_callerClassName;
protected final String m_calleeClassName;
protected final String m_callerClassSignature;
protected final String m_calleeClassSignature;
protected final String m_joinPointClassName;
protected final int m_joinPointType;
protected final int m_joinPointHash;
protected final String m_callerMethodName;
protected final String m_callerMethodDesc;
protected final int m_callerMethodModifiers;
protected final String m_calleeMemberName;
protected final String m_calleeMemberDesc;
protected final int m_calleeMemberModifiers;
private final CompilationInfo.Model m_model;
protected ClassWriter m_cw;
protected AspectInfo[] m_aspectInfos;
protected AspectModel[] m_aspectModels;
protected AdviceMethodInfo[] m_aroundAdviceMethodInfos;
protected AdviceMethodInfo[] m_beforeAdviceMethodInfos;
protected AdviceMethodInfo[] m_afterFinallyAdviceMethodInfos;
protected AdviceMethodInfo[] m_afterReturningAdviceMethodInfos;
protected AdviceMethodInfo[] m_afterThrowingAdviceMethodInfos;
protected boolean m_hasAroundAdvices = false;
protected boolean m_requiresThisOrTarget = false;
protected boolean m_requiresJoinPoint = false;
protected boolean m_requiresProceedMethod = false;
protected String[] m_fieldNames;
protected Type[] m_argumentTypes;
protected Type m_returnType;
protected boolean m_isThisAdvisable = false;
private CompilerInput m_input;
/**
* Creates a new join point compiler instance.
*
* @param model the compilation model
*/
public AbstractJoinPointCompiler(final CompilationInfo.Model model) {
m_model = model;
m_joinPointClassName = model.getJoinPointClassName();
final EmittedJoinPoint emittedJoinPoint = model.getEmittedJoinPoint();
m_joinPointHash = emittedJoinPoint.getJoinPointHash();
m_joinPointType = emittedJoinPoint.getJoinPointType();
m_callerMethodName = emittedJoinPoint.getCallerMethodName();
m_callerMethodDesc = emittedJoinPoint.getCallerMethodDesc();
m_callerMethodModifiers = emittedJoinPoint.getCallerMethodModifiers();
m_calleeMemberName = emittedJoinPoint.getCalleeMemberName();
m_calleeMemberDesc = emittedJoinPoint.getCalleeMemberDesc();
m_calleeMemberModifiers = emittedJoinPoint.getCalleeMemberModifiers();
// NOTE: internal compiler class name format is ALWAYS using '/'
m_callerClassName = emittedJoinPoint.getCallerClassName().replace('.', '/');
m_calleeClassName = emittedJoinPoint.getCalleeClassName().replace('.', '/');
m_callerClassSignature = L + emittedJoinPoint.getCallerClassName().replace('.', '/') + SEMICOLON;
m_calleeClassSignature = L + emittedJoinPoint.getCalleeClassName().replace('.', '/') + SEMICOLON;
m_argumentTypes = getJoinPointArgumentTypes();
m_returnType = getJoinPointReturnType();
// collect information from the compilation model and setup the aspect model
initialize(model);
// prepare a CompilerInput instance that will host most of the arguments visible to the models
initializeCompilerInput();
}
//-- implementation of JoinPointCompiler
public String getCallerClassName() {
return m_callerClassName;
}
public String getCalleeClassName() {
return m_calleeClassName;
}
public String getCallerClassSignature() {
return m_callerClassSignature;
}
public String getCalleeClassSignature() {
return m_calleeClassSignature;
}
public String getJoinPointClassName() {
return m_joinPointClassName;
}
/**
* Initializes the the join point compiler.
*
* @param model the compilation model
*/
private void initialize(final CompilationInfo.Model model) {
// collect the advices
final AdviceInfoContainer advices = model.getAdviceInfoContainer();
collectAdviceInfo(advices);
// setup models at the end so that they can override m_requiresJoinPoint
setupReferencedAspectModels();
// compute the optimization we can use
m_hasAroundAdvices = m_aroundAdviceMethodInfos.length > 0;
// check if 'caller'(this) is Advisable, e.g. can handle runtime per instance deployment
m_isThisAdvisable = isCallerAdvisable(model);
m_requiresThisOrTarget = requiresThisOrTarget();
m_requiresJoinPoint = requiresJoinPoint();
m_requiresProceedMethod = requiresProceedMethod();
m_cw = AsmHelper.newClassWriter(true);
}
/**
* Compute and store index and common information that can be passed thru the aspect model
*/
private void initializeCompilerInput() {
m_input = new CompilerInput();
// signatures
m_input.calleeClassSignature = m_calleeClassSignature;
m_input.callerClassSignature = m_callerClassSignature;
m_input.joinPointClassName = m_joinPointClassName;
// compute the callee and caller index from the invoke(..) signature
m_input.calleeIndex = INDEX_NOTAVAILABLE;
m_input.argStartIndex = 0;
if (!Modifier.isStatic(m_calleeMemberModifiers) &&
m_joinPointType != JoinPointType.CONSTRUCTOR_CALL_INT &&
m_joinPointType != JoinPointType.HANDLER_INT) {
m_input.calleeIndex = 0;
m_input.argStartIndex++;
} else {
// no callee in the invoke(..) parameters for static call/exe/get/set, ctor call and handler jp
m_input.calleeIndex = INDEX_NOTAVAILABLE;
}
// caller is always last
m_input.callerIndex = m_input.argStartIndex + AsmHelper.getRegisterDepth(m_argumentTypes);
// custom logic overrides for handler jp
if (m_joinPointType == JoinPointType.HANDLER_INT) {
m_input.calleeIndex = 0;
m_input.callerIndex = 2;
m_input.argStartIndex = 1;
}
// optimization level
// do we need to keep track of CALLEE, ARGS etc, if not then completely skip it
// and make use of the optimized join point instance
// while not using its fields (does not support reentrancy and thread safety)
m_input.isOptimizedJoinPoint = !m_requiresJoinPoint && !m_requiresProceedMethod;
if (m_input.isOptimizedJoinPoint) {
// we will use the static field that host the sole jp shared instance
m_input.joinPointInstanceIndex = INDEX_NOTAVAILABLE;
} else {
// joinpoint will be new() and stored on first local var
m_input.joinPointInstanceIndex = m_input.callerIndex + 1;
}
}
/**
* Collects the advice info.
*
* @param advices
*/
private void collectAdviceInfo(final AdviceInfoContainer advices) {
//final List aspectQualifiedNames = new ArrayList();// in fact a Set but we need indexOf
final Map aspectInfoByQualifiedName = new HashMap();
m_beforeAdviceMethodInfos = getAdviceMethodInfos(
aspectInfoByQualifiedName, advices.getBeforeAdviceInfos()
);
m_aroundAdviceMethodInfos = getAdviceMethodInfos(
aspectInfoByQualifiedName, advices.getAroundAdviceInfos()
);
m_afterReturningAdviceMethodInfos = getAdviceMethodInfos(
aspectInfoByQualifiedName, advices.getAfterReturningAdviceInfos()
);
m_afterFinallyAdviceMethodInfos = getAdviceMethodInfos(
aspectInfoByQualifiedName, advices.getAfterFinallyAdviceInfos()
);
m_afterThrowingAdviceMethodInfos = getAdviceMethodInfos(
aspectInfoByQualifiedName, advices.getAfterThrowingAdviceInfos()
);
m_aspectInfos = (AspectInfo[]) aspectInfoByQualifiedName.values().toArray(new AspectInfo[aspectInfoByQualifiedName.size()]);
//
}
/**
* Checks if the caller class implements the Advisable interface.
*
* @param model
*/
private boolean isCallerAdvisable(final CompilationInfo.Model model) {
if (!Modifier.isStatic(m_callerMethodModifiers)) {
ClassInfo[] interfaces = model.getThisClassInfo().getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
if (interfaces[i].getName().equals(ADVISABLE_CLASS_JAVA_NAME)) {
return true;
}
}
}
return false;
}
/**
* Retrieves and sets the aspect models that are referenced in this compilation phase.
*/
private void setupReferencedAspectModels() {
Map aspectModelInstanceByType = new HashMap();
for (int i = 0; i < m_aspectInfos.length; i++) {
AspectDefinition aspectDef = m_aspectInfos[i].getAspectDefinition();
if (!aspectModelInstanceByType.containsKey(aspectDef.getAspectModel())) {
AspectModel aspectModel = AspectModelManager.getModelFor(aspectDef.getAspectModel()).getInstance(
m_model
);
aspectModelInstanceByType.put(aspectDef.getAspectModel(), aspectModel);
}
// set the model for each aspect info for fast access
AspectModel aspectModel = (AspectModel) aspectModelInstanceByType.get(aspectDef.getAspectModel());
if (aspectModel == null) {
throw new Error("Could not find AspectModel " + aspectDef.getAspectModel() + " for " + m_aspectInfos[i].getAspectQualifiedName());
}
m_aspectInfos[i].setAspectModel(aspectModel);
}
// keep track of the model instance for fast acccess
m_aspectModels = (AspectModel[]) aspectModelInstanceByType.values().toArray(new AspectModel[]{});
}
/**
* Returns the join point interface class name.
*
* @return
*/
private String getJoinPointInterface() {
String joinPointInterface;
if (m_requiresProceedMethod || m_requiresJoinPoint) {
joinPointInterface = JOIN_POINT_CLASS_NAME;
} else {
joinPointInterface = STATIC_JOIN_POINT_CLASS_NAME;
}
return joinPointInterface;
}
/**
* Retrieves the advice method infos.
*
* @param aspectInfoByQualifiedName populated
* @param adviceInfos
* @return
*/
private AdviceMethodInfo[] getAdviceMethodInfos(final Map aspectInfoByQualifiedName,
final AdviceInfo[] adviceInfos) {
List adviceMethodInfosSet = new ArrayList();
for (int i = 0; i < adviceInfos.length; i++) {
AdviceInfo adviceInfo = adviceInfos[i];
// if we have a perinstance deployed aspect and a static member CALLER -> skip and go on
DeploymentModel deploymentModel = adviceInfo.getAspectDeploymentModel();
if (requiresCallerInstance(deploymentModel) && Modifier.isStatic(m_callerMethodModifiers)) {
continue;
}
if (requiresCalleeInstance(deploymentModel) && Modifier.isStatic(m_calleeMemberModifiers)) {
continue;
}
final String aspectClassName = adviceInfo.getAspectClassName().replace('.', '/');
final AspectInfo aspectInfo;
if (!aspectInfoByQualifiedName.containsKey(adviceInfo.getAspectQualifiedName())) {
aspectInfo = new AspectInfo(
adviceInfo.getAdviceDefinition().getAspectDefinition(),
ASPECT_FIELD_PREFIX + (aspectInfoByQualifiedName.size()),
aspectClassName,
L + aspectClassName + SEMICOLON
);
aspectInfoByQualifiedName.put(adviceInfo.getAspectQualifiedName(), aspectInfo);
} else {
aspectInfo = (AspectInfo)aspectInfoByQualifiedName.get(adviceInfo.getAspectQualifiedName());
}
AdviceMethodInfo adviceMethodInfo = new AdviceMethodInfo(
aspectInfo,
adviceInfo,
m_callerClassSignature,
m_calleeClassSignature,
m_joinPointClassName,
m_calleeMemberDesc
);
adviceMethodInfosSet.add(adviceMethodInfo);
}
return (AdviceMethodInfo[]) adviceMethodInfosSet.toArray(new AdviceMethodInfo[adviceMethodInfosSet.size()]);
}
/**
* Creates join point specific fields.
*/
protected abstract void createJoinPointSpecificFields();
/**
* Creates the signature for the join point.
*
* @param cv
*/
protected abstract void createSignature(final MethodVisitor cv);
/**
* Optimized implementation that does not retrieve the parameters from the join point instance but is passed
* directly to the method from the input parameters in the 'invoke' method. Can only be used if no around advice
* exists.
*
* @param cv
* @param input
*/
protected abstract void createInlinedJoinPointInvocation(final MethodVisitor cv,
final CompilerInput input);
/**
* Creates a call to the target join point, the parameter(s) to the join point are retrieved from the invocation
* local join point instance.
*
* @param cv
*/
protected abstract void createJoinPointInvocation(final MethodVisitor cv);
/**
* Returns the join points return type.
*
* @return
*/
protected abstract Type getJoinPointReturnType();
/**
* Returns the join points argument type(s).
*
* @return
*/
protected abstract Type[] getJoinPointArgumentTypes();
/**
* Creates the getRtti method
*/
protected abstract void createGetRttiMethod();
/**
* Creates the getSignature method
*/
protected abstract void createGetSignatureMethod();
/**
* Compiles a join point class, one specific class for each distinct join point. The compiled join point class
* inherits the base join point class.
*
* @return the generated, compiled and loaded join point class
*/
public final byte[] compile() {
try {
createClassHeader();
createFieldsCommonToAllJoinPoints();
createJoinPointSpecificFields();
createMandatoryMethodInAspectModels();
createStaticInitializer();
createClinit();
createInit();
createUtilityMethods();
// not needed anymore - createCopyMethod();//TODO remove
createGetSignatureMethod();
createInvokeMethod();
if (m_requiresProceedMethod) {
// prepare a new CompilerInput since jp index changes when in proceed()
createProceedMethod(m_input.getCopyForProceed());
}
if (m_requiresJoinPoint) {
createGetRttiMethod();
}
m_cw.visitEnd();
if (DUMP_JIT_CLASSES
&& AspectWerkzPreProcessor.DUMP_PATTERN.matches(m_joinPointClassName.replace('/', '.'))) {
AsmHelper.dumpClass(AspectWerkzPreProcessor.DUMP_DIR_AFTER, m_joinPointClassName, m_cw);
}
return m_cw.toByteArray();
} catch (Exception e) {
e.printStackTrace();
StringBuffer buf = new StringBuffer();
buf.append("could not compile join point instance for join point with hash [");
buf.append(m_joinPointHash);
buf.append("] and declaring class [");
buf.append(m_callerClassName);
buf.append("] due to: ");
if (e instanceof InvocationTargetException) {
buf.append(((InvocationTargetException) e).getTargetException().toString());
} else {
buf.append(e.toString());
}
throw new RuntimeException(buf.toString());
}
}
/**
* Creates join point specific fields.
*/
private void createFieldsCommonToAllJoinPoints() {
if (m_returnType.getSort() != Type.VOID) {
m_cw.visitField(ACC_PRIVATE, RETURN_VALUE_FIELD_NAME, m_returnType.getDescriptor(), null, null);
}
m_cw.visitField(
ACC_PRIVATE + ACC_STATIC,
TARGET_CLASS_FIELD_NAME_IN_JP,
CLASS_CLASS_SIGNATURE,
null,
null
);
m_cw.visitField(
ACC_PRIVATE + ACC_STATIC + ACC_FINAL,
THIS_CLASS_FIELD_NAME_IN_JP,
CLASS_CLASS_SIGNATURE,
null,
null
);
m_cw.visitField(
ACC_PRIVATE + ACC_STATIC + ACC_FINAL,
ENCLOSING_SJP_FIELD_NAME,
ENCLOSING_SJP_FIELD_CLASS_SIGNATURE,
null,
null
);
m_cw.visitField(ACC_PRIVATE + ACC_STATIC, META_DATA_FIELD_NAME, MAP_CLASS_SIGNATURE, null, null);
m_cw.visitField(
ACC_PRIVATE + ACC_STATIC,
OPTIMIZED_JOIN_POINT_INSTANCE_FIELD_NAME,
L + m_joinPointClassName + SEMICOLON,
null, null
);
m_cw.visitField(ACC_PRIVATE, CALLEE_INSTANCE_FIELD_NAME, m_calleeClassSignature, null, null);
m_cw.visitField(ACC_PRIVATE, CALLER_INSTANCE_FIELD_NAME, m_callerClassSignature, null, null);
m_cw.visitField(ACC_PRIVATE, STACK_FRAME_COUNTER_FIELD_NAME, I, null, null);
if (m_isThisAdvisable) {
m_cw.visitField(ACC_PRIVATE, INTERCEPTOR_INDEX_FIELD_NAME, I, null, null);
m_cw.visitField(
ACC_PRIVATE, AROUND_INTERCEPTORS_FIELD_NAME,
AROUND_ADVICE_ARRAY_CLASS_SIGNATURE, null, null
);
m_cw.visitField(ACC_PRIVATE, NR_OF_AROUND_INTERCEPTORS_FIELD_NAME, I, null, null);
m_cw.visitField(
ACC_PRIVATE, BEFORE_INTERCEPTORS_FIELD_NAME,
BEFORE_ADVICE_ARRAY_CLASS_SIGNATURE, null, null
);
m_cw.visitField(ACC_PRIVATE, NR_OF_BEFORE_INTERCEPTORS_FIELD_NAME, I, null, null);
m_cw.visitField(
ACC_PRIVATE, AFTER_INTERCEPTORS_FIELD_NAME,
AFTER_ADVICE_ARRAY_CLASS_SIGNATURE, null, null
);
m_cw.visitField(ACC_PRIVATE, NR_OF_AFTER_INTERCEPTORS_FIELD_NAME, I, null, null);
m_cw.visitField(
ACC_PRIVATE, AFTER_RETURNING_INTERCEPTORS_FIELD_NAME,
AFTER_RETURNING_ADVICE_ARRAY_CLASS_SIGNATURE, null, null
);
m_cw.visitField(ACC_PRIVATE, NR_OF_AFTER_RETURNING_INTERCEPTORS_FIELD_NAME, I, null, null);
m_cw.visitField(
ACC_PRIVATE, AFTER_THROWING_INTERCEPTORS_FIELD_NAME,
AFTER_THROWING_ADVICE_ARRAY_CLASS_SIGNATURE, null, null
);
m_cw.visitField(ACC_PRIVATE, NR_OF_AFTER_THROWING_INTERCEPTORS_FIELD_NAME, I, null, null);
}
}
/**
* Creates the clinit method for the join point.
*/
private void createClinit() {
MethodVisitor cv = m_cw.visitMethod(ACC_STATIC, CLINIT_METHOD_NAME, NO_PARAM_RETURN_VOID_SIGNATURE, null, null);
cv.visitMethodInsn(
INVOKESTATIC, m_joinPointClassName,
STATIC_INITIALIZATION_METHOD_NAME, NO_PARAM_RETURN_VOID_SIGNATURE
);
cv.visitInsn(RETURN);
cv.visitMaxs(0, 0);
}
/**
* Creates the init method for the join point.
*/
private void createInit() {
MethodVisitor cv = m_cw.visitMethod(ACC_PRIVATE, INIT_METHOD_NAME, NO_PARAM_RETURN_VOID_SIGNATURE, null, null);
cv.visitVarInsn(ALOAD, 0);
boolean hasAroundClosureBaseClass = false;
AspectModel aspectModel = null;
for (int i = 0; i < m_aspectModels.length; i++) {
aspectModel = m_aspectModels[i];
if (aspectModel.getAroundClosureClassInfo().getSuperClassName() != null
&& !OBJECT_CLASS_NAME.equals(aspectModel.getAroundClosureClassInfo().getSuperClassName())) {
hasAroundClosureBaseClass = true;
break;
}
}
if (hasAroundClosureBaseClass) {
// invoke the super class constructor
aspectModel.createInvocationOfAroundClosureSuperClass(cv);
} else {
// invoke the constructor of java.lang.Object
cv.visitMethodInsn(INVOKESPECIAL, OBJECT_CLASS_NAME, INIT_METHOD_NAME, NO_PARAM_RETURN_VOID_SIGNATURE);
}
resetStackFrameCounter(cv);
cv.visitInsn(RETURN);
cv.visitMaxs(0, 0);
}
/**
* Creates the class header for the join point.
*/
private void createClassHeader() {
Set interfaces = new HashSet();
String baseClass = OBJECT_CLASS_NAME;
// get the different aspect models required interfaces
for (int i = 0; i < m_aspectModels.length; i++) {
AspectModel aspectModel = m_aspectModels[i];
AspectModel.AroundClosureClassInfo closureClassInfo = aspectModel.getAroundClosureClassInfo();
final String superClassName = closureClassInfo.getSuperClassName();
final String[] interfaceNames = closureClassInfo.getInterfaceNames();
if (superClassName != null) {
if (!baseClass.equals(OBJECT_CLASS_NAME)) {
throw new RuntimeException(
"compiled join point can only subclass one around closure base class but more than registered aspect model requires a closure base class"
);
}
baseClass = superClassName;
}
if (interfaceNames.length != 0) {
for (int j = 0; j < interfaceNames.length; j++) {
interfaces.add(interfaceNames[j]);
}
}
}
int i = 1;
String[] interfaceArr = new String[interfaces.size() + 1];
interfaceArr[0] = getJoinPointInterface();
for (Iterator it = interfaces.iterator(); it.hasNext(); i++) {
interfaceArr[i] = (String) it.next();
}
m_cw.visit(
AsmHelper.JAVA_VERSION,
ACC_PUBLIC + ACC_SUPER,
m_joinPointClassName,
null,
baseClass,
interfaceArr
);
}
/**
* Creates the methods that are mandatory methods in the around closure in the different aspect models.
*/
private void createMandatoryMethodInAspectModels() {
for (int i = 0; i < m_aspectModels.length; i++) {
m_aspectModels[i].createMandatoryMethods(m_cw, this);
}
}
/**
* Creates the static initialization method (not clinit) for the join point.
*/
private void createStaticInitializer() {
MethodVisitor cv = m_cw.visitMethod(
ACC_STATIC | ACC_PUBLIC,
STATIC_INITIALIZATION_METHOD_NAME,
NO_PARAM_RETURN_VOID_SIGNATURE,
null, null
);
Label tryLabel = new Label();
cv.visitLabel(tryLabel);
cv.visitLdcInsn(m_calleeClassName.replace('/', '.'));
cv.visitMethodInsn(INVOKESTATIC, CLASS_CLASS, FOR_NAME_METHOD_NAME, FOR_NAME_METHOD_SIGNATURE);
cv.visitFieldInsn(PUTSTATIC, m_joinPointClassName, TARGET_CLASS_FIELD_NAME_IN_JP, CLASS_CLASS_SIGNATURE);
cv.visitLdcInsn(m_callerClassName.replace('/', '.'));
cv.visitMethodInsn(INVOKESTATIC, CLASS_CLASS, FOR_NAME_METHOD_NAME, FOR_NAME_METHOD_SIGNATURE);
cv.visitFieldInsn(PUTSTATIC, m_joinPointClassName, THIS_CLASS_FIELD_NAME_IN_JP, CLASS_CLASS_SIGNATURE);
Label finallyLabel = new Label();
cv.visitLabel(finallyLabel);
Label gotoFinallyLabel = new Label();
cv.visitJumpInsn(GOTO, gotoFinallyLabel);
Label catchLabel = new Label();
cv.visitLabel(catchLabel);
cv.visitVarInsn(ASTORE, 0);
cv.visitVarInsn(ALOAD, 0);
cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Throwable", "printStackTrace", "()V");
cv.visitTypeInsn(NEW, RUNTIME_EXCEPTION_CLASS_NAME);
cv.visitInsn(DUP);
cv.visitLdcInsn(
"could not load target class using Class.forName() in generated join point base class "
+ m_joinPointClassName
);
cv.visitMethodInsn(
INVOKESPECIAL,
RUNTIME_EXCEPTION_CLASS_NAME,
INIT_METHOD_NAME,
RUNTIME_EXCEPTION_INIT_METHOD_SIGNATURE
);
cv.visitInsn(ATHROW);
cv.visitLabel(gotoFinallyLabel);
// create the enclosing static joinpoint
createEnclosingStaticJoinPoint(cv);
// create the metadata map
cv.visitTypeInsn(NEW, HASH_MAP_CLASS_NAME);
cv.visitInsn(DUP);
cv.visitMethodInsn(INVOKESPECIAL, HASH_MAP_CLASS_NAME, INIT_METHOD_NAME, NO_PARAM_RETURN_VOID_SIGNATURE);
cv.visitFieldInsn(PUTSTATIC, m_joinPointClassName, META_DATA_FIELD_NAME, MAP_CLASS_SIGNATURE);
// create the Signature instance
createSignature(cv);
// create the static JoinPoint instance
cv.visitTypeInsn(NEW, m_joinPointClassName);
cv.visitInsn(DUP);
cv.visitMethodInsn(INVOKESPECIAL, m_joinPointClassName, INIT_METHOD_NAME, NO_PARAM_RETURN_VOID_SIGNATURE);
cv.visitFieldInsn(
PUTSTATIC,
m_joinPointClassName,
OPTIMIZED_JOIN_POINT_INSTANCE_FIELD_NAME,
L + m_joinPointClassName + SEMICOLON
);
// ensure aspect factories are all loaded
for (int i = 0; i < m_aspectInfos.length; i++) {
AspectInfo m_aspectInfo = m_aspectInfos[i];
cv.visitLdcInsn(m_aspectInfo.getAspectFactoryClassName());
cv.visitLdcInsn(m_aspectInfo.getAspectDefinition().getSystemDefinition().getUuid());
cv.visitLdcInsn(m_aspectInfo.getAspectClassName());
cv.visitLdcInsn(m_aspectInfo.getAspectQualifiedName());
AsmHelper.loadStringConstant(cv, m_aspectInfo.getAspectDefinition().getContainerClassName());
//TODO AVF do it once per aspect def
StringBuffer sb = new StringBuffer();
boolean hasOne = false;
boolean isFirst = true;
for (Iterator iterator = m_aspectInfo.getAspectDefinition().getParameters().entrySet().iterator(); iterator.hasNext();) {
Map.Entry entry = (Map.Entry) iterator.next();
if (!isFirst) {
sb.append(DELIMITER);
}
isFirst = false;
hasOne = true;
sb.append(entry.getKey()).append(DELIMITER).append(entry.getValue());
}
if (hasOne) {
cv.visitLdcInsn(sb.toString());
} else {
cv.visitInsn(ACONST_NULL);
}
cv.visitFieldInsn(GETSTATIC, m_joinPointClassName, THIS_CLASS_FIELD_NAME_IN_JP, CLASS_CLASS_SIGNATURE);
cv.visitMethodInsn(INVOKEVIRTUAL, CLASS_CLASS, GETCLASSLOADER_METHOD_NAME, CLASS_CLASS_GETCLASSLOADER_METHOD_SIGNATURE);
cv.visitLdcInsn(m_aspectInfo.getDeploymentModel().toString());
cv.visitMethodInsn(
INVOKESTATIC,
Type.getInternalName(AspectFactoryManager.class),
"loadAspectFactory",
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/ClassLoader;Ljava/lang/String;)V"
);
}
// create and initialize the aspect fields
for (int i = 0; i < m_aspectInfos.length; i++) {
m_aspectInfos[i].getAspectModel().createAndStoreStaticAspectInstantiation(
m_cw,
cv,
m_aspectInfos[i],
m_joinPointClassName
);
}
cv.visitInsn(RETURN);
cv.visitTryCatchBlock(tryLabel, finallyLabel, catchLabel, CLASS_NOT_FOUND_EXCEPTION_CLASS_NAME);
cv.visitMaxs(0, 0);
}
/**
* Add and initialize the static field for enclosing joint point static part
*
* @param cv
*/
private void createEnclosingStaticJoinPoint(MethodVisitor cv) {
cv.visitFieldInsn(
GETSTATIC,
m_joinPointClassName,
THIS_CLASS_FIELD_NAME_IN_JP,
CLASS_CLASS_SIGNATURE
);
cv.visitLdcInsn(m_callerMethodName);
cv.visitLdcInsn(m_callerMethodDesc);
cv.visitMethodInsn(
INVOKESTATIC,
SIGNATURE_FACTORY_CLASS,
NEW_ENCLOSING_SJP_METHOD_NAME,
NEW_ENCLOSING_SJP_METHOD_SIGNATURE
);
cv.visitFieldInsn(
PUTSTATIC,
m_joinPointClassName,
ENCLOSING_SJP_FIELD_NAME,
ENCLOSING_SJP_FIELD_CLASS_SIGNATURE
);
}
/**
* Creates the 'invoke' method. If possible delegates to the target join point directly, e.g. does not invoke the
* 'proceed' method (Used when a join point has zero around advice).
* <p/>
* The implementation here is suitable for regular JP but not for delegating JP upon hotswap
*/
protected void createInvokeMethod() {
final String invokeDesc = buildInvokeMethodSignature();
// create the method
MethodVisitor cv = m_cw.visitMethod(
ACC_PUBLIC + ACC_FINAL + ACC_STATIC,
INVOKE_METHOD_NAME,
invokeDesc,
null,
new String[]{
THROWABLE_CLASS_NAME
}
);
if (!m_input.isOptimizedJoinPoint) {
// create a new JP and makes use of it
createInvocationLocalJoinPointInstance(cv, m_input);
}
//FIXME: see loadAspect and AssociationScopeTest_2_1456425365_738_9001546___AW_JoinPoint f.e.
// there is redundant checks because
// the system perObject aspect for a perX aspect will be called *AFTER* the initializeInstanceLevelAspects
// and thus the aspects.hasAspect will change in the middle of the invoke method
//
// flow should be: invoke perObject before aspect, init instance level, invoke all other before aspects
// we can wether have a createBeforeBefore(...) that checks for this perObject aspect
// initialize the instance level aspects (perInstance)
initializeInstanceLevelAspects(cv, m_input);
// before advices
createBeforeAdviceInvocations(cv, m_input);
// handle different combinations of after advice (finally/throwing/returning)
if (m_afterFinallyAdviceMethodInfos.length == 0 &&
m_afterThrowingAdviceMethodInfos.length == 0 &&
!m_isThisAdvisable) {
createPartOfInvokeMethodWithoutAfterFinallyAndAfterThrowingAdviceTypes(cv, m_input);
} else if (m_afterThrowingAdviceMethodInfos.length == 0 &&
!m_isThisAdvisable) {
createPartOfInvokeMethodWithoutAfterThrowingAdviceTypes(cv, m_input);
} else {
//FIXME AV why forcing OPTIMIZED_JOIN_POINT here ???
// createPartOfInvokeMethodWithAllAdviceTypes(cv,
// cv, OPTIMIZED_JOIN_POINT, joinPointIndex, argStartIndex, callerIndex, calleeIndex
// );
createPartOfInvokeMethodWithAllAdviceTypes(cv, m_input);
}
cv.visitMaxs(0, 0);
}
/**
* Initializes instance level aspects, retrieves them from the target instance through the
* <code>HasInstanceLevelAspect</code> interfaces.
* <p/>
* Use by 'perInstance', 'perThis' and 'perTarget' deployment models.
*
* @param cv
* @param input
*/
private void initializeInstanceLevelAspects(final MethodVisitor cv, final CompilerInput input) {
for (int i = 0; i < m_aspectInfos.length; i++) {
m_aspectInfos[i].getAspectModel().createAndStoreRuntimeAspectInstantiation(cv, input, m_aspectInfos[i]);
}
}
/**
* @param cv
* @param input
*/
private void createPartOfInvokeMethodWithAllAdviceTypes(final MethodVisitor cv,
final CompilerInput input) {
final int returnValueIndex = (input.joinPointInstanceIndex != INDEX_NOTAVAILABLE) ?
(input.joinPointInstanceIndex + 1) : input.callerIndex + 1;
final int exceptionIndex1 = returnValueIndex + 1;
final int exceptionIndex2 = returnValueIndex + 2;
cv.visitInsn(ACONST_NULL);
cv.visitVarInsn(ASTORE, returnValueIndex);
Label tryLabel = new Label();
cv.visitLabel(tryLabel);
if (!m_requiresProceedMethod) {
// if no around advice then optimize by invoking the target JP directly and no call to proceed()
createInlinedJoinPointInvocation(cv, input);
int stackIndex = returnValueIndex;//use another int since storeType will update it
AsmHelper.storeType(cv, stackIndex, m_returnType);
addReturnedValueToJoinPoint(cv, input, returnValueIndex, false);
} else {
createInvocationToProceedMethod(cv, input.joinPointInstanceIndex, returnValueIndex);
}
createAfterReturningAdviceInvocations(cv, input);
Label finallyLabel1 = new Label();
cv.visitLabel(finallyLabel1);
if (m_isThisAdvisable) {
final int registerDepth = input.callerIndex + 2; // caller is using last register + possible return value
createAfterInterceptorInvocations(cv, input.joinPointInstanceIndex, registerDepth);
}
createAfterFinallyAdviceInvocations(cv, input);
Label gotoFinallyLabel = new Label();
cv.visitJumpInsn(GOTO, gotoFinallyLabel);
Label catchLabel = new Label();
cv.visitLabel(catchLabel);
// store the exception
cv.visitVarInsn(ASTORE, exceptionIndex1);
if (m_isThisAdvisable) {
createAfterThrowingInterceptorInvocations(cv, input.joinPointInstanceIndex, exceptionIndex1);
}
// loop over the after throwing advices
for (int i = m_afterThrowingAdviceMethodInfos.length - 1; i >= 0; i--) {
AdviceMethodInfo advice = m_afterThrowingAdviceMethodInfos[i];
// set the exception argument index
advice.setSpecialArgumentIndex(exceptionIndex1);
// if (e instanceof TYPE) {...}
cv.visitVarInsn(ALOAD, exceptionIndex1);
final String specialArgTypeName = advice.getSpecialArgumentTypeName();
if (specialArgTypeName != null) {
// after throwing <TYPE>
cv.visitTypeInsn(INSTANCEOF, specialArgTypeName);
Label ifInstanceOfLabel = new Label();
cv.visitJumpInsn(IFEQ, ifInstanceOfLabel);
// after throwing advice invocation
createAfterAdviceInvocation(cv, input, advice, exceptionIndex1);
cv.visitLabel(ifInstanceOfLabel);
} else {
// after throwing
createAfterAdviceInvocation(cv, input, advice, INDEX_NOTAVAILABLE);
}
}
// rethrow exception
cv.visitVarInsn(ALOAD, exceptionIndex1);
cv.visitInsn(ATHROW);
// store exception
Label exceptionLabel = new Label();
cv.visitLabel(exceptionLabel);
cv.visitVarInsn(ASTORE, exceptionIndex2);
// after finally advice invocation
Label finallyLabel2 = new Label();
cv.visitLabel(finallyLabel2);
if (m_isThisAdvisable) {
final int registerDepth = input.callerIndex + 2; // caller is using last register + possible return value
createAfterInterceptorInvocations(cv, input.joinPointInstanceIndex, registerDepth);
}
createAfterFinallyAdviceInvocations(cv, input);
// rethrow exception
cv.visitVarInsn(ALOAD, exceptionIndex2);
cv.visitInsn(ATHROW);
cv.visitLabel(gotoFinallyLabel);
// unwrap if around advice and return in all cases
if (m_returnType.getSort() != Type.VOID) {
if (m_requiresProceedMethod) {
cv.visitVarInsn(ALOAD, returnValueIndex);
AsmHelper.unwrapType(cv, m_returnType);
} else {
AsmHelper.loadType(cv, returnValueIndex, m_returnType);
}
}
AsmHelper.addReturnStatement(cv, m_returnType);
// build up the exception table
cv.visitTryCatchBlock(tryLabel, finallyLabel1, catchLabel, THROWABLE_CLASS_NAME);
cv.visitTryCatchBlock(tryLabel, finallyLabel1, exceptionLabel, null);
cv.visitTryCatchBlock(catchLabel, finallyLabel2, exceptionLabel, null);
}
/**
* @param cv
* @param input
*/
private void createPartOfInvokeMethodWithoutAfterThrowingAdviceTypes(final MethodVisitor cv,
final CompilerInput input) {
final int returnValueIndex = (input.joinPointInstanceIndex != INDEX_NOTAVAILABLE) ?
(input.joinPointInstanceIndex + 1) : input.callerIndex + 1;
final int exceptionIndex = returnValueIndex + 1;
cv.visitInsn(ACONST_NULL);
cv.visitVarInsn(ASTORE, returnValueIndex);
Label tryLabel = new Label();
cv.visitLabel(tryLabel);
if (!m_requiresProceedMethod) {
// if no around advice then optimize by invoking the target JP directly and no call to proceed()
createInlinedJoinPointInvocation(cv, input);
int stackIndex = returnValueIndex;//use another int since storeType will update it
AsmHelper.storeType(cv, stackIndex, m_returnType);
addReturnedValueToJoinPoint(cv, input, returnValueIndex, false);
} else {
createInvocationToProceedMethod(cv, input.joinPointInstanceIndex, returnValueIndex);
}
createAfterReturningAdviceInvocations(cv, input);
Label finallyLabel1 = new Label();
cv.visitLabel(finallyLabel1);
createAfterFinallyAdviceInvocations(cv, input);
Label gotoFinallyLabel = new Label();
cv.visitJumpInsn(GOTO, gotoFinallyLabel);
Label exceptionLabel = new Label();
cv.visitLabel(exceptionLabel);
cv.visitVarInsn(ASTORE, exceptionIndex);
Label finallyLabel2 = new Label();
cv.visitLabel(finallyLabel2);
createAfterFinallyAdviceInvocations(cv, input);
cv.visitVarInsn(ALOAD, exceptionIndex);
cv.visitInsn(ATHROW);
cv.visitLabel(gotoFinallyLabel);
// unwrap if around advice and return in all cases
if (m_returnType.getSort() != Type.VOID) {
if (m_requiresProceedMethod) {
cv.visitVarInsn(ALOAD, returnValueIndex);
AsmHelper.unwrapType(cv, m_returnType);
} else {
AsmHelper.loadType(cv, returnValueIndex, m_returnType);
}
}
AsmHelper.addReturnStatement(cv, m_returnType);
cv.visitTryCatchBlock(tryLabel, finallyLabel1, exceptionLabel, null);
cv.visitTryCatchBlock(exceptionLabel, finallyLabel2, exceptionLabel, null);
}
/**
* @param cv
* @param input
*/
private void createPartOfInvokeMethodWithoutAfterFinallyAndAfterThrowingAdviceTypes(final MethodVisitor cv,
final CompilerInput input) {
final int returnValueIndex = (input.joinPointInstanceIndex != INDEX_NOTAVAILABLE) ?
(input.joinPointInstanceIndex + 1) : input.callerIndex + 1;
if (!m_requiresProceedMethod) {
// if no around advice then optimize by invoking the target JP directly and no call to proceed()
createInlinedJoinPointInvocation(cv, input);
int stackIndex = returnValueIndex;//use another int since storeType will update it
AsmHelper.storeType(cv, stackIndex, m_returnType);
addReturnedValueToJoinPoint(cv, input, returnValueIndex, false);
} else {
createInvocationToProceedMethod(cv, input.joinPointInstanceIndex, returnValueIndex);
}
// after returning advice invocations
createAfterReturningAdviceInvocations(cv, input);
// unwrap if around advice and return in all cases
if (m_returnType.getSort() != Type.VOID) {
if (m_requiresProceedMethod) {
cv.visitVarInsn(ALOAD, returnValueIndex);
AsmHelper.unwrapType(cv, m_returnType);
} else {
AsmHelper.loadType(cv, returnValueIndex, m_returnType);
}
}
AsmHelper.addReturnStatement(cv, m_returnType);
}
/**
* Creates an invocation to the proceed method.
*
* @param cv
* @param joinPointInstanceIndex
* @param returnValueIndex
*/
private void createInvocationToProceedMethod(final MethodVisitor cv,
final int joinPointInstanceIndex,
final int returnValueIndex) {
cv.visitVarInsn(ALOAD, joinPointInstanceIndex);
cv.visitMethodInsn(INVOKEVIRTUAL, m_joinPointClassName, PROCEED_METHOD_NAME, PROCEED_METHOD_SIGNATURE);
cv.visitVarInsn(ASTORE, returnValueIndex);
}
/**
* Creates an "invocation local" join point instance, e.g. one join point per invocation. Needed for thread-safety
* when invoking around advice.
*
* @param cv
* @param input
*/
private void createInvocationLocalJoinPointInstance(final MethodVisitor cv, final CompilerInput input) {
// create the join point instance
cv.visitTypeInsn(NEW, m_joinPointClassName);
cv.visitInsn(DUP);
cv.visitMethodInsn(INVOKESPECIAL, m_joinPointClassName, INIT_METHOD_NAME, NO_PARAM_RETURN_VOID_SIGNATURE);
// store the jp on the stack
cv.visitVarInsn(ASTORE, input.joinPointInstanceIndex);
// set the argument fields in the join point instance (jp.m_arg<i> = <arg_i>)
int argStackIndex = input.argStartIndex;
for (int i = 0; i < m_fieldNames.length; i++) {
String fieldName = m_fieldNames[i];
cv.visitVarInsn(ALOAD, input.joinPointInstanceIndex);
Type type = m_argumentTypes[i];
argStackIndex = AsmHelper.loadType(cv, argStackIndex, type);
cv.visitFieldInsn(PUTFIELD, m_joinPointClassName, fieldName, type.getDescriptor());
}
// caller (can be assigned to null)
cv.visitVarInsn(ALOAD, input.joinPointInstanceIndex);
cv.visitVarInsn(ALOAD, input.callerIndex);
cv.visitFieldInsn(PUTFIELD, m_joinPointClassName, CALLER_INSTANCE_FIELD_NAME, m_callerClassSignature);
// callee (can be not available)
cv.visitVarInsn(ALOAD, input.joinPointInstanceIndex);
if (input.calleeIndex != INDEX_NOTAVAILABLE) {
cv.visitVarInsn(ALOAD, 0);
} else {
cv.visitInsn(ACONST_NULL);
}
cv.visitFieldInsn(PUTFIELD, m_joinPointClassName, CALLEE_INSTANCE_FIELD_NAME, m_calleeClassSignature);
if (m_isThisAdvisable) {
createInitializationForAdvisableManagement(cv, input.joinPointInstanceIndex, input.callerIndex);
}
}
/**
* Create the proceed() method.
*
* @param input a slightly different CompilerInput since jp index, is changed and caller and callee are meaningless
* in the proceed() method.
*/
private void createProceedMethod(CompilerInput input) {
MethodVisitor cv = m_cw.visitMethod(
ACC_PUBLIC | ACC_FINAL,
PROCEED_METHOD_NAME,
PROCEED_METHOD_SIGNATURE,
null,
new String[]{
THROWABLE_CLASS_NAME
}
);
if (m_isThisAdvisable) {
createAroundInterceptorInvocations(cv);
}
incrementStackFrameCounter(cv);
// set up the labels
Label tryLabel = new Label();
Label defaultCaseLabel = new Label();
Label gotoLabel = new Label();
Label handlerLabel = new Label();
Label endLabel = new Label();
int nrOfCases = m_aroundAdviceMethodInfos.length;
if (m_isThisAdvisable) {
nrOfCases++;
}
Label[] caseLabels = new Label[nrOfCases];
Label[] returnLabels = new Label[nrOfCases];
int[] caseNumbers = new int[nrOfCases];
for (int i = 0; i < caseLabels.length; i++) {
caseLabels[i] = new Label();
caseNumbers[i] = i;
}
for (int i = 0; i < returnLabels.length; i++) {
returnLabels[i] = new Label();
}
// start try-catch block
cv.visitLabel(tryLabel);
// start the switch block and set the stackframe as the param to the switch
cv.visitVarInsn(ALOAD, 0);
cv.visitFieldInsn(GETFIELD, m_joinPointClassName, STACK_FRAME_COUNTER_FIELD_NAME, I);
cv.visitLookupSwitchInsn(defaultCaseLabel, caseNumbers, caseLabels);
// add one case for each around advice invocation
for (int i = 0; i < m_aroundAdviceMethodInfos.length; i++) {
cv.visitLabel(caseLabels[i]);
// gather advice info
AdviceMethodInfo adviceInfo = m_aroundAdviceMethodInfos[i];
Label endInstanceOflabel = beginRuntimeCheck(cv, input, adviceInfo.getAdviceInfo());
// get the aspect instance
adviceInfo.getAspectInfo().getAspectModel().loadAspect(cv, input, adviceInfo.getAspectInfo());
// load the arguments to the advice
adviceInfo.getAspectInfo().getAspectModel().createAroundAdviceArgumentHandling(
cv,
input,
m_argumentTypes,
adviceInfo
);
// invoke the advice method
cv.visitMethodInsn(
INVOKEVIRTUAL,
adviceInfo.getAspectInfo().getAspectClassName(),
adviceInfo.getAdviceInfo().getMethodName(),
adviceInfo.getAdviceInfo().getMethodSignature()
);
cv.visitVarInsn(ASTORE, 1);
// we need to handle the case when the advice was skipped due to runtime check
// that is : if (runtimeCheck) { ret = advice() } else { ret = proceed() }
if (endInstanceOflabel != null) {
Label elseInstanceOfLabel = new Label();
cv.visitJumpInsn(GOTO, elseInstanceOfLabel);
endRuntimeCheck(cv, adviceInfo.getAdviceInfo(), endInstanceOflabel);
cv.visitVarInsn(ALOAD, 0);
cv.visitMethodInsn(INVOKESPECIAL, m_joinPointClassName, PROCEED_METHOD_NAME, PROCEED_METHOD_SIGNATURE);
cv.visitVarInsn(ASTORE, 1);
cv.visitLabel(elseInstanceOfLabel);
}
cv.visitLabel(returnLabels[i]);
cv.visitVarInsn(ALOAD, 1);
cv.visitInsn(ARETURN);
}
if (m_isThisAdvisable) {
int delegationCaseIndex = caseLabels.length - 1;
cv.visitLabel(caseLabels[delegationCaseIndex]);
cv.visitVarInsn(ALOAD, 0);
cv.visitInsn(ICONST_0);
cv.visitFieldInsn(PUTFIELD, m_joinPointClassName, INTERCEPTOR_INDEX_FIELD_NAME, I);
cv.visitVarInsn(ALOAD, 0);
cv.visitMethodInsn(INVOKEVIRTUAL, m_joinPointClassName, PROCEED_METHOD_NAME, PROCEED_METHOD_SIGNATURE);
cv.visitLabel(returnLabels[delegationCaseIndex]);
cv.visitInsn(ARETURN);
}
// invoke the target join point in the default case
cv.visitLabel(defaultCaseLabel);
AsmHelper.prepareWrappingOfPrimitiveType(cv, Type.getReturnType(m_calleeMemberDesc));
createJoinPointInvocation(cv);
Type m_returnType = null;
if (m_joinPointType != JoinPointType.CONSTRUCTOR_CALL_INT) {
m_returnType = Type.getReturnType(m_calleeMemberDesc);
} else {
m_returnType = Type.getType(m_calleeClassSignature);
}
AsmHelper.wrapPrimitiveType(cv, m_returnType);
cv.visitVarInsn(ASTORE, 1);
// store it in Rtti return value
addReturnedValueToJoinPoint(cv, input, 1, true);
// set it as the CALLEE instance for ctor call - TODO refactor somewhere else
if (m_joinPointType == JoinPointType.CONSTRUCTOR_CALL_INT) {
cv.visitVarInsn(ALOAD, 0);
cv.visitVarInsn(ALOAD, 1);
cv.visitFieldInsn(PUTFIELD, m_joinPointClassName, CALLEE_INSTANCE_FIELD_NAME, m_calleeClassSignature);
}
cv.visitLabel(gotoLabel);
cv.visitVarInsn(ALOAD, 1);
cv.visitInsn(ARETURN);
// finally clause
cv.visitLabel(handlerLabel);
cv.visitVarInsn(ASTORE, 2);
cv.visitLabel(endLabel);
cv.visitVarInsn(ALOAD, 2);
cv.visitInsn(ATHROW);
// set up the label table
cv.visitTryCatchBlock(tryLabel, returnLabels[0], handlerLabel, null);
for (int i = 1; i < caseLabels.length; i++) {
Label caseLabel = caseLabels[i];
Label returnLabel = returnLabels[i];
cv.visitTryCatchBlock(caseLabel, returnLabel, handlerLabel, null);
}
cv.visitTryCatchBlock(defaultCaseLabel, gotoLabel, handlerLabel, null);
cv.visitTryCatchBlock(handlerLabel, endLabel, handlerLabel, null);
cv.visitMaxs(0, 0);
}
/**
* Adds before advice invocations.
*
* @param cv
*/
private void createBeforeAdviceInvocations(final MethodVisitor cv, CompilerInput input) {
for (int i = 0; i < m_beforeAdviceMethodInfos.length; i++) {
AdviceMethodInfo adviceMethodInfo = m_beforeAdviceMethodInfos[i];
AspectInfo aspectInfo = adviceMethodInfo.getAspectInfo();
if (requiresCallerInstance(aspectInfo.getDeploymentModel())
&& input.callerIndex < 0) {
continue;
}
if (requiresCalleeInstance(aspectInfo.getDeploymentModel())
&& input.calleeIndex < 0) {
continue;
}
// runtime check for target() etc
Label endInstanceOflabel = beginRuntimeCheck(cv, input, adviceMethodInfo.getAdviceInfo());
//get the aspect instance
final AspectModel aspectModel = adviceMethodInfo.getAspectInfo().getAspectModel();
aspectModel.loadAspect(cv, input, adviceMethodInfo.getAspectInfo());
// push any needed arguments for the advice invocation
aspectModel.createBeforeOrAfterAdviceArgumentHandling(
cv, input, m_argumentTypes, adviceMethodInfo, INDEX_NOTAVAILABLE
);
// invoke the advice
cv.visitMethodInsn(
INVOKEVIRTUAL,
adviceMethodInfo.getAspectInfo().getAspectClassName(),
adviceMethodInfo.getAdviceInfo().getMethodName(),
adviceMethodInfo.getAdviceInfo().getMethodSignature()
);
// end label of runtime checks
endRuntimeCheck(cv, adviceMethodInfo.getAdviceInfo(), endInstanceOflabel);
}
if (m_isThisAdvisable) {
createBeforeInterceptorInvocations(
cv,
input.joinPointInstanceIndex,
input.callerIndex + 1
);
}
}
/**
* Adds after advice invocations.
*
* @param cv
* @param input
*/
private void createAfterFinallyAdviceInvocations(final MethodVisitor cv,
final CompilerInput input) {
// add after advice in reverse order
for (int i = m_afterFinallyAdviceMethodInfos.length - 1; i >= 0; i--) {
AdviceMethodInfo advice = m_afterFinallyAdviceMethodInfos[i];
createAfterAdviceInvocation(cv, input, advice, INDEX_NOTAVAILABLE);
}
}
/**
* Adds after returning advice invocations.
*
* @param cv
* @param input
*/
private void createAfterReturningAdviceInvocations(final MethodVisitor cv,
final CompilerInput input) {
final int returnValueIndex = (input.joinPointInstanceIndex != INDEX_NOTAVAILABLE) ?
(input.joinPointInstanceIndex + 1) : input.callerIndex + 1;
if (m_isThisAdvisable) {
createAfterReturningInterceptorInvocations(cv, input.joinPointInstanceIndex, returnValueIndex);
}
boolean hasPoppedReturnValueFromStack = false;
for (int i = m_afterReturningAdviceMethodInfos.length - 1; i >= 0; i--) {
AdviceMethodInfo advice = m_afterReturningAdviceMethodInfos[i];
// set the return value index that will be used as arg to advice
advice.setSpecialArgumentIndex(returnValueIndex);
String specialArgDesc = advice.getSpecialArgumentTypeDesc();
if (specialArgDesc == null) {
// after returning
createAfterAdviceInvocation(cv, input, advice, INDEX_NOTAVAILABLE);
} else {
// after returning <TYPE>
if (AsmHelper.isPrimitive(m_returnType)) {
if (m_returnType.getDescriptor().equals(specialArgDesc)) {
createAfterAdviceInvocation(cv, input, advice, returnValueIndex);
}
} else {
cv.visitVarInsn(ALOAD, returnValueIndex);
cv.visitTypeInsn(INSTANCEOF, advice.getSpecialArgumentTypeName());
Label label = new Label();
cv.visitJumpInsn(IFEQ, label);
createAfterAdviceInvocation(cv, input, advice, returnValueIndex);
cv.visitLabel(label);
}
}
}
// need the return value in return operation
if (!m_requiresProceedMethod && hasPoppedReturnValueFromStack) {
cv.visitVarInsn(ALOAD, returnValueIndex);
}
}
/**
* Adds a single generic after advice invocation.
*
* @param cv
* @param input
* @param adviceMethodInfo
* @param specialArgIndex for afterReturning / Throwing when binding is used
*/
private void createAfterAdviceInvocation(final MethodVisitor cv,
final CompilerInput input,
final AdviceMethodInfo adviceMethodInfo,
final int specialArgIndex) {
AspectInfo aspectInfo = adviceMethodInfo.getAspectInfo();
if (requiresCallerInstance(aspectInfo.getDeploymentModel())
&& input.callerIndex < 0) {
return; // without callER instance we cannot load a PER_THIS aspect instance
}
if (requiresCalleeInstance(aspectInfo.getDeploymentModel())
&& input.calleeIndex < 0) {
return;
}
// runtime check for target() etc
Label endInstanceOflabel = beginRuntimeCheck(cv, input, adviceMethodInfo.getAdviceInfo());
// get the aspect instance
final AspectModel aspectModel = adviceMethodInfo.getAspectInfo().getAspectModel();
aspectModel.loadAspect(cv, input, aspectInfo);
aspectModel.createBeforeOrAfterAdviceArgumentHandling(
cv, input, m_argumentTypes, adviceMethodInfo, specialArgIndex
);
cv.visitMethodInsn(
INVOKEVIRTUAL,
adviceMethodInfo.getAspectInfo().getAspectClassName(),
adviceMethodInfo.getAdviceInfo().getMethodName(),
adviceMethodInfo.getAdviceInfo().getMethodSignature()
);
// end label of runtime checks
endRuntimeCheck(cv, adviceMethodInfo.getAdviceInfo(), endInstanceOflabel);
}
/**
* Adds the return value to the RETURNED field.
*
* @param cv
* @param input
* @param returnValueIndex
* @param unwrap set to true if already wrapped on the stack (within proceed() code)
*/
private void addReturnedValueToJoinPoint(final MethodVisitor cv,
final CompilerInput input,
final int returnValueIndex,
final boolean unwrap) {
if (m_requiresJoinPoint && m_returnType.getSort() != Type.VOID) {
if (m_joinPointType == JoinPointType.METHOD_EXECUTION_INT
|| m_joinPointType == JoinPointType.METHOD_CALL_INT
|| m_joinPointType == JoinPointType.CONSTRUCTOR_CALL_INT) {
//TODO should we do something for field get / set
loadJoinPointInstance(cv, input);
if (unwrap && AsmHelper.isPrimitive(m_returnType)) {
cv.visitVarInsn(ALOAD, returnValueIndex);
AsmHelper.unwrapType(cv, m_returnType);
} else {
AsmHelper.loadType(cv, returnValueIndex, m_returnType);
}
cv.visitFieldInsn(
PUTFIELD, m_joinPointClassName,
RETURN_VALUE_FIELD_NAME, m_returnType.getDescriptor()
);
}
}
}
/**
* Loads the join point instance, takes static/non-static join point access into account.
*
* @param cv
* @param input
*/
static void loadJoinPointInstance(final MethodVisitor cv,
final CompilerInput input) {
if (input.isOptimizedJoinPoint) {
cv.visitFieldInsn(
GETSTATIC, input.joinPointClassName,
OPTIMIZED_JOIN_POINT_INSTANCE_FIELD_NAME,
L + input.joinPointClassName + SEMICOLON
);
} else {
cv.visitVarInsn(ALOAD, input.joinPointInstanceIndex);
}
}
/**
* Loads the argument member fields.
*
* @param cv
* @param argStartIndex
*/
protected final void loadArgumentMemberFields(final MethodVisitor cv, final int argStartIndex) {
int argStackIndex = argStartIndex;
for (int index = 0; index < m_argumentTypes.length; index++) {
Type argumentType = m_argumentTypes[index];
argStackIndex = AsmHelper.loadType(cv, argStackIndex, argumentType);
}
}
/**
* Loads the arguments.
*
* @param cv
*/
protected final void loadArguments(final MethodVisitor cv) {
for (int i = 0; i < m_fieldNames.length; i++) {
String fieldName = m_fieldNames[i];
Type argumentType = m_argumentTypes[i];
cv.visitVarInsn(ALOAD, 0);
cv.visitFieldInsn(GETFIELD, m_joinPointClassName, fieldName, argumentType.getDescriptor());
}
}
/**
* Resets the stack frame counter.
*
* @param cv
*/
private void resetStackFrameCounter(final MethodVisitor cv) {
cv.visitVarInsn(ALOAD, 0);
cv.visitInsn(ICONST_M1);
cv.visitFieldInsn(PUTFIELD, m_joinPointClassName, STACK_FRAME_COUNTER_FIELD_NAME, I);
}
/**
* Handles the incrementation of the stack frame.
*
* @param cv
*/
private void incrementStackFrameCounter(final MethodVisitor cv) {
cv.visitVarInsn(ALOAD, 0);
cv.visitInsn(DUP);
cv.visitFieldInsn(GETFIELD, m_joinPointClassName, STACK_FRAME_COUNTER_FIELD_NAME, I);
cv.visitInsn(ICONST_1);
cv.visitInsn(IADD);
cv.visitFieldInsn(PUTFIELD, m_joinPointClassName, STACK_FRAME_COUNTER_FIELD_NAME, I);
}
/**
* Create and load a structure (f.e. array of Object) where args are stored, before setting the Rtti
* with it (See addParametersToRttiInstance). The structure is stored at the given stackFreeIndex.
*
* Note: public for createMandatoryMethods in the models
*
* @param cv
* @param stackFreeIndex
*/
public final void createArgumentArrayAt(final MethodVisitor cv, final int stackFreeIndex) {
AsmHelper.loadIntegerConstant(cv, m_fieldNames.length);
cv.visitTypeInsn(ANEWARRAY, OBJECT_CLASS_NAME);
cv.visitVarInsn(ASTORE, stackFreeIndex);
for (int i = 0; i < m_argumentTypes.length; i++) {
cv.visitVarInsn(ALOAD, stackFreeIndex);
AsmHelper.loadIntegerConstant(cv, i);
AsmHelper.prepareWrappingOfPrimitiveType(cv, m_argumentTypes[i]);
cv.visitVarInsn(ALOAD, 0);
cv.visitFieldInsn(GETFIELD, m_joinPointClassName, ARGUMENT_FIELD + i, m_argumentTypes[i].getDescriptor());
AsmHelper.wrapPrimitiveType(cv, m_argumentTypes[i]);
cv.visitInsn(AASTORE);
}
}
/**
* Creates utility methods for the join point (getter, setters etc.).
*/
private void createUtilityMethods() {
MethodVisitor cv;
// addMetaData
{
cv = m_cw.visitMethod(ACC_PUBLIC, ADD_META_DATA_METHOD_NAME, ADD_META_DATA_METHOD_SIGNATURE, null, null);
cv.visitFieldInsn(GETSTATIC, m_joinPointClassName, META_DATA_FIELD_NAME, MAP_CLASS_SIGNATURE);
cv.visitVarInsn(ALOAD, 1);
cv.visitVarInsn(ALOAD, 2);
cv.visitMethodInsn(
INVOKEINTERFACE,
MAP_CLASS_NAME,
PUT_METHOD_NAME,
PUT_METHOD_SIGNATURE
);
cv.visitInsn(POP);
cv.visitInsn(RETURN);
cv.visitMaxs(0, 0);
}
// getMetaData
{
cv = m_cw.visitMethod(ACC_PUBLIC, GET_META_DATA_METHOD_NAME, GET_META_DATA_METHOD_SIGNATURE, null, null);
cv.visitFieldInsn(GETSTATIC, m_joinPointClassName, META_DATA_FIELD_NAME, MAP_CLASS_SIGNATURE);
cv.visitVarInsn(ALOAD, 1);
cv.visitMethodInsn(INVOKEINTERFACE, MAP_CLASS_NAME, GET_METHOD_NAME, GET_METHOD_SIGNATURE);
cv.visitInsn(ARETURN);
cv.visitMaxs(0, 0);
}
// getCallee
{
cv = m_cw.visitMethod(
ACC_PUBLIC,
GET_CALLEE_METHOD_NAME,
NO_PARAMS_SIGNATURE + OBJECT_CLASS_SIGNATURE,
null, null
);
cv.visitVarInsn(ALOAD, 0);
cv.visitFieldInsn(GETFIELD, m_joinPointClassName, CALLEE_INSTANCE_FIELD_NAME, m_calleeClassSignature);
cv.visitInsn(ARETURN);
cv.visitMaxs(0, 0);
}
// getCaller
{
cv = m_cw.visitMethod(
ACC_PUBLIC,
GET_CALLER_METHOD_NAME,
NO_PARAMS_SIGNATURE + OBJECT_CLASS_SIGNATURE,
null, null
);
cv.visitVarInsn(ALOAD, 0);
cv.visitFieldInsn(GETFIELD, m_joinPointClassName, CALLER_INSTANCE_FIELD_NAME, m_callerClassSignature);
cv.visitInsn(ARETURN);
cv.visitMaxs(0, 0);
}
// getTarget
{
cv = m_cw.visitMethod(
ACC_PUBLIC,
GET_TARGET_METHOD_NAME,
NO_PARAMS_SIGNATURE + OBJECT_CLASS_SIGNATURE,
null, null
);
cv.visitVarInsn(ALOAD, 0);
cv.visitFieldInsn(GETFIELD, m_joinPointClassName, CALLEE_INSTANCE_FIELD_NAME, m_calleeClassSignature);
cv.visitInsn(ARETURN);
cv.visitMaxs(0, 0);
}
// getThis
{
cv = m_cw.visitMethod(
ACC_PUBLIC,
GET_THIS_METHOD_NAME,
NO_PARAMS_SIGNATURE + OBJECT_CLASS_SIGNATURE,
null, null
);
cv.visitVarInsn(ALOAD, 0);
cv.visitFieldInsn(GETFIELD, m_joinPointClassName, CALLER_INSTANCE_FIELD_NAME, m_callerClassSignature);
cv.visitInsn(ARETURN);
cv.visitMaxs(0, 0);
}
// getCallerClass
{
cv =
m_cw.visitMethod(
ACC_PUBLIC,
GET_CALLER_CLASS_METHOD_NAME,
GET_CALLER_CLASS_METHOD_SIGNATURE,
null,
null
);
cv.visitFieldInsn(GETSTATIC, m_joinPointClassName, THIS_CLASS_FIELD_NAME_IN_JP, CLASS_CLASS_SIGNATURE);
cv.visitInsn(ARETURN);
cv.visitMaxs(0, 0);
}
// getCalleeClass
{
cv =
m_cw.visitMethod(
ACC_PUBLIC,
GET_CALLEE_CLASS_METHOD_NAME,
GET_CALLEE_CLASS_METHOD_SIGNATURE,
null,
null
);
cv.visitFieldInsn(GETSTATIC, m_joinPointClassName, TARGET_CLASS_FIELD_NAME_IN_JP, CLASS_CLASS_SIGNATURE);
cv.visitInsn(ARETURN);
cv.visitMaxs(0, 0);
}
// getTargetClass, deprecated but still there
{
cv =
m_cw.visitMethod(
ACC_PUBLIC,
GET_TARGET_CLASS_METHOD_NAME,
GET_TARGET_CLASS_METHOD_SIGNATURE,
null,
null
);
cv.visitFieldInsn(GETSTATIC, m_joinPointClassName, TARGET_CLASS_FIELD_NAME_IN_JP, CLASS_CLASS_SIGNATURE);
cv.visitInsn(ARETURN);
cv.visitMaxs(0, 0);
}
// getType
{
cv = m_cw.visitMethod(ACC_PUBLIC, GET_TYPE_METHOD_NAME, GET_TYPE_METHOD_SIGNATURE, null, null);
AsmHelper.loadIntegerConstant(cv, m_joinPointType);
cv.visitMethodInsn(
INVOKESTATIC, Type.getType(JoinPointType.class).getInternalName(), "fromInt",
"(I)" + Type.getType(JoinPointType.class).getDescriptor()
);
cv.visitInsn(ARETURN);
cv.visitMaxs(0, 0);
}
// getEnclosingStaticJoinPoint
{
cv = m_cw.visitMethod(
ACC_PUBLIC,
GET_ENCLOSING_SJP_METHOD_NAME,
GET_ENCLOSING_SJP_METHOD_SIGNATURE,
null,
null
);
cv.visitVarInsn(ALOAD, 0);
cv.visitFieldInsn(
GETSTATIC,
m_joinPointClassName,
ENCLOSING_SJP_FIELD_NAME,
ENCLOSING_SJP_FIELD_CLASS_SIGNATURE
);
cv.visitInsn(ARETURN);
cv.visitMaxs(0, 0);
}
}
// /**
// * Creates the copy method.
// * <p/>
// * TODO refactor and put in subclasses
// */
// protected void createCopyMethod() {
//
// MethodVisitor cv = m_cw.visitMethod(ACC_PUBLIC, COPY_METHOD_NAME, COPY_METHOD_SIGNATURE, null, null);
//
// // create a new join point instance
// cv.visitTypeInsn(NEW, m_joinPointClassName);
// cv.visitInsn(DUP);
// int joinPointCloneIndex = 1;
// cv.visitMethodInsn(INVOKESPECIAL, m_joinPointClassName, INIT_METHOD_NAME, NO_PARAM_RETURN_VOID_SIGNATURE);
// cv.visitVarInsn(ASTORE, joinPointCloneIndex);
//
// // set stack frame index
// cv.visitVarInsn(ALOAD, joinPointCloneIndex);
// cv.visitVarInsn(ALOAD, 0);
// cv.visitFieldInsn(GETFIELD, m_joinPointClassName, STACK_FRAME_COUNTER_FIELD_NAME, I);
// cv.visitFieldInsn(PUTFIELD, m_joinPointClassName, STACK_FRAME_COUNTER_FIELD_NAME, I);
//
// if (m_isThisAdvisable) {
// // set interceptor index
// cv.visitVarInsn(ALOAD, joinPointCloneIndex);
// cv.visitVarInsn(ALOAD, 0);
// cv.visitFieldInsn(GETFIELD, m_joinPointClassName, INTERCEPTOR_INDEX_FIELD_NAME, I);
// cv.visitFieldInsn(PUTFIELD, m_joinPointClassName, INTERCEPTOR_INDEX_FIELD_NAME, I);
//
// // set array length fields
// cv.visitVarInsn(ALOAD, joinPointCloneIndex);
// cv.visitVarInsn(ALOAD, 0);
// cv.visitFieldInsn(GETFIELD, m_joinPointClassName, NR_OF_BEFORE_INTERCEPTORS_FIELD_NAME, I);
// cv.visitFieldInsn(PUTFIELD, m_joinPointClassName, NR_OF_BEFORE_INTERCEPTORS_FIELD_NAME, I);
// cv.visitVarInsn(ALOAD, joinPointCloneIndex);
// cv.visitVarInsn(ALOAD, 0);
// cv.visitFieldInsn(GETFIELD, m_joinPointClassName, NR_OF_AROUND_INTERCEPTORS_FIELD_NAME, I);
// cv.visitFieldInsn(PUTFIELD, m_joinPointClassName, NR_OF_AROUND_INTERCEPTORS_FIELD_NAME, I);
// cv.visitVarInsn(ALOAD, joinPointCloneIndex);
// cv.visitVarInsn(ALOAD, 0);
// cv.visitFieldInsn(GETFIELD, m_joinPointClassName, NR_OF_AFTER_INTERCEPTORS_FIELD_NAME, I);
// cv.visitFieldInsn(PUTFIELD, m_joinPointClassName, NR_OF_AFTER_INTERCEPTORS_FIELD_NAME, I);
// cv.visitVarInsn(ALOAD, joinPointCloneIndex);
// cv.visitVarInsn(ALOAD, 0);
// cv.visitFieldInsn(GETFIELD, m_joinPointClassName, NR_OF_AFTER_RETURNING_INTERCEPTORS_FIELD_NAME, I);
// cv.visitFieldInsn(PUTFIELD, m_joinPointClassName, NR_OF_AFTER_RETURNING_INTERCEPTORS_FIELD_NAME, I);
// cv.visitVarInsn(ALOAD, joinPointCloneIndex);
// cv.visitVarInsn(ALOAD, 0);
// cv.visitFieldInsn(GETFIELD, m_joinPointClassName, NR_OF_AFTER_THROWING_INTERCEPTORS_FIELD_NAME, I);
// cv.visitFieldInsn(PUTFIELD, m_joinPointClassName, NR_OF_AFTER_THROWING_INTERCEPTORS_FIELD_NAME, I);
//
// // set arrays
// cv.visitVarInsn(ALOAD, joinPointCloneIndex);
// cv.visitVarInsn(ALOAD, 0);
// cv.visitFieldInsn(
// GETFIELD, m_joinPointClassName, BEFORE_INTERCEPTORS_FIELD_NAME,
// BEFORE_ADVICE_ARRAY_CLASS_SIGNATURE
// );
// cv.visitFieldInsn(
// PUTFIELD, m_joinPointClassName, BEFORE_INTERCEPTORS_FIELD_NAME,
// BEFORE_ADVICE_ARRAY_CLASS_SIGNATURE
// );
// cv.visitVarInsn(ALOAD, joinPointCloneIndex);
// cv.visitVarInsn(ALOAD, 0);
// cv.visitFieldInsn(
// GETFIELD, m_joinPointClassName, AROUND_INTERCEPTORS_FIELD_NAME,
// AROUND_ADVICE_ARRAY_CLASS_SIGNATURE
// );
// cv.visitFieldInsn(
// PUTFIELD, m_joinPointClassName, AROUND_INTERCEPTORS_FIELD_NAME,
// AROUND_ADVICE_ARRAY_CLASS_SIGNATURE
// );
// cv.visitVarInsn(ALOAD, joinPointCloneIndex);
// cv.visitVarInsn(ALOAD, 0);
// cv.visitFieldInsn(
// GETFIELD, m_joinPointClassName, AFTER_INTERCEPTORS_FIELD_NAME, AFTER_ADVICE_ARRAY_CLASS_SIGNATURE
// );
// cv.visitFieldInsn(
// PUTFIELD, m_joinPointClassName, AFTER_INTERCEPTORS_FIELD_NAME, AFTER_ADVICE_ARRAY_CLASS_SIGNATURE
// );
// cv.visitVarInsn(ALOAD, joinPointCloneIndex);
// cv.visitVarInsn(ALOAD, 0);
// cv.visitFieldInsn(
// GETFIELD, m_joinPointClassName, AFTER_RETURNING_INTERCEPTORS_FIELD_NAME,
// AFTER_RETURNING_ADVICE_ARRAY_CLASS_SIGNATURE
// );
// cv.visitFieldInsn(
// PUTFIELD, m_joinPointClassName, AFTER_RETURNING_INTERCEPTORS_FIELD_NAME,
// AFTER_RETURNING_ADVICE_ARRAY_CLASS_SIGNATURE
// );
// cv.visitVarInsn(ALOAD, joinPointCloneIndex);
// cv.visitVarInsn(ALOAD, 0);
// cv.visitFieldInsn(
// GETFIELD, m_joinPointClassName, AFTER_THROWING_INTERCEPTORS_FIELD_NAME,
// AFTER_THROWING_ADVICE_ARRAY_CLASS_SIGNATURE
// );
// cv.visitFieldInsn(
// PUTFIELD, m_joinPointClassName, AFTER_THROWING_INTERCEPTORS_FIELD_NAME,
// AFTER_THROWING_ADVICE_ARRAY_CLASS_SIGNATURE
// );
// }
//
// // set callee
// cv.visitVarInsn(ALOAD, joinPointCloneIndex);
// cv.visitVarInsn(ALOAD, 0);
// cv.visitFieldInsn(GETFIELD, m_joinPointClassName, CALLEE_INSTANCE_FIELD_NAME, m_calleeClassSignature);
// cv.visitFieldInsn(PUTFIELD, m_joinPointClassName, CALLEE_INSTANCE_FIELD_NAME, m_calleeClassSignature);
//
// // set caller
// cv.visitVarInsn(ALOAD, joinPointCloneIndex);
// cv.visitVarInsn(ALOAD, 0);
// cv.visitFieldInsn(GETFIELD, m_joinPointClassName, CALLER_INSTANCE_FIELD_NAME, m_callerClassSignature);
// cv.visitFieldInsn(PUTFIELD, m_joinPointClassName, CALLER_INSTANCE_FIELD_NAME, m_callerClassSignature);
//
// // set the arguments
// for (int i = 0; i < m_fieldNames.length; i++) {
// String fieldName = m_fieldNames[i];
// cv.visitVarInsn(ALOAD, joinPointCloneIndex);
// cv.visitVarInsn(ALOAD, 0);
// cv.visitFieldInsn(GETFIELD, m_joinPointClassName, fieldName, m_argumentTypes[i].getDescriptor());
// cv.visitFieldInsn(PUTFIELD, m_joinPointClassName, fieldName, m_argumentTypes[i].getDescriptor());
// }
//
// // set the returned field if any
// if (m_returnType.getSort() != Type.VOID) {
// cv.visitVarInsn(ALOAD, joinPointCloneIndex);
// cv.visitVarInsn(ALOAD, 0);
// cv.visitFieldInsn(GETFIELD, m_joinPointClassName, RETURN_VALUE_FIELD_NAME, m_returnType.getDescriptor());
// cv.visitFieldInsn(PUTFIELD, m_joinPointClassName, RETURN_VALUE_FIELD_NAME, m_returnType.getDescriptor());
// }
//
// cv.visitVarInsn(ALOAD, joinPointCloneIndex);
// cv.visitInsn(ARETURN);
// cv.visitMaxs(0, 0);
// }
/**
* Build up the signature of the 'invoke' methods.
*
* @return
*/
protected String buildInvokeMethodSignature() {
StringBuffer invokeDescBuf = new StringBuffer();
invokeDescBuf.append('(');
if (m_joinPointType != JoinPointType.CONSTRUCTOR_CALL_INT) {
if (!Modifier.isStatic(m_calleeMemberModifiers)) {
// callee
invokeDescBuf.append(m_calleeClassSignature);
}
}
// args
for (int i = 0; i < m_argumentTypes.length; i++) {
Type type = m_argumentTypes[i];
invokeDescBuf.append(type.getDescriptor());
}
// caller
invokeDescBuf.append(m_callerClassSignature);
invokeDescBuf.append(')');
invokeDescBuf.append(m_returnType.getDescriptor());
return invokeDescBuf.toString();
}
/**
* Checks if at least one advice is using this or target (bounded or runtime check)
*
* @return true if so
*/
private boolean requiresThisOrTarget() {
return m_isThisAdvisable ||
requiresThisOrTarget(m_aroundAdviceMethodInfos) ||
requiresThisOrTarget(m_beforeAdviceMethodInfos) ||
requiresThisOrTarget(m_afterFinallyAdviceMethodInfos) ||
requiresThisOrTarget(m_afterReturningAdviceMethodInfos) ||
requiresThisOrTarget(m_afterThrowingAdviceMethodInfos);
}
/**
* Checks if at least one advice is using the non static JoinPoint explicitly
*
* @return true if so
*/
private boolean requiresJoinPoint() {
if (m_isThisAdvisable ||
requiresJoinPoint(m_aroundAdviceMethodInfos) ||
requiresJoinPoint(m_beforeAdviceMethodInfos) ||
requiresJoinPoint(m_afterFinallyAdviceMethodInfos) ||
requiresJoinPoint(m_afterReturningAdviceMethodInfos) ||
requiresJoinPoint(m_afterThrowingAdviceMethodInfos)) {
return true;
}
// query the models to know which level of optimization we can use
for (int i = 0; i < m_aspectModels.length; i++) {
if (m_aspectModels[i].requiresReflectiveInfo()) {
// if at least one model requries RTTI then build it
return true;
}
}
return false;
}
/**
* Checks if at least one advice is using target or this (bounded or runtime check)
*
* @param adviceMethodInfos
* @return true if so
*/
private boolean requiresThisOrTarget(final AdviceMethodInfo[] adviceMethodInfos) {
for (int i = 0; i < adviceMethodInfos.length; i++) {
if (adviceMethodInfos[i].requiresThisOrTarget()) {
return true;
}
}
return false;
}
/**
* Checks if at least one advice is using non static JoinPoint explicitly
*
* @param adviceMethodInfos
* @return true if so
*/
private boolean requiresJoinPoint(final AdviceMethodInfo[] adviceMethodInfos) {
for (int i = 0; i < adviceMethodInfos.length; i++) {
if (adviceMethodInfos[i].requiresJoinPoint()) {
return true;
}
}
return false;
}
/**
* Handles the if case for runtime check (target instanceof, cflow)
*
* @param cv
* @param adviceInfo
* @return the label for endIf or null if the adviceInfo did not required runtime check
*/
private Label beginRuntimeCheck(final MethodVisitor cv,
final CompilerInput input,
final AdviceInfo adviceInfo) {
Label endRuntimeCheckLabel = null;
DeploymentModel deploymentModel = adviceInfo.getAspectDeploymentModel();
if (adviceInfo.hasTargetWithRuntimeCheck()
|| adviceInfo.getAdviceDefinition().hasCflowOrCflowBelow()
|| DeploymentModel.PER_THIS.equals(deploymentModel)
|| DeploymentModel.PER_TARGET.equals(deploymentModel)) {
int perObjectCheckType = RuntimeCheckVisitor.NULL_PER_OBJECT_TYPE;
if (DeploymentModel.PER_THIS.equals(deploymentModel)) {
perObjectCheckType = RuntimeCheckVisitor.PER_THIS_TYPE;
} else if (DeploymentModel.PER_TARGET.equals(deploymentModel)) {
perObjectCheckType = RuntimeCheckVisitor.PER_TARGET_TYPE;
}
endRuntimeCheckLabel = new Label();
// create a specific visitor everytime
RuntimeCheckVisitor runtimeCheckVisitor = new RuntimeCheckVisitor(
cv,
adviceInfo.getExpressionInfo(),
input,
perObjectCheckType,
adviceInfo.getAspectQualifiedName()
);
runtimeCheckVisitor.pushCheckOnStack(adviceInfo);
cv.visitJumpInsn(IFEQ, endRuntimeCheckLabel);
}
return endRuntimeCheckLabel;
}
/**
* Ends the ifLabel of a runtime check
*
* @param cv
* @param adviceInfo
* @param label if null, then do nothing (means we did not had a runtime check)
*/
private void endRuntimeCheck(final MethodVisitor cv, final AdviceInfo adviceInfo, final Label label) {
DeploymentModel deployModel = adviceInfo.getAspectDeploymentModel();
if (adviceInfo.hasTargetWithRuntimeCheck()
|| adviceInfo.getAdviceDefinition().hasCflowOrCflowBelow()
|| DeploymentModel.PER_THIS.equals(deployModel)
|| DeploymentModel.PER_TARGET.equals(deployModel)) {
cv.visitLabel(label);
}
}
/**
* Helper method to load the callee on the stack
*
* @param cv
* @param input
*/
public static void loadCallee(final MethodVisitor cv,
final CompilerInput input) {
if (input.isOptimizedJoinPoint) {
// grab the callee from the invoke parameters directly
cv.visitVarInsn(ALOAD, input.calleeIndex);
} else {
loadJoinPointInstance(cv, input);
cv.visitFieldInsn(
GETFIELD, input.joinPointClassName, CALLEE_INSTANCE_FIELD_NAME, input.calleeClassSignature
);
}
}
/**
* Helper method to load the caller on the stack
*
* @param cv
* @param input
*/
public static void loadCaller(final MethodVisitor cv,
final CompilerInput input) {
if (input.isOptimizedJoinPoint) {
// grab the callee from the invoke parameters directly
cv.visitVarInsn(ALOAD, input.callerIndex);
} else {
loadJoinPointInstance(cv, input);
cv.visitFieldInsn(
GETFIELD, input.joinPointClassName, CALLER_INSTANCE_FIELD_NAME, input.callerClassSignature
);
}
}
// /**
// * Creates an invocation to Aspects.aspectOf(..).
// *
// * @param cv
// * @param isOptimizedJoinPoint
// * @param joinPointIndex
// * @param callerIndex
// * @param calleeIndex
// * @param aspectInfo
// */
// public void createInvocationToAspectOf(final MethodVisitor cv,
// final boolean isOptimizedJoinPoint,
// final int joinPointIndex,
// final int callerIndex,
// final int calleeIndex,
// final AspectInfo aspectInfo) {
// if (DeploymentModel.PER_INSTANCE.equals(aspectInfo.getDeploymentModel())) {
//
// //generates code: aspectField = (cast) Aspects.aspect$Of(aspectQN, containerClassName, callee)
// loadJoinPointInstance(cv, m_joinPointClassName, isOptimizedJoinPoint, joinPointIndex);
// cv.visitLdcInsn(aspectInfo.getAspectQualifiedName());
// if (calleeIndex >= 0) {
// cv.visitVarInsn(ALOAD, calleeIndex);
// cv.visitLdcInsn(aspectInfo.getAspectDefinition().getContainerClassName());
// cv.visitMethodInsn(
// INVOKESTATIC,
// ASPECTS_CLASS_NAME,
// ASPECT_OF_METHOD_NAME,
// ASPECT_OF_PER_INSTANCE_METHOD_SIGNATURE
// );
// } else {
// // TODO: should this really happen? we are filtering at early stage now. - REMOVE CODE BLOCK
// // fallback to perClass
// //aspectField = (cast) Aspects.aspectOf(aspectQN, containerClass, calleeClass)
// cv.visitFieldInsn(GETSTATIC, m_joinPointClassName, TARGET_CLASS_FIELD_NAME_IN_JP, CLASS_CLASS_SIGNATURE);
// cv.visitLdcInsn(aspectInfo.getAspectDefinition().getContainerClassName());
// cv.visitMethodInsn(
// INVOKESTATIC,
// ASPECTS_CLASS_NAME,
// ASPECT_OF_METHOD_NAME,
// ASPECT_OF_PER_CLASS_METHOD_SIGNATURE
// );
// }
// cv.visitTypeInsn(CHECKCAST, aspectInfo.getAspectClassName());
// cv.visitFieldInsn(
// PUTFIELD, m_joinPointClassName, aspectInfo.getAspectFieldName(),
// aspectInfo.getAspectClassSignature()
// );
// }
// }
/**
* Generates code needed for handling Advisable management for the target class.
*
* @param cv
* @param joinPointInstanceIndex
* @param advisableIndex
*/
private void createInitializationForAdvisableManagement(final MethodVisitor cv,
final int joinPointInstanceIndex,
final int advisableIndex) {
// interceptor index
cv.visitVarInsn(ALOAD, joinPointInstanceIndex);
cv.visitInsn(ICONST_M1);
cv.visitFieldInsn(PUTFIELD, m_joinPointClassName, INTERCEPTOR_INDEX_FIELD_NAME, I);
initializeAroundInterceptors(cv, joinPointInstanceIndex, advisableIndex);
initializeBeforeInterceptors(cv, joinPointInstanceIndex, advisableIndex);
initializeAfterInterceptors(cv, joinPointInstanceIndex, advisableIndex);
initializeAfterReturningInterceptors(cv, joinPointInstanceIndex, advisableIndex);
initializeAfterThrowingInterceptors(cv, joinPointInstanceIndex, advisableIndex);
}
/**
* Handle the around interceptor init.
*
* @param cv
* @param joinPointInstanceIndex
* @param advisableIndex
*/
private void initializeAroundInterceptors(final MethodVisitor cv,
final int joinPointInstanceIndex,
final int advisableIndex) {
cv.visitVarInsn(ALOAD, joinPointInstanceIndex);
cv.visitVarInsn(ALOAD, advisableIndex);
cv.visitTypeInsn(CHECKCAST, ADVISABLE_CLASS_NAME);
cv.visitLdcInsn(new Integer(m_joinPointClassName.hashCode()));
cv.visitMethodInsn(
INVOKEINTERFACE,
ADVISABLE_CLASS_NAME,
GET_AROUND_ADVICE_METHOD_NAME,
GET_AROUND_ADVICE_METHOD_SIGNATURE
);
cv.visitFieldInsn(
PUTFIELD,
m_joinPointClassName,
AROUND_INTERCEPTORS_FIELD_NAME,
AROUND_ADVICE_ARRAY_CLASS_SIGNATURE
);
cv.visitVarInsn(ALOAD, joinPointInstanceIndex);
cv.visitVarInsn(ALOAD, joinPointInstanceIndex);
cv.visitFieldInsn(
GETFIELD,
m_joinPointClassName,
AROUND_INTERCEPTORS_FIELD_NAME,
AROUND_ADVICE_ARRAY_CLASS_SIGNATURE
);
cv.visitInsn(ARRAYLENGTH);
cv.visitFieldInsn(PUTFIELD, m_joinPointClassName, NR_OF_AROUND_INTERCEPTORS_FIELD_NAME, I);
}
/**
* Handle the before interceptor init.
*
* @param cv
* @param joinPointInstanceIndex
* @param advisableIndex
*/
private void initializeBeforeInterceptors(final MethodVisitor cv,
final int joinPointInstanceIndex,
final int advisableIndex) {
cv.visitVarInsn(ALOAD, joinPointInstanceIndex);
cv.visitVarInsn(ALOAD, advisableIndex);
cv.visitTypeInsn(CHECKCAST, ADVISABLE_CLASS_NAME);
cv.visitLdcInsn(new Integer(m_joinPointClassName.hashCode()));
cv.visitMethodInsn(
INVOKEINTERFACE,
ADVISABLE_CLASS_NAME,
GET_BEFORE_ADVICE_METHOD_NAME,
GET_BEFORE_ADVICE_METHOD_SIGNATURE
);
cv.visitFieldInsn(
PUTFIELD,
m_joinPointClassName,
BEFORE_INTERCEPTORS_FIELD_NAME,
BEFORE_ADVICE_ARRAY_CLASS_SIGNATURE
);
cv.visitVarInsn(ALOAD, joinPointInstanceIndex);
cv.visitVarInsn(ALOAD, joinPointInstanceIndex);
cv.visitFieldInsn(
GETFIELD,
m_joinPointClassName,
BEFORE_INTERCEPTORS_FIELD_NAME,
BEFORE_ADVICE_ARRAY_CLASS_SIGNATURE
);
cv.visitInsn(ARRAYLENGTH);
cv.visitFieldInsn(PUTFIELD, m_joinPointClassName, NR_OF_BEFORE_INTERCEPTORS_FIELD_NAME, I);
}
/**
* Handle the after finally interceptor init.
*
* @param cv
* @param joinPointInstanceIndex
* @param advisableIndex
*/
private void initializeAfterInterceptors(final MethodVisitor cv,
final int joinPointInstanceIndex,
final int advisableIndex) {
cv.visitVarInsn(ALOAD, joinPointInstanceIndex);
cv.visitVarInsn(ALOAD, advisableIndex);
cv.visitTypeInsn(CHECKCAST, ADVISABLE_CLASS_NAME);
cv.visitLdcInsn(new Integer(m_joinPointClassName.hashCode()));
cv.visitMethodInsn(
INVOKEINTERFACE,
ADVISABLE_CLASS_NAME,
GET_AFTER_ADVICE_METHOD_NAME,
GET_AFTER_ADVICE_METHOD_SIGNATURE
);
cv.visitFieldInsn(
PUTFIELD,
m_joinPointClassName,
AFTER_INTERCEPTORS_FIELD_NAME,
AFTER_ADVICE_ARRAY_CLASS_SIGNATURE
);
cv.visitVarInsn(ALOAD, joinPointInstanceIndex);
cv.visitVarInsn(ALOAD, joinPointInstanceIndex);
cv.visitFieldInsn(
GETFIELD,
m_joinPointClassName,
AFTER_INTERCEPTORS_FIELD_NAME,
AFTER_ADVICE_ARRAY_CLASS_SIGNATURE
);
cv.visitInsn(ARRAYLENGTH);
cv.visitFieldInsn(PUTFIELD, m_joinPointClassName, NR_OF_AFTER_INTERCEPTORS_FIELD_NAME, I);
}
/**
* Handle the after returning interceptor init.
*
* @param cv
* @param joinPointInstanceIndex
* @param advisableIndex
*/
private void initializeAfterReturningInterceptors(final MethodVisitor cv,
final int joinPointInstanceIndex,
final int advisableIndex) {
cv.visitVarInsn(ALOAD, joinPointInstanceIndex);
cv.visitVarInsn(ALOAD, advisableIndex);
cv.visitTypeInsn(CHECKCAST, ADVISABLE_CLASS_NAME);
cv.visitLdcInsn(new Integer(m_joinPointClassName.hashCode()));
cv.visitMethodInsn(
INVOKEINTERFACE,
ADVISABLE_CLASS_NAME,
GET_AFTER_RETURNING_ADVICE_METHOD_NAME,
GET_AFTER_RETURNING_ADVICE_METHOD_SIGNATURE
);
cv.visitFieldInsn(
PUTFIELD,
m_joinPointClassName,
AFTER_RETURNING_INTERCEPTORS_FIELD_NAME,
AFTER_RETURNING_ADVICE_ARRAY_CLASS_SIGNATURE
);
cv.visitVarInsn(ALOAD, joinPointInstanceIndex);
cv.visitVarInsn(ALOAD, joinPointInstanceIndex);
cv.visitFieldInsn(
GETFIELD,
m_joinPointClassName,
AFTER_RETURNING_INTERCEPTORS_FIELD_NAME,
AFTER_RETURNING_ADVICE_ARRAY_CLASS_SIGNATURE
);
cv.visitInsn(ARRAYLENGTH);
cv.visitFieldInsn(PUTFIELD, m_joinPointClassName, NR_OF_AFTER_RETURNING_INTERCEPTORS_FIELD_NAME, I);
}
/**
* Handle the after throwing interceptor init.
*
* @param cv
* @param joinPointInstanceIndex
* @param advisableIndex
*/
private void initializeAfterThrowingInterceptors(final MethodVisitor cv,
final int joinPointInstanceIndex,
final int advisableIndex) {
cv.visitVarInsn(ALOAD, joinPointInstanceIndex);
cv.visitVarInsn(ALOAD, advisableIndex);
cv.visitTypeInsn(CHECKCAST, ADVISABLE_CLASS_NAME);
cv.visitLdcInsn(new Integer(m_joinPointClassName.hashCode()));
cv.visitMethodInsn(
INVOKEINTERFACE,
ADVISABLE_CLASS_NAME,
GET_AFTER_THROWING_ADVICE_METHOD_NAME,
GET_AFTER_THROWING_ADVICE_METHOD_SIGNATURE
);
cv.visitFieldInsn(
PUTFIELD,
m_joinPointClassName,
AFTER_THROWING_INTERCEPTORS_FIELD_NAME,
AFTER_THROWING_ADVICE_ARRAY_CLASS_SIGNATURE
);
cv.visitVarInsn(ALOAD, joinPointInstanceIndex);
cv.visitVarInsn(ALOAD, joinPointInstanceIndex);
cv.visitFieldInsn(
GETFIELD,
m_joinPointClassName,
AFTER_THROWING_INTERCEPTORS_FIELD_NAME,
AFTER_THROWING_ADVICE_ARRAY_CLASS_SIGNATURE
);
cv.visitInsn(ARRAYLENGTH);
cv.visitFieldInsn(PUTFIELD, m_joinPointClassName, NR_OF_AFTER_THROWING_INTERCEPTORS_FIELD_NAME, I);
}
/**
* Handles the around interceptor invocations.
*
* @param cv
*/
private void createAroundInterceptorInvocations(final MethodVisitor cv) {
cv.visitVarInsn(ALOAD, 0);
cv.visitFieldInsn(GETFIELD, m_joinPointClassName, INTERCEPTOR_INDEX_FIELD_NAME, I);
cv.visitInsn(ICONST_M1);
Label ifStatementLabel = new Label();
cv.visitJumpInsn(IF_ICMPEQ, ifStatementLabel);
cv.visitVarInsn(ALOAD, 0);
cv.visitFieldInsn(GETFIELD, m_joinPointClassName, INTERCEPTOR_INDEX_FIELD_NAME, I);
cv.visitVarInsn(ALOAD, 0);
cv.visitFieldInsn(GETFIELD, m_joinPointClassName, NR_OF_AROUND_INTERCEPTORS_FIELD_NAME, I);
cv.visitJumpInsn(IF_ICMPGE, ifStatementLabel);
cv.visitVarInsn(ALOAD, 0);
cv.visitFieldInsn(
GETFIELD,
m_joinPointClassName,
AROUND_INTERCEPTORS_FIELD_NAME,
AROUND_ADVICE_ARRAY_CLASS_SIGNATURE
);
cv.visitVarInsn(ALOAD, 0);
cv.visitInsn(DUP);
cv.visitFieldInsn(GETFIELD, m_joinPointClassName, INTERCEPTOR_INDEX_FIELD_NAME, I);
cv.visitInsn(DUP_X1);
cv.visitInsn(ICONST_1);
cv.visitInsn(IADD);
cv.visitFieldInsn(PUTFIELD, m_joinPointClassName, INTERCEPTOR_INDEX_FIELD_NAME, I);
cv.visitInsn(AALOAD);
cv.visitVarInsn(ALOAD, 0);
cv.visitMethodInsn(
INVOKEINTERFACE,
AROUND_ADVICE_CLASS_NAME,
INTERCEPT_INVOKE_METHOD_NAME,
AROUND_ADVICE_INVOKE_METHOD_SIGNATURE
);
cv.visitInsn(ARETURN);
cv.visitLabel(ifStatementLabel);
}
/**
* Creates invocations fo the before interceptors.
*
* @param cv
* @param joinPointInstanceIndex
* @param registerDepth
*/
private void createBeforeInterceptorInvocations(final MethodVisitor cv,
final int joinPointInstanceIndex,
final int registerDepth) {
final int loopIndex = registerDepth + 1;
cv.visitInsn(ICONST_0);
cv.visitVarInsn(ISTORE, loopIndex);
Label loopStartLabel = new Label();
cv.visitLabel(loopStartLabel);
cv.visitVarInsn(ILOAD, loopIndex);
cv.visitVarInsn(ALOAD, joinPointInstanceIndex);
cv.visitFieldInsn(
GETFIELD,
m_joinPointClassName,
NR_OF_BEFORE_INTERCEPTORS_FIELD_NAME,
I
);
Label loopCheckCondLabel = new Label();
cv.visitJumpInsn(IF_ICMPGE, loopCheckCondLabel);
cv.visitVarInsn(ALOAD, joinPointInstanceIndex);
cv.visitFieldInsn(
GETFIELD,
m_joinPointClassName,
BEFORE_INTERCEPTORS_FIELD_NAME,
BEFORE_ADVICE_ARRAY_CLASS_SIGNATURE
);
cv.visitVarInsn(ILOAD, loopIndex);
cv.visitInsn(AALOAD);
cv.visitVarInsn(ALOAD, joinPointInstanceIndex);
cv.visitMethodInsn(
INVOKEINTERFACE,
BEFORE_ADVICE_CLASS_NAME,
INTERCEPT_INVOKE_METHOD_NAME,
BEFORE_ADVICE_INVOKE_METHOD_SIGNATURE
);
cv.visitIincInsn(loopIndex, 1);
cv.visitJumpInsn(GOTO, loopStartLabel);
cv.visitLabel(loopCheckCondLabel);
}
/**
* Creates invocations fo the after finally interceptors.
*
* @param cv
* @param joinPointInstanceIndex
* @param registerDepth
*/
private void createAfterInterceptorInvocations(final MethodVisitor cv,
final int joinPointInstanceIndex,
final int registerDepth) {
final int loopIndex = registerDepth + 1;
cv.visitVarInsn(ALOAD, joinPointInstanceIndex);
cv.visitFieldInsn(
GETFIELD,
m_joinPointClassName,
NR_OF_AFTER_INTERCEPTORS_FIELD_NAME,
I
);
cv.visitInsn(ICONST_1);
cv.visitInsn(ISUB);
cv.visitVarInsn(ISTORE, loopIndex);
Label loopLabel1 = new Label();
cv.visitLabel(loopLabel1);
cv.visitVarInsn(ILOAD, loopIndex);
Label loopLabel2 = new Label();
cv.visitJumpInsn(IFLT, loopLabel2);
cv.visitVarInsn(ALOAD, joinPointInstanceIndex);
cv.visitFieldInsn(
GETFIELD,
m_joinPointClassName,
AFTER_INTERCEPTORS_FIELD_NAME,
AFTER_ADVICE_ARRAY_CLASS_SIGNATURE
);
cv.visitVarInsn(ILOAD, loopIndex);
cv.visitInsn(AALOAD);
cv.visitVarInsn(ALOAD, joinPointInstanceIndex);
cv.visitMethodInsn(
INVOKEINTERFACE,
AFTER_ADVICE_CLASS_NAME,
INTERCEPT_INVOKE_METHOD_NAME,
AFTER_ADVICE_INVOKE_METHOD_SIGNATURE
);
cv.visitIincInsn(loopIndex, -1);
cv.visitJumpInsn(GOTO, loopLabel1);
cv.visitLabel(loopLabel2);
}
/**
* Creates invocations fo the after returning interceptors.
*
* @param cv
* @param joinPointInstanceIndex
* @param returnValueInstanceIndex
*/
private void createAfterReturningInterceptorInvocations(final MethodVisitor cv,
final int joinPointInstanceIndex,
final int returnValueInstanceIndex) {
final int loopIndex = returnValueInstanceIndex + 1;
cv.visitVarInsn(ALOAD, joinPointInstanceIndex);
cv.visitFieldInsn(
GETFIELD,
m_joinPointClassName,
NR_OF_AFTER_RETURNING_INTERCEPTORS_FIELD_NAME,
I
);
cv.visitInsn(ICONST_1);
cv.visitInsn(ISUB);
cv.visitVarInsn(ISTORE, loopIndex);
Label loopLabel1 = new Label();
cv.visitLabel(loopLabel1);
cv.visitVarInsn(ILOAD, loopIndex);
Label loopLabel2 = new Label();
cv.visitJumpInsn(IFLT, loopLabel2);
cv.visitVarInsn(ALOAD, joinPointInstanceIndex);
cv.visitFieldInsn(
GETFIELD,
m_joinPointClassName,
AFTER_RETURNING_INTERCEPTORS_FIELD_NAME,
AFTER_RETURNING_ADVICE_ARRAY_CLASS_SIGNATURE
);
cv.visitVarInsn(ILOAD, loopIndex);
cv.visitInsn(AALOAD);
cv.visitVarInsn(ALOAD, joinPointInstanceIndex);
cv.visitVarInsn(ALOAD, returnValueInstanceIndex);
cv.visitMethodInsn(
INVOKEINTERFACE,
AFTER_RETURNING_ADVICE_CLASS_NAME,
INTERCEPT_INVOKE_METHOD_NAME,
AFTER_RETURNING_ADVICE_INVOKE_METHOD_SIGNATURE
);
cv.visitIincInsn(loopIndex, -1);
cv.visitJumpInsn(GOTO, loopLabel1);
cv.visitLabel(loopLabel2);
}
/**
* Creates invocations fo the after returning interceptors.
*
* @param cv
* @param joinPointInstanceIndex
* @param exceptionInstanceIndex
*/
private void createAfterThrowingInterceptorInvocations(final MethodVisitor cv,
final int joinPointInstanceIndex,
final int exceptionInstanceIndex) {
final int loopIndex = exceptionInstanceIndex + 1;
cv.visitVarInsn(ALOAD, joinPointInstanceIndex);
cv.visitFieldInsn(
GETFIELD,
m_joinPointClassName,
NR_OF_AFTER_THROWING_INTERCEPTORS_FIELD_NAME,
I
);
cv.visitInsn(ICONST_1);
cv.visitInsn(ISUB);
cv.visitVarInsn(ISTORE, loopIndex);
Label loopLabel1 = new Label();
cv.visitLabel(loopLabel1);
cv.visitVarInsn(ILOAD, loopIndex);
Label loopLabel2 = new Label();
cv.visitJumpInsn(IFLT, loopLabel2);
cv.visitVarInsn(ALOAD, joinPointInstanceIndex);
cv.visitFieldInsn(
GETFIELD,
m_joinPointClassName,
AFTER_THROWING_INTERCEPTORS_FIELD_NAME,
AFTER_THROWING_ADVICE_ARRAY_CLASS_SIGNATURE
);
cv.visitVarInsn(ILOAD, loopIndex);
cv.visitInsn(AALOAD);
cv.visitVarInsn(ALOAD, joinPointInstanceIndex);
cv.visitVarInsn(ALOAD, exceptionInstanceIndex);
cv.visitMethodInsn(
INVOKEINTERFACE,
AFTER_THROWING_ADVICE_CLASS_NAME,
INTERCEPT_INVOKE_METHOD_NAME,
AFTER_THROWING_ADVICE_INVOKE_METHOD_SIGNATURE
);
cv.visitIincInsn(loopIndex, -1);
cv.visitJumpInsn(GOTO, loopLabel1);
cv.visitLabel(loopLabel2);
}
/**
* Checks if the join point requires a proceed() method.
*
* @return
*/
private boolean requiresProceedMethod() {
return m_hasAroundAdvices || m_isThisAdvisable;
}
static boolean requiresCallerInstance(DeploymentModel deployModel) {
return DeploymentModel.PER_INSTANCE.equals(deployModel)
|| DeploymentModel.PER_THIS.equals(deployModel);
}
static boolean requiresCalleeInstance(DeploymentModel deployModel) {
return DeploymentModel.PER_TARGET.equals(deployModel);
}
static boolean requiresCallerOrCallee(DeploymentModel deploymentModel) {
return requiresCallerInstance(deploymentModel)
|| requiresCalleeInstance(deploymentModel);
}
public final AspectModel[] getAspectModels() {
return m_aspectModels;
}
}