Package org.codehaus.aspectwerkz.transform.inlining

Source Code of org.codehaus.aspectwerkz.transform.inlining.JoinPointCompiler

/**************************************************************************************
* Copyright (c) Jonas Bon�r, Alexandre Vasseur. All rights reserved.                 *
* http://aspectwerkz.codehaus.org                                                    *
* ---------------------------------------------------------------------------------- *
* The software in this package is published under the terms of the LGPL license      *
* a copy of which has been included with this distribution in the license.txt file.  *
**************************************************************************************/
package org.codehaus.aspectwerkz.transform.inlining;

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.CodeVisitor;
import org.objectweb.asm.Constants;
import org.objectweb.asm.Label;
import org.objectweb.asm.Type;
import org.codehaus.aspectwerkz.CrossCuttingInfo;
import org.codehaus.aspectwerkz.DeploymentModel;
import org.codehaus.aspectwerkz.AdviceInfo;
import org.codehaus.aspectwerkz.transform.TransformationUtil;
import org.codehaus.aspectwerkz.joinpoint.management.JoinPointType;
import org.codehaus.aspectwerkz.joinpoint.management.JoinPointManager;
import org.codehaus.aspectwerkz.joinpoint.management.AdviceIndexInfo;
import org.codehaus.aspectwerkz.joinpoint.Signature;
import org.codehaus.aspectwerkz.joinpoint.Rtti;
import org.codehaus.aspectwerkz.aspect.AspectContainer;
import org.codehaus.aspectwerkz.expression.ExpressionContext;

import java.util.List;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;

/**
* A compiler that compiles/generates a class that represents a specific join point, a class which invokes the advices
* and the target join point statically.
*
* @author <a href="mailto:jboner@codehaus.org">Jonas Bon�r </a>
* @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur </a>
*/
public class JoinPointCompiler implements Constants, TransformationConstants {

    // static and member field names
    private static final String TARGET_CLASS_FIELD_NAME = "TARGET_CLASS";
    private static final String SYSTEM_FIELD_NAME = "SYSTEM";
    private static final String SIGNATURE_FIELD_NAME = "SIGNATURE";
    private static final String META_DATA_FIELD_NAME = "META_DATA";
    private static final String STATIC_JOIN_POINT_INSTANCE_FIELD_NAME = "STATIC_JOIN_POINT";
    private static final String AROUND_ADVICE_FIELD_PREFIX = "AROUND";
    private static final String BEFORE_ADVICE_FIELD_PREFIX = "BEFORE";
    private static final String AFTER_ADVICE_FIELD_PREFIX = "AFTER";
    private static final String STACK_FRAME_FIELD_NAME = "m_stackFrame";
    private static final String CALLEE_INSTANCE_FIELD_NAME = "m_callee";
    private static final String CALLER_INSTANCE_FIELD_NAME = "m_caller";
    private static final String ARGUMENT_FIELD = "m_argument";

    // runtime system signatures and types
    private static final String INVOKE_METHOD_NAME = "invoke";
    private static final String SIGNATURE_CLASS_SIGNATURE = "Lorg/codehaus/aspectwerkz/joinpoint/Signature;";
    private static final String NEW_SIGNATURE_METHOD_SIGNATURE = "(Ljava/lang/Class;I)Lorg/codehaus/aspectwerkz/joinpoint/Signature;";
    private static final String SIGNATURE_FACTORY_CLASS = "org/codehaus/aspectwerkz/joinpoint/management/SignatureFactory";
    private static final String SYSTEM_CLASS_SIGNATURE = "Lorg/codehaus/aspectwerkz/AspectSystem;";
    private static final String SYSTEM_CLASS_NAME = "org/codehaus/aspectwerkz/AspectSystem";
    private static final String ASPECT_MANAGER_CLASS_NAME = "org/codehaus/aspectwerkz/aspect/management/AspectManager";
    private static final String ASPECT_CONTAINER_CLASS_NAME = "org/codehaus/aspectwerkz/aspect/AspectContainer";
    private static final String GET_ASPECT_MANAGER_METHOD_NAME = "getAspectManager";
    private static final String GET_ASPECT_MANAGER_METHOD_SIGNATURE = "(Ljava/lang/String;)Lorg/codehaus/aspectwerkz/aspect/management/AspectManager;";
    private static final String GET_ASPECT_CONTAINER_METHOD_NAME = "getAspectContainer";
    private static final String GET_ASPECT_CONTAINER_METHOD_SIGNATURE = "(I)Lorg/codehaus/aspectwerkz/aspect/AspectContainer;";
    private static final String GET_PER_JVM_ASPECT_METHOD_NAME = "createPerJvmAspect";
    private static final String GET_PER_JVM_ASPECT_METHOD_SIGNATURE = "()Ljava/lang/Object;";
    private static final String GET_PER_CLASS_ASPECT_METHOD_NAME = "createPerClassAspect";
    private static final String GET_PER_CLASS_ASPECT_METHOD_SIGNATURE = "(Ljava/lang/Class;)Ljava/lang/Object;";
    private static final String SYSTEM_LOADER_CLASS_NAME = "org/codehaus/aspectwerkz/SystemLoader";
    private static final String GET_SYSTEM_METHOD_NAME = "getSystem";
    private static final String GET_SYSTEM_METHOD_NAME_SIGNATURE = "(Ljava/lang/Class;)Lorg/codehaus/aspectwerkz/AspectSystem;";
    private static final String GET_SIGNATURE_METHOD_NAME = "getSignature";
    private static final String GET_SIGNATURE_METHOD_SIGNATURE = "()Lorg/codehaus/aspectwerkz/joinpoint/Signature;";
    private static final String GET_RTTI_METHOD_NAME = "getRtti";
    private static final String GET_RTTI_METHOD_SIGNATURE = "()Lorg/codehaus/aspectwerkz/joinpoint/Rtti;";
    private static final String PROCEED_METHOD_NAME = "proceed";
    private static final String PROCEED_METHOD_SIGNATURE = "()Ljava/lang/Object;";
    private static final String JOIN_POINT_CLASS_SIGNATURE = "(Lorg/codehaus/aspectwerkz/joinpoint/JoinPoint;";
    private static final String ADD_META_DATA_METHOD_NAME = "addMetaData";
    private static final String ADD_META_DATA_METHOD_SIGNATURE = "(Ljava/lang/Object;Ljava/lang/Object;)V";
    private static final String MAP_CLASS_SIGNATURE = "Ljava/util/Map;";
    private static final String MAP_CLASS_NAME = "java/util/Map";
    private static final String PUT_METHOD_NAME = "put";
    private static final String PUT_METHOD_SIGNATURE = "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;";
    private static final String GET_META_DATA_METHOD_NAME = "getMetaData";
    private static final String GET_TARGET_METHOD_NAME = "getTarget";
    private static final String GET_THIS_METHOD_NAME = "getThis";
    private static final String GET_METHOD_NAME = "get";
    private static final String GET_METHOD_SIGNATURE = "(Ljava/lang/Object;)Ljava/lang/Object;";
    private static final String GET_META_DATA_METHOD_SIGNATURE = "(Ljava/lang/Object;)Ljava/lang/Object;";
    private static final String NEW_METHOD_SIGNATURE_METHOD_NAME = "newMethodSignature";
    private static final String NEW_CONSTRUCTOR_SIGNATURE_METHOD_NAME = "newConstructorSignature";
    private static final String NEW_FIELD_SIGNATURE_METHOD_NAME = "newFieldSignature";
    private static final String NEW_CATCH_CLAUSE_SIGNATURE_METHOD_NAME = "newCatchClauseSignature";
    private static final String HASH_MAP_CLASS_NAME = "java/util/HashMap";
    private static final String NO_PARAM_RETURN_VOID_SIGNATURE = "()V";
    private static final String CLASS_NOT_FOUND_EXCEPTION_CLASS_NAME = "java/lang/ClassNotFoundException";
    private static final String GET_TARGET_CLASS_METHOD_NAME = "getTargetClass";
    private static final String GET_TARGET_CLASS_METHOD_SIGNATURE = "()Ljava/lang/Class;";
    private static final String GET_TYPE_METHOD_NAME = "getType";
    private static final String GET_TYPE_METHOD_SIGNATURE = "()Ljava/lang/String;";
    private static final String RESET_METHOD_NAME = "reset";
    private static final String RUNTIME_EXCEPTION_CLASS_NAME = "java/lang/RuntimeException";
    private static final String FOR_NAME_METHOD_NAME = "forName";
    private static final String FOR_NAME_METHOD_SIGNATURE = "(Ljava/lang/String;)Ljava/lang/Class;";
    private static final String RUNTIME_EXCEPTION_INIT_METHOD_SIGNATURE = "(Ljava/lang/String;)V";
    private static final String IS_IN_CFLOW_METOD_NAME = "isInCflow";
    private static final String IS_IN_CFLOW_METOD_SIGNATURE = "()Z";
    private static final String JOIN_POINT_CLASS_NAME = "org/codehaus/aspectwerkz/joinpoint/JoinPoint";

