KickJava   Java API By Example, From Geeks To Geeks.

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


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.objectweb.asm.Label;
16 import org.codehaus.aspectwerkz.definition.SystemDefinition;
17 import org.codehaus.aspectwerkz.expression.ExpressionContext;
18 import org.codehaus.aspectwerkz.expression.PointcutType;
19 import org.codehaus.aspectwerkz.joinpoint.management.JoinPointType;
20 import org.codehaus.aspectwerkz.reflect.ClassInfo;
21 import org.codehaus.aspectwerkz.reflect.MethodInfo;
22 import org.codehaus.aspectwerkz.reflect.MemberInfo;
23 import org.codehaus.aspectwerkz.reflect.ClassInfoHelper;
24 import org.codehaus.aspectwerkz.reflect.impl.asm.AsmClassInfo;
25 import org.codehaus.aspectwerkz.transform.Context;
26 import org.codehaus.aspectwerkz.transform.TransformationUtil;
27 import org.codehaus.aspectwerkz.transform.TransformationConstants;
28 import org.codehaus.aspectwerkz.transform.inlining.compiler.AbstractJoinPointCompiler;
29 import org.codehaus.aspectwerkz.transform.inlining.ContextImpl;
30 import org.codehaus.aspectwerkz.transform.inlining.AsmHelper;
31 import org.codehaus.aspectwerkz.transform.inlining.EmittedJoinPoint;
32
33 import java.lang.reflect.Modifier JavaDoc;
34 import java.util.Iterator JavaDoc;
35 import java.util.Set JavaDoc;
36
37 /**
38  * Instruments method CALL join points by replacing INVOKEXXX instructions with invocations of the compiled join point.
39  * <br/>
40  * It calls the JPClass.invoke static method. The signature of the invoke method depends if the
41  * target method is static or not as follow:
42  * <pre>
43  * invoke(callee, args.., caller) // non static
44  * invoke(args.., caller) // static
45  * </pre>
46  * (The reason why is that it simplifies call pointcut stack management)
47  *
48  * @author <a HREF="mailto:jboner@codehaus.org">Jonas Bonér </a>
49  * @author <a HREF="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
50  */

