KickJava   Java API By Example, From Geeks To Geeks.

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


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.Type;
16 import org.objectweb.asm.Label;
17 import org.codehaus.aspectwerkz.definition.SystemDefinition;
18 import org.codehaus.aspectwerkz.expression.ExpressionContext;
19 import org.codehaus.aspectwerkz.expression.PointcutType;
20 import org.codehaus.aspectwerkz.joinpoint.management.JoinPointType;
21 import org.codehaus.aspectwerkz.reflect.ClassInfo;
22 import org.codehaus.aspectwerkz.reflect.FieldInfo;
23 import org.codehaus.aspectwerkz.reflect.MemberInfo;
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 SET and GET join points by replacing PUTFIELD and GETFIELD instructions with invocations
39  * of the compiled join point.
40  *
41  * @author <a HREF="mailto:jboner@codehaus.org">Jonas Bonér </a>
42  */

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

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

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

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

125         public ReplacePutFieldAndGetFieldInstructionCodeAdapter(final CodeVisitor ca,
126                                                                 final ClassLoader JavaDoc loader,
127                                                                 final ClassInfo callerClassInfo,
128                                                                 final String JavaDoc callerClassName,
129                                                                 final String JavaDoc callerMethodName,
130                                                                 final String JavaDoc callerMethodDesc) {
131             super(ca, callerMethodName);
132             m_loader = loader;
133             m_callerClassInfo = callerClassInfo;
134             m_callerClassName = callerClassName;
135             m_callerMethodName = callerMethodName;
136             m_callerMethodDesc = callerMethodDesc;
137
138             if (CLINIT_METHOD_NAME.equals(m_callerMethodName)) {
139                 m_callerMemberInfo = m_callerClassInfo.staticInitializer();
140             } else if (INIT_METHOD_NAME.equals(m_callerMethodName)) {
141                 int hash = AsmHelper.calculateConstructorHash(m_callerMethodDesc);
142                 m_callerMemberInfo = m_callerClassInfo.getConstructor(hash);
143             } else {
144                 int hash = AsmHelper.calculateMethodHash(m_callerMethodName, m_callerMethodDesc);
145                 m_callerMemberInfo = m_callerClassInfo.getMethod(hash);
146             }
147             if (m_callerMemberInfo == null) {
148                 System.err.println(
149                         "AW::WARNING " +
150                         "metadata structure could not be build for method ["
151                         + m_callerClassInfo.getName().replace('/', '.')
152                         + '.' + m_callerMethodName + ':' + m_callerMethodDesc + ']'
153                 );
154             }
155         }
156
157         /**
158          * Label
159          *
160          * @param label
161          */

162         public void visitLabel(Label label) {
163             m_lastLabelForLineNumber = label;
164             super.visitLabel(label);
165         }
166
167         /**
168          * Visits PUTFIELD and GETFIELD instructions.
169          *
170          * @param opcode
171          * @param className
172          * @param fieldName
173          * @param fieldDesc
174          */

