KickJava   Java API By Example, From Geeks To Geeks.

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


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.ClassAdapter;
7 import com.tc.asm.ClassVisitor;
8 import com.tc.asm.MethodVisitor;
9 import com.tc.asm.Type;
10 import com.tc.asm.MethodAdapter;
11
12 import com.tc.aspectwerkz.definition.SystemDefinition;
13 import com.tc.aspectwerkz.joinpoint.management.JoinPointType;
14 import com.tc.aspectwerkz.transform.InstrumentationContext;
15 import com.tc.aspectwerkz.transform.TransformationConstants;
16 import com.tc.aspectwerkz.transform.TransformationUtil;
17 import com.tc.aspectwerkz.transform.inlining.AsmHelper;
18 import com.tc.aspectwerkz.transform.inlining.EmittedJoinPoint;
19 import com.tc.aspectwerkz.reflect.ClassInfo;
20 import com.tc.aspectwerkz.reflect.ConstructorInfo;
21 import com.tc.aspectwerkz.expression.ExpressionContext;
22 import com.tc.aspectwerkz.expression.PointcutType;
23
24 import java.util.Iterator JavaDoc;
25 import java.util.Set JavaDoc;
26
27 /**
28  * Handles constructor execution weaving.
29  * For each matching ctor, a static method is added with the same signature and with the extra thisClass parameter
30  * prepended to the list. Then the orginal ctor body is changed to call the JP.invoke, only after call to this / super
31  * initializers.
32  * <p/>
33  * TODO rename in ..execution..
34  *
35  * @author <a HREF="mailto:alex@gnilux.com">Alexandre Vasseur</a>
36  */

