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.ClassAdapter;
    11  import org.objectweb.asm.ClassVisitor;
    12  import org.objectweb.asm.CodeVisitor;
    13  import org.objectweb.asm.Attribute;
    14  import org.objectweb.asm.CodeAdapter;
    15  import org.codehaus.aspectwerkz.transform.Context;
    16  import org.codehaus.aspectwerkz.transform.TransformationConstants;
    17  import org.codehaus.aspectwerkz.transform.inlining.ContextImpl;
    18  import org.codehaus.aspectwerkz.transform.inlining.EmittedJoinPoint;
    19
    20  import java.util.Iterator;
    21
    22  /***
    23   * A ClassAdapter that take care of all weaved class and add the glue between the class and its JIT dependencies.
    24   * <p/>
    25   * Adds a 'private static final Class aw$clazz' field a 'private static void ___AW_$_AW_$initJoinPoints()' method
    26   * and patches the 'clinit' method.
    27   * <p/>
    28   * If the class has been made advisable, we also add a ___AW_$_AW_$emittedJoinPoints fields that gets populated.
    29   *
    30   *
    31   * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur </a>
    32   * @author <a href="mailto:jboner@codehaus.org">Jonas BonŽr </a>
    33   * @TODO: for multi weaving, we could go on in adding several AW initJoinPoints_xxWeaveCount method, but then cannot be
    34   * done with RW
    35   */
    36  public class JoinPointInitVisitor extends ClassAdapter implements TransformationConstants {
    37
    38      private final ContextImpl m_ctx;
    39      private boolean m_hasClinitMethod = false;
    40      private boolean m_hasInitJoinPointsMethod = false;
    41      private boolean m_hasClassField = false;
    42      private boolean m_hasEmittedJoinPointsField = false;
    43
    44      /***
    45       * Creates a new instance.
    46       *
    47       * @param cv
    48       * @param ctx
    49       */
    50      public JoinPointInitVisitor(final ClassVisitor cv, final Context ctx) {
    51          super(cv);
    52          m_ctx = (ContextImpl) ctx;
    53      }
    54
    55      /***
    56       * Visits the methods. If the AW joinPointsInit method is found, remember that, it means we are in a multi-weaving
    57       * scheme. Patch the 'clinit' method if already present.
    58       *
    59       * @TODO: multi-weaving will lead to several invocation of AW initJoinPoints and several assigment of __AW_Clazz in the patched clinit which slows down a bit the load time
    60       * @see org.objectweb.asm.ClassVisitor#visitMethod(int, java.lang.String, java.lang.String, java.lang.String[],
    61              *      org.objectweb.asm.Attribute)
    62       */
    63      public CodeVisitor visitMethod(final int access,
    64                                     final String name,
    65                                     final String desc,
    66                                     final String[] exceptions,
    67                                     final Attribute attrs) {
    68
    69          if (CLINIT_METHOD_NAME.equals(name)) {
    70              m_hasClinitMethod = true;
    71              // at the beginning of the existing <clinit> method
    72              //      ___AWClazz = Class.forName("TargetClassName");
    73              //      ___AW_$_AW_$initJoinPoints();
    74              CodeVisitor ca = new InsertBeforeClinitCodeAdapter(cv.visitMethod(access, name, desc, exceptions, attrs));
    75              ca.visitMaxs(0, 0);
    76              return ca;
    77
    78          } else if (INIT_JOIN_POINTS_METHOD_NAME.equals(name)) {
    79              m_hasInitJoinPointsMethod = true;
    80              // add the gathered JIT dependencies for multi-weaving support
    81              CodeVisitor ca = new InsertBeforeInitJoinPointsCodeAdapter(
    82                      cv.visitMethod(access, name, desc, exceptions, attrs)
    83              );
    84              ca.visitMaxs(0, 0);
    85              return ca;
    86          } else {
    87              return super.visitMethod(access, name, desc, exceptions, attrs);
    88          }
    89      }
    90
    91      /***
    92       * Remember if we have already the static class field for multi-weaving scheme.
    93       *
    94       * @param access
    95       * @param name
    96       * @param desc
    97       * @param value
    98       * @param attrs
    99       */
    100     public void visitField(int access, String name, String desc, Object value, Attribute attrs) {
    101         if (TARGET_CLASS_FIELD_NAME.equals(name)) {
    102             m_hasClassField = true;
    103         } else if (EMITTED_JOINPOINTS_FIELD_NAME.equals(name)) {
    104             m_hasEmittedJoinPointsField = true;
    105         }
    106         super.visitField(access, name, desc, value, attrs);
    107     }
    108
    109     /***
    110      * Finalize the visit. Add static class field if needed, add initJoinPoints method if needed, add <clinit>if
    111      * needed.
    112      */
    113     public void visitEnd() {
    114         if (!m_ctx.isAdvised()) {
    115             super.visitEnd();
    116             return;
    117         }
    118
    119         if (!m_hasClassField) {
    120             // create field
    121             //      private final static Class aw$clazz = Class.forName("TargetClassName");
    122             cv.visitField(
    123                     ACC_PRIVATE + ACC_FINAL + ACC_STATIC + ACC_SYNTHETIC,
    124                     TARGET_CLASS_FIELD_NAME,
    125                     CLASS_CLASS_SIGNATURE,
    126                     null,
    127                     null
    128             );
    129         }
    130
    131         if (!m_hasEmittedJoinPointsField && m_ctx.isMadeAdvisable()) {
    132             // create field
    133             //      private final static Class aw$emittedJoinPoints that will host a Trove int Object map
    134             cv.visitField(
    135                     ACC_PRIVATE + ACC_FINAL + ACC_STATIC + ACC_SYNTHETIC,
    136                     EMITTED_JOINPOINTS_FIELD_NAME,
    137                     "Lgnu/trove/TIntObjectHashMap;",
    138                     null,
    139                     null
    140             );
    141         }
    142
    143         if (!m_hasClinitMethod) {
    144             CodeVisitor ca = new InsertBeforeClinitCodeAdapter(
    145                     cv.visitMethod(
    146                             ACC_STATIC,
    147                             CLINIT_METHOD_NAME,
    148                             NO_PARAMS_RETURN_VOID_METHOD_SIGNATURE,
    149                             null,
    150                             null
    151                     )
    152             );
    153             ca.visitInsn(RETURN);
    154             ca.visitMaxs(0, 0);
    155         }
    156
    157         if (!m_hasInitJoinPointsMethod) {
    158             CodeVisitor mv = new InsertBeforeInitJoinPointsCodeAdapter(
    159                     cv.visitMethod(
    160                             ACC_PRIVATE + ACC_FINAL + ACC_STATIC + ACC_SYNTHETIC,
    161                             INIT_JOIN_POINTS_METHOD_NAME,
    162                             NO_PARAMS_RETURN_VOID_METHOD_SIGNATURE,
    163                             null,
    164                             null
    165                     )
    166             );
    167             mv.visitInsn(RETURN);
    168             mv.visitMaxs(0, 0);
    169         }
    170
    171         cv.visitEnd();
    172     }
    173
    174     /***
    175      * Handles the method body of the <clinit>method.
    176      *
    177      * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur </a>
    178      */
    179     public class InsertBeforeClinitCodeAdapter extends CodeAdapter {
    180
    181         public InsertBeforeClinitCodeAdapter(CodeVisitor ca) {
    182             super(ca);
    183             if (!m_hasClassField) {
    184                 cv.visitLdcInsn(m_ctx.getClassName().replace('/', '.'));
    185                 cv.visitMethodInsn(INVOKESTATIC, CLASS_CLASS, FOR_NAME_METHOD_NAME, FOR_NAME_METHOD_SIGNATURE);
    186                 cv.visitFieldInsn(PUTSTATIC, m_ctx.getClassName(), TARGET_CLASS_FIELD_NAME, CLASS_CLASS_SIGNATURE);
    187             }
    188             if (!m_hasEmittedJoinPointsField && m_ctx.isMadeAdvisable()) {
    189                 // aw$emittedJoinPoints = new TIntObjectHashMap()
    190                 cv.visitTypeInsn(NEW, "gnu/trove/TIntObjectHashMap");
    191                 cv.visitInsn(DUP);
    192                 cv.visitMethodInsn(INVOKESPECIAL, "gnu/trove/TIntObjectHashMap", "<init>", "()V");
    193                 cv.visitFieldInsn(PUTSTATIC, m_ctx.getClassName(), EMITTED_JOINPOINTS_FIELD_NAME, "Lgnu/trove/TIntObjectHashMap;");
    194             }
    195             if (!m_hasClassField) {
    196                 cv.visitMethodInsn(
    197                         INVOKESTATIC,
    198                         m_ctx.getClassName(),
    199                         INIT_JOIN_POINTS_METHOD_NAME,
    200                         NO_PARAMS_RETURN_VOID_METHOD_SIGNATURE
    201                 );
    202             }
    203         }
    204     }
    205
    206     /***
    207      * Handles the method body of the AW initJoinPoints method.
    208      *
    209      * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur </a>
    210      * @author <a href="mailto:jboner@codehaus.org">Jonas BonŽr </a>
    211      */
    212     public class InsertBeforeInitJoinPointsCodeAdapter extends CodeAdapter {
    213
    214         public InsertBeforeInitJoinPointsCodeAdapter(CodeVisitor ca) {
    215             super(ca);
    216
    217             // loop over emitted jp and insert call to "JoinPointManager.loadJoinPoint(...)"
    218             // add calls to aw$emittedJoinPoints.put(.. new EmittedJoinPoint) if needed.
    219             for (Iterator iterator = m_ctx.getEmittedJoinPoints().iterator(); iterator.hasNext();) {
    220
    221                 EmittedJoinPoint jp = (EmittedJoinPoint) iterator.next();
    222                 cv.visitLdcInsn(new Integer(jp.getJoinPointType()));
    223
    224                 cv.visitFieldInsn(GETSTATIC, m_ctx.getClassName(), TARGET_CLASS_FIELD_NAME, CLASS_CLASS_SIGNATURE);
    225                 cv.visitLdcInsn(jp.getCallerMethodName());
    226                 cv.visitLdcInsn(jp.getCallerMethodDesc());
    227                 cv.visitLdcInsn(new Integer(jp.getCallerMethodModifiers()));
    228
    229                 cv.visitLdcInsn(jp.getCalleeClassName());
    230                 cv.visitLdcInsn(jp.getCalleeMemberName());
    231                 cv.visitLdcInsn(jp.getCalleeMemberDesc());
    232                 cv.visitLdcInsn(new Integer(jp.getCalleeMemberModifiers()));
    233
    234                 cv.visitLdcInsn(new Integer(jp.getJoinPointHash()));
    235                 cv.visitLdcInsn(jp.getJoinPointClassName());
    236                 cv.visitMethodInsn(
    237                         INVOKESTATIC,
    238                         JOIN_POINT_MANAGER_CLASS_NAME,
    239                         LOAD_JOIN_POINT_METHOD_NAME,
    240                         LOAD_JOIN_POINT_METHOD_SIGNATURE
    241                 );
    242
    243                 if (m_ctx.isMadeAdvisable()) {
    244                     // trove map
    245                     cv.visitFieldInsn(GETSTATIC, m_ctx.getClassName(), EMITTED_JOINPOINTS_FIELD_NAME, "Lgnu/trove/TIntObjectHashMap;");
    246                     // trove map key
    247                     cv.visitLdcInsn(new Integer(jp.getJoinPointClassName().hashCode()));
    248
    249
    250                     cv.visitTypeInsn(NEW, "org/codehaus/aspectwerkz/transform/inlining/EmittedJoinPoint");
    251                     cv.visitInsn(DUP);
    252
    253                     cv.visitLdcInsn(new Integer(jp.getJoinPointType()));
    254
    255                     cv.visitLdcInsn(m_ctx.getClassName());
    256                     cv.visitLdcInsn(jp.getCallerMethodName());
    257                     cv.visitLdcInsn(jp.getCallerMethodDesc());
    258                     cv.visitLdcInsn(new Integer(jp.getCallerMethodModifiers()));
    259
    260                     cv.visitLdcInsn(jp.getCalleeClassName());
    261                     cv.visitLdcInsn(jp.getCalleeMemberName());
    262                     cv.visitLdcInsn(jp.getCalleeMemberDesc());
    263                     cv.visitLdcInsn(new Integer(jp.getCalleeMemberModifiers()));
    264
    265                     cv.visitLdcInsn(new Integer(jp.getJoinPointHash()));
    266                     cv.visitLdcInsn(jp.getJoinPointClassName());
    267
    268                     cv.visitMethodInsn(INVOKESPECIAL, "org/codehaus/aspectwerkz/transform/inlining/EmittedJoinPoint", "<init>",
    269                             "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;IILjava/lang/String;)V"
    270                             );
    271                     cv.visitMethodInsn(
    272                             INVOKEVIRTUAL,
    273                             "gnu/trove/TIntObjectHashMap",
    274                             "put",
    275                             "(ILjava/lang/Object;)Ljava/lang/Object;"
    276                     );
    277                 }
    278             }
    279         }
    280     }
    281
    282 }