175         public void visitFieldInsn(final int opcode,
176                                    final String JavaDoc className,
177                                    final String JavaDoc fieldName,
178                                    final String JavaDoc fieldDesc) {
179
180             if (className.endsWith(AbstractJoinPointCompiler.JOIN_POINT_CLASS_SUFFIX) ||
181                 fieldName.startsWith(ASPECTWERKZ_PREFIX) ||
182                 fieldName.startsWith(SYNTHETIC_MEMBER_PREFIX) || // synthetic field
183
fieldName.equals(SERIAL_VERSION_UID_FIELD_NAME) // can have been added by the weaver (not safe)
184
) {
185                 super.visitFieldInsn(opcode, className, fieldName, fieldDesc);
186                 return;
187             }
188
189             // if within ctor, make sure object initialization has been reached
190
if (!m_isObjectInitialized) {
191                 super.visitFieldInsn(opcode, className, fieldName, fieldDesc);
192                 return;
193             }
194
195
196             final Type fieldType = Type.getType(fieldDesc);
197             final int joinPointHash = AsmHelper.calculateFieldHash(fieldName, fieldDesc);
198             final ClassInfo classInfo = AsmClassInfo.getClassInfo(className, m_loader);
199             final FieldInfo fieldInfo = getFieldInfo(classInfo, className, fieldName, fieldDesc, joinPointHash);
200
201             if (opcode == PUTFIELD || opcode == PUTSTATIC) {
202                 handleFieldModification(fieldInfo, opcode, className, fieldName, fieldDesc, joinPointHash);
203             } else if (opcode == GETFIELD || opcode == GETSTATIC) {
204                 handleFieldAccess(fieldInfo, opcode, className, fieldName, fieldDesc, joinPointHash, fieldType);
205             } else {
206                 super.visitFieldInsn(opcode, className, fieldName, fieldDesc);
207             }
208         }
209
210         /**
211          * Handles field access.
212          *
213          * @param fieldInfo
214          * @param opcode
215          * @param className
216          * @param fieldName
217          * @param fieldDesc
218          * @param joinPointHash
219          * @param fieldType
220          */

221         private void handleFieldAccess(final FieldInfo fieldInfo,
222                                        final int opcode,
223                                        final String JavaDoc className,
224                                        final String JavaDoc fieldName,
225                                        final String JavaDoc fieldDesc,
226                                        int joinPointHash,
227                                        final Type fieldType) {
228             if (m_callerMemberInfo == null) {
229                 super.visitFieldInsn(opcode, className, fieldName, fieldDesc);
230                 return;
231             }
232
233             ExpressionContext ctx = new ExpressionContext(PointcutType.GET, fieldInfo, m_callerMemberInfo);
234
235             if (fieldFilter(m_ctx.getDefinitions(), ctx, fieldInfo)) {
236                 super.visitFieldInsn(opcode, className, fieldName, fieldDesc);
237             } else {
238                 m_ctx.markAsAdvised();
239
240                 String JavaDoc joinPointClassName = TransformationUtil.getJoinPointClassName(
241                         m_callerClassName,
242                         m_callerMethodName,
243                         m_callerMethodDesc,
244                         className,
245                         JoinPointType.FIELD_GET_INT,
246                         joinPointHash
247                 );
248
249                 // no param to field, so pass a default value to the invoke method
250
AsmHelper.addDefaultValue(this, fieldType);
251
252                 // if static context load NULL else 'this'
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.getInvokeSignatureForFieldJoinPoints(
265                                 fieldInfo.getModifiers(), fieldDesc, m_callerClassName, className
266                         )
267                 );
268
269                 // emit the joinpoint
270
m_ctx.addEmittedJoinPoint(
271                         new EmittedJoinPoint(
272                                 JoinPointType.FIELD_GET_INT,
273                                 m_callerClassName,
274                                 m_callerMethodName,
275                                 m_callerMethodDesc,
276                                 m_callerMemberInfo.getModifiers(),
277                                 className,
278                                 fieldName,
279                                 fieldDesc,
280                                 fieldInfo.getModifiers(),
281                                 joinPointHash,
282                                 joinPointClassName,
283                                 m_lastLabelForLineNumber
284                         )
285                 );
286             }
287         }
288
289         /**
290          * Handles field modification.
291          *
292          * @param fieldInfo
293          * @param opcode
294          * @param className
295          * @param fieldName
296          * @param fieldDesc
297          * @param joinPointHash
298          */

