View Javadoc

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.compiler;
9   
10  
11  import org.codehaus.aspectwerkz.expression.ExpressionVisitor;
12  import org.codehaus.aspectwerkz.expression.Undeterministic;
13  import org.codehaus.aspectwerkz.expression.ExpressionContext;
14  import org.codehaus.aspectwerkz.expression.ExpressionNamespace;
15  import org.codehaus.aspectwerkz.expression.ExpressionInfo;
16  import org.codehaus.aspectwerkz.expression.ast.ASTOr;
17  import org.codehaus.aspectwerkz.expression.ast.ASTAnd;
18  import org.codehaus.aspectwerkz.expression.ast.ASTNot;
19  import org.codehaus.aspectwerkz.expression.ast.ASTTarget;
20  import org.codehaus.aspectwerkz.expression.ast.ASTPointcutReference;
21  import org.codehaus.aspectwerkz.expression.ast.ASTExecution;
22  import org.codehaus.aspectwerkz.expression.ast.ASTCall;
23  import org.codehaus.aspectwerkz.expression.ast.ASTSet;
24  import org.codehaus.aspectwerkz.expression.ast.ASTGet;
25  import org.codehaus.aspectwerkz.expression.ast.ASTHandler;
26  import org.codehaus.aspectwerkz.expression.ast.ASTStaticInitialization;
27  import org.codehaus.aspectwerkz.expression.ast.ASTWithin;
28  import org.codehaus.aspectwerkz.expression.ast.ASTWithinCode;
29  import org.codehaus.aspectwerkz.expression.ast.ASTHasMethod;
30  import org.codehaus.aspectwerkz.expression.ast.ASTHasField;
31  import org.codehaus.aspectwerkz.expression.ast.ASTThis;
32  import org.codehaus.aspectwerkz.expression.ast.ASTCflow;
33  import org.codehaus.aspectwerkz.expression.ast.ASTCflowBelow;
34  import org.codehaus.aspectwerkz.expression.ast.ASTArgs;
35  import org.codehaus.aspectwerkz.transform.inlining.compiler.AbstractJoinPointCompiler;
36  import org.codehaus.aspectwerkz.transform.inlining.AsmHelper;
37  import org.codehaus.aspectwerkz.transform.TransformationConstants;
38  import org.codehaus.aspectwerkz.cflow.CflowCompiler;
39  import org.objectweb.asm.CodeVisitor;
40  import org.objectweb.asm.Constants;
41  
42  /***
43   * Visit an expression and push on the bytecode stack the boolean expression that corresponds to the residual
44   * part for the target(CALLEE) filtering and cflow / cflowbelow runtime checks
45   * <p/>
46   * TODO: for now OR / AND / NOT are turned in IAND etc, ie "&" and not "&&" that is more efficient but is using labels.
47   * <p/>
48   * Note: we have to override here (and maintain) every visit Method that visit a node that appears in an expression
49   * (f.e. set , get, etc, but not ASTParameter), since we cannot rely on AND/OR/NOT nodes to push the boolean expressions.
50   *
51   * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur</a>
52   */
53  public class RuntimeCheckVisitor extends ExpressionVisitor implements Constants {
54  
55      private AbstractJoinPointCompiler m_compiler;
56  
57      private CodeVisitor cv;
58  
59      private ExpressionInfo m_expressionInfo;
60  
61      private boolean m_isOptimizedJoinPoint;
62  
63      private int m_joinPointIndex;
64  
65      private int m_calleeIndex;
66  
67      /***
68       * Create a new visitor given a specific AdviceInfo
69       *
70       * @param compiler             we are working for
71       * @param cv                   of the method block we are compiling
72       * @param info                 expression info
73       * @param isOptimizedJoinPoint
74       * @param joinPointIndex
75       */
76      public RuntimeCheckVisitor(final AbstractJoinPointCompiler compiler, final CodeVisitor cv,
77                                 final ExpressionInfo info, final boolean isOptimizedJoinPoint,
78                                 final int joinPointIndex, final int calleeIndex) {
79          super(
80                  info,
81                  info.toString(),
82                  info.getNamespace(),
83                  info.getExpression().getASTRoot()
84          );
85          m_compiler = compiler;
86          m_expressionInfo = info;
87          m_isOptimizedJoinPoint = isOptimizedJoinPoint;
88          m_joinPointIndex = joinPointIndex;
89          m_calleeIndex = calleeIndex;
90          this.cv = cv;
91      }
92  
93      /***
94       * Push the boolean typed expression on the stack.
95       *
96       * @param context
97       */
98      public void pushCheckOnStack(ExpressionContext context) {
99          super.match(context);
100     }
101 
102     /***
103      * Handles OR expression
104      *
105      * @param node
106      * @param data
107      * @return
108      */
109     public Object visit(ASTOr node, Object data) {
110         Boolean matchL = (Boolean) node.jjtGetChild(0).jjtAccept(this, data);
111         Boolean matchR = (Boolean) node.jjtGetChild(1).jjtAccept(this, data);
112         Boolean intermediate = Undeterministic.or(matchL, matchR);
113         cv.visitInsn(IOR);
114         for (int i = 2; i < node.jjtGetNumChildren(); i++) {
115             Boolean matchNext = (Boolean) node.jjtGetChild(i).jjtAccept(this, data);
116             intermediate = Undeterministic.or(intermediate, matchNext);
117             cv.visitInsn(IOR);
118         }
119         return intermediate;
120     }
121 
122     public Object visit(ASTAnd node, Object data) {
123         Boolean matchL = (Boolean) node.jjtGetChild(0).jjtAccept(this, data);
124         Boolean matchR = (Boolean) node.jjtGetChild(1).jjtAccept(this, data);
125         Boolean intermediate = Undeterministic.and(matchL, matchR);
126         cv.visitInsn(IAND);
127         for (int i = 2; i < node.jjtGetNumChildren(); i++) {
128             Boolean matchNext = (Boolean) node.jjtGetChild(i).jjtAccept(this, data);
129             intermediate = Undeterministic.and(intermediate, matchNext);
130             cv.visitInsn(IAND);
131         }
132         return intermediate;
133     }
134 
135     public Object visit(ASTNot node, Object data) {
136         Boolean match = (Boolean) node.jjtGetChild(0).jjtAccept(this, data);
137         cv.visitInsn(INEG);
138         return Undeterministic.not(match);
139     }
140 
141     public Object visit(ASTTarget node, Object data) {
142         Boolean match = (Boolean) super.visit(node, data);
143         if (match != null) {
144             push(match);
145         } else {
146             // runtime check
147             String boundedTypeDesc = AsmHelper.convertReflectDescToTypeDesc(node.getBoundedType(m_expressionInfo));
148             m_compiler.loadCallee(cv, m_isOptimizedJoinPoint, m_joinPointIndex, m_calleeIndex);
149             cv.visitTypeInsn(INSTANCEOF, boundedTypeDesc.substring(1, boundedTypeDesc.length() - 1));
150         }
151         return match;
152     }
153 
154     public Object visit(ASTThis node, Object data) {
155         Boolean match = (Boolean) super.visit(node, data);
156         push(match);
157         return match;
158     }
159 
160     public Object visit(ASTCflow node, Object data) {
161         // runtime check
162         String cflowClassName = CflowCompiler.getCflowAspectClassName(node.hashCode());
163         cv.visitMethodInsn(
164                 INVOKESTATIC,
165                 cflowClassName,
166                 TransformationConstants.IS_IN_CFLOW_METOD_NAME,
167                 TransformationConstants.IS_IN_CFLOW_METOD_SIGNATURE
168         );
169         return (Boolean) super.visit(node, data);
170     }
171 
172     public Object visit(ASTCflowBelow node, Object data) {
173         // runtime check
174         //TODO: cflowbelow ID will differ from cflow one.. => not optimized
175         String cflowClassName = CflowCompiler.getCflowAspectClassName(node.hashCode());
176         cv.visitMethodInsn(
177                 INVOKESTATIC,
178                 cflowClassName,
179                 TransformationConstants.IS_IN_CFLOW_METOD_NAME,
180                 TransformationConstants.IS_IN_CFLOW_METOD_SIGNATURE
181         );
182         return (Boolean) super.visit(node, data);
183     }
184 
185     public Object visit(ASTArgs node, Object data) {
186         Boolean match = (Boolean) super.visit(node, data);
187         push(match);
188         return match;
189     }
190 
191     public Object visit(ASTPointcutReference node, Object data) {
192         ExpressionContext context = (ExpressionContext) data;
193         ExpressionNamespace namespace = ExpressionNamespace.getNamespace(m_namespace);
194         ExpressionVisitor expression = namespace.getExpression(node.getName());
195 
196         // build a new RuntimeCheckVisitor to visit the sub expression
197         RuntimeCheckVisitor referenced = new RuntimeCheckVisitor(
198                 m_compiler, cv, expression.getExpressionInfo(),
199                 m_isOptimizedJoinPoint, m_joinPointIndex,
200                 m_calleeIndex
201         );
202         return referenced.matchUndeterministic(context);
203     }
204 
205     public Object visit(ASTExecution node, Object data) {
206         Boolean match = (Boolean) super.visit(node, data);
207         push(match);
208         return match;
209     }
210 
211     public Object visit(ASTCall node, Object data) {
212         Boolean match = (Boolean) super.visit(node, data);
213         push(match);
214         return match;
215     }
216 
217     public Object visit(ASTSet node, Object data) {
218         Boolean match = (Boolean) super.visit(node, data);
219         push(match);
220         return match;
221     }
222 
223     public Object visit(ASTGet node, Object data) {
224         Boolean match = (Boolean) super.visit(node, data);
225         push(match);
226         return match;
227     }
228 
229     public Object visit(ASTHandler node, Object data) {
230         Boolean match = (Boolean) super.visit(node, data);
231         push(match);
232         return match;
233     }
234 
235     public Object visit(ASTStaticInitialization node, Object data) {
236         Boolean match = (Boolean) super.visit(node, data);
237         push(match);
238         return match;
239     }
240 
241     public Object visit(ASTWithin node, Object data) {
242         Boolean match = (Boolean) super.visit(node, data);
243         push(match);
244         return match;
245     }
246 
247     public Object visit(ASTWithinCode node, Object data) {
248         Boolean match = (Boolean) super.visit(node, data);
249         push(match);
250         return match;
251     }
252 
253     public Object visit(ASTHasMethod node, Object data) {
254         Boolean match = (Boolean) super.visit(node, data);
255         push(match);
256         return match;
257     }
258 
259     public Object visit(ASTHasField node, Object data) {
260         Boolean match = (Boolean) super.visit(node, data);
261         push(match);
262         return match;
263     }
264 
265 
266     private void push(Boolean b) {
267         if (b == null) {
268             throw new Error("attempt to push an undetermined match result");
269         } else if (b.booleanValue()) {
270             cv.visitInsn(ICONST_1);
271         } else {
272             cv.visitInsn(ICONST_M1);
273         }
274     }
275 }