KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > aspectwerkz > transform > inlining > weaver > JoinPointInitVisitor


1 /*
2  * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
3  */

4 package com.tc.aspectwerkz.transform.inlining.weaver;
5
6 import com.tc.asm.*;
7
8 import com.tc.aspectwerkz.transform.InstrumentationContext;
9 import com.tc.aspectwerkz.transform.TransformationConstants;
10 import com.tc.aspectwerkz.transform.inlining.EmittedJoinPoint;
11
12 import java.util.Iterator JavaDoc;
13
14 /**
15  * A ClassAdapter that take care of all weaved class and add the glue between the class and its JIT dependencies.
16  * <p/>
17  * Adds a 'private static final Class aw$clazz' field a 'private static void ___AW_$_AW_$initJoinPoints()' method
18  * and patches the 'clinit' method.
19  * <p/>
20  * If the class has been made advisable, we also add a ___AW_$_AW_$emittedJoinPoints fields that gets populated.
21  *
22  * @author <a HREF="mailto:alex@gnilux.com">Alexandre Vasseur </a>
23  * @author <a HREF="mailto:jboner@codehaus.org">Jonas Bonér </a>
24  * TODO: for multi weaving, we could go on in adding several AW initJoinPoints_xxWeaveCount method, but then cannot be
25  * done with RW
26  */

