org.codehaus.aspectwerkz.transform.inlining.compiler.AbstractJoinPointCompiler.java Source code

Java tutorial

Introduction

Here is the source code for org.codehaus.aspectwerkz.transform.inlining.compiler.AbstractJoinPointCompiler.java

Source

/**************************************************************************************
 * Copyright (c) Jonas Bonr, 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 Bonr </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;
    }

}