KickJava   Java API By Example, From Geeks To Geeks.

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


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

44 public class MethodCallVisitor extends ClassAdapter implements TransformationConstants {
45
46   private final InstrumentationContext m_ctx;
47   private final ClassLoader JavaDoc m_loader;
48   private final ClassInfo m_callerClassInfo;
49
50   private Label m_lastLabelForLineNumber = EmittedJoinPoint.NO_LINE_NUMBER;
51
52   /**
53    * Creates a new instance.
54    *
55    * @param cv
56    * @param loader
57    * @param classInfo
58    * @param ctx
59    */

60   public MethodCallVisitor(final ClassVisitor cv,
61                            final ClassLoader JavaDoc loader,
62                            final ClassInfo classInfo,
63                            final InstrumentationContext ctx) {
64     super(cv);
65     m_loader = loader;
66     m_callerClassInfo = classInfo;
67     m_ctx = (InstrumentationContext) ctx;
68   }
69
70   /**
71    * Visits the caller methods.
72    *
73    * @param access
74    * @param name
75    * @param desc
76    * @param signature
77    * @param exceptions
78    * @return
79    */

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

109   public class ReplaceInvokeInstructionCodeAdapter extends AfterObjectInitializationCodeAdapter {
110
111     private final ClassLoader JavaDoc m_loader;
112     private final ClassInfo m_callerClassInfo;
113     private final String JavaDoc m_callerClassName;
114     private final String JavaDoc m_callerMethodName;
115     private final String JavaDoc m_callerMethodDesc;
116     private final MemberInfo m_callerMemberInfo;
117
118     /**
119      * Creates a new instance.
120      *
121      * @param ca
122      * @param loader
123      * @param callerClassInfo
124      * @param callerClassName
125      * @param callerMethodName
126      * @param callerMethodDesc
127      */

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

157     public void visitLabel(Label label) {
158       m_lastLabelForLineNumber = label;
159       super.visitLabel(label);
160     }
161
162     /**
163      * Visits 'INVOKEXXX' instructions.
164      *
165      * @param opcode
166      * @param calleeClassName
167      * @param calleeMethodName
168      * @param calleeMethodDesc
169      */

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

297     public boolean methodFilter(final Set JavaDoc definitions,
298                                 final ExpressionContext ctx,
299                                 final MethodInfo calleeMethodInfo) {
300       if (calleeMethodInfo.getName().equals(INIT_METHOD_NAME) ||
301               calleeMethodInfo.getName().equals(CLINIT_METHOD_NAME) ||
302               calleeMethodInfo.getName().startsWith(ORIGINAL_METHOD_PREFIX)) {
303         return true;
304       }
305       for (Iterator JavaDoc it = definitions.iterator(); it.hasNext();) {
306         if (((SystemDefinition) it.next()).hasPointcut(ctx)) {
307           return false;
308         } else {
309           continue;
310         }
311       }
312       return true;
313     }
314   }
315 }
Popular Tags