299         private void handleFieldModification(final FieldInfo fieldInfo,
300                                              final int opcode,
301                                              final String JavaDoc className,
302                                              final String JavaDoc fieldName,
303                                              final String JavaDoc fieldDesc,
304                                              final int joinPointHash) {
305             if (m_callerMemberInfo == null) {
306                 super.visitFieldInsn(opcode, className, fieldName, fieldDesc);
307                 return;
308             }
309
310             ExpressionContext ctx = new ExpressionContext(PointcutType.SET, fieldInfo, m_callerMemberInfo);
311
312             if (fieldFilter(m_ctx.getDefinitions(), ctx, fieldInfo)) {
313                 super.visitFieldInsn(opcode, className, fieldName, fieldDesc);
314             } else {
315                 m_ctx.markAsAdvised();
316
317                 String JavaDoc joinPointClassName = TransformationUtil.getJoinPointClassName(
318                         m_callerClassName,
319                         m_callerMethodName,
320                         m_callerMethodDesc,
321                         className,
322                         JoinPointType.FIELD_SET_INT,
323                         joinPointHash
324                 );
325
326                 // load the caller instance (this), or null if in a static context
327
// note that callee instance [optional] and args are already on the stack
328
if (Modifier.isStatic(m_callerMemberInfo.getModifiers())) {
329                     visitInsn(ACONST_NULL);
330                 } else {
331                     visitVarInsn(ALOAD, 0);
332                 }
333
334                 // add the call to the join point
335
super.visitMethodInsn(
336                         INVOKESTATIC,
337                         joinPointClassName,
338                         INVOKE_METHOD_NAME,
339                         TransformationUtil.getInvokeSignatureForFieldJoinPoints(
340                                 fieldInfo.getModifiers(), fieldDesc, m_callerClassName, className
341                         )
342                 );
343
344                 final int sort = Type.getType(fieldDesc).getSort();
345                 if (sort != Type.LONG && sort != Type.DOUBLE) {
346                     super.visitInsn(POP);
347                 } else {
348                     //AW-437
349
super.visitInsn(POP2);
350                 }
351
352                 // emit the joinpoint
353
m_ctx.addEmittedJoinPoint(
354                         new EmittedJoinPoint(
355                                 JoinPointType.FIELD_SET_INT,
356                                 m_callerClassName,
357                                 m_callerMethodName,
358                                 m_callerMethodDesc,
359                                 m_callerMemberInfo.getModifiers(),
360                                 className,
361                                 fieldName,
362                                 fieldDesc,
363                                 fieldInfo.getModifiers(),
364                                 joinPointHash,
365                                 joinPointClassName,
366                                 m_lastLabelForLineNumber
367                         )
368                 );
369             }
370         }
371
372         /**
373          * Returns the field info.
374          *
375          * @param classInfo
376          * @param className
377          * @param fieldName
378          * @param fieldDesc
379          * @param joinPointHash
380          * @return
381          */

382         private FieldInfo getFieldInfo(final ClassInfo classInfo,
383                                        final String JavaDoc className,
384                                        final String JavaDoc fieldName,
385                                        final String JavaDoc fieldDesc,
386                                        final int joinPointHash) {
387             FieldInfo fieldInfo = classInfo.getField(joinPointHash);
388             if (fieldInfo == null) {
389                 throw new Error JavaDoc(
390                         "field info metadata structure could not be build for field: "
391                         + className
392                         + '.'
393                         + fieldName
394                         + ':'
395                         + fieldDesc
396                 );
397             }
398             return fieldInfo;
399         }
400
401         /**
402          * Filters out the fields that are not eligible for transformation.
403          *
404          * @param definitions
405          * @param ctx
406          * @param fieldInfo
407          * @return boolean true if the field should be filtered out
408          */

409         public boolean fieldFilter(final Set JavaDoc definitions,
410                                    final ExpressionContext ctx,
411                                    final FieldInfo fieldInfo) {
412             if (fieldInfo.getName().startsWith(ORIGINAL_METHOD_PREFIX)) {
413                 return true;
414             }
415             for (Iterator JavaDoc it = definitions.iterator(); it.hasNext();) {
416                 if (((SystemDefinition) it.next()).hasPointcut(ctx)) {
417                     return false;
418                 } else {
419                     continue;
420                 }
421             }
422             return true;
423         }
424     }
425 }
Popular Tags