View Javadoc

    1   /***************************************************************************************
    2    * Copyright (c) Jonas BonŽr, Alexandre Vasseur. All rights reserved.                 *
    3    * http://aspectwerkz.codehaus.org                                                    *
    4    * ---------------------------------------------------------------------------------- *
    5    * The software in this package is published under the terms of the LGPL license      *
    6    * a copy of which has been included with this distribution in the license.txt file.  *
    7    **************************************************************************************/
    8   package org.codehaus.aspectwerkz.transform.inlining.compiler;
    9
    10  import org.objectweb.asm.CodeVisitor;
    11  import org.objectweb.asm.Type;
    12
    13  import org.codehaus.aspectwerkz.transform.TransformationUtil;
    14  import org.codehaus.aspectwerkz.transform.inlining.AsmHelper;
    15
    16  import java.lang.reflect.Modifier;
    17
    18  /***
    19   * A compiler that compiles/generates a class that represents a specific join point, a class which invokes the advices
    20   * and the target join point statically.
    21   *
    22   * @author <a href="mailto:jboner@codehaus.org">Jonas BonŽr </a>
    23   * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur </a>
    24   */
    25  public class MethodCallJoinPointCompiler extends AbstractJoinPointCompiler {
    26
    27      /***
    28       * Creates a new join point compiler instance.
    29       *
    30       * @param model
    31       */
    32      MethodCallJoinPointCompiler(final CompilationInfo.Model model) {
    33          super(model);
    34      }
    35
    36      /***
    37       * Creates join point specific fields.
    38       */
    39      protected void createJoinPointSpecificFields() {
    40          String[] fieldNames = null;
    41          // create the method argument fields
    42          Type[] argumentTypes = Type.getArgumentTypes(m_calleeMemberDesc);
    43          fieldNames = new String[argumentTypes.length];
    44          for (int i = 0; i < argumentTypes.length; i++) {
    45              Type argumentType = argumentTypes[i];
    46              String fieldName = ARGUMENT_FIELD + i;
    47              fieldNames[i] = fieldName;
    48              m_cw.visitField(ACC_PRIVATE, fieldName, argumentType.getDescriptor(), null, null);
    49          }
    50          m_fieldNames = fieldNames;
    51
    52          m_cw.visitField(
    53                  ACC_PRIVATE + ACC_STATIC,
    54                  SIGNATURE_FIELD_NAME,
    55                  METHOD_SIGNATURE_IMPL_CLASS_SIGNATURE,
    56                  null,
    57                  null
    58          );
    59      }
    60
    61      /***
    62       * Creates the signature for the join point.
    63       * <p/>
    64       * FIXME signature field should NOT be of type Signature but of the specific type (update all refs as well)
    65       *
    66       * @param cv
    67       */
    68      protected void createSignature(final CodeVisitor cv) {
    69          cv.visitFieldInsn(GETSTATIC, m_joinPointClassName, TARGET_CLASS_FIELD_NAME, CLASS_CLASS_SIGNATURE);
    70          cv.visitLdcInsn(new Integer(m_joinPointHash));
    71
    72
    73          cv.visitMethodInsn(
    74                  INVOKESTATIC,
    75                  SIGNATURE_FACTORY_CLASS,
    76                  NEW_METHOD_SIGNATURE_METHOD_NAME,
    77                  NEW_METHOD_SIGNATURE_METHOD_SIGNATURE
    78          );
    79          cv.visitFieldInsn(
    80                  PUTSTATIC, m_joinPointClassName, SIGNATURE_FIELD_NAME, METHOD_SIGNATURE_IMPL_CLASS_SIGNATURE
    81          );
    82
    83      }
    84
    85      /***
    86       * Optimized implementation that does not retrieve the parameters from the join point instance but is passed
    87       * directly to the method from the input parameters in the 'invoke' method. Can only be used if no around advice
    88       * exists.
    89       *
    90       * @param cv
    91       * @param argStartIndex index on stack of first target method arg (0 or 1, depends of static target or not)
    92       */
    93      protected void createInlinedJoinPointInvocation(final CodeVisitor cv, final boolean isOptimizedJoinPoint,
    94                                                      final int argStartIndex, final int joinPointIndex) {
    95
    96          // load the target instance (arg0 else not available for static target)
    97          if (!Modifier.isStatic(m_calleeMemberModifiers)) {
    98              cv.visitVarInsn(ALOAD, 0);
    99          }
    100
    101         String joinPointName = null; // can be prefixed
    102
    103         loadArgumentMemberFields(cv, argStartIndex);
    104
    105         // call the package protected wrapper method if target method is not public
    106         if (!Modifier.isPublic(m_calleeMemberModifiers)) {
    107             joinPointName = TransformationUtil.getWrapperMethodName(
    108                     m_calleeMemberName,
    109                     m_calleeMemberDesc,
    110                     m_calleeClassName,
    111                     INVOKE_WRAPPER_METHOD_PREFIX
    112             );
    113         } else {
    114             joinPointName = m_calleeMemberName;
    115         }
    116         // FIXME - pbly broken if we are using a wrapper method - refactor this if / else
    117         if (Modifier.isStatic(m_calleeMemberModifiers)) {
    118             cv.visitMethodInsn(INVOKESTATIC, m_calleeClassName, joinPointName, m_calleeMemberDesc);
    119         } else if (isInvokeInterface(m_calleeMemberModifiers)) {
    120             // AW-253
    121             cv.visitMethodInsn(INVOKEINTERFACE, m_calleeClassName, joinPointName, m_calleeMemberDesc);
    122         } else {
    123             cv.visitMethodInsn(INVOKEVIRTUAL, m_calleeClassName, joinPointName, m_calleeMemberDesc);
    124         }
    125     }
    126
    127     /***
    128      * Creates a call to the target join point, the parameter(s) to the join point are retrieved from the invocation
    129      * local join point instance.
    130      *
    131      * @param cv
    132      */
    133     protected void createJoinPointInvocation(final CodeVisitor cv) {
    134
    135         // load the target instance member field unless calleeMember is static
    136         if (!Modifier.isStatic(m_calleeMemberModifiers)) {
    137             cv.visitVarInsn(ALOAD, 0);
    138             cv.visitFieldInsn(GETFIELD, m_joinPointClassName, CALLEE_INSTANCE_FIELD_NAME, m_calleeClassSignature);
    139         }
    140
    141         String joinPointName;
    142         loadArguments(cv);
    143         if (!Modifier.isPublic(m_calleeMemberModifiers)) {
    144             joinPointName = TransformationUtil.getWrapperMethodName(
    145                     m_calleeMemberName,
    146                     m_calleeMemberDesc,
    147                     m_calleeClassName,
    148                     INVOKE_WRAPPER_METHOD_PREFIX
    149             );
    150         } else {
    151             joinPointName = m_calleeMemberName;
    152         }
    153         // FIXME - pbly broken if we are using a wrapper method - refactor this if / else
    154         if (Modifier.isStatic(m_calleeMemberModifiers)) {
    155             cv.visitMethodInsn(INVOKESTATIC, m_calleeClassName, joinPointName, m_calleeMemberDesc);
    156         } else if (isInvokeInterface(m_calleeMemberModifiers)) {
    157             // AW-253
    158             cv.visitMethodInsn(INVOKEINTERFACE, m_calleeClassName, joinPointName, m_calleeMemberDesc);
    159         } else {
    160             cv.visitMethodInsn(INVOKEVIRTUAL, m_calleeClassName, joinPointName, m_calleeMemberDesc);
    161         }
    162     }
    163
    164     /***
    165      * Returns the join points return type.
    166      *
    167      * @return
    168      */
    169     protected Type getJoinPointReturnType() {
    170         return Type.getReturnType(m_calleeMemberDesc);
    171     }
    172
    173     /***
    174      * Returns the join points argument type(s).
    175      *
    176      * @return
    177      */
    178     protected Type[] getJoinPointArgumentTypes() {
    179         return Type.getArgumentTypes(m_calleeMemberDesc);
    180     }
    181
    182     /***
    183      * Creates the getRtti method
    184      */
    185     protected void createGetRttiMethod() {
    186         CodeVisitor cv = m_cw.visitMethod(ACC_PUBLIC, GET_RTTI_METHOD_NAME, GET_RTTI_METHOD_SIGNATURE, null, null);
    187
    188         // new MethodRttiImpl( .. )
    189         cv.visitTypeInsn(NEW, METHOD_RTTI_IMPL_CLASS_NAME);
    190         cv.visitInsn(DUP);
    191         cv.visitFieldInsn(
    192                 GETSTATIC, m_joinPointClassName, SIGNATURE_FIELD_NAME, METHOD_SIGNATURE_IMPL_CLASS_SIGNATURE
    193         );
    194         cv.visitVarInsn(ALOAD, 0);
    195         cv.visitFieldInsn(GETFIELD, m_joinPointClassName, CALLER_INSTANCE_FIELD_NAME, m_callerClassSignature);
    196         cv.visitVarInsn(ALOAD, 0);
    197         cv.visitFieldInsn(GETFIELD, m_joinPointClassName, CALLEE_INSTANCE_FIELD_NAME, m_calleeClassSignature);
    198         cv.visitMethodInsn(
    199                 INVOKESPECIAL, METHOD_RTTI_IMPL_CLASS_NAME, INIT_METHOD_NAME, METHOD_RTTI_IMPL_INIT_SIGNATURE
    200         );
    201
    202         // set the arguments
    203         cv.visitInsn(DUP);
    204         createArgumentArrayAt(cv, 1);
    205         cv.visitVarInsn(ALOAD, 1);
    206         cv.visitMethodInsn(
    207                 INVOKEVIRTUAL, METHOD_RTTI_IMPL_CLASS_NAME, SET_PARAMETER_VALUES_METHOD_NAME,
    208                 SET_PARAMETER_VALUES_METHOD_SIGNATURE
    209         );
    210
    211         // set the Returned instance
    212         if (m_returnType.getSort() != Type.VOID) {
    213             cv.visitInsn(DUP);
    214             if (AsmHelper.isPrimitive(m_returnType)) {
    215                 AsmHelper.prepareWrappingOfPrimitiveType(cv, m_returnType);
    216                 cv.visitVarInsn(ALOAD, 0);
    217                 cv.visitFieldInsn(
    218                         GETFIELD, m_joinPointClassName, RETURN_VALUE_FIELD_NAME, m_returnType.getDescriptor()
    219                 );
    220                 AsmHelper.wrapPrimitiveType(cv, m_returnType);
    221             } else {
    222                 cv.visitVarInsn(ALOAD, 0);
    223                 cv.visitFieldInsn(
    224                         GETFIELD, m_joinPointClassName, RETURN_VALUE_FIELD_NAME, m_returnType.getDescriptor()
    225                 );
    226             }
    227             cv.visitMethodInsn(
    228                     INVOKEVIRTUAL, METHOD_RTTI_IMPL_CLASS_NAME, SET_RETURN_VALUE_METHOD_NAME,
    229                     SET_RETURN_VALUE_METHOD_SIGNATURE
    230             );
    231         }
    232
    233         cv.visitInsn(ARETURN);
    234         cv.visitMaxs(0, 0);
    235     }
    236
    237     /***
    238      * Creates the getSignature method.
    239      */
    240     protected void createGetSignatureMethod() {
    241         CodeVisitor cv = m_cw.visitMethod(
    242                 ACC_PUBLIC,
    243                 GET_SIGNATURE_METHOD_NAME,
    244                 GET_SIGNATURE_METHOD_SIGNATURE,
    245                 null,
    246                 null
    247         );
    248
    249         cv.visitFieldInsn(
    250                 GETSTATIC, m_joinPointClassName,
    251                 SIGNATURE_FIELD_NAME, METHOD_SIGNATURE_IMPL_CLASS_SIGNATURE
    252         );
    253         cv.visitInsn(ARETURN);
    254         cv.visitMaxs(0, 0);
    255     }
    256
    257     /***
    258      * See AW-253
    259      * For INVOKE INTERFACE, we are using a custom modifier to track it down in order to avoid to do the
    260      * hierarchy resolution ourself here
    261      */
    262     private boolean isInvokeInterface(int modifier) {
    263         return (modifier & MODIFIER_INVOKEINTERFACE) != 0;
    264     }
    265 }