001: /**************************************************************************************
002: * Copyright (c) Jonas Bon?r, Alexandre Vasseur. All rights reserved. *
003: * http://aspectwerkz.codehaus.org *
004: * ---------------------------------------------------------------------------------- *
005: * The software in this package is published under the terms of the LGPL license *
006: * a copy of which has been included with this distribution in the license.txt file. *
007: **************************************************************************************/package org.codehaus.aspectwerkz.transform.inlining.compiler;
008:
009: import org.codehaus.aspectwerkz.expression.ExpressionVisitor;
010: import org.codehaus.aspectwerkz.expression.Undeterministic;
011: import org.codehaus.aspectwerkz.expression.ExpressionContext;
012: import org.codehaus.aspectwerkz.expression.ExpressionNamespace;
013: import org.codehaus.aspectwerkz.expression.ExpressionInfo;
014: import org.codehaus.aspectwerkz.expression.ast.ASTOr;
015: import org.codehaus.aspectwerkz.expression.ast.ASTAnd;
016: import org.codehaus.aspectwerkz.expression.ast.ASTNot;
017: import org.codehaus.aspectwerkz.expression.ast.ASTTarget;
018: import org.codehaus.aspectwerkz.expression.ast.ASTPointcutReference;
019: import org.codehaus.aspectwerkz.expression.ast.ASTExecution;
020: import org.codehaus.aspectwerkz.expression.ast.ASTCall;
021: import org.codehaus.aspectwerkz.expression.ast.ASTSet;
022: import org.codehaus.aspectwerkz.expression.ast.ASTGet;
023: import org.codehaus.aspectwerkz.expression.ast.ASTHandler;
024: import org.codehaus.aspectwerkz.expression.ast.ASTStaticInitialization;
025: import org.codehaus.aspectwerkz.expression.ast.ASTWithin;
026: import org.codehaus.aspectwerkz.expression.ast.ASTWithinCode;
027: import org.codehaus.aspectwerkz.expression.ast.ASTHasMethod;
028: import org.codehaus.aspectwerkz.expression.ast.ASTHasField;
029: import org.codehaus.aspectwerkz.expression.ast.ASTThis;
030: import org.codehaus.aspectwerkz.expression.ast.ASTCflow;
031: import org.codehaus.aspectwerkz.expression.ast.ASTCflowBelow;
032: import org.codehaus.aspectwerkz.expression.ast.ASTArgs;
033: import org.codehaus.aspectwerkz.transform.inlining.compiler.AbstractJoinPointCompiler;
034: import org.codehaus.aspectwerkz.transform.inlining.AsmHelper;
035: import org.codehaus.aspectwerkz.transform.TransformationConstants;
036: import org.codehaus.aspectwerkz.cflow.CflowCompiler;
037: import org.objectweb.asm.CodeVisitor;
038: import org.objectweb.asm.Constants;
039:
040: /**
041: * Visit an expression and push on the bytecode stack the boolean expression that corresponds to the residual
042: * part for the target(CALLEE) filtering and cflow / cflowbelow runtime checks
043: * <p/>
044: * TODO: for now OR / AND / NOT are turned in IAND etc, ie "&" and not "&&" that is more efficient but is using labels.
045: * <p/>
046: * Note: we have to override here (and maintain) every visit Method that visit a node that appears in an expression
047: * (f.e. set , get, etc, but not ASTParameter), since we cannot rely on AND/OR/NOT nodes to push the boolean expressions.
048: *
049: * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur</a>
050: */
051: public class RuntimeCheckVisitor extends ExpressionVisitor implements
052: Constants {
053:
054: private AbstractJoinPointCompiler m_compiler;
055:
056: private CodeVisitor cv;
057:
058: private ExpressionInfo m_expressionInfo;
059:
060: private boolean m_isOptimizedJoinPoint;
061:
062: private int m_joinPointIndex;
063:
064: private int m_calleeIndex;
065:
066: /**
067: * Create a new visitor given a specific AdviceInfo
068: *
069: * @param compiler we are working for
070: * @param cv of the method block we are compiling
071: * @param info expression info
072: * @param isOptimizedJoinPoint
073: * @param joinPointIndex
074: */
075: public RuntimeCheckVisitor(
076: final AbstractJoinPointCompiler compiler,
077: final CodeVisitor cv, final ExpressionInfo info,
078: final boolean isOptimizedJoinPoint,
079: final int joinPointIndex, final int calleeIndex) {
080: super (info, info.toString(), info.getNamespace(), info
081: .getExpression().getASTRoot());
082: m_compiler = compiler;
083: m_expressionInfo = info;
084: m_isOptimizedJoinPoint = isOptimizedJoinPoint;
085: m_joinPointIndex = joinPointIndex;
086: m_calleeIndex = calleeIndex;
087: this .cv = cv;
088: }
089:
090: /**
091: * Push the boolean typed expression on the stack.
092: *
093: * @param context
094: */
095: public void pushCheckOnStack(ExpressionContext context) {
096: super .match(context);
097: }
098:
099: /**
100: * Handles OR expression
101: *
102: * @param node
103: * @param data
104: * @return
105: */
106: public Object visit(ASTOr node, Object data) {
107: Boolean matchL = (Boolean) node.jjtGetChild(0).jjtAccept(this ,
108: data);
109: Boolean matchR = (Boolean) node.jjtGetChild(1).jjtAccept(this ,
110: data);
111: Boolean intermediate = Undeterministic.or(matchL, matchR);
112: cv.visitInsn(IOR);
113: for (int i = 2; i < node.jjtGetNumChildren(); i++) {
114: Boolean matchNext = (Boolean) node.jjtGetChild(i)
115: .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 ,
124: data);
125: Boolean matchR = (Boolean) node.jjtGetChild(1).jjtAccept(this ,
126: data);
127: Boolean intermediate = Undeterministic.and(matchL, matchR);
128: cv.visitInsn(IAND);
129: for (int i = 2; i < node.jjtGetNumChildren(); i++) {
130: Boolean matchNext = (Boolean) node.jjtGetChild(i)
131: .jjtAccept(this , data);
132: intermediate = Undeterministic.and(intermediate, matchNext);
133: cv.visitInsn(IAND);
134: }
135: return intermediate;
136: }
137:
138: public Object visit(ASTNot node, Object data) {
139: Boolean match = (Boolean) node.jjtGetChild(0).jjtAccept(this ,
140: data);
141: cv.visitInsn(INEG);
142: return Undeterministic.not(match);
143: }
144:
145: public Object visit(ASTTarget node, Object data) {
146: Boolean match = (Boolean) super .visit(node, data);
147: if (match != null) {
148: push(match);
149: } else {
150: // runtime check
151: String boundedTypeDesc = AsmHelper
152: .convertReflectDescToTypeDesc(node
153: .getBoundedType(m_expressionInfo));
154: m_compiler.loadCallee(cv, m_isOptimizedJoinPoint,
155: m_joinPointIndex, m_calleeIndex);
156: cv.visitTypeInsn(INSTANCEOF, boundedTypeDesc.substring(1,
157: boundedTypeDesc.length() - 1));
158: }
159: return match;
160: }
161:
162: public Object visit(ASTThis node, Object data) {
163: Boolean match = (Boolean) super .visit(node, data);
164: push(match);
165: return match;
166: }
167:
168: public Object visit(ASTCflow node, Object data) {
169: // runtime check
170: String cflowClassName = CflowCompiler
171: .getCflowAspectClassName(node.hashCode());
172: cv.visitMethodInsn(INVOKESTATIC, cflowClassName,
173: TransformationConstants.IS_IN_CFLOW_METOD_NAME,
174: TransformationConstants.IS_IN_CFLOW_METOD_SIGNATURE);
175: return (Boolean) super .visit(node, data);
176: }
177:
178: public Object visit(ASTCflowBelow node, Object data) {
179: // runtime check
180: //TODO: cflowbelow ID will differ from cflow one.. => not optimized
181: String cflowClassName = CflowCompiler
182: .getCflowAspectClassName(node.hashCode());
183: cv.visitMethodInsn(INVOKESTATIC, cflowClassName,
184: TransformationConstants.IS_IN_CFLOW_METOD_NAME,
185: TransformationConstants.IS_IN_CFLOW_METOD_SIGNATURE);
186: return (Boolean) super .visit(node, data);
187: }
188:
189: public Object visit(ASTArgs node, Object data) {
190: Boolean match = (Boolean) super .visit(node, data);
191: push(match);
192: return match;
193: }
194:
195: public Object visit(ASTPointcutReference node, Object data) {
196: ExpressionContext context = (ExpressionContext) data;
197: ExpressionNamespace namespace = ExpressionNamespace
198: .getNamespace(m_namespace);
199: ExpressionVisitor expression = namespace.getExpression(node
200: .getName());
201:
202: // build a new RuntimeCheckVisitor to visit the sub expression
203: RuntimeCheckVisitor referenced = new RuntimeCheckVisitor(
204: m_compiler, cv, expression.getExpressionInfo(),
205: m_isOptimizedJoinPoint, m_joinPointIndex, m_calleeIndex);
206: return referenced.matchUndeterministic(context);
207: }
208:
209: public Object visit(ASTExecution node, Object data) {
210: Boolean match = (Boolean) super .visit(node, data);
211: push(match);
212: return match;
213: }
214:
215: public Object visit(ASTCall node, Object data) {
216: Boolean match = (Boolean) super .visit(node, data);
217: push(match);
218: return match;
219: }
220:
221: public Object visit(ASTSet node, Object data) {
222: Boolean match = (Boolean) super .visit(node, data);
223: push(match);
224: return match;
225: }
226:
227: public Object visit(ASTGet node, Object data) {
228: Boolean match = (Boolean) super .visit(node, data);
229: push(match);
230: return match;
231: }
232:
233: public Object visit(ASTHandler node, Object data) {
234: Boolean match = (Boolean) super .visit(node, data);
235: push(match);
236: return match;
237: }
238:
239: public Object visit(ASTStaticInitialization node, Object data) {
240: Boolean match = (Boolean) super .visit(node, data);
241: push(match);
242: return match;
243: }
244:
245: public Object visit(ASTWithin node, Object data) {
246: Boolean match = (Boolean) super .visit(node, data);
247: push(match);
248: return match;
249: }
250:
251: public Object visit(ASTWithinCode node, Object data) {
252: Boolean match = (Boolean) super .visit(node, data);
253: push(match);
254: return match;
255: }
256:
257: public Object visit(ASTHasMethod node, Object data) {
258: Boolean match = (Boolean) super .visit(node, data);
259: push(match);
260: return match;
261: }
262:
263: public Object visit(ASTHasField node, Object data) {
264: Boolean match = (Boolean) super .visit(node, data);
265: push(match);
266: return match;
267: }
268:
269: private void push(Boolean b) {
270: if (b == null) {
271: throw new Error(
272: "attempt to push an undetermined match result");
273: } else if (b.booleanValue()) {
274: cv.visitInsn(ICONST_1);
275: } else {
276: cv.visitInsn(ICONST_M1);
277: }
278: }
279: }
|