KickJava   Java API By Example, From Geeks To Geeks.

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


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.Label;
9 import com.tc.asm.MethodVisitor;
10 import com.tc.asm.Type;
11
12 import com.tc.aspectwerkz.definition.SystemDefinition;
13 import com.tc.aspectwerkz.joinpoint.management.JoinPointType;
14 import com.tc.aspectwerkz.reflect.impl.asm.AsmClassInfo;
15 import com.tc.aspectwerkz.reflect.ClassInfo;
16 import com.tc.aspectwerkz.reflect.MemberInfo;
17 import com.tc.aspectwerkz.reflect.FieldInfo;
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.transform.inlining.compiler.AbstractJoinPointCompiler;
24 import com.tc.aspectwerkz.expression.ExpressionContext;
25 import com.tc.aspectwerkz.expression.PointcutType;
26
27 import java.lang.reflect.Modifier JavaDoc;
28 import java.util.Iterator JavaDoc;
29 import java.util.Set JavaDoc;
30
31 /**
32  * Instruments method SET and GET join points by replacing PUTFIELD and GETFIELD instructions with invocations
33  * of the compiled join point.
34  *
35  * @author <a HREF="mailto:jboner@codehaus.org">Jonas BonŽr </a>
36  */

37 public class FieldSetFieldGetVisitor extends ClassAdapter implements TransformationConstants {
38
39   private final InstrumentationContext m_ctx;
40   private final ClassLoader JavaDoc m_loader;
41   private final ClassInfo m_callerClassInfo;
42
43   private Label m_lastLabelForLineNumber = EmittedJoinPoint.NO_LINE_NUMBER;
44
45   /**
46    * Creates a new instance.
47    *
48    * @param cv
49    * @param loader
50    * @param classInfo
51    * @param ctx
52    */

53   public FieldSetFieldGetVisitor(final ClassVisitor cv,
54                                  final ClassLoader JavaDoc loader,
55                                  final ClassInfo classInfo,
56                                  final InstrumentationContext ctx) {
57     super(cv);
58     m_loader = loader;
59     m_callerClassInfo = classInfo;
60     m_ctx = ctx;
61   }
62
63   /**
64    * Visits the caller methods.
65    *
66    * @param access
67    * @param name
68    * @param desc
69    * @param signature
70    * @param exceptions
71    * @return visitor
72    */

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

100   public class ReplacePutFieldAndGetFieldInstructionCodeAdapter extends AfterObjectInitializationCodeAdapter {
101
102     private final ClassLoader JavaDoc m_loader;
103     private final String JavaDoc m_callerClassName;
104     private final String JavaDoc m_callerMethodName;
105     private final String JavaDoc m_callerMethodDesc;
106     private final MemberInfo m_callerMemberInfo;
107
108     /**
109      * Creates a new instance.
110      *
111      * @param ca
112      * @param loader
113      * @param callerClassInfo
114      * @param callerClassName
115      * @param callerMethodName
116      * @param callerMethodDesc
117      */

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

154     public void visitLabel(Label label) {
155       m_lastLabelForLineNumber = label;
156       super.visitLabel(label);
157     }
158
159     /**
160      * Visits PUTFIELD and GETFIELD instructions.
161      *
162      * @param opcode
163      * @param className
164      * @param fieldName
165      * @param fieldDesc
166      */

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

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

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

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

401     public boolean fieldFilter(final Set JavaDoc definitions,
402                                final ExpressionContext ctx,
403                                final FieldInfo fieldInfo) {
404       if (fieldInfo.getName().startsWith(ORIGINAL_METHOD_PREFIX)) {
405         return true;
406       }
407       for (Iterator JavaDoc it = definitions.iterator(); it.hasNext();) {
408         if (((SystemDefinition) it.next()).hasPointcut(ctx)) {
409           return false;
410         } else {
411           continue;
412         }
413       }
414       return true;
415     }
416   }
417 }
Popular Tags