    // FIXME define using VM option
    private static final boolean DUMP_CLASSES = true;

    private static final String DUMP_DIR = "_dump/jp";
    private static final String NO_PARAMS_SIGNATURE = "()";

    /**
     * Compiles a join point class, one specific class for each distinct join point. The compiled join point class
     * inherits the base join point class.
     *
     * @param joinPointClassName
     * @param joinPointType
     * @param joinPointHash
     * @param callerClassName
     * @param callerMethodName
     * @param callerMethodDesc
     * @param callerMethodModifiers
     * @param calleeClassName
     * @param calleeMemberName
     * @param calleeMemberDesc
     * @param calleeMemberModifiers
     * @param advices
     * @param loader
     * @param joinPointSequence
     * @return
     */
    public static Class loadJoinPoint(final String joinPointClassName,
                                      final int joinPointType,
                                      final int joinPointHash,
                                      final String callerClassName,
                                      final String callerMethodName,
                                      final String callerMethodDesc,
                                      final int callerMethodModifiers,
                                      final String calleeClassName,
                                      final String calleeMemberName,
                                      final String calleeMemberDesc,
                                      final int calleeMemberModifiers,
                                      final AdviceIndexInfo[] advices,
                                      final ClassLoader loader,
                                      final int joinPointSequence) {

        // compile the join point class
        byte[] joinPointBytes = compileJoinPoint(joinPointClassName,
                joinPointType,
                joinPointHash,
                callerClassName,
                callerMethodName,
                callerMethodDesc,
                callerMethodModifiers,
                calleeClassName,
                calleeMemberName,
                calleeMemberDesc,
                calleeMemberModifiers,
                advices,
                joinPointSequence);

        // load and return the generated join point class
        return AsmHelper.loadClass(loader, joinPointBytes, joinPointClassName);
    }

    /**
     * Compiles a join point class, one specific class for each distinct join point. The compiled join point class
     * inherits the base join point class.
     *
     * @param joinPointClassName
     * @param joinPointType
     * @param joinPointHash
     * @param callerClassName
     * @param callerMethodName
     * @param callerMethodDesc
     * @param callerMethodModifiers
     * @param calleeClassName
     * @param calleeMemberName
     * @param calleeMemberDesc
     * @param calleeMemberModifiers
     * @param advices
     * @param joinPointSequence
     * @return the generated, compiled and loaded join point class
     */
    public static byte[] compileJoinPoint(final String joinPointClassName,
                                          final int joinPointType,
                                          final int joinPointHash,
                                          String callerClassName,
                                          final String callerMethodName,
                                          final String callerMethodDesc,
                                          final int callerMethodModifiers,
                                          String calleeClassName,
                                          final String calleeMemberName,
                                          final String calleeMemberDesc,
                                          final int calleeMemberModifiers,
                                          final AdviceIndexInfo[] advices,
                                          final int joinPointSequence) {

        // NOTE: internal compiler class name format is ALWAYS using '/'
        callerClassName = callerClassName.replace('.', '/');
        calleeClassName = calleeClassName.replace('.', '/');

        String callerClassSignature = L + callerClassName + SEMICOLON;
        String calleeClassSignature = L + calleeClassName + SEMICOLON;

        try {
            // grab the specific advice
            AdviceInfo[] aroundAdvices = JoinPointManager.extractAroundAdvice(advices);
            AdviceInfo[] beforeAdvices = JoinPointManager.extractBeforeAdvice(advices);
            AdviceInfo[] afterAdvices = JoinPointManager.extractAfterAdvice(advices);

            // start the class compilation
            ClassWriter cw = AsmHelper.newClassWriter(true);

            // define the class
            cw.visit(ACC_PUBLIC + ACC_SUPER,
                    joinPointClassName,
                    OBJECT_CLASS,
                    new String[]{JOIN_POINT_CLASS_NAME},
                    null);

            // TODO: INNER CLASS OR NOT?
            // flag it as a public static inner class
            // Note: if <init> changes, we will need to pass the containing instance as arg0 and add a syntetic field
//            int innerIndex = joinPointClassName.lastIndexOf('$');
//            cw.visitInnerClass(joinPointClassName,
//                    joinPointClassName.substring(0, innerIndex),
//                    joinPointClassName.substring(innerIndex + 1, joinPointClassName.length()),
//                    ACC_PUBLIC + ACC_STATIC);

            createFieldsCommonToAllJoinPoints(cw, joinPointClassName, callerClassSignature, calleeClassSignature);

            String[] fieldNames = createJoinPointSpecificFields(cw, joinPointType, calleeMemberDesc);

            createStaticInitializer(cw,
                    joinPointClassName,
                    joinPointType,
                    joinPointHash,
                    calleeClassName,
                    aroundAdvices,
                    beforeAdvices,
                    afterAdvices);

            createConstructor(cw, joinPointClassName);

            createUtilityMethods(cw, joinPointClassName, callerClassSignature, calleeClassSignature);

            if (aroundAdvices.length == 0) {
                createInlinedInvokeMethod(cw,
                        callerClassName,
                        callerClassSignature,
                        callerMethodName,
                        callerMethodDesc,
                        callerMethodModifiers,
                        calleeClassName,
                        calleeClassSignature,
                        calleeMemberName,
                        calleeMemberDesc,
                        calleeMemberModifiers,
                        joinPointClassName,
                        joinPointType,
                        fieldNames,
                        joinPointSequence,
                        aroundAdvices,
                        beforeAdvices,
                        afterAdvices);
            } else {
                createInvokeMethod(cw,
                        callerClassName,
                        callerClassSignature,
                        callerMethodName,
                        callerMethodDesc,
                        callerMethodModifiers,
                        calleeClassName,
                        calleeClassSignature,
                        calleeMemberName,
                        calleeMemberDesc,
                        calleeMemberModifiers,
                        joinPointClassName,
                        joinPointType,
                        fieldNames,
                        joinPointSequence,
                        aroundAdvices,
                        beforeAdvices,
                        afterAdvices);

                createProceedMethod(cw,
                        calleeClassName,
                        calleeClassSignature,
                        calleeMemberName,
                        calleeMemberDesc,
                        calleeMemberModifiers,
                        joinPointClassName,
                        joinPointType,
                        fieldNames,
                        joinPointSequence,
                        aroundAdvices,
                        null);
            }

            cw.visitEnd();

            if (DUMP_CLASSES) {
                AsmHelper.dumpClass(DUMP_DIR, joinPointClassName, cw);
            }
            return 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(joinPointHash);
            buf.append("] and declaring class [");
            buf.append(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());
        }
    }

    /**
     * Computes the joinpoint classname : "target/class_type_hash_suffix"
     *
     * @param thisClassName
     * @param joinPointType
     * @param joinPointHash
     * @return the JIT joinpoint classname
     */
    public static String getJoinPointClassName(final String thisClassName,
                                               final int joinPointType,
                                               final int joinPointHash) {

        StringBuffer classNameBuf = new StringBuffer(thisClassName);
        // TODO: INNER CLASS OR NOT?
//        classNameBuf.append("$");
        classNameBuf.append('_');
        classNameBuf.append(joinPointType);
        classNameBuf.append('_');
        classNameBuf.append(joinPointHash);
        classNameBuf.append(JOIN_POINT_CLASS_SUFFIX);

        //replace minus signs on joinPointHash
        String joinPointClassName = classNameBuf.toString().replace('-', '_');
        return joinPointClassName.replace('.', '/');
    }

    /**
     * Creates fields common for all join point classes.
     *
     * @param cw
     * @param joinPointClassName
     * @param callerClassSignature
     * @param calleeClassSignature
     */
    private static void createFieldsCommonToAllJoinPoints(final ClassWriter cw,
                                                          final String joinPointClassName,
                                                          final String callerClassSignature,
                                                          final String calleeClassSignature) {
        cw.visitField(ACC_PROTECTED + ACC_FINAL + ACC_STATIC,
                TARGET_CLASS_FIELD_NAME,
                CLASS_CLASS_SIGNATURE,
                null,
                null);
        cw.visitField(ACC_PROTECTED + ACC_FINAL + ACC_STATIC,
                SYSTEM_FIELD_NAME,
                SYSTEM_CLASS_SIGNATURE,
                null,
                null);
        cw.visitField(ACC_PRIVATE + ACC_FINAL + ACC_STATIC,
                SIGNATURE_FIELD_NAME,
                SIGNATURE_CLASS_SIGNATURE,
                null,
                null);
        cw.visitField(ACC_PRIVATE + ACC_FINAL + ACC_STATIC, META_DATA_FIELD_NAME, MAP_CLASS_SIGNATURE, null, null);
        cw.visitField(ACC_PRIVATE + ACC_FINAL + ACC_STATIC,
                STATIC_JOIN_POINT_INSTANCE_FIELD_NAME,
                L + joinPointClassName + SEMICOLON,
                null, null);
        cw.visitField(ACC_PRIVATE, CALLEE_INSTANCE_FIELD_NAME, calleeClassSignature, null, null);
        cw.visitField(ACC_PRIVATE, CALLER_INSTANCE_FIELD_NAME, callerClassSignature, null, null);
        cw.visitField(ACC_PRIVATE, JoinPointCompiler.STACK_FRAME_FIELD_NAME, I, null, null);
    }

