KickJava   Java API By Example, From Geeks To Geeks.

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


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 java.lang.reflect.Modifier JavaDoc;
7 import java.util.Iterator JavaDoc;
8 import java.util.Set JavaDoc;
9
10 import com.tc.asm.*;
11
12 import com.tc.aspectwerkz.definition.SystemDefinition;
13 import com.tc.aspectwerkz.intercept.AdvisableImpl;
14 import com.tc.aspectwerkz.joinpoint.management.JoinPointType;
15 import com.tc.aspectwerkz.transform.InstrumentationContext;
16 import com.tc.aspectwerkz.transform.TransformationConstants;
17 import com.tc.aspectwerkz.transform.TransformationUtil;
18 import com.tc.aspectwerkz.transform.inlining.AsmCopyAdapter;
19 import com.tc.aspectwerkz.transform.inlining.AsmHelper;
20 import com.tc.aspectwerkz.transform.inlining.EmittedJoinPoint;
21 import com.tc.aspectwerkz.reflect.ClassInfo;
22 import com.tc.aspectwerkz.reflect.MethodInfo;
23 import com.tc.aspectwerkz.expression.PointcutType;
24 import com.tc.aspectwerkz.expression.ExpressionContext;
25
26 /**
27  * Adds a "proxy method" to the methods that matches an <tt>execution</tt> pointcut as well as prefixing the "original
28  * method".
29  * <br/>
30  * The proxy method calls the JPClass.invoke static method. The signature of the invoke method depends if the
31  * target method is static or not as follow:
32  * <pre>
33  * invoke(callee, args.., caller) // non static
34  * invoke(args.., caller) // static
35  * </pre>
36  * (The reason why is that it simplifies call pointcut stack management)
37  *
38  * @author <a HREF="mailto:jboner@codehaus.org">Jonas Bonér </a>
39  * @author <a HREF="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
40  */

