001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */
004: package com.tc.aspectwerkz.transform.inlining.compiler;
005:
006: import com.tc.asm.MethodVisitor;
007: import com.tc.asm.Opcodes;
008:
009: import com.tc.aspectwerkz.aspect.AdviceInfo;
010: import com.tc.aspectwerkz.aspect.container.AspectFactoryManager;
011: import com.tc.aspectwerkz.cflow.CflowCompiler;
012: import com.tc.aspectwerkz.expression.ast.ASTAnd;
013: import com.tc.aspectwerkz.expression.ast.ASTArgs;
014: import com.tc.aspectwerkz.expression.ast.ASTCall;
015: import com.tc.aspectwerkz.expression.ast.ASTCflow;
016: import com.tc.aspectwerkz.expression.ast.ASTCflowBelow;
017: import com.tc.aspectwerkz.expression.ast.ASTExecution;
018: import com.tc.aspectwerkz.expression.ast.ASTGet;
019: import com.tc.aspectwerkz.expression.ast.ASTHandler;
020: import com.tc.aspectwerkz.expression.ast.ASTHasField;
021: import com.tc.aspectwerkz.expression.ast.ASTHasMethod;
022: import com.tc.aspectwerkz.expression.ast.ASTNot;
023: import com.tc.aspectwerkz.expression.ast.ASTOr;
024: import com.tc.aspectwerkz.expression.ast.ASTPointcutReference;
025: import com.tc.aspectwerkz.expression.ast.ASTSet;
026: import com.tc.aspectwerkz.expression.ast.ASTStaticInitialization;
027: import com.tc.aspectwerkz.expression.ast.ASTTarget;
028: import com.tc.aspectwerkz.expression.ast.ASTThis;
029: import com.tc.aspectwerkz.expression.ast.ASTWithin;
030: import com.tc.aspectwerkz.expression.ast.ASTWithinCode;
031: import com.tc.aspectwerkz.expression.ExpressionVisitor;
032: import com.tc.aspectwerkz.expression.ExpressionInfo;
033: import com.tc.aspectwerkz.expression.Undeterministic;
034: import com.tc.aspectwerkz.expression.ExpressionNamespace;
035: import com.tc.aspectwerkz.expression.ExpressionContext;
036: import com.tc.aspectwerkz.transform.TransformationConstants;
037: import com.tc.aspectwerkz.transform.inlining.AsmHelper;
038: import com.tc.aspectwerkz.transform.inlining.compiler.AbstractJoinPointCompiler;
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 , getDefault, 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: Opcodes {
053: public static final int NULL_PER_OBJECT_TYPE = -1;
054: public static final int PER_THIS_TYPE = 1;
055: public static final int PER_TARGET_TYPE = 2;
056:
057: private MethodVisitor cv;
058:
059: private CompilerInput m_input;
060:
061: private int m_perObjectCheckType = NULL_PER_OBJECT_TYPE;
062:
063: private String m_aspectQName;
064:
065: /**
066: * Create a new visitor given a specific AdviceInfo
067: *
068: * @param cv of the method block we are compiling
069: * @param info expression info
070: * @param input
071: * @param perObjectType
072: * @param aspectQName
073: */
074: public RuntimeCheckVisitor(final MethodVisitor cv,
075: final ExpressionInfo info, final CompilerInput input,
076: final int perObjectType, final String aspectQName) {
077: super (info, info.toString(), info.getNamespace(), info
078: .getExpression().getASTRoot());
079: m_input = input;
080: m_perObjectCheckType = perObjectType;
081: m_aspectQName = aspectQName;
082:
083: this .cv = cv;
084: }
085:
086: /**
087: * Push the boolean typed expression on the stack.
088: *
089: * @param adviceInfo
090: */
091: public void pushCheckOnStack(AdviceInfo adviceInfo) {
092: super .match(adviceInfo.getExpressionContext());
093:
094: switch (m_perObjectCheckType) {
095: case PER_THIS_TYPE: {
096: AbstractJoinPointCompiler.loadCaller(cv, m_input);
097: cv
098: .visitMethodInsn(
099: INVOKESTATIC,
100: AspectFactoryManager
101: .getAspectFactoryClassName(
102: adviceInfo
103: .getAspectClassName(),
104: adviceInfo
105: .getAspectQualifiedName()),
106: TransformationConstants.FACTORY_HASASPECT_METHOD_NAME,
107: TransformationConstants.FACTORY_HASASPECT_PEROBJECT_METHOD_SIGNATURE);
108: cv.visitInsn(IAND);
109:
110: break;
111: }
112:
113: case PER_TARGET_TYPE: {
114: AbstractJoinPointCompiler.loadCallee(cv, m_input);
115: cv
116: .visitMethodInsn(
117: INVOKESTATIC,
118: AspectFactoryManager
119: .getAspectFactoryClassName(
120: adviceInfo
121: .getAspectClassName(),
122: adviceInfo
123: .getAspectQualifiedName()),
124: TransformationConstants.FACTORY_HASASPECT_METHOD_NAME,
125: TransformationConstants.FACTORY_HASASPECT_PEROBJECT_METHOD_SIGNATURE);
126: cv.visitInsn(IAND);
127:
128: break;
129: }
130: }
131: }
132:
133: /**
134: * Handles OR expression
135: *
136: * @param node
137: * @param data
138: * @return
139: */
140: public Object visit(ASTOr node, Object data) {
141: Boolean matchL = (Boolean) node.jjtGetChild(0).jjtAccept(this ,
142: data);
143: Boolean matchR = (Boolean) node.jjtGetChild(1).jjtAccept(this ,
144: data);
145: Boolean intermediate = Undeterministic.or(matchL, matchR);
146: cv.visitInsn(IOR);
147: for (int i = 2; i < node.jjtGetNumChildren(); i++) {
148: Boolean matchNext = (Boolean) node.jjtGetChild(i)
149: .jjtAccept(this , data);
150: intermediate = Undeterministic.or(intermediate, matchNext);
151: cv.visitInsn(IOR);
152: }
153: return intermediate;
154: }
155:
156: public Object visit(ASTAnd node, Object data) {
157: Boolean matchL = (Boolean) node.jjtGetChild(0).jjtAccept(this ,
158: data);
159: Boolean matchR = (Boolean) node.jjtGetChild(1).jjtAccept(this ,
160: data);
161: Boolean intermediate = Undeterministic.and(matchL, matchR);
162: cv.visitInsn(IAND);
163: for (int i = 2; i < node.jjtGetNumChildren(); i++) {
164: Boolean matchNext = (Boolean) node.jjtGetChild(i)
165: .jjtAccept(this , data);
166: intermediate = Undeterministic.and(intermediate, matchNext);
167: cv.visitInsn(IAND);
168: }
169: return intermediate;
170: }
171:
172: public Object visit(ASTNot node, Object data) {
173: Boolean match = (Boolean) node.jjtGetChild(0).jjtAccept(this ,
174: data);
175: cv.visitInsn(INEG);
176: return Undeterministic.not(match);
177: }
178:
179: public Object visit(ASTTarget node, Object data) {
180: Boolean match = (Boolean) super .visit(node, data);
181: if (match != null) {
182: push(match);
183: } else {
184: // runtime check
185: String boundedTypeDesc = AsmHelper
186: .convertReflectDescToTypeDesc(node
187: .getBoundedType(m_expressionInfo));
188: AbstractJoinPointCompiler.loadCallee(cv, m_input);
189: cv.visitTypeInsn(INSTANCEOF, boundedTypeDesc.substring(1,
190: boundedTypeDesc.length() - 1));
191: }
192: return match;
193: }
194:
195: public Object visit(ASTThis node, Object data) {
196: Boolean match = (Boolean) super .visit(node, data);
197: push(match);
198: return match;
199: }
200:
201: public Object visit(ASTCflow node, Object data) {
202: // runtime check
203: String cflowClassName = CflowCompiler
204: .getCflowAspectClassName(node.hashCode());
205: cv.visitMethodInsn(INVOKESTATIC, cflowClassName,
206: TransformationConstants.IS_IN_CFLOW_METOD_NAME,
207: TransformationConstants.IS_IN_CFLOW_METOD_SIGNATURE);
208: return super .visit(node, data);
209: }
210:
211: public Object visit(ASTCflowBelow node, Object data) {
212: // runtime check
213: //TODO: cflowbelow ID will differ from cflow one.. => not optimized
214: String cflowClassName = CflowCompiler
215: .getCflowAspectClassName(node.hashCode());
216: cv.visitMethodInsn(INVOKESTATIC, cflowClassName,
217: TransformationConstants.IS_IN_CFLOW_METOD_NAME,
218: TransformationConstants.IS_IN_CFLOW_METOD_SIGNATURE);
219: return super .visit(node, data);
220: }
221:
222: public Object visit(ASTArgs node, Object data) {
223: Boolean match = (Boolean) super .visit(node, data);
224: push(match);
225: return match;
226: }
227:
228: public Object visit(ASTPointcutReference node, Object data) {
229: ExpressionContext context = (ExpressionContext) data;
230: ExpressionNamespace namespace = ExpressionNamespace
231: .getNamespace(m_namespace);
232: ExpressionVisitor expression = namespace.getExpression(node
233: .getName());
234:
235: // build a new RuntimeCheckVisitor to visit the sub expression
236: RuntimeCheckVisitor referenced = new RuntimeCheckVisitor(cv,
237: expression.getExpressionInfo(), m_input,
238: m_perObjectCheckType, m_aspectQName);
239: return referenced.matchUndeterministic(context);
240: }
241:
242: public Object visit(ASTExecution node, Object data) {
243: Boolean match = (Boolean) super .visit(node, data);
244: push(match);
245: return match;
246: }
247:
248: public Object visit(ASTCall node, Object data) {
249: Boolean match = (Boolean) super .visit(node, data);
250: push(match);
251: return match;
252: }
253:
254: public Object visit(ASTSet node, Object data) {
255: Boolean match = (Boolean) super .visit(node, data);
256: push(match);
257: return match;
258: }
259:
260: public Object visit(ASTGet node, Object data) {
261: Boolean match = (Boolean) super .visit(node, data);
262: push(match);
263: return match;
264: }
265:
266: public Object visit(ASTHandler node, Object data) {
267: Boolean match = (Boolean) super .visit(node, data);
268: push(match);
269: return match;
270: }
271:
272: public Object visit(ASTStaticInitialization node, Object data) {
273: Boolean match = (Boolean) super .visit(node, data);
274: push(match);
275: return match;
276: }
277:
278: public Object visit(ASTWithin node, Object data) {
279: Boolean match = (Boolean) super .visit(node, data);
280: push(match);
281: return match;
282: }
283:
284: public Object visit(ASTWithinCode node, Object data) {
285: Boolean match = (Boolean) super .visit(node, data);
286: push(match);
287: return match;
288: }
289:
290: public Object visit(ASTHasMethod node, Object data) {
291: Boolean match = (Boolean) super .visit(node, data);
292: push(match);
293: return match;
294: }
295:
296: public Object visit(ASTHasField node, Object data) {
297: Boolean match = (Boolean) super .visit(node, data);
298: push(match);
299: return match;
300: }
301:
302: private void push(Boolean b) {
303: if (b == null) {
304: throw new Error(
305: "attempt to push an undetermined match result");
306: } else if (b.booleanValue()) {
307: cv.visitInsn(ICONST_1);
308: } else {
309: cv.visitInsn(ICONST_M1);
310: }
311: }
312: }
|