KickJava   Java API By Example, From Geeks To Geeks.

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


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.MethodAdapter;
10 import com.tc.asm.Label;
11 import com.tc.asm.Type;
12
13 import com.tc.aspectwerkz.definition.SystemDefinition;
14 import com.tc.aspectwerkz.joinpoint.management.JoinPointType;
15 import com.tc.aspectwerkz.reflect.impl.asm.AsmClassInfo;
16 import com.tc.aspectwerkz.reflect.ClassInfo;
17 import com.tc.aspectwerkz.reflect.MemberInfo;
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.util.Iterator JavaDoc;
27 import java.util.Set JavaDoc;
28 import java.util.ArrayList JavaDoc;
29 import java.util.List JavaDoc;
30 import java.util.Map JavaDoc;
31 import java.util.HashMap JavaDoc;
32 import java.lang.reflect.Modifier JavaDoc;
33
34 /**
35  * Advises catch clauses by inserting a call to the join point as the first thing in the catch block.
36  *
37  * @author <a HREF="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
38  */

39 public class HandlerVisitor extends ClassAdapter implements TransformationConstants {
40
41   /**
42    * A visitor that looks for all catch clause and keep track of them
43    * providing that they match
44    *
45    * @author <a HREF="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
46    */

47   public static class LookaheadCatchLabelsClassAdapter extends ClassAdapter {
48
49     /**
50      * list of CatchLabelStruct that matches
51      */

52     List JavaDoc m_catchLabels = new ArrayList JavaDoc();
53
54     /**
55      * map of Integer(index in whole class)-->asm.Label for all the visited labels
56      */

57     private final Map JavaDoc m_labelIndexes = new HashMap JavaDoc();
58
59     /**
60      * current label index in whole class, from 0 to N
61      */

62     private int m_labelIndex = -1;
63
64     private final InstrumentationContext m_ctx;
65     private final ClassLoader JavaDoc m_loader;
66     private final ClassInfo m_callerClassInfo;
67
68     /**
69      * Visit the class
70      *
71      * @param cv
72      * @param loader
73      * @param callerClassInfo
74      * @param ctx
75      * @param catchLabels
76      */

77     public LookaheadCatchLabelsClassAdapter(ClassVisitor cv, ClassLoader JavaDoc loader, ClassInfo callerClassInfo,
78                                             InstrumentationContext ctx, List JavaDoc catchLabels) {
79       super(cv);
80       m_catchLabels = catchLabels;
81       m_loader = loader;
82       m_callerClassInfo = callerClassInfo;
83       m_ctx = (InstrumentationContext) ctx;
84     }
85
86     /**
87      * Visit method bodies
88      *
89      * @param access
90      * @param callerMethodName
91      * @param callerMethodDesc
92      * @param exceptions
93      * @return
94      */

95     public MethodVisitor visitMethod(final int access,
96                                      final String JavaDoc callerMethodName,
97                                      final String JavaDoc callerMethodDesc,
98                                      final String JavaDoc callerMethodsignature,
99                                      final String JavaDoc[] exceptions) {
100       if (callerMethodName.startsWith(WRAPPER_METHOD_PREFIX)) {
101         return super.visitMethod(access, callerMethodName, callerMethodDesc, callerMethodsignature, exceptions);
102       }
103
104       MethodVisitor mv = cv.visitMethod(access, callerMethodName, callerMethodDesc, callerMethodsignature, exceptions);
105       if (mv == null) {
106         return mv;
107       }
108
109       final MemberInfo callerMemberInfo;
110       if (CLINIT_METHOD_NAME.equals(callerMethodName)) {
111         callerMemberInfo = m_callerClassInfo.staticInitializer();
112       } else if (INIT_METHOD_NAME.equals(callerMethodName)) {
113         int hash = AsmHelper.calculateConstructorHash(callerMethodDesc);
114         callerMemberInfo = m_callerClassInfo.getConstructor(hash);
115       } else {
116         int hash = AsmHelper.calculateMethodHash(callerMethodName, callerMethodDesc);
117         callerMemberInfo = m_callerClassInfo.getMethod(hash);
118       }
119       if (callerMemberInfo == null) {
120         System.err.println(
121                 "AW::WARNING " +
122                         "metadata structure could not be build for method ["
123                         + m_callerClassInfo.getName().replace('/', '.')
124                         + '.' + callerMethodName + ':' + callerMethodDesc + ']'
125         );
126         return mv;
127       }
128
129       return new LookaheadCatchLabelsMethodAdapter(mv, callerMemberInfo, this);
130     }
131   }
132
133   /**
134    * Visit the method, and keep track of all labels so that when visittryCatch is reached
135    * we can remember the index
136    *
137    * @author <a HREF="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
138    */

139   private static final class LookaheadCatchLabelsMethodAdapter extends MethodAdapter {
140     private final MemberInfo info;
141     private final LookaheadCatchLabelsClassAdapter classAdapter;
142
143     private LookaheadCatchLabelsMethodAdapter(MethodVisitor mv, MemberInfo info, LookaheadCatchLabelsClassAdapter classAdapter) {
144       super(mv);
145       this.info = info;
146       this.classAdapter = classAdapter;
147     }
148
149     public void visitLabel(Label label) {
150       classAdapter.m_labelIndexes.put(label, new Integer JavaDoc(++classAdapter.m_labelIndex));
151       super.visitLabel(label);
152     }
153
154     public void visitTryCatchBlock(Label startLabel, Label endLabel, Label handlerLabel,
155                                    String JavaDoc exceptionTypeName) {
156       if (exceptionTypeName == null) {
157         // finally block
158
super.visitTryCatchBlock(startLabel, endLabel, handlerLabel, exceptionTypeName);
159         return;
160       }
161       final ClassInfo exceptionClassInfo = AsmClassInfo.getClassInfo(exceptionTypeName, classAdapter.m_loader);
162       final ExpressionContext ctx = new ExpressionContext(
163               PointcutType.HANDLER, exceptionClassInfo, info
164       );
165       if (!handlerFilter(classAdapter.m_ctx.getDefinitions(), ctx)) {
166         // remember its index and the exception exceptionClassInfo
167
Integer JavaDoc index = (Integer JavaDoc) classAdapter.m_labelIndexes.get(handlerLabel);
168         if (index != null) {
169           classAdapter.m_catchLabels.add(
170                   new CatchLabelStruct(
171                           index.intValue(),
172                           exceptionClassInfo,
173                           classAdapter.m_callerClassInfo,
174                           info
175                   )
176           );
177         }
178       }
179       super.visitTryCatchBlock(startLabel, endLabel, handlerLabel, exceptionTypeName);
180     }
181   }
182   
183   
184   //---- non lookahead visitor
185

186   private final InstrumentationContext m_ctx;
187
188   /**
189    * List of matching catch clause
190    */

191   private final List JavaDoc m_catchLabels;
192
193   /**
194    * catch clause index in whole class
195    */

196   private int m_labelIndex = -1;
197
198   private Label m_lastLabelForLineNumber = EmittedJoinPoint.NO_LINE_NUMBER;
199
200   /**
201    * Creates a new instance.
202    *
203    * @param cv
204    * @param ctx
205    */

206   public HandlerVisitor(final ClassVisitor cv,
207                         final InstrumentationContext ctx,
208                         final List JavaDoc catchLabels) {
209     super(cv);
210     m_ctx = ctx;
211     m_catchLabels = catchLabels;
212   }
213
214   /**
215    * Visits the methods bodies to weave in JP calls at catch clauses
216    *
217    * @param access
218    * @param name
219    * @param desc
220    * @param signature
221    * @param exceptions
222    * @return
223    */

224   public MethodVisitor visitMethod(final int access,
225                                    final String JavaDoc name,
226                                    final String JavaDoc desc,
227                                    final String JavaDoc signature,
228                                    final String JavaDoc[] exceptions) {
229     if (name.startsWith(WRAPPER_METHOD_PREFIX)) {
230       return super.visitMethod(access, name, desc, signature, exceptions);
231     }
232
233     MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions);
234     return mv == null ? null : new CatchClauseCodeAdapter(mv);
235   }
236
237   /**
238    * Advises catch clauses by inserting a call to the join point as the first thing in the catch block.
239    *
240    * @author <a HREF="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
241    */

