KickJava   Java API By Example, From Geeks To Geeks.

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


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

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

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

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

97     public CodeVisitor visitMethod(final int access,
98                                    final String JavaDoc name,
99                                    final String JavaDoc desc,
100                                    final String JavaDoc[] exceptions,
101                                    final Attribute attrs) {
102
103         if (INIT_METHOD_NAME.equals(name) ||
104             CLINIT_METHOD_NAME.equals(name) ||
105             name.startsWith(ASPECTWERKZ_PREFIX) ||
106             name.startsWith(SYNTHETIC_MEMBER_PREFIX) ||
107             name.startsWith(WRAPPER_METHOD_PREFIX)) {
108             return cv.visitMethod(access, name, desc, exceptions, attrs);
109         }
110
111         int hash = AsmHelper.calculateMethodHash(name, desc);
112         MethodInfo methodInfo = m_classInfo.getMethod(hash);
113         if (methodInfo == null) {
114             System.err.println(
115                     "AW::WARNING " +
116                     "metadata structure could not be build for method ["
117                     + m_classInfo.getName().replace('/', '.')
118                     + '.' + name + ':' + desc + ']'
119             );
120             // bail out
121
return cv.visitMethod(access, name, desc, exceptions, attrs);
122         }
123
124         ExpressionContext ctx = new ExpressionContext(PointcutType.EXECUTION, methodInfo, methodInfo);
125
126         if (methodFilter(m_ctx.getDefinitions(), ctx, methodInfo)) {
127             return cv.visitMethod(access, name, desc, exceptions, attrs);
128         } else {
129             String JavaDoc prefixedOriginalName = TransformationUtil.getPrefixedOriginalMethodName(name, m_declaringTypeName);
130             if (m_addedMethods.contains(AlreadyAddedMethodAdapter.getMethodKey(prefixedOriginalName, desc))) {
131                 return cv.visitMethod(access, name, desc, exceptions, attrs);
132             }
133
134             m_ctx.markAsAdvised();
135
136             // create the proxy for the original method
137
createProxyMethod(access, name, desc, exceptions, attrs, methodInfo);
138
139             int modifiers = ACC_SYNTHETIC;
140             if (Modifier.isStatic(access)) {
141                 modifiers |= ACC_STATIC;
142             }
143             // prefix the original method
144
return cv.visitMethod(
145                     modifiers,
146                     prefixedOriginalName,
147                     desc, exceptions, attrs
148             );
149         }
150     }
151
152     /**
153      * Creates the "proxy method", e.g. the method that has the same name and signature as the original method but a
154      * completely other implementation.
155      *
156      * @param access
157      * @param name
158      * @param desc
159      * @param exceptions
160      * @param attrs
161      */

162     private void createProxyMethod(final int access,
163                                    final String JavaDoc name,
164                                    final String JavaDoc desc,
165                                    final String JavaDoc[] exceptions,
166                                    final Attribute attrs,
167                                    final MethodInfo methodInfo) {
168         CodeVisitor mv = cv.visitMethod(access, name, desc, exceptions, attrs);
169
170         // load "this" ie callee if target method is not static
171
if (!Modifier.isStatic(access)) {
172             mv.visitVarInsn(ALOAD, 0);
173         }
174         // load args
175
AsmHelper.loadArgumentTypes(mv, Type.getArgumentTypes(desc), Modifier.isStatic(access));
176         // load "this" ie caller or null if method is static
177
if (Modifier.isStatic(access)) {
178             mv.visitInsn(ACONST_NULL);
179         } else {
180             mv.visitVarInsn(ALOAD, 0);
181         }
182
183         int joinPointHash = AsmHelper.calculateMethodHash(name, desc);
184         String JavaDoc joinPointClassName = TransformationUtil.getJoinPointClassName(
185                 m_declaringTypeName,
186                 name,
187                 desc,
188                 m_declaringTypeName,
189                 JoinPointType.METHOD_EXECUTION_INT,
190                 joinPointHash
191         );
192
193         // TODO: should we provide some sort of option to do JITgen when weaving instead of when loading ?
194
// use case: offline full packaging and alike
195

196         mv.visitMethodInsn(
197                 INVOKESTATIC,
198                 joinPointClassName,
199                 INVOKE_METHOD_NAME,
200                 TransformationUtil.getInvokeSignatureForCodeJoinPoints(
201                         access, desc, m_declaringTypeName, m_declaringTypeName
202                 )
203         );
204
205         AsmHelper.addReturnStatement(mv, Type.getReturnType(desc));
206         mv.visitMaxs(0, 0);
207
208         // emit the joinpoint
209
m_ctx.addEmittedJoinPoint(
210                 new EmittedJoinPoint(
211                         JoinPointType.METHOD_EXECUTION_INT,
212                         m_declaringTypeName,
213                         name,
214                         desc,
215                         access,
216                         m_declaringTypeName,
217                         name,
218                         desc,
219                         access,
220                         joinPointHash,
221                         joinPointClassName,
222                         EmittedJoinPoint.NO_LINE_NUMBER
223                 )
224         );
225     }
226
227     /**
228      * Filters out the methods that are not eligible for transformation.
229      *
230      * @param definitions
231      * @param ctx
232      * @param methodInfo
233      * @return boolean true if the method should be filtered out
234      */

235     public static boolean methodFilter(final Set JavaDoc definitions,
236                                        final ExpressionContext ctx,
237                                        final MethodInfo methodInfo) {
238         if (Modifier.isAbstract(methodInfo.getModifiers())
239             || Modifier.isNative(methodInfo.getModifiers())
240             || methodInfo.getName().equals(INIT_METHOD_NAME)
241             || methodInfo.getName().equals(CLINIT_METHOD_NAME)
242             || methodInfo.getName().startsWith(ORIGINAL_METHOD_PREFIX)) {
243             return true;
244         }
245         for (Iterator JavaDoc it = definitions.iterator(); it.hasNext();) {
246             if (((SystemDefinition) it.next()).hasPointcut(ctx)) {
247                 return false;
248             } else {
249                 continue;
250             }
251         }
252         return true;
253     }
254 }
Popular Tags