    /**
     * Creates join point specific fields.
     *
     * @param cw
     * @param joinPointType
     * @param signature     the join point signature
     * @return an array with the names of the fields
     */
    private static String[] createJoinPointSpecificFields(final ClassWriter cw,
                                                          final int joinPointType,
                                                          final String signature) {

        String[] fieldNames = null;
        switch (joinPointType) {
            case JoinPointType.METHOD_EXECUTION:
            case JoinPointType.METHOD_CALL:
            case JoinPointType.CONSTRUCTOR_CALL:
            case JoinPointType.CONSTRUCTOR_EXECUTION:
                // create the method argument fields
                Type[] argumentTypes = Type.getArgumentTypes(signature);
                fieldNames = new String[argumentTypes.length];
                for (int i = 0; i < argumentTypes.length; i++) {
                    Type argumentType = argumentTypes[i];
                    String fieldName = ARGUMENT_FIELD + i;
                    fieldNames[i] = fieldName;
                    cw.visitField(ACC_PRIVATE + ACC_FINAL, fieldName, argumentType.getDescriptor(), null, null);
                }
                break;
            case JoinPointType.FIELD_SET:
            case JoinPointType.FIELD_GET:
                // create the field argument field
                Type fieldType = Type.getType(signature);
                fieldNames = new String[1];
                    String fieldName = ARGUMENT_FIELD + 1;
                    fieldNames[0] = fieldName;
                    cw.visitField(ACC_PRIVATE + ACC_FINAL, fieldName, fieldType.getDescriptor(), null, null);
                break;
            case JoinPointType.HANDLER:
                break;
            case JoinPointType.STATIC_INITALIZATION:
                break;
        }
        return fieldNames;

    }

    /**
     * Creates the static initializer for the join point.
     *
     * @param cw
     * @param joinPointClassName
     * @param joinPointType
     * @param joinPointHash
     * @param calleeClassName
     * @param aroundAdvices
     * @param beforeAdvices
     * @param afterAdvices
     */
    private static void createStaticInitializer(final ClassWriter cw,
                                                final String joinPointClassName,
                                                final int joinPointType,
                                                final int joinPointHash,
                                                final String calleeClassName,
                                                final AdviceInfo[] aroundAdvices,
                                                final AdviceInfo[] beforeAdvices,
                                                final AdviceInfo[] afterAdvices) {

        CodeVisitor cv = cw.visitMethod(ACC_STATIC, CLINIT_METHOD_NAME, NO_PARAM_RETURN_VOID_SIGNATURE, null, null);

        Label l0 = new Label();
        cv.visitLabel(l0);
        cv.visitLdcInsn(calleeClassName.replace('/', '.'));
        cv.visitMethodInsn(INVOKESTATIC, CLASS_CLASS, FOR_NAME_METHOD_NAME, FOR_NAME_METHOD_SIGNATURE);
        cv.visitFieldInsn(PUTSTATIC, joinPointClassName, TARGET_CLASS_FIELD_NAME, CLASS_CLASS_SIGNATURE);
        Label l1 = new Label();
        cv.visitLabel(l1);
        Label l2 = new Label();
        cv.visitJumpInsn(GOTO, l2);
        Label l3 = new Label();
        cv.visitLabel(l3);
        cv.visitVarInsn(ASTORE, 0);
        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");
        cv.visitMethodInsn(INVOKESPECIAL,
                RUNTIME_EXCEPTION_CLASS_NAME,
                INIT_METHOD_NAME,
                RUNTIME_EXCEPTION_INIT_METHOD_SIGNATURE);
        cv.visitInsn(ATHROW);
        cv.visitLabel(l2);

        cv.visitFieldInsn(GETSTATIC, joinPointClassName, TARGET_CLASS_FIELD_NAME, CLASS_CLASS_SIGNATURE);
        cv.visitMethodInsn(INVOKESTATIC,
                SYSTEM_LOADER_CLASS_NAME,
                GET_SYSTEM_METHOD_NAME,
                GET_SYSTEM_METHOD_NAME_SIGNATURE);
        cv.visitFieldInsn(PUTSTATIC, joinPointClassName, SYSTEM_FIELD_NAME, SYSTEM_CLASS_SIGNATURE);

        // 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, joinPointClassName, META_DATA_FIELD_NAME, MAP_CLASS_SIGNATURE);

        // create the Signature instance
        createSignature(joinPointType, cv, joinPointClassName, joinPointHash);

        // create the static JoinPoint instance
        cv.visitTypeInsn(NEW, joinPointClassName);
        cv.visitInsn(DUP);
        cv.visitMethodInsn(INVOKESPECIAL, joinPointClassName, INIT_METHOD_NAME, NO_PARAM_RETURN_VOID_SIGNATURE);
        cv.visitFieldInsn(PUTSTATIC,
                joinPointClassName,
                STATIC_JOIN_POINT_INSTANCE_FIELD_NAME,
                L + joinPointClassName + SEMICOLON);

        // retrieve the aspect instances
        for (int i = 0; i < aroundAdvices.length; i++) {
            initAspectField(aroundAdvices[i], cw, AROUND_ADVICE_FIELD_PREFIX + i, cv, joinPointClassName);
        }
        for (int i = 0; i < beforeAdvices.length; i++) {
            initAspectField(beforeAdvices[i], cw, BEFORE_ADVICE_FIELD_PREFIX + i, cv, joinPointClassName);
        }
        for (int i = 0; i < afterAdvices.length; i++) {
            initAspectField(afterAdvices[i], cw, AFTER_ADVICE_FIELD_PREFIX + i, cv, joinPointClassName);
        }

        cv.visitInsn(RETURN);
        cv.visitTryCatchBlock(l0, l1, l3, CLASS_NOT_FOUND_EXCEPTION_CLASS_NAME);
        cv.visitMaxs(0, 0);
    }

    /**
     * Creates the constructor for the join point.
     *
     * @param cw
     * @param className
     */
    private static void createConstructor(final ClassWriter cw, final String className) {
        CodeVisitor cv = cw.visitMethod(ACC_PRIVATE, INIT_METHOD_NAME, NO_PARAM_RETURN_VOID_SIGNATURE, null, null);
        cv.visitVarInsn(ALOAD, 0);
        cv.visitMethodInsn(INVOKESPECIAL, OBJECT_CLASS, INIT_METHOD_NAME, NO_PARAM_RETURN_VOID_SIGNATURE);
        cv.visitVarInsn(ALOAD, 0);
        cv.visitInsn(ICONST_M1);
        cv.visitFieldInsn(PUTFIELD, className, STACK_FRAME_FIELD_NAME, I);
        cv.visitInsn(RETURN);
        cv.visitMaxs(0, 0);
    }

    /**
     * Creates the signature for the join point.
     *
     * @param joinPointType
     * @param cv
     * @param className
     * @param joinPointHash
     */
    private static void createSignature(final int joinPointType,
                                        final CodeVisitor cv,
                                        final String className,
                                        final int joinPointHash) {
        cv.visitFieldInsn(GETSTATIC, className, TARGET_CLASS_FIELD_NAME, CLASS_CLASS_SIGNATURE);
        cv.visitLdcInsn(new Integer(joinPointHash));
        switch (joinPointType) {
            case JoinPointType.METHOD_EXECUTION:
            case JoinPointType.METHOD_CALL:
                cv.visitMethodInsn(INVOKESTATIC,
                        SIGNATURE_FACTORY_CLASS,
                        NEW_METHOD_SIGNATURE_METHOD_NAME,
                        NEW_SIGNATURE_METHOD_SIGNATURE);
                break;
            case JoinPointType.CONSTRUCTOR_CALL:
            case JoinPointType.CONSTRUCTOR_EXECUTION:
                cv.visitMethodInsn(INVOKESTATIC,
                        SIGNATURE_FACTORY_CLASS,
                        NEW_CONSTRUCTOR_SIGNATURE_METHOD_NAME,
                        NEW_SIGNATURE_METHOD_SIGNATURE);
                break;
            case JoinPointType.FIELD_SET:
            case JoinPointType.FIELD_GET:
                cv.visitMethodInsn(INVOKESTATIC,
                        SIGNATURE_FACTORY_CLASS,
                        NEW_FIELD_SIGNATURE_METHOD_NAME,
                        NEW_SIGNATURE_METHOD_SIGNATURE);
                break;
            case JoinPointType.HANDLER:
                cv.visitMethodInsn(INVOKESTATIC,
                        SIGNATURE_FACTORY_CLASS,
                        NEW_CATCH_CLAUSE_SIGNATURE_METHOD_NAME,
                        NEW_SIGNATURE_METHOD_SIGNATURE);
                break;
            case JoinPointType.STATIC_INITALIZATION:
                break;
        }
        cv.visitFieldInsn(PUTSTATIC, className, SIGNATURE_FIELD_NAME, SIGNATURE_CLASS_SIGNATURE);
    }

