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 }