27 public class JoinPointInitVisitor extends ClassAdapter implements TransformationConstants {
28
29   private final InstrumentationContext m_ctx;
30   private boolean m_hasClinitMethod = false;
31   private boolean m_hasInitJoinPointsMethod = false;
32   private boolean m_hasClassField = false;
33   private boolean m_hasEmittedJoinPointsField = false;
34
35   /**
36    * Creates a new instance.
37    *
38    * @param cv
39    * @param ctx
40    */

41   public JoinPointInitVisitor(final ClassVisitor cv, final InstrumentationContext ctx) {
42     super(cv);
43     m_ctx = ctx;
44   }
45
46   /**
47    * Visits the methods. If the AW joinPointsInit method is found, remember that, it means we are in a multi-weaving
48    * scheme. Patch the 'clinit' method if already present.
49    * <p/>
50    * 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
51    *
52    * @see org.objectweb.asm.ClassVisitor#visitMethod(int, String, String, String, String[])
53    */

54   public MethodVisitor visitMethod(final int access,
55                                    final String JavaDoc name,
56                                    final String JavaDoc desc,
57                                    final String JavaDoc signature,
58                                    final String JavaDoc[] exceptions) {
59
60     if (CLINIT_METHOD_NAME.equals(name)) {
61       m_hasClinitMethod = true;
62       // at the beginning of the existing <clinit> method
63
// ___AWClazz = Class.forName("TargetClassName");
64
// ___AW_$_AW_$initJoinPoints();
65
MethodVisitor ca = new InsertBeforeClinitCodeAdapter(cv.visitMethod(access, name, desc, signature, exceptions));
66       ca.visitMaxs(0, 0);
67       return ca;
68
69     } else if (INIT_JOIN_POINTS_METHOD_NAME.equals(name)) {
70       m_hasInitJoinPointsMethod = true;
71       // add the gathered JIT dependencies for multi-weaving support
72
MethodVisitor ca = new InsertBeforeInitJoinPointsCodeAdapter(
73               cv.visitMethod(access, name, desc, signature, exceptions)
74       );
75       ca.visitMaxs(0, 0);
76       return ca;
77     } else {
78       return super.visitMethod(access, name, desc, signature, exceptions);
79     }
80   }
81
82   /**
83    * Remember if we have already the static class field for multi-weaving scheme.
84    *
85    * @param access
86    * @param name
87    * @param desc
88    * @param signature
89    * @param value
90    */

91   public FieldVisitor visitField(int access, String JavaDoc name, String JavaDoc desc, String JavaDoc signature, Object JavaDoc value) {
92     if (TARGET_CLASS_FIELD_NAME.equals(name)) {
93       m_hasClassField = true;
94     } else if (EMITTED_JOINPOINTS_FIELD_NAME.equals(name)) {
95       m_hasEmittedJoinPointsField = true;
96     }
97     return super.visitField(access, name, desc, signature, value);
98   }
99
100   /**
101    * Finalize the visit. Add static class field if needed, add initJoinPoints method if needed, add <clinit>if
102    * needed.
103    */

104   public void visitEnd() {
105     if (!m_ctx.isAdvised()) {
106       super.visitEnd();
107       return;
108     }
109
110     if (!m_hasClassField && !m_ctx.isProxy()) {
111       // create field
112
// private final static Class aw$clazz = Class.forName("TargetClassName");
113
cv.visitField(
114               ACC_PRIVATE + ACC_FINAL + ACC_STATIC + ACC_SYNTHETIC,
115               TARGET_CLASS_FIELD_NAME,
116               CLASS_CLASS_SIGNATURE,
117               null,
118               null
119       );
120     }
121
122     if (!m_hasEmittedJoinPointsField && (m_ctx.isMadeAdvisable() || m_ctx.isProxy())) {
123       // create field
124
// private final static Class aw$emittedJoinPoints that will host an int to Object map
125
cv.visitField(
126               ACC_PRIVATE + ACC_FINAL + ACC_STATIC + ACC_SYNTHETIC,
127               EMITTED_JOINPOINTS_FIELD_NAME,
128               "Ljava/util/HashMap;",
129               null,
130               null
131       );
132     }
133
134     if (!m_hasClinitMethod) {
135       MethodVisitor ca = new InsertBeforeClinitCodeAdapter(
136               cv.visitMethod(
137                       ACC_STATIC,
138                       CLINIT_METHOD_NAME,
139                       NO_PARAM_RETURN_VOID_SIGNATURE,
140                       null,
141                       null
142               )
143       );
144       ca.visitInsn(RETURN);
145       ca.visitMaxs(0, 0);
146     }
147
148     if (!m_hasInitJoinPointsMethod) {
149       MethodVisitor mv = new InsertBeforeInitJoinPointsCodeAdapter(
150               cv.visitMethod(
151                       ACC_PRIVATE + ACC_FINAL + ACC_STATIC + ACC_SYNTHETIC,
152                       INIT_JOIN_POINTS_METHOD_NAME,
153                       NO_PARAM_RETURN_VOID_SIGNATURE,
154                       null,
155                       null
156               )
157       );
158       mv.visitInsn(RETURN);
159       mv.visitMaxs(0, 0);
160     }
161
162     cv.visitEnd();
163   }
164
165   /**
166    * Handles the method body of the <clinit>method.
167    *
168    * @author <a HREF="mailto:alex@gnilux.com">Alexandre Vasseur </a>
169    */

170   public class InsertBeforeClinitCodeAdapter extends MethodAdapter {
171
172     public InsertBeforeClinitCodeAdapter(MethodVisitor ca) {
173       super(ca);
174       if (!m_hasClassField && !m_ctx.isProxy()) {
175         mv.visitLdcInsn(m_ctx.getClassName().replace('/', '.'));
176         mv.visitMethodInsn(INVOKESTATIC, CLASS_CLASS, FOR_NAME_METHOD_NAME, FOR_NAME_METHOD_SIGNATURE);
177         mv.visitFieldInsn(PUTSTATIC, m_ctx.getClassName(), TARGET_CLASS_FIELD_NAME, CLASS_CLASS_SIGNATURE);
178       }
179       if (!m_hasEmittedJoinPointsField && (m_ctx.isMadeAdvisable() || m_ctx.isProxy())) {
180         // aw$emittedJoinPoints = new HashMap()
181
mv.visitTypeInsn(NEW, "java/util/HashMap");
182         mv.visitInsn(DUP);
183         mv.visitMethodInsn(INVOKESPECIAL, "java/util/HashMap", "<init>", "()V");
184         mv.visitFieldInsn(PUTSTATIC, m_ctx.getClassName(), EMITTED_JOINPOINTS_FIELD_NAME, "Ljava/util/HashMap;");
185       }
186       if (!m_hasClassField) {
187         mv.visitMethodInsn(
188                 INVOKESTATIC,
189                 m_ctx.getClassName(),
190                 INIT_JOIN_POINTS_METHOD_NAME,
191                 NO_PARAM_RETURN_VOID_SIGNATURE
192         );
193       }
194     }
195   }
196
197   /**
198    * Handles the method body of the AW initJoinPoints method.
199    *
200    * @author <a HREF="mailto:alex@gnilux.com">Alexandre Vasseur </a>
201    * @author <a HREF="mailto:jboner@codehaus.org">Jonas Bonér </a>
202    */

203   public class InsertBeforeInitJoinPointsCodeAdapter extends MethodAdapter {
204
205     public InsertBeforeInitJoinPointsCodeAdapter(MethodVisitor ca) {
206       super(ca);
207
208       // loop over emitted jp and insert call to "JoinPointManager.loadJoinPoint(...)"
209
// add calls to aw$emittedJoinPoints.put(.. new EmittedJoinPoint) if needed.
210
for (Iterator JavaDoc iterator = m_ctx.getEmittedJoinPoints().iterator(); iterator.hasNext();) {
211
212         EmittedJoinPoint jp = (EmittedJoinPoint) iterator.next();
213
214         // do not add the call to loadJoinPoint if we are doing proxy weaving
215
// (since eagerly loaded already)
216
if (!m_ctx.isProxy()) {
217           mv.visitLdcInsn(new Integer JavaDoc(jp.getJoinPointType()));
218           mv.visitFieldInsn(GETSTATIC, m_ctx.getClassName(), TARGET_CLASS_FIELD_NAME, CLASS_CLASS_SIGNATURE);
219           mv.visitLdcInsn(jp.getCallerMethodName());
220           mv.visitLdcInsn(jp.getCallerMethodDesc());
221           mv.visitLdcInsn(new Integer JavaDoc(jp.getCallerMethodModifiers()));
222           mv.visitLdcInsn(jp.getCalleeClassName());
223           mv.visitLdcInsn(jp.getCalleeMemberName());
224           mv.visitLdcInsn(jp.getCalleeMemberDesc());
225           mv.visitLdcInsn(new Integer JavaDoc(jp.getCalleeMemberModifiers()));
226           mv.visitLdcInsn(new Integer JavaDoc(jp.getJoinPointHash()));
227           mv.visitLdcInsn(jp.getJoinPointClassName());
228           mv.visitMethodInsn(
229                   INVOKESTATIC,
230                   JOIN_POINT_MANAGER_CLASS_NAME,
231                   LOAD_JOIN_POINT_METHOD_NAME,
232                   LOAD_JOIN_POINT_METHOD_SIGNATURE
233           );
234         }
235
236         // add map with emitted JP if advisable or proxy weaving
237
if (m_ctx.isMadeAdvisable() || m_ctx.isProxy()) {
238           // emittedJoinPoints map
239
mv.visitFieldInsn(GETSTATIC, m_ctx.getClassName(), EMITTED_JOINPOINTS_FIELD_NAME, "Ljava/util/HashMap;");
240           // "boxed" map key
241
mv.visitTypeInsn(NEW, "java/lang/Integer");
242           mv.visitInsn(DUP);
243           mv.visitLdcInsn(new Integer JavaDoc(jp.getJoinPointClassName().hashCode()));
244           mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Integer", "<init>", "(I)V");
245
246           mv.visitTypeInsn(NEW, "com/tc/aspectwerkz/transform/inlining/EmittedJoinPoint");
247           mv.visitInsn(DUP);
248
249           mv.visitLdcInsn(new Integer JavaDoc(jp.getJoinPointType()));
250
251           mv.visitLdcInsn(m_ctx.getClassName());
252           mv.visitLdcInsn(jp.getCallerMethodName());
253           mv.visitLdcInsn(jp.getCallerMethodDesc());
254           mv.visitLdcInsn(new Integer JavaDoc(jp.getCallerMethodModifiers()));
255
256           mv.visitLdcInsn(jp.getCalleeClassName());
257           mv.visitLdcInsn(jp.getCalleeMemberName());
258           mv.visitLdcInsn(jp.getCalleeMemberDesc());
259           mv.visitLdcInsn(new Integer JavaDoc(jp.getCalleeMemberModifiers()));
260
261           mv.visitLdcInsn(new Integer JavaDoc(jp.getJoinPointHash()));
262           mv.visitLdcInsn(jp.getJoinPointClassName());
263
264           mv.visitMethodInsn(INVOKESPECIAL, "com/tc/aspectwerkz/transform/inlining/EmittedJoinPoint", "<init>",
265                   "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;IILjava/lang/String;)V"
266           );
267           mv.visitMethodInsn(
268                   INVOKEVIRTUAL,
269                   "java/util/HashMap",
270                   "put",
271                   "(ILjava/lang/Object;)Ljava/lang/Object;"
272           );
273         }
274       }
275     }
276   }
277 }
Popular Tags