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
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
82 m_cw.visitField(
83 ACC_PRIVATE + ACC_STATIC,
84 INSTANCE_CFLOW_FIELD_NAME,
85 m_classSignature,
86 null,
87 null
88 );
89
90
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
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
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
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
166
167
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;
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 }