37 public class ConstructorBodyVisitor extends ClassAdapter implements TransformationConstants {
38
39   private final InstrumentationContext m_ctx;
40   private final ClassInfo m_calleeClassInfo;
41   private String JavaDoc m_declaringTypeName;
42   private Set JavaDoc m_addedMethods;
43
44   /**
45    * Creates a new instance.
46    *
47    * @param cv
48    * @param classInfo
49    * @param ctx
50    * @param addedMethods
51    */

52   public ConstructorBodyVisitor(final ClassVisitor cv,
53                                 final ClassInfo classInfo,
54                                 final InstrumentationContext ctx,
55                                 final Set JavaDoc addedMethods) {
56     super(cv);
57     m_calleeClassInfo = classInfo;
58     m_ctx = (InstrumentationContext) ctx;
59     m_addedMethods = addedMethods;
60   }
61
62   /**
63    * Visits the class.
64    *
65    * @param access
66    * @param name
67    * @param signature
68    * @param superName
69    * @param interfaces
70    */

71   public void visit(final int version,
72                     final int access,
73                     final String JavaDoc name,
74                     final String JavaDoc signature,
75                     final String JavaDoc superName,
76                     final String JavaDoc[] interfaces) {
77     m_declaringTypeName = name;
78     super.visit(version, access, name, signature, superName, interfaces);
79   }
80
81   /**
82    * @param access
83    * @param name
84    * @param desc
85    * @param signature
86    * @param exceptions
87    * @return
88    */

89   public MethodVisitor visitMethod(int access,
90                                    String JavaDoc name,
91                                    String JavaDoc desc,
92                                    String JavaDoc signature,
93                                    String JavaDoc[] exceptions) {
94     if (!INIT_METHOD_NAME.equals(name)) {
95       return super.visitMethod(access, name, desc, signature, exceptions);
96     }
97
98     int hash = AsmHelper.calculateConstructorHash(desc);
99     ConstructorInfo constructorInfo = m_calleeClassInfo.getConstructor(hash);
100     if (constructorInfo == null) {
101       System.err.println(
102               "AW::WARNING " +
103                       "metadata structure could not be build for constructor ["
104                       + m_calleeClassInfo.getName().replace('/', '.')
105                       + ".<init>: " + desc + ']'
106       );
107       return cv.visitMethod(access, name, desc, signature, exceptions);
108     }
109
110     ExpressionContext ctx = new ExpressionContext(PointcutType.EXECUTION, constructorInfo, constructorInfo);
111
112     if (constructorFilter(m_ctx.getDefinitions(), ctx)) {
113       return cv.visitMethod(access, name, desc, signature, exceptions);
114     } else {
115       String JavaDoc wrapperName = TransformationUtil.getConstructorBodyMethodName(m_declaringTypeName);
116       String JavaDoc wrapperDesc = TransformationUtil.getConstructorBodyMethodSignature(desc, m_declaringTypeName);
117       if (m_addedMethods.contains(AlreadyAddedMethodAdapter.getMethodKey(wrapperName, wrapperDesc))) {
118         return cv.visitMethod(access, name, desc, signature, exceptions);
119       }
120
121       m_ctx.markAsAdvised();
122
123       // create the proxy constructor for the original constructor
124
MethodVisitor proxyCtorMethodVisitor = cv.visitMethod(access, name, desc, signature, exceptions);
125       // create the ctorBodyMethod for the original constructor body
126
int modifiers = ACC_SYNTHETIC | ACC_STATIC;
127       MethodVisitor ctorBodyMethodMethodVisitor = cv.visitMethod(
128               modifiers, wrapperName, wrapperDesc, signature, exceptions
129       );
130
131       // return a dispatch Code Adapter in between the orginal one and both of them
132
return new DispatchCtorBodyCodeAdapter(proxyCtorMethodVisitor, ctorBodyMethodMethodVisitor, access, desc);
133     }
134   }
135
136
137   /**
138    * Creates the "proxy constructor" join point invocation body
139    *
140    * @param ctorProxy
141    * @param access
142    * @param desc
143    */

144   private void insertJoinPointInvoke(final MethodVisitor ctorProxy,
145                                      final int access,
146                                      final String JavaDoc desc) {
147     // load "this"
148
ctorProxy.visitVarInsn(ALOAD, 0);// is too simple f.e. when DUP was used
149
// load args
150
AsmHelper.loadArgumentTypes(ctorProxy, Type.getArgumentTypes(desc), false);
151
152     // caller = callee
153
ctorProxy.visitVarInsn(ALOAD, 0);
154
155     int joinPointHash = AsmHelper.calculateConstructorHash(desc);
156     String JavaDoc joinPointClassName = TransformationUtil.getJoinPointClassName(
157             m_declaringTypeName,
158             INIT_METHOD_NAME,
159             desc,
160             m_declaringTypeName,
161             JoinPointType.CONSTRUCTOR_EXECUTION_INT,
162             joinPointHash
163     );
164
165     ctorProxy.visitMethodInsn(
166             INVOKESTATIC,
167             joinPointClassName,
168             INVOKE_METHOD_NAME,
169             TransformationUtil.getInvokeSignatureForCodeJoinPoints(
170                     access, desc, m_declaringTypeName, m_declaringTypeName
171             )
172     );
173
174     // emit the joinpoint
175
m_ctx.addEmittedJoinPoint(
176             new EmittedJoinPoint(
177                     JoinPointType.CONSTRUCTOR_EXECUTION_INT,
178                     m_declaringTypeName,
179                     TransformationConstants.INIT_METHOD_NAME,
180                     desc,
181                     access,
182                     m_declaringTypeName,
183                     TransformationConstants.INIT_METHOD_NAME,
184                     desc,
185                     access,
186                     joinPointHash,
187                     joinPointClassName,
188                     EmittedJoinPoint.NO_LINE_NUMBER
189             )
190     );
191   }
192
193   /**
194    * Filters out the constructor that are not eligible for transformation.
195    *
196    * @param definitions
197    * @param ctx
198    * @return boolean true if the constructor should be filtered out
199    */

200   public static boolean constructorFilter(final Set JavaDoc definitions,
201                                           final ExpressionContext ctx) {
202     for (Iterator JavaDoc it = definitions.iterator(); it.hasNext();) {
203       if (((SystemDefinition) it.next()).hasPointcut(ctx)) {
204         return false;
205       } else {
206         continue;
207       }
208     }
209     return true;
210   }
211
212   /**
213    * A class that dispatch the ctor body instruction to any other given code visitor
214    * </p>
215    * The behavior is like this:
216    * 1/ as long as the INVOKESPECIAL for the object initialization has not been reached, every bytecode
217    * instruction is dispatched in the ctor code visitor. [note 1]
218    * 2/ when this one is reached, it is only added in the ctor code visitor and a JP invoke is added
219    * 3/ after that, only the other code visitor receives the instructions
220    * </p>
221    * [note 1] To support schemes like http://java.sun.com/docs/books/vmspec/2nd-edition/html/ClassFile.doc.html#9839
222    * where the stack is like ALOAD_0 + DUP, we handle a special case.
223    * f.e. CGlib proxy ctor are like that..
224    * Don't know if some other info can be left on the stack (f.e. ILOAD 1, DUP ...)
225    */

226   private class DispatchCtorBodyCodeAdapter extends MethodAdapter {
227     private MethodVisitor m_ctorBodyMethodMethodVisitor;
228     private MethodVisitor m_proxyCtorMethodVisitor;
229     private final int m_constructorAccess;
230     private final String JavaDoc m_constructorDesc;
231
232     private int m_newCount = 0;
233
234     private boolean m_proxyCtorCodeDone = false;
235     private boolean m_isALOADDUPHeuristic = false;
236     private int m_index = -1;
237
238     public DispatchCtorBodyCodeAdapter(MethodVisitor proxyCtor, MethodVisitor ctorBodyMethod, final int access,
239                                        final String JavaDoc desc) {
240       super(proxyCtor);
241       m_proxyCtorMethodVisitor = proxyCtor;
242       m_ctorBodyMethodMethodVisitor = ctorBodyMethod;
243       m_constructorAccess = access;
244       m_constructorDesc = desc;
245     }
246
247     public void visitInsn(int opcode) {
248       super.visitInsn(opcode);
249       if (!m_proxyCtorCodeDone && opcode == DUP && m_index == 0) {
250         // heuristic for ALOAD_0 + DUP confirmed
251
m_isALOADDUPHeuristic = true;
252         m_index++;
253       }
254     }
255
256     public void visitIntInsn(int i, int i1) {
257       super.visitIntInsn(i, i1);
258     }
259
260     public void visitVarInsn(int opcode, int i1) {
261       super.visitVarInsn(opcode, i1);
262       if (!m_proxyCtorCodeDone) {
263         if (opcode == ALOAD && i1 == 0) {
264           m_index++;
265         }
266       }
267     }
268
269     public void visitFieldInsn(int i, String JavaDoc s, String JavaDoc s1, String JavaDoc s2) {
270       super.visitFieldInsn(i, s, s1, s2);
271     }
272
273     public void visitLdcInsn(Object JavaDoc o) {
274       super.visitLdcInsn(o);
275     }
276
277     public void visitIincInsn(int i, int i1) {
278       super.visitIincInsn(i, i1);
279     }
280
281     public void visitMultiANewArrayInsn(String JavaDoc s, int i) {
282       super.visitMultiANewArrayInsn(s, i);
283     }
284
285     /**
286      * Visit NEW type to ignore corresponding INVOKESPECIAL for those
287      *
288      * @param opcode
289      * @param name
290      */

291     public void visitTypeInsn(int opcode, String JavaDoc name) {
292       super.visitTypeInsn(opcode, name);
293       if (opcode == NEW) {
294         m_newCount++;
295       }
296     }
297
298     public void visitMethodInsn(int opcode,
299                                 String JavaDoc owner,
300                                 String JavaDoc name,
301                                 String JavaDoc desc) {
302       if (!m_proxyCtorCodeDone) {
303         if (opcode == INVOKESPECIAL) {
304           if (m_newCount == 0) {
305             // first INVOKESPECIAL encountered to <init> for a NON new XXX()
306
m_proxyCtorMethodVisitor.visitMethodInsn(opcode, owner, name, desc);
307             // insert the JoinPoint invocation
308
insertJoinPointInvoke(m_proxyCtorMethodVisitor, m_constructorAccess, m_constructorDesc);
309             m_proxyCtorMethodVisitor.visitInsn(RETURN);
310             m_proxyCtorMethodVisitor.visitMaxs(0, 0);
311             m_proxyCtorMethodVisitor = null;
312             m_proxyCtorCodeDone = true;
313             mv = m_ctorBodyMethodMethodVisitor;
314             // load ALOAD 0 if under heuristic
315
if (m_isALOADDUPHeuristic) {
316               m_ctorBodyMethodMethodVisitor.visitVarInsn(ALOAD, 0);
317             }
318           } else {
319             m_newCount--;
320             mv.visitMethodInsn(opcode, owner, name, desc);
321           }
322         } else {
323           mv.visitMethodInsn(opcode, owner, name, desc);
324         }
325       } else {
326         mv.visitMethodInsn(opcode, owner, name, desc);
327       }
328     }
329
330   }
331 }
332
Popular Tags