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.weaver;
    9
    10  import org.objectweb.asm.Constants;
    11  import org.objectweb.asm.ClassAdapter;
    12  import org.objectweb.asm.ClassVisitor;
    13  import org.objectweb.asm.CodeVisitor;
    14  import org.objectweb.asm.Type;
    15  import org.objectweb.asm.Attribute;
    16  import org.codehaus.aspectwerkz.transform.Context;
    17  import org.codehaus.aspectwerkz.transform.TransformationUtil;
    18  import org.codehaus.aspectwerkz.transform.TransformationConstants;
    19  import org.codehaus.aspectwerkz.transform.inlining.ContextImpl;
    20  import org.codehaus.aspectwerkz.transform.inlining.EmittedJoinPoint;
    21  import org.codehaus.aspectwerkz.transform.inlining.AsmHelper;
    22  import org.codehaus.aspectwerkz.joinpoint.management.JoinPointType;
    23
    24  import java.util.List;
    25  import java.util.Iterator;
    26  import java.util.Set;
    27  import java.lang.reflect.Modifier;
    28
    29  /***
    30   * Adds field and method wrappers when there has been at least one joinpoint emitted.
    31   *
    32   * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
    33   * @author <a href="mailto:jboner@codehaus.org">Jonas Bonér </a>
    34   */
    35  public class AddWrapperVisitor extends ClassAdapter implements Constants, TransformationConstants {
    36
    37      private ContextImpl m_context;
    38
    39      private Set m_addedMethods;
    40
    41
    42      public AddWrapperVisitor(ClassVisitor classVisitor, Context context, Set alreadyAddedMethods) {
    43          super(classVisitor);
    44          m_context = (ContextImpl) context;
    45          m_addedMethods = alreadyAddedMethods;
    46      }
    47
    48      /***
    49       * Visits the class.
    50       *
    51       * @param access
    52       * @param name
    53       * @param superName
    54       * @param interfaces
    55       * @param sourceFile
    56       */
    57      public void visit(final int version, final int access,
    58                        final String name,
    59                        final String superName,
    60                        final String[] interfaces,
    61                        final String sourceFile) {
    62          // iterate on the emitted joinpoints
    63          // we don't need to filter more since the joinpoint type and the weaving phase did that for us
    64          List jps = m_context.getEmittedJoinPoints();
    65          for (Iterator iterator = jps.iterator(); iterator.hasNext();) {
    66              EmittedJoinPoint emittedJoinPoint = (EmittedJoinPoint) iterator.next();
    67              int jpType = emittedJoinPoint.getJoinPointType();
    68              String calleeName = emittedJoinPoint.getCalleeMemberName();
    69              if (Modifier.isPublic(emittedJoinPoint.getCalleeMemberModifiers())
    70                  || !name.equals(emittedJoinPoint.getCalleeClassName())) {//TODO ?
    71                  continue;
    72              }
    73              switch (jpType) {
    74                  case (JoinPointType.FIELD_GET_INT) :
    75                      createGetFieldWrapperMethod(
    76                              Modifier.isStatic(emittedJoinPoint.getCalleeMemberModifiers()),
    77                              name,
    78                              emittedJoinPoint.getCalleeMemberName(),
    79                              emittedJoinPoint.getCalleeMemberDesc()
    80                      );
    81                      break;
    82                  case (JoinPointType.FIELD_SET_INT) :
    83                          createPutFieldWrapperMethod(
    84                                  Modifier.isStatic(emittedJoinPoint.getCalleeMemberModifiers()),
    85                                  name,
    86                                  emittedJoinPoint.getCalleeMemberName(),
    87                                  emittedJoinPoint.getCalleeMemberDesc()
    88                          );
    89                      break;
    90                  case (JoinPointType.METHOD_EXECUTION_INT) :
    91                  case (JoinPointType.METHOD_CALL_INT) :
    92                      createMethodWrapperMethod(
    93                              emittedJoinPoint.getCalleeMemberModifiers(),
    94                              name,
    95                              emittedJoinPoint.getCalleeMemberName(),
    96                              emittedJoinPoint.getCalleeMemberDesc(),
    97                              new String[0],//TODO should throw Throwable ??
    98                              null//TODO do we need the attr ??
    99                      );
    100                     break;
    101             }
    102         }
    103
    104         super.visit(version, access, name, superName, interfaces, sourceFile);
    105     }
    106
    107     /***
    108      * Creates a public wrapper method that delegates to the GETFIELD instruction of the non-public field.
    109      *
    110      * @param isStaticField
    111      * @param declaringTypeName
    112      * @param name
    113      * @param desc
    114      */
    115     private void createGetFieldWrapperMethod(final boolean isStaticField,
    116                                              final String declaringTypeName,
    117                                              final String name,
    118                                              final String desc) {
    119         String wrapperName = TransformationUtil.getWrapperMethodName(
    120                 name, desc, declaringTypeName, GETFIELD_WRAPPER_METHOD_PREFIX
    121         );
    122
    123         StringBuffer signature = new StringBuffer();
    124         signature.append('(');
    125         signature.append(')');
    126         signature.append(desc);
    127
    128         final String wrapperKey = AlreadyAddedMethodAdapter.getMethodKey(wrapperName, signature.toString());
    129         if (m_addedMethods.contains(wrapperKey)) {
    130             return;
    131         }
    132         m_addedMethods.add(wrapperKey);
    133
    134         int modifiers = ACC_SYNTHETIC;
    135         if (isStaticField) {
    136             modifiers |= ACC_STATIC;
    137         }
    138
    139         CodeVisitor mv = cv.visitMethod(
    140                 modifiers,
    141                 wrapperName,
    142                 signature.toString(),
    143                 new String[]{},
    144                 null
    145         );
    146
    147         if (isStaticField) {
    148             mv.visitFieldInsn(GETSTATIC, declaringTypeName, name, desc);
    149         } else {
    150             mv.visitVarInsn(ALOAD, 0);
    151             mv.visitFieldInsn(GETFIELD, declaringTypeName, name, desc);
    152         }
    153
    154         AsmHelper.addReturnStatement(mv, Type.getType(desc));
    155         mv.visitMaxs(0, 0);
    156     }
    157
    158     /***
    159      * Creates a public wrapper method that delegates to the PUTFIELD instruction of the non-public field.
    160      * Static method if field is static (PUTSTATIC instr)
    161      *
    162      * @param isStaticField
    163      * @param declaringTypeName
    164      * @param name
    165      * @param desc
    166      */
    167     private void createPutFieldWrapperMethod(boolean isStaticField,
    168                                              final String declaringTypeName,
    169                                              final String name,
    170                                              final String desc) {
    171         String wrapperName = TransformationUtil.getWrapperMethodName(
    172                 name, desc, declaringTypeName, PUTFIELD_WRAPPER_METHOD_PREFIX
    173         );
    174
    175         StringBuffer signature = new StringBuffer();
    176         signature.append('(');
    177         signature.append(desc);
    178         signature.append(')');
    179         signature.append('V');
    180
    181         final String wrapperKey = AlreadyAddedMethodAdapter.getMethodKey(wrapperName, signature.toString());
    182         if (m_addedMethods.contains(wrapperKey)) {
    183             return;
    184         }
    185         m_addedMethods.add(wrapperKey);
    186
    187         int modifiers = ACC_SYNTHETIC;
    188         if (isStaticField) {
    189             modifiers |= ACC_STATIC;
    190         }
    191
    192         CodeVisitor mv = cv.visitMethod(
    193                 modifiers,
    194                 wrapperName,
    195                 signature.toString(),
    196                 new String[]{},
    197                 null
    198         );
    199
    200         Type fieldType = Type.getType(desc);
    201         if (isStaticField) {
    202             AsmHelper.loadArgumentTypes(mv, new Type[]{fieldType}, true);
    203             mv.visitFieldInsn(PUTSTATIC, declaringTypeName, name, desc);
    204         } else {
    205             mv.visitVarInsn(ALOAD, 0);
    206             AsmHelper.loadArgumentTypes(mv, new Type[]{fieldType}, false);
    207             mv.visitFieldInsn(PUTFIELD, declaringTypeName, name, desc);
    208         }
    209
    210         AsmHelper.addReturnStatement(mv, Type.VOID_TYPE);
    211         mv.visitMaxs(0, 0);
    212     }
    213
    214     /***
    215      * Creates a public wrapper method that delegates to the non-public target method.
    216      *
    217      * @param access
    218      * @param declaringTypeName
    219      * @param name
    220      * @param desc
    221      * @param exceptions
    222      * @param attrs
    223      */
    224     private void createMethodWrapperMethod(final int access,
    225                                            final String declaringTypeName,
    226                                            final String name,
    227                                            final String desc,
    228                                            final String[] exceptions,
    229                                            final Attribute attrs) {
    230         final String wrapperName = TransformationUtil.getWrapperMethodName(
    231                 name, desc, declaringTypeName, INVOKE_WRAPPER_METHOD_PREFIX
    232         );
    233
    234         final String wrapperKey = AlreadyAddedMethodAdapter.getMethodKey(wrapperName, desc);
    235         if (m_addedMethods.contains(wrapperKey)) {
    236             return;
    237         }
    238         m_addedMethods.add(wrapperKey);
    239
    240         int modifiers = ACC_SYNTHETIC;
    241         if (Modifier.isStatic(access)) {
    242             modifiers |= ACC_STATIC;
    243         }
    244
    245         CodeVisitor mv = super.visitMethod(
    246                 modifiers,
    247                 wrapperName,
    248                 desc,
    249                 exceptions,
    250                 attrs
    251         );
    252
    253         if (Modifier.isStatic(access)) {
    254             AsmHelper.loadArgumentTypes(mv, Type.getArgumentTypes(desc), Modifier.isStatic(access));
    255             mv.visitMethodInsn(INVOKESTATIC, declaringTypeName, name, desc);
    256         } else {
    257             mv.visitVarInsn(ALOAD, 0);
    258             AsmHelper.loadArgumentTypes(mv, Type.getArgumentTypes(desc), Modifier.isStatic(access));
    259             mv.visitMethodInsn(INVOKEVIRTUAL, declaringTypeName, name, desc);
    260         }
    261
    262         AsmHelper.addReturnStatement(mv, Type.getReturnType(desc));
    263
    264         mv.visitMaxs(0, 0);
    265     }
    266
    267 }