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
72
73
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
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
121
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
133
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
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
218
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
245 cv.visitFieldInsn(GETSTATIC, m_ctx.getClassName(), EMITTED_JOINPOINTS_FIELD_NAME, "Lgnu/trove/TIntObjectHashMap;");
246
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 }