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 }