    /**
     * Create and initialize the aspect field for a specific advice.
     *
     * @param adviceTuple
     * @param cw
     * @param aspectFieldName
     * @param cv
     * @param joinPointClassName
     */
    private static boolean initAspectField(final AdviceInfo adviceTuple,
                                           final ClassWriter cw,
                                           final String aspectFieldName,
                                           final CodeVisitor cv,
                                           final String joinPointClassName) {

        final CrossCuttingInfo info = adviceTuple.getAspectManager().getAspectContainer(adviceTuple.getAspectIndex())
                .getCrossCuttingInfo();
        final String aspectClassName = info.getAspectClass().getName().replace('.', '/');
        final String aspectClassSignature = L + aspectClassName + SEMICOLON;

        // add the aspect field
        cw.visitField(ACC_PRIVATE + ACC_FINAL + ACC_STATIC, aspectFieldName, aspectClassSignature, null, null);

        // retrieve the aspect set it to the field
        cv.visitFieldInsn(GETSTATIC, joinPointClassName, SYSTEM_FIELD_NAME, SYSTEM_CLASS_SIGNATURE);
        cv.visitLdcInsn(info.getUuid());
        cv.visitMethodInsn(INVOKEVIRTUAL,
                SYSTEM_CLASS_NAME,
                GET_ASPECT_MANAGER_METHOD_NAME,
                GET_ASPECT_MANAGER_METHOD_SIGNATURE);
        cv.visitIntInsn(BIPUSH, adviceTuple.getAspectIndex());
        cv.visitMethodInsn(INVOKEVIRTUAL,
                ASPECT_MANAGER_CLASS_NAME,
                GET_ASPECT_CONTAINER_METHOD_NAME,
                GET_ASPECT_CONTAINER_METHOD_SIGNATURE);

        switch (info.getDeploymentModel()) {
            case DeploymentModel.PER_JVM:
                cv.visitMethodInsn(INVOKEINTERFACE,
                        ASPECT_CONTAINER_CLASS_NAME,
                        GET_PER_JVM_ASPECT_METHOD_NAME,
                        GET_PER_JVM_ASPECT_METHOD_SIGNATURE);
                break;
            case DeploymentModel.PER_CLASS:
                cv.visitMethodInsn(INVOKEINTERFACE,
                        ASPECT_CONTAINER_CLASS_NAME,
                        GET_PER_CLASS_ASPECT_METHOD_NAME,
                        GET_PER_CLASS_ASPECT_METHOD_SIGNATURE);
                break;
            default:
                throw new UnsupportedOperationException(
                        "JITGen - unsupported deployment model - " + aspectFieldName + " " + DeploymentModel.getDeploymentModelAsString(
                                info.getDeploymentModel()));
                //return true;
        }

        cv.visitTypeInsn(CHECKCAST, aspectClassName);
        cv.visitFieldInsn(PUTSTATIC, joinPointClassName, aspectFieldName, aspectClassSignature);

        return false;
    }

    /**
     * Creates the 'invoke' method. This version 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/>
     * Alex note:
     * FIXME: design is unclear. If JP is used to access params, then the STATIC JP is not enough.
     * Same issue may appear for CALL JP.
     * The decision should be both "NO AROUND Advice" AND "no before/after advices using the jp non-static part".
     * As in AJ thisStaticJP / thisJP.
     * We can solve the issue easily without the grammar with simple advice signature analysis
     * and having STATIC JP implementing a TBD subset interface of JoinPoint (StaticJoinPoint).
     * But the StaticJP could then be used for around advice as well.
     * => optim A: no around = no wrapping = invoke + delegate directly to target
     * => optim B: no JP used but only StaticJP used: no JP creation + RTTI handling
     * => optim A is using JP unless optim B applies as well.
     *
     *
     * @param cw
     * @param callerClassName
     * @param callerClassSignature
     * @param callerMethodName
     * @param callerMethodSignature
     * @param callerMethodModifiers
     * @param calleeClassName
     * @param calleeClassSignature
     * @param calleeMemberName
     * @param calleeMemberSignature
     * @param calleeMemberModifiers
     * @param joinPointClassName
     * @param joinPointType
     * @param fieldNames
     * @param joinPointSequence
     * @param aroundAdvice
     * @param beforeAdvice
     * @param afterAdvice
     */
    private static void createInlinedInvokeMethod(final ClassWriter cw,
                                                  final String callerClassName,
                                                  final String callerClassSignature,
                                                  final String callerMethodName,
                                                  final String callerMethodSignature,
                                                  final int callerMethodModifiers,
                                                  final String calleeClassName,
                                                  final String calleeClassSignature,
                                                  final String calleeMemberName,
                                                  final String calleeMemberSignature,
                                                  final int calleeMemberModifiers,
                                                  final String joinPointClassName,
                                                  final int joinPointType,
                                                  final String[] fieldNames,
                                                  final int joinPointSequence,
                                                  final AdviceInfo[] aroundAdvice,
                                                  final AdviceInfo[] beforeAdvice,
                                                  final AdviceInfo[] afterAdvice) {

        Type[] argumentTypes = getJoinPointArgumentTypes(joinPointType, calleeMemberSignature);
        Type returnType = getJoinPointReturnType(joinPointType, calleeMemberSignature);

        String invokeDesc = buildInvokeMethodSignature(argumentTypes,
                calleeClassSignature,
                callerClassSignature,
                returnType,
                calleeMemberModifiers);

        // create the method
        CodeVisitor cv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL + ACC_STATIC,
                INVOKE_METHOD_NAME,
                invokeDesc,
                new String[]{
                    THROWABLE_CLASS_NAME
                },
                null);

        // StaticJP.m_callee = null or arg0 if target method is not static
        cv.visitFieldInsn(GETSTATIC, joinPointClassName, STATIC_JOIN_POINT_INSTANCE_FIELD_NAME,L + joinPointClassName + SEMICOLON);
        int argStartIndex = 0;
        if (!Modifier.isStatic(calleeMemberModifiers)) {
            cv.visitVarInsn(ALOAD, argStartIndex);
            argStartIndex++;
        } else {
            cv.visitInsn(ACONST_NULL);
        }
        cv.visitFieldInsn(PUTFIELD, joinPointClassName, CALLEE_INSTANCE_FIELD_NAME, calleeClassSignature);

        // StaticJP.m_caller = arg<last>
        cv.visitFieldInsn(GETSTATIC, joinPointClassName,STATIC_JOIN_POINT_INSTANCE_FIELD_NAME,L + joinPointClassName + SEMICOLON);
        cv.visitVarInsn(ALOAD, argStartIndex + AsmHelper.getRegisterDepth(argumentTypes));
        cv.visitFieldInsn(PUTFIELD, joinPointClassName, CALLER_INSTANCE_FIELD_NAME, callerClassSignature);

        addBeforeAdviceInvocations(cv, beforeAdvice, joinPointClassName, argumentTypes, argStartIndex, -1);

        // if no around advice then optimize by invoking the target JP directly and no call to proceed()
        createInlinedJoinPointInvocation(cv,
                joinPointType,
                joinPointSequence,
                calleeClassName,
                calleeMemberName,
                calleeMemberSignature,
                calleeMemberModifiers,
                argumentTypes,
                argStartIndex);

        addAfterAdviceInvocations(cv, afterAdvice, joinPointClassName, argumentTypes, argStartIndex, -1);

        AsmHelper.addReturnStatement(cv, returnType);

