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.cflow;
    9
    10  import org.objectweb.asm.Constants;
    11  import org.objectweb.asm.ClassWriter;
    12  import org.objectweb.asm.CodeVisitor;
    13  import org.objectweb.asm.Label;
    14  import org.codehaus.aspectwerkz.transform.TransformationConstants;
    15  import org.codehaus.aspectwerkz.transform.inlining.AsmHelper;
    16  import org.codehaus.aspectwerkz.transform.inlining.compiler.AbstractJoinPointCompiler;
    17
    18  /***
    19   * Compiler for the JIT cflow Aspect
    20   *
    21   * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
    22   */
    23  public class CflowCompiler implements Constants, TransformationConstants {
    24
    25      public final static String JIT_CFLOW_CLASS = "org/codehaus/aspectwerkz/cflow/Cflow_";
    26      private final static String ABSTRACT_CFLOW_CLASS = "org/codehaus/aspectwerkz/cflow/AbstractCflowSystemAspect";
    27      private final static String INSTANCE_CFLOW_FIELD_NAME = "INSTANCE";
    28      private final static String[] EMPTY_STRING_ARRAY = new String[0];
    29      public static final String IN_CFLOW_METOD_NAME = "inCflow";
    30      public static final String IN_CFLOW_METOD_SIGNATURE = "()Z";
    31      public static final String CFLOW_ASPECTOF_METHOD_NAME = "aspectOf";
    32
    33      /***
    34       * Checks if a class name (ASM style) is a cflow name
    35       *
    36       * @param className
    37       * @return
    38       */
    39      public static boolean isCflowClass(String className) {
    40          return className.indexOf(JIT_CFLOW_CLASS) >= 0;
    41      }
    42
    43      /***
    44       * The jit cflow aspect class name (with /)
    45       */
    46      private final String m_className;
    47
    48      /***
    49       * The jit cflow aspect class name (with /)
    50       */
    51      private final String m_classSignature;
    52
    53      private ClassWriter m_cw;
    54
    55      /***
    56       * private ctor
    57       * @param cflowId
    58       */
    59      private CflowCompiler(int cflowId) {
    60          m_className = getCflowAspectClassName(cflowId);
    61          m_classSignature = "L"+m_className+";";
    62      }
    63
    64      /***
    65       * compile the jit cflow aspect
    66       * @return bytecode for the concrete jit cflow aspect
    67       */
    68      private byte[] compile() {
    69          m_cw = AsmHelper.newClassWriter(true);
    70
    71          // class extends AbstractCflowsystemAspect
    72          m_cw.visit(
    73                  AsmHelper.JAVA_VERSION,
    74                  ACC_PUBLIC + ACC_SUPER + ACC_SYNTHETIC,
    75                  m_className,
    76                  ABSTRACT_CFLOW_CLASS,
    77                  EMPTY_STRING_ARRAY,
    78                  null
    79          );
    80
    81          // static INSTANCE field
    82          m_cw.visitField(
    83                  ACC_PRIVATE + ACC_STATIC,
    84                  INSTANCE_CFLOW_FIELD_NAME,
    85                  m_classSignature,
    86                  null,
    87                  null
    88          );
    89
    90          // private ctor
    91          CodeVisitor ctor = m_cw.visitMethod(
    92                  ACC_PRIVATE,
    93                  INIT_METHOD_NAME,
    94                  NO_PARAM_RETURN_VOID_SIGNATURE,
    95                  EMPTY_STRING_ARRAY,
    96                  null
    97          );
    98          // invoke the constructor of abstract
    99          ctor.visitVarInsn(ALOAD, 0);
    100         ctor.visitMethodInsn(INVOKESPECIAL, ABSTRACT_CFLOW_CLASS, INIT_METHOD_NAME, NO_PARAM_RETURN_VOID_SIGNATURE);
    101         ctor.visitInsn(RETURN);
    102         ctor.visitMaxs(0, 0);
    103
    104         // static isInCflow() delegators
    105         CodeVisitor isInCflow = m_cw.visitMethod(
    106                 ACC_PUBLIC + ACC_STATIC,
    107                 IS_IN_CFLOW_METOD_NAME,
    108                 IS_IN_CFLOW_METOD_SIGNATURE,
    109                 EMPTY_STRING_ARRAY,
    110                 null
    111         );
    112         isInCflow.visitFieldInsn(GETSTATIC, m_className, INSTANCE_CFLOW_FIELD_NAME, m_classSignature);
    113         Label isNull = new Label();
    114         isInCflow.visitJumpInsn(IFNULL, isNull);
    115         isInCflow.visitFieldInsn(GETSTATIC, m_className, INSTANCE_CFLOW_FIELD_NAME, m_classSignature);
    116         isInCflow.visitMethodInsn(INVOKEVIRTUAL, ABSTRACT_CFLOW_CLASS, IN_CFLOW_METOD_NAME, IN_CFLOW_METOD_SIGNATURE);
    117         isInCflow.visitInsn(IRETURN);
    118         isInCflow.visitLabel(isNull);
    119         isInCflow.visitInsn(ICONST_0);
    120         isInCflow.visitInsn(IRETURN);
    121         isInCflow.visitMaxs(0, 0);
    122
    123         // static aspectOf()
    124         CodeVisitor aspectOf = m_cw.visitMethod(
    125                 ACC_PUBLIC + ACC_STATIC,
    126                 CFLOW_ASPECTOF_METHOD_NAME,
    127                 "()"+m_classSignature,
    128                 EMPTY_STRING_ARRAY,
    129                 null
    130         );
    131         aspectOf.visitFieldInsn(GETSTATIC, m_className, INSTANCE_CFLOW_FIELD_NAME, m_classSignature);
    132         Label isNotNull = new Label();
    133         aspectOf.visitJumpInsn(IFNONNULL, isNotNull);
    134         aspectOf.visitTypeInsn(NEW, m_className);
    135         aspectOf.visitInsn(DUP);
    136         aspectOf.visitMethodInsn(INVOKESPECIAL, m_className, INIT_METHOD_NAME, NO_PARAM_RETURN_VOID_SIGNATURE);
    137         aspectOf.visitFieldInsn(PUTSTATIC, m_className, INSTANCE_CFLOW_FIELD_NAME, m_classSignature);
    138         aspectOf.visitLabel(isNotNull);
    139         aspectOf.visitFieldInsn(GETSTATIC, m_className, INSTANCE_CFLOW_FIELD_NAME, m_classSignature);
    140         aspectOf.visitInsn(ARETURN);
    141         aspectOf.visitMaxs(0, 0);
    142
    143         m_cw.visitEnd();
    144
    145         return m_cw.toByteArray();
    146     }
    147
    148     /***
    149      * The naming strategy for jit cflow aspect
    150      * @param cflowID
    151      * @return org.codehaus.aspectwerkz.cflow.Cflow_cflowID
    152      */
    153     public static String getCflowAspectClassName(int cflowID) {
    154         return JIT_CFLOW_CLASS + cflowID;
    155     }
    156
    157     /***
    158      * If necessary, compile a jit cflow aspect and attach it to the given classloader
    159      *
    160      * @param loader
    161      * @param cflowID
    162      * @return
    163      */
    164     public static Class compileCflowAspectAndAttachToClassLoader(ClassLoader loader, int cflowID) {
    165         //TODO we need a Class.forName check first to avoid unecessary compilation
    166         // else it will fail in defineClass and fallback on Class.forName ie uneeded compilation
    167         // -> price to pay between compilation + exception in the worse case vs Class.forName each time
    168         CompiledCflowAspect cflowAspect = compileCflowAspect(cflowID);
    169
    170         if (AbstractJoinPointCompiler.DUMP_JIT_CLASSES) {
    171             try {
    172                 AsmHelper.dumpClass("_dump", getCflowAspectClassName(cflowID), cflowAspect.bytecode);
    173             } catch (Throwable t) {;}
    174         }
    175
    176         Class cflowAspectClass = AsmHelper.defineClass(
    177                 loader,
    178                 cflowAspect.bytecode,
    179                 getCflowAspectClassName(cflowID)
    180         );
    181         return cflowAspectClass;
    182     }
    183
    184     /***
    185      * Compile a jit cflow aspect
    186      *
    187      * @param cflowID
    188      * @return
    189      */
    190     public static CompiledCflowAspect compileCflowAspect(int cflowID) {
    191         CompiledCflowAspect cflowAspect = new CompiledCflowAspect();
    192         CflowCompiler compiler = new CflowCompiler(cflowID);
    193         cflowAspect.bytecode = compiler.compile();
    194         cflowAspect.className = compiler.m_className;
    195         return cflowAspect;
    196     }
    197
    198     /***
    199      * Information about a compiled Cflow Aspect
    200      */
    201     public static class CompiledCflowAspect {
    202         public byte[] bytecode;
    203         public String className;// ASM style
    204
    205         public boolean equals(Object o) {
    206             if (this == o) return true;
    207             if (!(o instanceof CompiledCflowAspect)) return false;
    208
    209             final CompiledCflowAspect compiledCflowAspect = (CompiledCflowAspect) o;
    210
    211             if (!className.equals(compiledCflowAspect.className)) return false;
    212
    213             return true;
    214         }
    215
    216         public int hashCode() {
    217             return className.hashCode();
    218         }
    219     }
    220 }