242   public class CatchClauseCodeAdapter extends MethodAdapter {
243
244     /**
245      * Creates a new instance.
246      *
247      * @param ca
248      */

249     public CatchClauseCodeAdapter(final MethodVisitor ca) {
250       super(ca);
251     }
252
253     public void visitLabel(Label label) {
254       m_lastLabelForLineNumber = label;
255       super.visitLabel(label);
256
257       // check if it is a catch label
258
int index = ++m_labelIndex;
259       CatchLabelStruct catchLabel = null;
260       for (Iterator JavaDoc iterator = m_catchLabels.iterator(); iterator.hasNext();) {
261         CatchLabelStruct aCatchLabel = (CatchLabelStruct) iterator.next();
262         if (aCatchLabel.labelIndexInWholeClass == index) {
263           catchLabel = aCatchLabel;
264           break;
265         }
266       }
267       if (catchLabel == null) {
268         return;
269       }
270       // matched
271
m_ctx.markAsAdvised();
272       final String JavaDoc callerTypeName = catchLabel.caller.getName().replace('.', '/');
273       final String JavaDoc exceptionTypeDesc = catchLabel.exception.getSignature();
274       final String JavaDoc exceptionTypeName = Type.getType(exceptionTypeDesc).getInternalName();
275       final int joinPointHash = AsmHelper.calculateClassHash(exceptionTypeDesc);
276       final String JavaDoc joinPointClassName = TransformationUtil.getJoinPointClassName(
277               callerTypeName,
278               catchLabel.callerMember.getName(),
279               catchLabel.callerMember.getSignature(),
280               exceptionTypeName,
281               JoinPointType.HANDLER_INT,
282               joinPointHash
283       );
284
285       // add the call to the join point
286
// exception instance is on the stack
287
// dup it for ARG0
288
mv.visitInsn(DUP);
289
290       // load caller instance if any
291
if (Modifier.isStatic(catchLabel.callerMember.getModifiers())) {
292         mv.visitInsn(ACONST_NULL);
293       } else {
294         mv.visitVarInsn(ALOAD, 0);
295       }
296       //TODO for now we pass the exception as both CALLEE and ARG0 - may be callee must be NULL
297
//? check in AJ RTTI
298
mv.visitMethodInsn(
299               INVOKESTATIC, joinPointClassName, INVOKE_METHOD_NAME,
300               TransformationUtil.getInvokeSignatureForHandlerJoinPoints(callerTypeName, exceptionTypeName)
301       );
302
303       // emit the joinpoint
304
m_ctx.addEmittedJoinPoint(
305               new EmittedJoinPoint(
306                       JoinPointType.HANDLER_INT,
307                       callerTypeName,
308                       catchLabel.callerMember.getName(),
309                       catchLabel.callerMember.getSignature(),
310                       catchLabel.callerMember.getModifiers(),
311                       exceptionTypeName,
312                       "",
313                       exceptionTypeDesc,
314                       0, // a bit meaningless but must not be static
315
joinPointHash,
316                       joinPointClassName,
317                       m_lastLabelForLineNumber
318               )
319       );
320     }
321   }
322
323   /**
324    * Filters out the catch clauses that are not eligible for transformation.
325    *
326    * @param definitions
327    * @param ctx
328    * @return boolean true if the catch clause should be filtered out
329    */

330   static boolean handlerFilter(final Set JavaDoc definitions, final ExpressionContext ctx) {
331     for (Iterator JavaDoc it = definitions.iterator(); it.hasNext();) {
332       if (((SystemDefinition) it.next()).hasPointcut(ctx)) {
333         return false;
334       } else {
335         continue;
336       }
337     }
338     return true;
339   }
340
341   /**
342    * A struct to represent a catch clause.
343    * The index is class wide, and the exception class info is kept.
344    *
345    * @author <a HREF="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
346    */

347   private static class CatchLabelStruct {
348     int labelIndexInWholeClass = -1;
349     ClassInfo exception = null;
350     ClassInfo caller = null;
351     MemberInfo callerMember = null;
352
353     private CatchLabelStruct(int indexInClass, ClassInfo exception, ClassInfo caller, MemberInfo callerMember) {
354       labelIndexInWholeClass = indexInClass;
355       this.exception = exception;
356       this.caller = caller;
357       this.callerMember = callerMember;
358     }
359   }
360 }
Popular Tags