Example #1
0
    /**
     * Inline a call to an expression. Returns {@code InlineResult.BLACKLIST} if the method is
     * deemed not inlineable regardless of call site; {@code InlineResult.DO_NOT_BLACKLIST}
     * otherwise.
     */
    private InlineResult tryInlineBody(
        JMethodCall x,
        Context ctx,
        List<JExpression> bodyAsExpressionList,
        boolean ignoringReturn) {

      if (isTooComplexToInline(bodyAsExpressionList, ignoringReturn)) {
        return InlineResult.BLACKLIST;
      }

      // Do not inline anything that modifies one of its params.
      ExpressionAnalyzer targetAnalyzer = new ExpressionAnalyzer();
      targetAnalyzer.accept(bodyAsExpressionList);
      if (targetAnalyzer.hasAssignmentToParameter()) {
        return InlineResult.BLACKLIST;
      }

      // Make sure the expression we're about to inline doesn't include a call
      // to the target method!
      RecursionCheckVisitor recursionCheckVisitor = new RecursionCheckVisitor(x.getTarget());
      recursionCheckVisitor.accept(bodyAsExpressionList);
      if (recursionCheckVisitor.isRecursive()) {
        return InlineResult.BLACKLIST;
      }

      /*
       * After this point, it's possible that the method might be inlinable at
       * some call sites, depending on its arguments. From here on return 'true'
       * as the method might be inlinable elsewhere.
       */

      /*
       * There are a different number of parameters than args - this is likely a
       * result of parameter pruning. Don't consider this call site a candidate.
       *
       * TODO: would this be possible in the trivial delegation case?
       */
      if (x.getTarget().getParams().size() != x.getArgs().size()) {
        // Could not inline this call but the method might be inlineable at a different call site.
        return InlineResult.DO_NOT_BLACKLIST;
      }

      // Run the order check. This verifies that all the parameters are
      // referenced once and only once, not within a conditionally-executing
      // expression and before any tricky target expressions, such as:
      // - assignments to any variable
      // - expressions that throw exceptions
      // - field references

      /*
       * Ensure correct evaluation order or params relative to each other and to
       * other expressions.
       */
      OrderVisitor orderVisitor = new OrderVisitor(x.getTarget().getParams());
      orderVisitor.accept(bodyAsExpressionList);

      switch (orderVisitor.checkResults()) {
        case NO_REFERENCES:
          /*
           * A method that doesn't touch any parameters is trivially inlinable (this
           * covers the empty method case)
           */
          if (!x.hasSideEffects()) {
            markCallsAsSideEffectFree(bodyAsExpressionList);
          }
          new LocalVariableExtruder(getCurrentMethod()).accept(bodyAsExpressionList);
          List<JExpression> expressions = expressionsIncludingArgs(x);
          expressions.addAll(bodyAsExpressionList);
          ctx.replaceMe(JjsUtils.createOptimizedMultiExpression(ignoringReturn, expressions));
          return InlineResult.DO_NOT_BLACKLIST;
        case FAILS:
          /*
           * We can still inline in the case where all of the actual arguments are
           * "safe". They must have no side effects, and also have values which
           * could not be affected by the execution of any code within the callee.
           */
          for (JExpression arg : x.getArgs()) {
            ExpressionAnalyzer argAnalyzer = new ExpressionAnalyzer();
            argAnalyzer.accept(arg);

            if (argAnalyzer.hasAssignment()
                || argAnalyzer.accessesField()
                || argAnalyzer.createsObject()
                || argAnalyzer.canThrowException()) {

              /*
               * This argument evaluation could affect or be affected by the
               * callee so we cannot inline here.
               */
              // Could not inline this call but the method is potentially inlineable.
              return InlineResult.DO_NOT_BLACKLIST;
            }
          }
          // Fall through!
        case CORRECT_ORDER:
        default:
          if (!x.hasSideEffects()) {
            markCallsAsSideEffectFree(bodyAsExpressionList);
          }
          new LocalVariableExtruder(getCurrentMethod()).accept(bodyAsExpressionList);
          // Replace all params in the target expression with the actual arguments.
          ParameterReplacer replacer = new ParameterReplacer(x);
          replacer.accept(bodyAsExpressionList);
          bodyAsExpressionList.add(0, x.getInstance());
          bodyAsExpressionList.add(1, createClinitCall(x));
          ctx.replaceMe(
              JjsUtils.createOptimizedMultiExpression(ignoringReturn, bodyAsExpressionList));
          return InlineResult.DO_NOT_BLACKLIST;
      }
    }
