KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > codehaus > aspectwerkz > transform > inlining > weaver > ConstructorBodyVisitor


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

44 public class ConstructorBodyVisitor extends ClassAdapter implements TransformationConstants {
45
46     private final ContextImpl m_ctx;
47     private final ClassInfo m_calleeClassInfo;
48     private String JavaDoc m_declaringTypeName;
49     private Set JavaDoc m_addedMethods;
50
51     /**
52      * Creates a new instance.
53      *
54      * @param cv
55      * @param classInfo
56      * @param ctx
57      * @param addedMethods
58      */

59     public ConstructorBodyVisitor(final ClassVisitor cv,
60                                   final ClassInfo classInfo,
61                                   final Context ctx,
62                                   final Set JavaDoc addedMethods) {
63         super(cv);
64         m_calleeClassInfo = classInfo;
65         m_ctx = (ContextImpl) ctx;
66         m_addedMethods = addedMethods;
67     }
68
69     /**
70      * Visits the class.
71      *
72      * @param access
73      * @param name
74      * @param superName
75      * @param interfaces
76      * @param sourceFile
77      */

78     public void visit(final int version,
79                       final int access,
80                       final String JavaDoc name,
81                       final String JavaDoc superName,
82                       final String JavaDoc[] interfaces,
83                       final String JavaDoc sourceFile) {
84         m_declaringTypeName = name;
85         super.visit(version, access, name, superName, interfaces, sourceFile);
86     }
87
88     /**
89      * @param access
90      * @param name
91      * @param desc
92      * @param exceptions
93      * @param attrs
94      * @return
95      */

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

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

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

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

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