41 public class MethodExecutionVisitor extends ClassAdapter implements TransformationConstants {
42
43   private final ClassInfo m_classInfo;
44   private final InstrumentationContext m_ctx;
45   private String JavaDoc m_declaringTypeName;
46   private final Set JavaDoc m_addedMethods;
47
48   /**
49    * Creates a new class adapter.
50    *
51    * @param cv
52    * @param classInfo
53    * @param ctx
54    * @param addedMethods
55    */

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

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

95   public MethodVisitor visitMethod(final int access,
96                                    final String JavaDoc name,
97                                    final String JavaDoc desc,
98                                    final String JavaDoc signature,
99                                    final String JavaDoc[] exceptions) {
100
101     if (INIT_METHOD_NAME.equals(name) ||
102             CLINIT_METHOD_NAME.equals(name) ||
103             name.startsWith(ASPECTWERKZ_PREFIX) ||
104             name.startsWith(SYNTHETIC_MEMBER_PREFIX) ||
105             name.startsWith(WRAPPER_METHOD_PREFIX) ||
106             (AdvisableImpl.ADD_ADVICE_METHOD_NAME.equals(name) && AdvisableImpl.ADD_ADVICE_METHOD_DESC.equals(desc)) ||
107             (AdvisableImpl.REMOVE_ADVICE_METHOD_NAME.equals(name) && AdvisableImpl.REMOVE_ADVICE_METHOD_DESC.equals(desc)))
108     {
109       return cv.visitMethod(access, name, desc, signature, exceptions);
110     }
111
112     int hash = AsmHelper.calculateMethodHash(name, desc);
113     MethodInfo methodInfo = m_classInfo.getMethod(hash);
114     if (methodInfo == null) {
115       System.err.println(
116               "AW::WARNING " +
117                       "metadata structure could not be build for method ["
118                       + m_classInfo.getName().replace('/', '.')
119                       + '.' + name + ':' + desc + ']'
120       );
121       // bail out
122
return cv.visitMethod(access, name, desc, signature, exceptions);
123     }
124
125     ExpressionContext ctx = new ExpressionContext(PointcutType.EXECUTION, methodInfo, methodInfo);
126
127     if (methodFilter(m_ctx.getDefinitions(), ctx, methodInfo)) {
128       return cv.visitMethod(access, name, desc, signature, exceptions);
129     } else {
130       String JavaDoc prefixedOriginalName = TransformationUtil.getPrefixedOriginalMethodName(name, m_declaringTypeName);
131       if (m_addedMethods.contains(AlreadyAddedMethodAdapter.getMethodKey(prefixedOriginalName, desc))) {
132         return cv.visitMethod(access, name, desc, signature, exceptions);
133       }
134
135       m_ctx.markAsAdvised();
136
137       // create the proxy for the original method
138
final MethodVisitor proxyMethod = createProxyMethod(access, name, desc, signature, exceptions, methodInfo);
139
140       int modifiers = ACC_SYNTHETIC;
141       if (Modifier.isStatic(access)) {
142         modifiers |= ACC_STATIC;
143       }
144       // prefix the original method and make sure we copy method annotations to the proxyMethod
145
// while keeping the body for the prefixed method
146
return new MethodAdapter(cv.visitMethod(modifiers, prefixedOriginalName, desc, signature, exceptions)) {
147         public AnnotationVisitor visitAnnotation(String JavaDoc desc, boolean visible) {
148           return new AsmCopyAdapter.CopyAnnotationAdapter(
149                   super.visitAnnotation(desc, visible),
150                   proxyMethod.visitAnnotation(desc, visible)
151           );
152         }
153
154         public AnnotationVisitor visitParameterAnnotation(int parameter, String JavaDoc desc, boolean visible) {
155           return new AsmCopyAdapter.CopyAnnotationAdapter(
156                   super.visitParameterAnnotation(parameter, desc, visible),
157                   proxyMethod.visitParameterAnnotation(parameter, desc, visible)
158           );
159         }
160
161         public void visitAttribute(Attribute attr) {
162           super.visitAttribute(attr);
163           proxyMethod.visitAttribute(attr);
164         }
165       };
166     }
167   }
168
169   /**
170    * Creates the "proxy method", e.g. the method that has the same name and signature as the original method but a
171    * completely other implementation.
172    *
173    * @param access
174    * @param name
175    * @param desc
176    * @param signature
177    * @param exceptions
178    * @param methodInfo
179    * @return the method visitor
180    */

181   private MethodVisitor createProxyMethod(final int access,
182                                           final String JavaDoc name,
183                                           final String JavaDoc desc,
184                                           final String JavaDoc signature,
185                                           final String JavaDoc[] exceptions,
186                                           final MethodInfo methodInfo) {
187     MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions);
188
189     // load "this" ie callee if target method is not static
190
if (!Modifier.isStatic(access)) {
191       mv.visitVarInsn(ALOAD, 0);
192     }
193     // load args
194
AsmHelper.loadArgumentTypes(mv, Type.getArgumentTypes(desc), Modifier.isStatic(access));
195     // load "this" ie caller or null if method is static
196
if (Modifier.isStatic(access)) {
197       mv.visitInsn(ACONST_NULL);
198     } else {
199       mv.visitVarInsn(ALOAD, 0);
200     }
201
202     int joinPointHash = AsmHelper.calculateMethodHash(name, desc);
203     String JavaDoc joinPointClassName = TransformationUtil.getJoinPointClassName(
204             m_declaringTypeName,
205             name,
206             desc,
207             m_declaringTypeName,
208             JoinPointType.METHOD_EXECUTION_INT,
209             joinPointHash
210     );
211
212     // TODO: should we provide some sort of option to do JITgen when weaving instead of when loading ?
213
// use case: offline full packaging and alike
214

215     mv.visitMethodInsn(
216             INVOKESTATIC,
217             joinPointClassName,
218             INVOKE_METHOD_NAME,
219             TransformationUtil.getInvokeSignatureForCodeJoinPoints(
220                     access, desc, m_declaringTypeName, m_declaringTypeName
221             )
222     );
223
224     AsmHelper.addReturnStatement(mv, Type.getReturnType(desc));
225     mv.visitMaxs(0, 0);
226
227     // emit the joinpoint
228
m_ctx.addEmittedJoinPoint(
229             new EmittedJoinPoint(
230                     JoinPointType.METHOD_EXECUTION_INT,
231                     m_declaringTypeName,
232                     name,
233                     desc,
234                     access,
235                     m_declaringTypeName,
236                     name,
237                     desc,
238                     access,
239                     joinPointHash,
240                     joinPointClassName,
241                     EmittedJoinPoint.NO_LINE_NUMBER
242             )
243     );
244
245     return mv;
246   }
247
248   /**
249    * Filters out the methods that are not eligible for transformation.
250    *
251    * @param definitions
252    * @param ctx
253    * @param methodInfo
254    * @return boolean true if the method should be filtered out
255    */

256   public static boolean methodFilter(final Set JavaDoc definitions,
257                                      final ExpressionContext ctx,
258                                      final MethodInfo methodInfo) {
259     if (Modifier.isAbstract(methodInfo.getModifiers())
260             || Modifier.isNative(methodInfo.getModifiers())
261             || methodInfo.getName().equals(INIT_METHOD_NAME)
262             || methodInfo.getName().equals(CLINIT_METHOD_NAME)
263             || methodInfo.getName().startsWith(ORIGINAL_METHOD_PREFIX)) {
264       return true;
265     }
266     for (Iterator JavaDoc it = definitions.iterator(); it.hasNext();) {
267       if (((SystemDefinition) it.next()).hasPointcut(ctx)) {
268         return false;
269       } else {
270         continue;
271       }
272     }
273     return true;
274   }
275 }
Popular Tags