        cv.visitMaxs(0, 0);
    }

    /**
     * Creates the 'invoke' method. This version delegates the call to the proceed method.
     * Used when we have at least one around advice.
     *
     * @param cw
     * @param callerClassName
     * @param callerClassSignature
     * @param callerMethodName
     * @param callerMethodSignature
     * @param callerMethodModifiers
     * @param calleeClassName
     * @param calleeClassSignature
     * @param calleeMemberName
     * @param calleeMemberSignature
     * @param calleeMemberModifiers
     * @param joinPointClassName
     * @param joinPointType
     * @param fieldNames
     * @param joinPointSequence
     * @param aroundAdvice
     * @param beforeAdvice
     * @param afterAdvice
     */
    private static void createInvokeMethod(final ClassWriter cw,
                                           final String callerClassName,
                                           final String callerClassSignature,
                                           final String callerMethodName,
                                           final String callerMethodSignature,
                                           final int callerMethodModifiers,
                                           final String calleeClassName,
                                           final String calleeClassSignature,
                                           final String calleeMemberName,
                                           final String calleeMemberSignature,
                                           final int calleeMemberModifiers,
                                           final String joinPointClassName,
                                           final int joinPointType,
                                           final String[] fieldNames,
                                           final int joinPointSequence,
                                           final AdviceInfo[] aroundAdvice,
                                           final AdviceInfo[] beforeAdvice,
                                           final AdviceInfo[] afterAdvice) {

        Type[] argumentTypes = getJoinPointArgumentTypes(joinPointType, calleeMemberSignature);
        Type returnType = getJoinPointReturnType(joinPointType, calleeMemberSignature);

        String invokeDesc = buildInvokeMethodSignature(argumentTypes,
                calleeClassSignature,
                callerClassSignature,
                returnType,
                calleeMemberModifiers);

        // create the method
        CodeVisitor cv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL + ACC_STATIC,
                INVOKE_METHOD_NAME,
                invokeDesc,
                new String[]{
                    THROWABLE_CLASS_NAME
                },
                null);

        // the created jp instance will be on the register stack
        // after the target method args
        // and we keep 2 index for caller and callee instances
        int joinPointInstanceIndex = AsmHelper.getRegisterDepth(argumentTypes) + 2;

        // target arg starts at 0 or 1
        int argStartIndex = 0;
        if (!Modifier.isStatic(calleeMemberModifiers)) {
            argStartIndex++;
        }

        // only create a new join point instance per invocation (and set the params)
        // if we have at least one around advice
        createInvocationLocalJoinPointInstance(cv,
                joinPointClassName,
                callerClassSignature,
                calleeClassSignature,
                fieldNames,
                argumentTypes,
                argStartIndex,
                joinPointInstanceIndex);

        addBeforeAdviceInvocations(cv, beforeAdvice, joinPointClassName, argumentTypes, argStartIndex, joinPointInstanceIndex);

        // invoke proceed()
        cv.visitVarInsn(ALOAD, joinPointInstanceIndex);
        cv.visitMethodInsn(INVOKEVIRTUAL, joinPointClassName, PROCEED_METHOD_NAME, PROCEED_METHOD_SIGNATURE);
        cv.visitVarInsn(ASTORE, joinPointInstanceIndex + 1);
        if (returnType.getSort() != Type.VOID) {
            cv.visitVarInsn(ALOAD, joinPointInstanceIndex + 1);
            AsmHelper.unwrapType(cv, returnType);
        }

        addAfterAdviceInvocations(cv, afterAdvice, joinPointClassName, argumentTypes, argStartIndex, joinPointInstanceIndex);

        AsmHelper.addReturnStatement(cv, returnType);

        cv.visitMaxs(0, 0);
    }

    /**
     * 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 joinPointClassName
     * @param callerClassSignature
     * @param calleeClassSignature
     * @param fieldNames
     * @param argumentTypes
     * @param argStartIndex index on stack of first target method arg (0 or 1, depends of static target or not)
     * @param joinPointInstanceIndex
     */
    private static void createInvocationLocalJoinPointInstance(final CodeVisitor cv,
                                                               final String joinPointClassName,
                                                               final String callerClassSignature,
                                                               final String calleeClassSignature,
                                                               final String[] fieldNames,
                                                               final Type[] argumentTypes,
                                                               final int argStartIndex,
                                                               final int joinPointInstanceIndex) {

        // create the join point instance
        cv.visitTypeInsn(NEW, joinPointClassName);
        cv.visitInsn(DUP);
        cv.visitMethodInsn(INVOKESPECIAL, joinPointClassName, INIT_METHOD_NAME, NO_PARAM_RETURN_VOID_SIGNATURE);

        // store the jp on the stack
        cv.visitVarInsn(ASTORE, joinPointInstanceIndex);

        // affect the target method arg to the jp (jp.m_arg<i> = <arg_i>)
        int argStackIndex = argStartIndex;
        for (int i = 0; i < fieldNames.length; i++) {
            String fieldName = fieldNames[i];
            cv.visitVarInsn(ALOAD, joinPointInstanceIndex);
            Type type = argumentTypes[i];
            argStackIndex = AsmHelper.loadType(cv, argStackIndex, type);
            cv.visitFieldInsn(PUTFIELD, joinPointClassName, fieldName, type.getDescriptor());
        }

        // caller is arg<last>
        cv.visitVarInsn(ALOAD, joinPointInstanceIndex);
        cv.visitVarInsn(ALOAD, argStackIndex++);
        cv.visitFieldInsn(PUTFIELD, joinPointClassName, CALLER_INSTANCE_FIELD_NAME, callerClassSignature);

        // callee is arg0 or null
        cv.visitVarInsn(ALOAD, joinPointInstanceIndex);
        if (argStartIndex > 0) {
            cv.visitVarInsn(ALOAD, 0);
        } else {
            cv.visitInsn(ACONST_NULL);
        }
        cv.visitFieldInsn(PUTFIELD, joinPointClassName, CALLEE_INSTANCE_FIELD_NAME, calleeClassSignature);
    }

    /**
     * Create the proceed() method.
     *
     * @param cw
     * @param calleeClassName
     * @param calleeClassSignature
     * @param calleeMemberName
     * @param calleeMemberSignature
     * @param calleeMemberModifiers
     * @param joinPointClassName
     * @param joinPointType
     * @param fieldNames
     * @param joinPointSequence
     * @param aroundAdvice
     * @param signatureCflowExprStruct
     */
    private static void createProceedMethod(final ClassWriter cw,
                                            final String calleeClassName,
                                            final String calleeClassSignature,
                                            final String calleeMemberName,
                                            final String calleeMemberSignature,
                                            final int calleeMemberModifiers,
                                            final String joinPointClassName,
                                            final int joinPointType,
                                            final String[] fieldNames,
                                            final int joinPointSequence,
                                            final AdviceInfo[] aroundAdvice,
                                            final JoinPointInfo signatureCflowExprStruct) {

        CodeVisitor cv = cw.visitMethod(ACC_PUBLIC | ACC_FINAL,
                PROCEED_METHOD_NAME,
                PROCEED_METHOD_SIGNATURE,
                new String[]{
                    THROWABLE_CLASS_NAME
                },
                null);

        Type[] argumentTypes = getJoinPointArgumentTypes(joinPointType, calleeMemberSignature);

        incrementStackFrameCounter(cv, joinPointClassName);

        // 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 = aroundAdvice.length;
        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, joinPointClassName, STACK_FRAME_FIELD_NAME, I);
        cv.visitLookupSwitchInsn(defaultCaseLabel, caseNumbers, caseLabels);

        // add one case for each around advice invocation
        for (int i = 0; i < aroundAdvice.length; i++) {
            cv.visitLabel(caseLabels[i]);

            // gather advice info
            AdviceInfo adviceInfo = aroundAdvice[i];
            AspectContainer container = adviceInfo.getAspectManager().getAspectContainer(adviceInfo.getAspectIndex());
            Method adviceMethod = container.getAdvice(adviceInfo.getMethodIndex());
            String aspectClassName = container.getCrossCuttingInfo().getAspectClass().getName().replace('.', '/');
            String aspectFieldName = AROUND_ADVICE_FIELD_PREFIX + i;
            String aspectClassSignature = L + aspectClassName + SEMICOLON;

            // get the aspect instance
            cv.visitFieldInsn(GETSTATIC, joinPointClassName, AROUND_ADVICE_FIELD_PREFIX + i, aspectClassSignature);

            // load the arguments to the advice from the join point instance plus build up the advice method signature
            int[] argIndexes = adviceInfo.getMethodToArgIndexes();
            // if empty, we consider for now that we have to push JoinPoint for old advice with JoinPoint as sole arg
            if (argIndexes.length <= 0) {
                cv.visitVarInsn(ALOAD, 0);
            }
            for (int j = 0; j < argIndexes.length; j++) {
                int argIndex = argIndexes[j];
                if (argIndex != -1) {
                    Type argumentType = argumentTypes[argIndex];
                    cv.visitVarInsn(ALOAD, 0);
                    cv.visitFieldInsn(GETFIELD,
                            joinPointClassName,
                            ARGUMENT_FIELD + argIndex,
                            argumentType.getDescriptor());
                } else {
                    cv.visitVarInsn(ALOAD, 0);
                }
            }

            // invoke the advice method
            cv.visitMethodInsn(INVOKEVIRTUAL,
                    aspectClassName,
                    adviceMethod.getName(),
                    Type.getMethodDescriptor(adviceMethod));

            cv.visitVarInsn(ASTORE, 1);
            cv.visitLabel(returnLabels[i]);

            decrementStackFrameCounter(cv, joinPointClassName);

            cv.visitVarInsn(ALOAD, 1);
            cv.visitInsn(ARETURN);
        }

        // invoke the target join point in the default case
        cv.visitLabel(defaultCaseLabel);
        AsmHelper.prepareWrappingOfPrimitiveType(cv, Type.getReturnType(calleeMemberSignature));

        createJoinPointInvocation(cv,
                joinPointType,
                calleeMemberName,
                joinPointSequence,
                calleeMemberSignature,
                calleeMemberModifiers,
                calleeClassName,
                calleeClassSignature,
                joinPointClassName,
                fieldNames);

        AsmHelper.wrapPrimitiveType(cv, Type.getReturnType(calleeMemberSignature));
        cv.visitVarInsn(ASTORE, 1);

        cv.visitLabel(gotoLabel);

        decrementStackFrameCounter(cv, joinPointClassName);
        cv.visitVarInsn(ALOAD, 1);
        cv.visitInsn(ARETURN);

        // finally clause
        cv.visitLabel(handlerLabel);
        cv.visitVarInsn(ASTORE, 2);
        cv.visitLabel(endLabel);

        decrementStackFrameCounter(cv, joinPointClassName);
        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
     * @param advices
     * @param joinPointClassName
     * @param argumentTypes
     * @param argStartIndex index on stack of first target method arg (0 or 1, depends of static target or not)
     * @param joinPointInstanceIndex >= 0 if STATIC_JOIN_POINT is NOT to be used (around advice)
     */
    private static void addBeforeAdviceInvocations(final CodeVisitor cv,
                                                   final AdviceInfo[] advices,
                                                   final String joinPointClassName,
                                                   final Type[] argumentTypes,
                                                   final int argStartIndex,
                                                   final int joinPointInstanceIndex) {

        for (int i = 0; i < advices.length; i++) {
            AdviceInfo advice = advices[i];
            AspectContainer container = advice.getAspectManager().getAspectContainer(advice.getAspectIndex());
            Method adviceMethod = container.getAdvice(advice.getMethodIndex());
            String aspectClassName = container.getCrossCuttingInfo().getAspectClass().getName().replace('.', '/');
            String aspectFieldName = BEFORE_ADVICE_FIELD_PREFIX + i;
            String aspectClassSignature = L + aspectClassName + SEMICOLON;

            //get the aspect instance
            cv.visitFieldInsn(GETSTATIC, joinPointClassName, aspectFieldName, aspectClassSignature);

            // load the arguments that should be passed to the advice
            int[] argIndexes = advice.getMethodToArgIndexes();
            // if empty, we consider for now that we have to push JoinPoint for old advice with JoinPoint as sole arg
            if (argIndexes.length == 0) {
                if (joinPointInstanceIndex < 0) {
                    // get the static instance of the join point
                    cv.visitFieldInsn(GETSTATIC,
                            joinPointClassName,
                            STATIC_JOIN_POINT_INSTANCE_FIELD_NAME,
                            L + joinPointClassName + SEMICOLON);
                } else {
                    cv.visitVarInsn(ALOAD, joinPointInstanceIndex);
                }
            }
            for (int j = 0; j < argIndexes.length; j++) {
                int argIndex = argIndexes[j];
                if (argIndex != -1) {
                    Type argumentType = argumentTypes[argIndex];
                    int argStackIndex = AsmHelper.getRegisterIndexOf(argumentTypes, argIndex) + argStartIndex;
                    AsmHelper.loadType(cv, argStackIndex, argumentType);
                } else {
                    // TODO handle staticJP etc optimization here
                    //cv.visitVarInsn(ALOAD, joinPointInstanceIndex);
                    if (joinPointInstanceIndex < 0) {
                        // get the static instance of the join point
                        cv.visitFieldInsn(GETSTATIC,
                                joinPointClassName,
                                STATIC_JOIN_POINT_INSTANCE_FIELD_NAME,
                                L + joinPointClassName + SEMICOLON);
                    } else {
                        cv.visitVarInsn(ALOAD, joinPointInstanceIndex);
                    }
                }
            }

            cv.visitMethodInsn(INVOKEVIRTUAL,
                    aspectClassName,
                    adviceMethod.getName(),
                    Type.getMethodDescriptor(adviceMethod));
        }
    }

    /**
     * Adds after advice invocations.
     *
     * @param cv
     * @param advices
     * @param joinPointClassName
     * @param argumentTypes
     * @param argStartIndex index on stack of first target method arg (0 or 1, depends of static target or not)
     * @param joinPointInstanceIndex >= 0 if STATIC_JOIN_POINT is NOT to be used (around advice)
     */
    private static void addAfterAdviceInvocations(final CodeVisitor cv,
                                                  final AdviceInfo[] advices,
                                                  final String joinPointClassName,
                                                  final Type[] argumentTypes,
                                                  final int argStartIndex,
                                                  final int joinPointInstanceIndex) {

        // add after advice in reverse order
        for (int i = advices.length - 1; i >= 0; i--) {
            AdviceInfo advice = advices[i];
            AspectContainer container = advice.getAspectManager().getAspectContainer(advice.getAspectIndex());
            Method adviceMethod = container.getAdvice(advice.getMethodIndex());
            String aspectClassName = container.getCrossCuttingInfo().getAspectClass().getName().replace('.', '/');
            String aspectFieldName = AFTER_ADVICE_FIELD_PREFIX + i;
            String aspectClassSignature = L + aspectClassName + SEMICOLON;

            // get the aspect instance
            cv.visitFieldInsn(GETSTATIC, joinPointClassName, aspectFieldName, aspectClassSignature);

            // load the arguments that should be passed to the advice
            int[] argIndexes = advice.getMethodToArgIndexes();
            // if empty, we consider for now that we have to push JoinPoint for old advice with JoinPoint as sole arg
            if (argIndexes.length == 0) {
                if (joinPointInstanceIndex < 0) {
                    // get the static instance of the join point
                    cv.visitFieldInsn(GETSTATIC,
                            joinPointClassName,
                            STATIC_JOIN_POINT_INSTANCE_FIELD_NAME,
                            L + joinPointClassName + SEMICOLON);
                } else {
                    cv.visitVarInsn(ALOAD, joinPointInstanceIndex);
                }
            }
            for (int j = 0; j < argIndexes.length; j++) {
                int argIndex = argIndexes[j];
                if (argIndex != -1) {
                    Type argumentType = argumentTypes[argIndex];
                    int argStackIndex = AsmHelper.getRegisterIndexOf(argumentTypes, argIndex) + argStartIndex;
                    AsmHelper.loadType(cv, argStackIndex, argumentType);
                } else {
                    // TODO handle staticJP etc optimization here
                    //cv.visitVarInsn(ALOAD, joinPointInstanceIndex);
                    if (joinPointInstanceIndex < 0) {
                        // get the static instance of the join point
                        cv.visitFieldInsn(GETSTATIC,
                                joinPointClassName,
                                STATIC_JOIN_POINT_INSTANCE_FIELD_NAME,
                                L + joinPointClassName + SEMICOLON);
                    } else {
                        cv.visitVarInsn(ALOAD, joinPointInstanceIndex);
                    }
                }
            }

            cv.visitMethodInsn(INVOKEVIRTUAL,
                    aspectClassName,
                    adviceMethod.getName(),
                    Type.getMethodDescriptor(adviceMethod));
        }
    }

    /**
     * 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 joinPointType
     * @param joinPointSequence
     * @param calleeClassName
     * @param calleeMemberName
     * @param calleeMemberSignature
     * @param calleeMemberModifiers
     * @param argumentTypes
     * @param argStartIndex index on stack of first target method arg (0 or 1, depends of static target or not)
     * @TODO refactor
     */
    private static void createInlinedJoinPointInvocation(final CodeVisitor cv,
                                                         final int joinPointType,
                                                         final int joinPointSequence,
                                                         final String calleeClassName,
                                                         final String calleeMemberName,
                                                         final String calleeMemberSignature,
                                                         final int calleeMemberModifiers,
                                                         final Type[] argumentTypes,
                                                         final int argStartIndex) {

        // load the target instance (arg0 else not available for static target)
        if (!Modifier.isStatic(calleeMemberModifiers)) {
            cv.visitVarInsn(ALOAD, 0);
        }
        String joinPointName = null; // can be prefixed
        int argStackIndex = argStartIndex;
        switch (joinPointType) {
            case JoinPointType.METHOD_EXECUTION:
                // load the argument member fields
                for (int index = 0; index < argumentTypes.length; index++) {
                    Type argumentType = argumentTypes[index];
                    argStackIndex = AsmHelper.loadType(cv, argStackIndex, argumentType);
                }
                joinPointName = TransformationUtil.getPrefixedOriginalMethodName(calleeMemberName,
                        joinPointSequence,
                        calleeClassName);
                if (Modifier.isStatic(calleeMemberModifiers)) {
                    cv.visitMethodInsn(INVOKESTATIC, calleeClassName, joinPointName, calleeMemberSignature);
                } else {
                    cv.visitMethodInsn(INVOKEVIRTUAL, calleeClassName, joinPointName, calleeMemberSignature);
                }
                break;

            case JoinPointType.METHOD_CALL:
                // load the argument member fields
                for (int index = 0; index < argumentTypes.length; index++) {
                    Type argumentType = argumentTypes[index];
                    argStackIndex = AsmHelper.loadType(cv, argStackIndex, argumentType);
                }
                // call the package private wrapper method if target method is not public
                if (!Modifier.isPublic(calleeMemberModifiers)) {
                    joinPointName = TransformationUtil.getWrapperMethodName(calleeMemberName,
                            joinPointSequence,
                            calleeClassName);
                } else {
                    joinPointName = calleeMemberName;
                }
                if (Modifier.isStatic(calleeMemberModifiers)) {
                    cv.visitMethodInsn(INVOKESTATIC, calleeClassName, joinPointName, calleeMemberSignature);
                } else {
                    cv.visitMethodInsn(INVOKEVIRTUAL, calleeClassName, joinPointName, calleeMemberSignature);
                }
                break;

            case JoinPointType.CONSTRUCTOR_CALL:
                throw new UnsupportedOperationException("CMH - join point type is not supported: CONSTRUCTOR_CALL");

            case JoinPointType.CONSTRUCTOR_EXECUTION:
                throw new UnsupportedOperationException(
                        "CMH - join point type is not supported: CONSTRUCTOR_EXECUTION");

            case JoinPointType.FIELD_SET:
                joinPointName = calleeMemberName;
                Type fieldType = argumentTypes[0];
                argStackIndex = AsmHelper.loadType(cv, argStackIndex, fieldType);
                if (Modifier.isStatic(calleeMemberModifiers)) {
                    cv.visitFieldInsn(PUTSTATIC, calleeClassName, joinPointName, calleeMemberSignature);
                    cv.visitVarInsn(ALOAD, 0);
                    cv.visitFieldInsn(GETSTATIC, calleeClassName, joinPointName, fieldType.getDescriptor());
                } else {
                    cv.visitFieldInsn(PUTFIELD, calleeClassName, joinPointName, calleeMemberSignature);
                    cv.visitVarInsn(ALOAD, 0);
                    cv.visitFieldInsn(GETFIELD, calleeClassName, joinPointName, fieldType.getDescriptor());
                }
                break;

            case JoinPointType.FIELD_GET:
                joinPointName = calleeMemberName;
                if (Modifier.isStatic(calleeMemberModifiers)) {
                    cv.visitFieldInsn(GETSTATIC, calleeClassName, joinPointName, calleeMemberSignature);
                } else {
                    cv.visitFieldInsn(GETFIELD, calleeClassName, joinPointName, calleeMemberSignature);
                }
                break;


            case JoinPointType.HANDLER:
                throw new UnsupportedOperationException("CMH - join point type is not supported: HANDLER");

            case JoinPointType.STATIC_INITALIZATION:
                throw new UnsupportedOperationException("CMH - join point type is not supported: STATIC_INITALIZATION");
        }
    }

    /**
     * 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
     * @param joinPointType
     * @param joinPointName
     * @param joinPointSequence
     * @param signature
     * @param modifiers
     * @param declaringClassName
     * @param declaringClassSignature
     * @param joinPointClassName
     * @param fieldNames
     */
    private static void createJoinPointInvocation(final CodeVisitor cv,
                                                  final int joinPointType,
                                                  final String joinPointName,
                                                  final int joinPointSequence,
                                                  final String signature,
                                                  final int modifiers,
                                                  final String declaringClassName,
                                                  final String declaringClassSignature,
                                                  final String joinPointClassName,
                                                  final String[] fieldNames) {

        // load the target instance member field
        cv.visitVarInsn(ALOAD, 0);
        cv.visitFieldInsn(GETFIELD, joinPointClassName, CALLEE_INSTANCE_FIELD_NAME, declaringClassSignature);

        if (Modifier.isStatic(modifiers)) {
            cv.visitInsn(POP); // pop the target instance if static context
        }

        // load the argument member fields
        Type[] argumentTypes = getJoinPointArgumentTypes(joinPointType, signature);

        for (int i = 0; i < fieldNames.length; i++) {
            String fieldName = fieldNames[i];
            Type argumentType = argumentTypes[i];
            cv.visitVarInsn(ALOAD, 0);
            cv.visitFieldInsn(GETFIELD, joinPointClassName, fieldName, argumentType.getDescriptor());
        }

        String targetJoinPointName;
        switch (joinPointType) {
            case JoinPointType.METHOD_EXECUTION:
                targetJoinPointName = TransformationUtil.getPrefixedOriginalMethodName(joinPointName,
                        joinPointSequence,
                        declaringClassName);
                if (Modifier.isStatic(modifiers)) {
                    cv.visitMethodInsn(INVOKESTATIC, declaringClassName, targetJoinPointName, signature);
                } else {
                    cv.visitMethodInsn(INVOKEVIRTUAL, declaringClassName, targetJoinPointName, signature);
                }
                break;

            case JoinPointType.METHOD_CALL:
                // call the package private wrapper method if target method is not public
                if (!Modifier.isPublic(modifiers)) {
                    targetJoinPointName = TransformationUtil.getWrapperMethodName(joinPointName,
                            joinPointSequence,
                            declaringClassName);
                } else {
                    targetJoinPointName = joinPointName;
                }
                if (Modifier.isStatic(modifiers)) {
                    cv.visitMethodInsn(INVOKESTATIC, declaringClassName, targetJoinPointName, signature);
                } else {
                    cv.visitMethodInsn(INVOKEVIRTUAL, declaringClassName, targetJoinPointName, signature);
                }
                break;

            case JoinPointType.CONSTRUCTOR_CALL:
                throw new UnsupportedOperationException("CMH - join point type is not supported: CONSTRUCTOR_CALL");

            case JoinPointType.CONSTRUCTOR_EXECUTION:
                throw new UnsupportedOperationException(
                        "CMH - join point type is not supported: CONSTRUCTOR_EXECUTION");

            case JoinPointType.FIELD_SET:
                String fieldName = fieldNames[0];
                Type fieldType = argumentTypes[0];
                if (Modifier.isStatic(modifiers)) {
                    cv.visitFieldInsn(PUTSTATIC, declaringClassName, joinPointName, signature);
                    cv.visitVarInsn(ALOAD, 0);
                    cv.visitFieldInsn(GETSTATIC, joinPointClassName, fieldName, fieldType.getDescriptor());
                } else {
                    cv.visitFieldInsn(PUTFIELD, declaringClassName, joinPointName, signature);
                    cv.visitVarInsn(ALOAD, 0);
                    cv.visitFieldInsn(GETFIELD, joinPointClassName, fieldName, fieldType.getDescriptor());
                }
                break;

            case JoinPointType.FIELD_GET:
                if (Modifier.isStatic(modifiers)) {
                    cv.visitFieldInsn(GETSTATIC, declaringClassName, joinPointName, signature);
                } else {
                    cv.visitFieldInsn(GETFIELD, declaringClassName, joinPointName, signature);
                }
                break;

            case JoinPointType.HANDLER:
                throw new UnsupportedOperationException("CMH - join point type is not supported: HANDLER");

            case JoinPointType.STATIC_INITALIZATION:
                throw new UnsupportedOperationException("CMH - join point type is not supported: STATIC_INITALIZATION");
        }
    }

    /**
     * Resets the stack frame counter.
     *
     * @param cv
     * @param className
     * @TODO: make use of this method
     */
    private static void resetStackFrameCounter(final CodeVisitor cv, final String className) {
        cv.visitVarInsn(ALOAD, 0);
        cv.visitInsn(ICONST_M1);
        cv.visitFieldInsn(PUTFIELD, className, STACK_FRAME_FIELD_NAME, I);
    }

    /**
     * Handles the incrementation of the stack frame.
     *
     * @param cv
     * @param className
     */
    private static void incrementStackFrameCounter(final CodeVisitor cv, final String className) {
        cv.visitVarInsn(ALOAD, 0);
        cv.visitInsn(DUP);
        cv.visitFieldInsn(GETFIELD, className, STACK_FRAME_FIELD_NAME, I);
        cv.visitInsn(ICONST_1);
        cv.visitInsn(IADD);
        cv.visitFieldInsn(PUTFIELD, className, STACK_FRAME_FIELD_NAME, I);
    }

    /**
     * Decrements the stack frame counter.
     *
     * @param cv
     * @param joinPointClassName
     */
    private static void decrementStackFrameCounter(final CodeVisitor cv, final String joinPointClassName) {
        cv.visitVarInsn(ALOAD, 0);
        cv.visitInsn(DUP);
        cv.visitFieldInsn(GETFIELD, joinPointClassName, STACK_FRAME_FIELD_NAME, I);
        cv.visitInsn(ICONST_1);
        cv.visitInsn(ISUB);
        cv.visitFieldInsn(PUTFIELD, joinPointClassName, STACK_FRAME_FIELD_NAME, I);
    }

    /**
     * Returns the join points return type.
     *
     * @param joinPointType
     * @param calleeMemberSignature
     * @return
     */
    private static Type getJoinPointReturnType(final int joinPointType, final String calleeMemberSignature) {
        Type returnType;
        switch (joinPointType) {
            case JoinPointType.HANDLER:
            case JoinPointType.METHOD_EXECUTION:
            case JoinPointType.METHOD_CALL:
            case JoinPointType.CONSTRUCTOR_EXECUTION:
            case JoinPointType.CONSTRUCTOR_CALL:
                returnType = Type.getReturnType(calleeMemberSignature);
                break;
            case JoinPointType.FIELD_SET:
            case JoinPointType.FIELD_GET:
                returnType = Type.getType(calleeMemberSignature);
                break;
            case JoinPointType.STATIC_INITALIZATION:
                throw new UnsupportedOperationException("static init not supported yet");
            default:
                throw new IllegalArgumentException("Illegal join point type: " + joinPointType);
        }
        return returnType;
    }

    /**
     * Returns the join points argument type(s).
     *
     * @param joinPointType
     * @param calleeMemberSignature
     * @return
     */
    private static Type[] getJoinPointArgumentTypes(final int joinPointType, final String calleeMemberSignature) {
        Type[] argumentTypes;
        switch (joinPointType) {
            case JoinPointType.HANDLER:
            case JoinPointType.METHOD_EXECUTION:
            case JoinPointType.METHOD_CALL:
            case JoinPointType.CONSTRUCTOR_EXECUTION:
            case JoinPointType.CONSTRUCTOR_CALL:
                argumentTypes = Type.getArgumentTypes(calleeMemberSignature);
                break;
            case JoinPointType.FIELD_SET:
            case JoinPointType.FIELD_GET:
                argumentTypes = new Type[]{Type.getType(calleeMemberSignature)};
                break;
            case JoinPointType.STATIC_INITALIZATION:
                throw new UnsupportedOperationException("static init not supported yet");
            default:
                throw new IllegalArgumentException("Illegal join point type: " + joinPointType);
        }
        return argumentTypes;
    }

    /**
     * Creates utility methods for the join point (getter, setters etc.).
     *
     * @param cw
     * @param joinPointClassName
     * @param callerClassSignature
     * @param calleeClassSignature
     */
    private static void createUtilityMethods(final ClassWriter cw,
                                             final String joinPointClassName,
                                             final String callerClassSignature,
                                             final String calleeClassSignature) {
        CodeVisitor cv;

        // getSignature
        {
            cv = cw.visitMethod(ACC_PUBLIC,
                    GET_SIGNATURE_METHOD_NAME,
                    GET_SIGNATURE_METHOD_SIGNATURE,
                    null,
                    null);
            cv.visitFieldInsn(GETSTATIC, joinPointClassName, SIGNATURE_FIELD_NAME, SIGNATURE_CLASS_SIGNATURE);
            cv.visitInsn(ARETURN);
            cv.visitMaxs(0, 0);
        }

        // addMetaData
        {
            cv = cw.visitMethod(ACC_PUBLIC, ADD_META_DATA_METHOD_NAME, ADD_META_DATA_METHOD_SIGNATURE, null, null);
            cv.visitFieldInsn(GETSTATIC, 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 = cw.visitMethod(ACC_PUBLIC, GET_META_DATA_METHOD_NAME, GET_META_DATA_METHOD_SIGNATURE, null, null);
            cv.visitFieldInsn(GETSTATIC, 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);
        }

        // getTarget
        {
            // TODO swap depending on PC type, not critical since it is working anyway
            cv = cw.visitMethod(ACC_PUBLIC,
                    GET_TARGET_METHOD_NAME,
                    NO_PARAMS_SIGNATURE + OBJECT_CLASS_SIGNATURE, //calleeClassSignature,
                    null, null);
            cv.visitVarInsn(ALOAD, 0);
            cv.visitFieldInsn(GETFIELD, joinPointClassName, CALLEE_INSTANCE_FIELD_NAME, calleeClassSignature);
            cv.visitInsn(ARETURN);
            cv.visitMaxs(0, 0);
        }

        // getThis
        {
            // TODO swap depending on PC type, not critical since it is working anyway
            cv = cw.visitMethod(ACC_PUBLIC,
                    GET_THIS_METHOD_NAME,
                    NO_PARAMS_SIGNATURE + callerClassSignature,
                    null, null);
            cv.visitVarInsn(ALOAD, 0);
            cv.visitFieldInsn(GETFIELD, joinPointClassName, CALLER_INSTANCE_FIELD_NAME, callerClassSignature);
            cv.visitInsn(ARETURN);
            cv.visitMaxs(0, 0);
        }

        // getTargetClass
        {
            cv =
                    cw.visitMethod(ACC_PUBLIC,
                            GET_TARGET_CLASS_METHOD_NAME,
                            GET_TARGET_CLASS_METHOD_SIGNATURE,
                            null,
                            null);
            cv.visitFieldInsn(GETSTATIC, joinPointClassName, TARGET_CLASS_FIELD_NAME, CLASS_CLASS_SIGNATURE);
            cv.visitInsn(ARETURN);
            cv.visitMaxs(0, 0);
        }

        // getRtti
        {
            // FIXME missing implementation
            cv = cw.visitMethod(ACC_PUBLIC, GET_RTTI_METHOD_NAME, GET_RTTI_METHOD_SIGNATURE, null, null);
            cv.visitInsn(ACONST_NULL);
            cv.visitInsn(ARETURN);
            cv.visitMaxs(0, 0);
        }

        // getType
        {
            // FIXME missing implementation
            cv = cw.visitMethod(ACC_PUBLIC, GET_TYPE_METHOD_NAME, GET_TYPE_METHOD_SIGNATURE, null, null);
            cv.visitInsn(ACONST_NULL);
            cv.visitInsn(ARETURN);
            cv.visitMaxs(0, 0);
        }

        // reset
        {
            // FIXME missing implementation
            cv = cw.visitMethod(ACC_PUBLIC, RESET_METHOD_NAME, NO_PARAM_RETURN_VOID_SIGNATURE, null, null);
            cv.visitInsn(RETURN);
            cv.visitMaxs(0, 0);
        }

        // setTarget
        {
            // FIXME REMOVE from both this class and the JoinPoint interface
            cv = cw.visitMethod(ACC_PUBLIC, "setTarget", "(Ljava/lang/Object;)V", null, null);
            cv.visitInsn(RETURN);
            cv.visitMaxs(0, 0);
        }
    }

    /**
     * Tests if the callee instance is equal to 'this' (and not 'target').
     *
     * @param joinPointType
     * @return boolean
     */
    private static boolean isCalleeEqualToThis(final int joinPointType) {
        return joinPointType == JoinPointType.METHOD_EXECUTION ||
                joinPointType == JoinPointType.CONSTRUCTOR_EXECUTION ||
                joinPointType == JoinPointType.FIELD_GET ||
                joinPointType == JoinPointType.FIELD_SET;
    }

    /**
     * Build up the signature of the 'invoke' methods.
     *
     * @param argumentTypes
     * @param targetClassSignature
     * @param thisClassSignature
     * @param returnType
     * @param calleeMemberModifiers
     * @return
     */
    private static String buildInvokeMethodSignature(final Type[] argumentTypes,
                                                     final String targetClassSignature,
                                                     final String thisClassSignature,
                                                     final Type returnType,
                                                     final int calleeMemberModifiers) {
        StringBuffer invokeDescBuf = new StringBuffer();
        invokeDescBuf.append('(');
        if (!Modifier.isStatic(calleeMemberModifiers)) {
            // callee
            invokeDescBuf.append(targetClassSignature);
        }
        for (int i = 0; i < argumentTypes.length; i++) {
            Type type = argumentTypes[i];
            invokeDescBuf.append(type.getDescriptor());
        }
        // caller
        invokeDescBuf.append(thisClassSignature);
        invokeDescBuf.append(')');
        invokeDescBuf.append(returnType.getDescriptor());
        return invokeDescBuf.toString();
    }

    /**
     * Struct with join point info.
     *
     * @author <a href="mailto:jboner@codehaus.org">Jonas Bon�r </a>
     */
    private static class JoinPointInfo {
        public Signature signature = null;
        public Rtti rtti = null;
        public List cflowExpressions = null;
        public ExpressionContext expressionContext = null;
    }
}
TOP

Related Classes of org.codehaus.aspectwerkz.transform.inlining.JoinPointCompiler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.