51 public class MethodCallVisitor extends ClassAdapter implements TransformationConstants {
52
53     private final ContextImpl m_ctx;
54     private final ClassLoader JavaDoc m_loader;
55     private final ClassInfo m_callerClassInfo;
56
57     private Label m_lastLabelForLineNumber = EmittedJoinPoint.NO_LINE_NUMBER;
58
59     /**
60      * Creates a new instance.
61      *
62      * @param cv
63      * @param loader
64      * @param classInfo
65      * @param ctx
66      */

67     public MethodCallVisitor(final ClassVisitor cv,
68                              final ClassLoader JavaDoc loader,
69                              final ClassInfo classInfo,
70                              final Context ctx) {
71         super(cv);
72         m_loader = loader;
73         m_callerClassInfo = classInfo;
74         m_ctx = (ContextImpl) ctx;
75     }
76
77     /**
78      * Visits the caller methods.
79      *
80      * @param access
81      * @param name
82      * @param desc
83      * @param exceptions
84      * @param attrs
85      * @return
86      */

87     public CodeVisitor visitMethod(final int access,
88                                    final String JavaDoc name,
89                                    final String JavaDoc desc,
90                                    final String JavaDoc[] exceptions,
91                                    final Attribute attrs) {
92
93         if (name.startsWith(WRAPPER_METHOD_PREFIX) ||
94             Modifier.isNative(access) ||
95             Modifier.isAbstract(access)) {
96             return super.visitMethod(access, name, desc, exceptions, attrs);
97         }
98
99         CodeVisitor mv = cv.visitMethod(access, name, desc, exceptions, attrs);
100         return mv == null ? null : new ReplaceInvokeInstructionCodeAdapter(
101                 mv,
102                 m_loader,
103                 m_callerClassInfo,
104                 m_ctx.getClassName(),
105                 name,
106                 desc
107         );
108     }
109
110     /**
111      * Replaces 'INVOKEXXX' instructions with a call to the compiled JoinPoint instance.
112      *
113      * @author <a HREF="mailto:jboner@codehaus.org">Jonas Bonťr </a>
114      * @author <a HREF="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
115      */

116     public class ReplaceInvokeInstructionCodeAdapter extends AfterObjectInitializationCodeAdapter {
117
118         private final ClassLoader JavaDoc m_loader;
119         private final ClassInfo m_callerClassInfo;
120         private final String JavaDoc m_callerClassName;
121         private final String JavaDoc m_callerMethodName;
122         private final String JavaDoc m_callerMethodDesc;
123         private final MemberInfo m_callerMemberInfo;
124
125         /**
126          * Creates a new instance.
127          *
128          * @param ca
129          * @param loader
130          * @param callerClassInfo
131          * @param callerClassName
132          * @param callerMethodName
133          * @param callerMethodDesc
134          */

135         public ReplaceInvokeInstructionCodeAdapter(final CodeVisitor ca,
136                                                    final ClassLoader JavaDoc loader,
137                                                    final ClassInfo callerClassInfo,
138                                                    final String JavaDoc callerClassName,
139                                                    final String JavaDoc callerMethodName,
140                                                    final String JavaDoc callerMethodDesc) {
141             super(ca, callerMethodName);
142             m_loader = loader;
143             m_callerClassInfo = callerClassInfo;
144             m_callerClassName = callerClassName;
145             m_callerMethodName = callerMethodName;
146             m_callerMethodDesc = callerMethodDesc;
147
148             if (CLINIT_METHOD_NAME.equals(callerMethodName)) {
149                 m_callerMemberInfo = m_callerClassInfo.staticInitializer();
150             } else if (INIT_METHOD_NAME.equals(callerMethodName)) {
151                 int hash = AsmHelper.calculateConstructorHash(m_callerMethodDesc);
152                 m_callerMemberInfo = m_callerClassInfo.getConstructor(hash);
153             } else {
154                 int hash = AsmHelper.calculateMethodHash(m_callerMethodName, m_callerMethodDesc);
155                 m_callerMemberInfo = m_callerClassInfo.getMethod(hash);
156             }
157         }
158
159         /**
160          * Label
161          *
162          * @param label
163          */

164         public void visitLabel(Label label) {
165             m_lastLabelForLineNumber = label;
166             super.visitLabel(label);
167         }
168
169         /**
170          * Visits 'INVOKEXXX' instructions.
171          *
172          * @param opcode
173          * @param calleeClassName
174          * @param calleeMethodName
175          * @param calleeMethodDesc
176          */

177         public void visitMethodInsn(final int opcode,
178                                     String JavaDoc calleeClassName,
179                                     final String JavaDoc calleeMethodName,
180                                     final String JavaDoc calleeMethodDesc) {
181
182             if (m_callerMemberInfo == null) {
183                 System.err.println(
184                         "AW::WARNING " +
185                         "metadata structure could not be build for method ["
186                         + m_callerClassInfo.getName().replace('/', '.')
187                         + '.' + m_callerMethodName + ':' + m_callerMethodDesc + ']'
188                 );
189                 super.visitMethodInsn(opcode, calleeClassName, calleeMethodName, calleeMethodDesc);
190                 return;
191             }
192
193             if (INIT_METHOD_NAME.equals(calleeMethodName) ||
194                 CLINIT_METHOD_NAME.equals(calleeMethodName) ||
195                 calleeMethodName.startsWith(ASPECTWERKZ_PREFIX)
196                 || calleeClassName.endsWith(JOIN_POINT_CLASS_SUFFIX)
197                 //calleeClassName.startsWith("org/aopalliance/")) { // FIXME make generic fix by invoking all AspectModels (same problem in other visitors as well)
198
){super.visitMethodInsn(opcode, calleeClassName, calleeMethodName, calleeMethodDesc);
199                 return;
200             }
201
202             // check if we have a super.sameMethod() call
203
if (opcode == INVOKESPECIAL
204                 && !calleeClassName.equals(m_callerClassName)
205                 && ClassInfoHelper.extendsSuperClass(m_callerClassInfo, calleeClassName.replace('/', '.'))) {
206                 super.visitMethodInsn(opcode, calleeClassName, calleeMethodName, calleeMethodDesc);
207                 return;
208             }
209
210             // check if object initialization has been reached
211
if (!m_isObjectInitialized) {
212                 super.visitMethodInsn(opcode, calleeClassName, calleeMethodName, calleeMethodDesc);
213                 return;
214             }
215
216             int joinPointHash = AsmHelper.calculateMethodHash(calleeMethodName, calleeMethodDesc);
217
218             ClassInfo classInfo = AsmClassInfo.getClassInfo(calleeClassName, m_loader);
219             MethodInfo calleeMethodInfo = classInfo.getMethod(joinPointHash);
220
221             if (calleeMethodInfo == null) {
222                 System.err.println(
223                         "AW::WARNING " +
224                         "metadata structure could not be build for method ["
225                         + classInfo.getName().replace('/', '.')
226                         + '.' + calleeMethodName + ':' + calleeMethodDesc
227                         + "] when parsing method ["
228                         + m_callerClassInfo.getName() + '.' + m_callerMethodName + "(..)]"
229                 );
230                 // bail out
231
super.visitMethodInsn(opcode, calleeClassName, calleeMethodName, calleeMethodDesc);
232                 return;
233             }
234
235             ExpressionContext ctx = new ExpressionContext(PointcutType.CALL, calleeMethodInfo, m_callerMemberInfo);
236
237             if (methodFilter(m_ctx.getDefinitions(), ctx, calleeMethodInfo)) {
238                 super.visitMethodInsn(opcode, calleeClassName, calleeMethodName, calleeMethodDesc);
239             } else {
240                 m_ctx.markAsAdvised();
241
242                 String JavaDoc joinPointClassName = TransformationUtil.getJoinPointClassName(
243                         m_callerClassName,
244                         m_callerMethodName,
245                         m_callerMethodDesc,
246                         calleeClassName,
247                         JoinPointType.METHOD_CALL_INT,
248                         joinPointHash
249                 );
250
251                 // load the caller instance (this), or null if in a static context
252
// note that callee instance [optional] and args are already on the stack
253
if (Modifier.isStatic(m_callerMemberInfo.getModifiers())) {
254                     visitInsn(ACONST_NULL);
255                 } else {
256                     visitVarInsn(ALOAD, 0);
257                 }
258
259                 // add the call to the join point
260
super.visitMethodInsn(
261                         INVOKESTATIC,
262                         joinPointClassName,
263                         INVOKE_METHOD_NAME,
264                         TransformationUtil.getInvokeSignatureForCodeJoinPoints(
265                                 calleeMethodInfo.getModifiers(), calleeMethodDesc,
266                                 m_callerClassName, calleeClassName
267                         )
268                 );
269
270                 // emit the joinpoint
271
//See AW-253 - we remember if we had an INVOKE INTERFACE opcode
272
int modifiers = calleeMethodInfo.getModifiers();
273                 if (opcode == INVOKEINTERFACE) {
274                     modifiers = modifiers | MODIFIER_INVOKEINTERFACE;
275                 }
276                 m_ctx.addEmittedJoinPoint(
277                         new EmittedJoinPoint(
278                                 JoinPointType.METHOD_CALL_INT,
279                                 m_callerClassName,
280                                 m_callerMethodName,
281                                 m_callerMethodDesc,
282                                 m_callerMemberInfo.getModifiers(),
283                                 calleeClassName,
284                                 calleeMethodName,
285                                 calleeMethodDesc,
286                                 modifiers,
287                                 joinPointHash,
288                                 joinPointClassName,
289                                 m_lastLabelForLineNumber
290                         )
291                 );
292             }
293         }
294
295         /**
296          * Filters out the methods that are not eligible for transformation.
297          * Do not filter on abstract callee method - needed for interface declared method call
298          * (invokeinterface instr.)
299          *
300          * @param definitions
301          * @param ctx
302          * @param calleeMethodInfo
303          * @return boolean true if the method should be filtered out
304          */

305         public boolean methodFilter(final Set JavaDoc definitions,
306                                     final ExpressionContext ctx,
307                                     final MethodInfo calleeMethodInfo) {
308             if (calleeMethodInfo.getName().equals(INIT_METHOD_NAME) ||
309                 calleeMethodInfo.getName().equals(CLINIT_METHOD_NAME) ||
310                 calleeMethodInfo.getName().startsWith(ORIGINAL_METHOD_PREFIX)) {
311                 return true;
312             }
313             for (Iterator JavaDoc it = definitions.iterator(); it.hasNext();) {
314                 if (((SystemDefinition) it.next()).hasPointcut(ctx)) {
315                     return false;
316                 } else {
317                     continue;
318                 }
319             }
320             return true;
321         }
322     }
323 }
Popular Tags