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.compiler.AbstractJoinPointCompiler;
    15  import org.codehaus.aspectwerkz.transform.inlining.AsmHelper;
    16
    17  import java.lang.reflect.Modifier;
    18
    19  /***
    20   * A compiler that compiles/generates a class that represents a specific join point, a class which invokes the advices
    21   * and the target join point statically.
    22   *
    23   * @author <a href="mailto:jboner@codehaus.org">Jonas BonŽr </a>
    24   * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur </a>
    25   */
    26  public class FieldSetJoinPointCompiler extends AbstractJoinPointCompiler {
    27
    28      /***
    29       * Creates a new join point compiler instance.
    30       *
    31       * @param model
    32       */
    33      FieldSetJoinPointCompiler(final CompilationInfo.Model model) {
    34          super(model);
    35      }
    36
    37      /***
    38       * Creates join point specific fields.
    39       */
    40      protected void createJoinPointSpecificFields() {
    41          String[] fieldNames = null;
    42          // create the field argument field
    43          Type fieldType = Type.getType(m_calleeMemberDesc);
    44          fieldNames = new String[1];
    45          String fieldName = ARGUMENT_FIELD + 0;
    46          fieldNames[0] = fieldName;
    47          m_cw.visitField(ACC_PRIVATE, fieldName, fieldType.getDescriptor(), null, null);
    48          m_fieldNames = fieldNames;
    49
    50          m_cw.visitField(
    51                  ACC_PRIVATE + ACC_STATIC,
    52                  SIGNATURE_FIELD_NAME,
    53                  FIELD_SIGNATURE_IMPL_CLASS_SIGNATURE,
    54                  null,
    55                  null
    56          );
    57      }
    58
    59      /***
    60       * Creates the signature for the join point.
    61       * <p/>
    62       * FIXME signature field should NOT be of type Signature but of the specific type (update all refs as well)
    63       *
    64       * @param cv
    65       */
    66      protected void createSignature(final CodeVisitor cv) {
    67          cv.visitFieldInsn(GETSTATIC, m_joinPointClassName, TARGET_CLASS_FIELD_NAME, CLASS_CLASS_SIGNATURE);
    68          cv.visitLdcInsn(new Integer(m_joinPointHash));
    69
    70          cv.visitMethodInsn(
    71                  INVOKESTATIC,
    72                  SIGNATURE_FACTORY_CLASS,
    73                  NEW_FIELD_SIGNATURE_METHOD_NAME,
    74                  NEW_FIELD_SIGNATURE_METHOD_SIGNATURE
    75          );
    76          cv.visitFieldInsn(PUTSTATIC, m_joinPointClassName, SIGNATURE_FIELD_NAME, FIELD_SIGNATURE_IMPL_CLASS_SIGNATURE);
    77      }
    78
    79      /***
    80       * Optimized implementation that does not retrieve the parameters from the join point instance but is passed
    81       * directly to the method from the input parameters in the 'invoke' method. Can only be used if no around advice
    82       * exists.
    83       *
    84       * @param cv
    85       * @param argStartIndex index on stack of first target method arg (0 or 1, depends of static target or not)
    86       */
    87      protected void createInlinedJoinPointInvocation(final CodeVisitor cv, final boolean isOptimizedJoinPoint,
    88                                                      final int argStartIndex, final int joinPointIndex) {
    89
    90          // load the target instance (arg0 else not available for static target)
    91          if (!Modifier.isStatic(m_calleeMemberModifiers)) {
    92              cv.visitVarInsn(ALOAD, 0);
    93          }
    94
    95          loadArgumentMemberFields(cv, argStartIndex);
    96
    97          // do we have a public field ? If so don't use the wrappers
    98          if (Modifier.isPublic(m_calleeMemberModifiers)) {
    99              if (Modifier.isStatic(m_calleeMemberModifiers)) {
    100                 cv.visitFieldInsn(PUTSTATIC, m_calleeClassName, m_calleeMemberName, m_calleeMemberDesc);
    101             } else {
    102                 cv.visitFieldInsn(PUTFIELD, m_calleeClassName, m_calleeMemberName, m_calleeMemberDesc);
    103             }
    104         } else {
    105             String joinPointName = null; // can be prefixed
    106             joinPointName = m_calleeMemberName;
    107             joinPointName = TransformationUtil.getWrapperMethodName(
    108                     joinPointName,
    109                     m_calleeMemberDesc,
    110                     m_calleeClassName,
    111                     PUTFIELD_WRAPPER_METHOD_PREFIX
    112             );
    113             StringBuffer sig = new StringBuffer();
    114             sig.append('(');
    115             sig.append(m_calleeMemberDesc);
    116             sig.append(')');
    117             sig.append('V');
    118             if (Modifier.isStatic(m_calleeMemberModifiers)) {
    119                 cv.visitMethodInsn(INVOKESTATIC, m_calleeClassName, joinPointName, sig.toString());
    120             } else {
    121                 cv.visitMethodInsn(INVOKEVIRTUAL, m_calleeClassName, joinPointName, sig.toString());
    122             }
    123         }
    124
    125         AsmHelper.addDefaultValue(cv, m_argumentTypes[0]);
    126     }
    127
    128     /***
    129      * Creates a call to the target join point, the parameter(s) to the join point are retrieved from the invocation
    130      * local join point instance.
    131      *
    132      * @param cv
    133      */
    134     protected void createJoinPointInvocation(final CodeVisitor cv) {
    135
    136         // load the target instance member field unless calleeMember is static
    137         if (!Modifier.isStatic(m_calleeMemberModifiers)) {
    138             cv.visitVarInsn(ALOAD, 0);
    139             cv.visitFieldInsn(GETFIELD, m_joinPointClassName, CALLEE_INSTANCE_FIELD_NAME, m_calleeClassSignature);
    140         }
    141
    142         loadArguments(cv);
    143
    144         // do we have a public field ? If so don't use the wrappers
    145         if (Modifier.isPublic(m_calleeMemberModifiers)) {
    146             if (Modifier.isStatic(m_calleeMemberModifiers)) {
    147                 cv.visitFieldInsn(PUTSTATIC, m_calleeClassName, m_calleeMemberName, m_calleeMemberDesc);
    148             } else {
    149                 cv.visitFieldInsn(PUTFIELD, m_calleeClassName, m_calleeMemberName, m_calleeMemberDesc);
    150             }
    151         } else {
    152             String joinPointName = TransformationUtil.getWrapperMethodName(
    153                     m_calleeMemberName,
    154                     m_calleeMemberDesc,
    155                     m_calleeClassName,
    156                     PUTFIELD_WRAPPER_METHOD_PREFIX
    157             );
    158             StringBuffer putFieldWrapperDesc = new StringBuffer();
    159             putFieldWrapperDesc.append('(');
    160             putFieldWrapperDesc.append(m_calleeMemberDesc);
    161             putFieldWrapperDesc.append(')');
    162             putFieldWrapperDesc.append('V');
    163             if (Modifier.isStatic(m_calleeMemberModifiers)) {
    164                 cv.visitMethodInsn(INVOKESTATIC, m_calleeClassName, joinPointName, putFieldWrapperDesc.toString());
    165             } else {
    166                 cv.visitMethodInsn(INVOKEVIRTUAL, m_calleeClassName, joinPointName, putFieldWrapperDesc.toString());
    167             }
    168         }
    169
    170         AsmHelper.addDefaultValue(cv, m_argumentTypes[0]);
    171     }
    172
    173     /***
    174      * Returns the join points return type.
    175      *
    176      * @return
    177      */
    178     protected Type getJoinPointReturnType() {
    179         return Type.getType(m_calleeMemberDesc);
    180     }
    181
    182     /***
    183      * Returns the join points argument type(s).
    184      *
    185      * @return
    186      */
    187     protected Type[] getJoinPointArgumentTypes() {
    188         return new Type[]{Type.getType(m_calleeMemberDesc)};
    189     }
    190
    191     /***
    192      * Creates the getRtti method
    193      */
    194     protected void createGetRttiMethod() {
    195         CodeVisitor cv = m_cw.visitMethod(ACC_PUBLIC, GET_RTTI_METHOD_NAME, GET_RTTI_METHOD_SIGNATURE, null, null);
    196
    197         // new FieldRttiImpl( .. )
    198         cv.visitTypeInsn(NEW, FIELD_RTTI_IMPL_CLASS_NAME);
    199         cv.visitInsn(DUP);
    200         cv.visitFieldInsn(GETSTATIC, m_joinPointClassName, SIGNATURE_FIELD_NAME, FIELD_SIGNATURE_IMPL_CLASS_SIGNATURE);
    201         cv.visitVarInsn(ALOAD, 0);
    202         cv.visitFieldInsn(GETFIELD, m_joinPointClassName, CALLER_INSTANCE_FIELD_NAME, m_callerClassSignature);
    203         cv.visitVarInsn(ALOAD, 0);
    204         cv.visitFieldInsn(GETFIELD, m_joinPointClassName, CALLEE_INSTANCE_FIELD_NAME, m_calleeClassSignature);
    205         cv.visitMethodInsn(
    206                 INVOKESPECIAL, FIELD_RTTI_IMPL_CLASS_NAME, INIT_METHOD_NAME, FIELD_RTTI_IMPL_INIT_SIGNATURE
    207         );
    208
    209         // set the value
    210         cv.visitInsn(DUP);
    211         if (AsmHelper.isPrimitive(m_returnType)) {
    212             AsmHelper.prepareWrappingOfPrimitiveType(cv, m_returnType);
    213             cv.visitVarInsn(ALOAD, 0);
    214             cv.visitFieldInsn(GETFIELD, m_joinPointClassName, RETURN_VALUE_FIELD_NAME, m_returnType.getDescriptor());
    215             AsmHelper.wrapPrimitiveType(cv, m_returnType);
    216         } else {
    217             cv.visitVarInsn(ALOAD, 0);
    218             cv.visitFieldInsn(GETFIELD, m_joinPointClassName, RETURN_VALUE_FIELD_NAME, m_returnType.getDescriptor());
    219         }
    220         cv.visitMethodInsn(
    221                 INVOKEVIRTUAL,
    222                 FIELD_RTTI_IMPL_CLASS_NAME,
    223                 SET_FIELD_VALUE_METHOD_NAME,
    224                 SET_FIELD_VALUE_METHOD_SIGNATURE
    225         );
    226
    227         cv.visitInsn(ARETURN);
    228         cv.visitMaxs(0, 0);
    229     }
    230
    231     /***
    232      * Creates the getSignature method.
    233      */
    234     protected void createGetSignatureMethod() {
    235         CodeVisitor cv = m_cw.visitMethod(
    236                 ACC_PUBLIC,
    237                 GET_SIGNATURE_METHOD_NAME,
    238                 GET_SIGNATURE_METHOD_SIGNATURE,
    239                 null,
    240                 null
    241         );
    242         cv.visitFieldInsn(
    243                 GETSTATIC, m_joinPointClassName,
    244                 SIGNATURE_FIELD_NAME, FIELD_SIGNATURE_IMPL_CLASS_SIGNATURE
    245         );
    246         cv.visitInsn(ARETURN);
    247         cv.visitMaxs(0, 0);
    248     }
    249 }