Example #2
0
    /** Inline a call to an expression. */
    private boolean tryInlineExpression(JMethodCall x, Context ctx, JMultiExpression targetExpr) {
      /*
       * Limit inlined methods to multiexpressions of length 2 for now. This
       * handles the simple { return JVariableRef; } or { expression; return
       * something; } cases.
       *
       * TODO: add an expression complexity analyzer.
       */
      if (targetExpr.getNumberOfExpressions() > 2) {
        return false;
      }

      // Do not inline anything that modifies one of its params.
      ExpressionAnalyzer targetAnalyzer = new ExpressionAnalyzer();
      targetAnalyzer.accept(targetExpr);
      if (targetAnalyzer.hasAssignmentToParameter()) {
        return false;
      }

      // Make sure the expression we're about to inline doesn't include a call
      // to the target method!
      RecursionCheckVisitor recursionCheckVisitor = new RecursionCheckVisitor(x.getTarget());
      recursionCheckVisitor.accept(targetExpr);
      if (recursionCheckVisitor.isRecursive()) {
        return false;
      }

      /*
       * After this point, it's possible that the method might be inlinable at
       * some call sites, depending on its arguments. From here on return 'true'
       * as the method might be inlinable elsewhere.
       */

      /*
       * There are a different number of parameters than args - this is likely a
       * result of parameter pruning. Don't consider this call site a candidate.
       *
       * TODO: would this be possible in the trivial delegation case?
       */
      if (x.getTarget().getParams().size() != x.getArgs().size()) {
        return true;
      }

      // Run the order check. This verifies that all the parameters are
      // referenced once and only once, not within a conditionally-executing
      // expression and before any tricky target expressions, such as:
      // - assignments to any variable
      // - expressions that throw exceptions
      // - field references

      /*
       * Ensure correct evaluation order or params relative to each other and to
       * other expressions.
       */
      OrderVisitor orderVisitor = new OrderVisitor(x.getTarget().getParams());
      orderVisitor.accept(targetExpr);

      /*
       * A method that doesn't touch any parameters is trivially inlinable (this
       * covers the empty method case)
       */
      if (orderVisitor.checkResults() == SideEffectCheck.NO_REFERENCES) {
        JMultiExpression multi = createMultiExpressionIncludingArgs(x);
        multi.addExpressions(targetExpr);
        replaceWithMulti(ctx, multi);
        return true;
      }

      /*
       * We can still inline in the case where all of the actual arguments are
       * "safe". They must have no side effects, and also have values which
       * could not be affected by the execution of any code within the callee.
       */
      if (orderVisitor.checkResults() == SideEffectCheck.FAILS) {
        for (JExpression arg : x.getArgs()) {
          ExpressionAnalyzer argAnalyzer = new ExpressionAnalyzer();
          argAnalyzer.accept(arg);

          if (argAnalyzer.hasAssignment()
              || argAnalyzer.accessesField()
              || argAnalyzer.createsObject()
              || argAnalyzer.canThrowException()) {

            /*
             * This argument evaluation could affect or be affected by the
             * callee so we cannot inline here.
             */
            return true;
          }
        }
      }

      // We're safe to inline.
      JMultiExpression multi = createMultiExpressionForInstanceAndClinit(x);

      // Replace all params in the target expression with the actual arguments.
      ParameterReplacer replacer = new ParameterReplacer(x);
      replacer.accept(targetExpr);

      multi.addExpressions(targetExpr);
      replaceWithMulti(ctx, multi);
      return true;
    }