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
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
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
174
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
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 }