/** Check statement */
 Vset check(Environment env, Context ctx, Vset vset, Hashtable exp) {
   checkLabel(env, ctx);
   CheckContext newctx = new CheckContext(ctx, this);
   // Vset vsExtra = vset.copy();  // See comment below.
   ConditionVars cvars = cond.checkCondition(env, newctx, reach(env, vset), exp);
   cond = convert(env, newctx, Type.tBoolean, cond);
   // The following code, now deleted, was apparently an erroneous attempt
   // at providing better error diagnostics.  The comment read: 'If either
   // the true clause or the false clause is unreachable, do a reasonable
   // check on the child anyway.'
   //    Vset vsTrue  = cvars.vsTrue.isDeadEnd() ? vsExtra : cvars.vsTrue;
   //    Vset vsFalse = cvars.vsFalse.isDeadEnd() ? vsExtra : cvars.vsFalse;
   // Unfortunately, this violates the rules laid out in the JLS, and leads to
   // blatantly incorrect results.  For example, 'i' will not be recognized
   // as definitely assigned following the statement 'if (true) i = 1;'.
   // It is best to slavishly follow the JLS here.  A cleverer approach could
   // only correctly issue warnings, as JLS 16.2.6 is quite explicit, and it
   // is OK for a dead branch of an if-statement to omit an assignment that
   // would be required in the other branch.  A complication: This code also
   // had the effect of implementing the special-case rules for 'if-then' and
   // 'if-then-else' in JLS 14.19, "Unreachable Statements".  We now use
   // 'Vset.clearDeadEnd' to remove the dead-end status of unreachable branches
   // without affecting the definite-assignment status of the variables, thus
   // maintaining a correct implementation of JLS 16.2.6.  Fixes 4094353.
   // Note that the code below will not consider the branches unreachable if
   // the entire statement is unreachable.  This is consistent with the error
   // recovery policy that reports the only the first unreachable statement
   // along an acyclic execution path.
   Vset vsTrue = cvars.vsTrue.clearDeadEnd();
   Vset vsFalse = cvars.vsFalse.clearDeadEnd();
   vsTrue = ifTrue.check(env, newctx, vsTrue, exp);
   if (ifFalse != null) vsFalse = ifFalse.check(env, newctx, vsFalse, exp);
   vset = vsTrue.join(vsFalse.join(newctx.vsBreak));
   return ctx.removeAdditionalVars(vset);
 }
示例#2
0
 /** Print */
 public void print(PrintStream out, int indent) {
   super.print(out, indent);
   out.print("return");
   if (expr != null) {
     out.print(" ");
     expr.print(out);
   }
   out.print(";");
 }
 /** The cost of inlining this statement */
 public int costInline(int thresh, Environment env, Context ctx) {
   int cost = 1 + cond.costInline(thresh, env, ctx);
   if (ifTrue != null) {
     cost += ifTrue.costInline(thresh, env, ctx);
   }
   if (ifFalse != null) {
     cost += ifFalse.costInline(thresh, env, ctx);
   }
   return cost;
 }
示例#4
0
 /** Code */
 public void code(Environment env, Context ctx, Assembler asm) {
   if (expr == null) {
     codeFinally(env, ctx, asm, null, null);
     asm.add(where, opc_return);
   } else {
     expr.codeValue(env, ctx, asm);
     codeFinally(env, ctx, asm, null, expr.type);
     asm.add(where, opc_ireturn + expr.type.getTypeCodeOffset());
   }
 }
示例#5
0
 /** Create a copy of the statement for method inlining */
 public Statement copyInline(Context ctx, boolean valNeeded) {
   Expression e = (expr != null) ? expr.copyInline(ctx) : null;
   if ((!valNeeded) && (e != null)) {
     Statement body[] = {
       new ExpressionStatement(where, e), new InlineReturnStatement(where, null)
     };
     return new CompoundStatement(where, body);
   }
   return new InlineReturnStatement(where, e);
 }
 /** Print */
 public void print(PrintStream out, int indent) {
   super.print(out, indent);
   out.print("if ");
   cond.print(out);
   out.print(" ");
   ifTrue.print(out, indent);
   if (ifFalse != null) {
     out.print(" else ");
     ifFalse.print(out, indent);
   }
 }
 /** Create a copy of the statement for method inlining */
 public Statement copyInline(Context ctx, boolean valNeeded) {
   IfStatement s = (IfStatement) clone();
   s.cond = cond.copyInline(ctx);
   if (ifTrue != null) {
     s.ifTrue = ifTrue.copyInline(ctx, valNeeded);
   }
   if (ifFalse != null) {
     s.ifFalse = ifFalse.copyInline(ctx, valNeeded);
   }
   return s;
 }
  /** Inline */
  public Statement inline(Environment env, Context ctx) {
    ctx = new Context(ctx, this);
    cond = cond.inlineValue(env, ctx);

    // The compiler currently needs to perform inlining on both
    // branches of the if statement -- even if `cond' is a constant
    // true or false.  Why?  The compiler will later try to compile
    // all classes that it has seen; this includes classes that
    // appear in dead code.  If we don't inline the dead branch here
    // then the compiler will never perform inlining on any local
    // classes appearing on the dead code.  When the compiler tries
    // to compile an un-inlined local class with uplevel references,
    // it dies.  (bug 4059492)
    //
    // A better solution to this would be to walk the dead branch and
    // mark any local classes appearing therein as unneeded.  Then the
    // compilation phase could skip these classes.
    if (ifTrue != null) {
      ifTrue = ifTrue.inline(env, ctx);
    }
    if (ifFalse != null) {
      ifFalse = ifFalse.inline(env, ctx);
    }
    if (cond.equals(true)) {
      return eliminate(env, ifTrue);
    }
    if (cond.equals(false)) {
      return eliminate(env, ifFalse);
    }
    if ((ifTrue == null) && (ifFalse == null)) {
      return eliminate(env, new ExpressionStatement(where, cond).inline(env, ctx));
    }
    if (ifTrue == null) {
      cond = new NotExpression(cond.where, cond).inlineValue(env, ctx);
      return eliminate(env, new IfStatement(where, cond, ifFalse, null));
    }
    return this;
  }
  /** Code */
  public void code(Environment env, Context ctx, Assembler asm) {
    CodeContext newctx = new CodeContext(ctx, this);

    Label l1 = new Label();
    cond.codeBranch(env, newctx, asm, l1, false);
    ifTrue.code(env, newctx, asm);
    if (ifFalse != null) {
      Label l2 = new Label();
      asm.add(true, where, opc_goto, l2);
      asm.add(l1);
      ifFalse.code(env, newctx, asm);
      asm.add(l2);
    } else {
      asm.add(l1);
    }

    asm.add(newctx.breakLabel);
  }
示例#10
0
  /** Check statement */
  Vset check(Environment env, Context ctx, Vset vset, Hashtable exp) {
    checkLabel(env, ctx);
    vset = reach(env, vset);
    if (expr != null) {
      vset = expr.checkValue(env, ctx, vset, exp);
    }

    // Make sure the return isn't inside a static initializer
    if (ctx.field.isInitializer()) {
      env.error(where, "return.inside.static.initializer");
      return DEAD_END;
    }
    // Check return type
    if (ctx.field.getType().getReturnType().isType(TC_VOID)) {
      if (expr != null) {
        if (ctx.field.isConstructor()) {
          env.error(where, "return.with.value.constr", ctx.field);
        } else {
          env.error(where, "return.with.value", ctx.field);
        }
        expr = null;
      }
    } else {
      if (expr == null) {
        env.error(where, "return.without.value", ctx.field);
      } else {
        expr = convert(env, ctx, ctx.field.getType().getReturnType(), expr);
      }
    }
    CheckContext mctx = ctx.getReturnContext();
    if (mctx != null) {
      mctx.vsBreak = mctx.vsBreak.join(vset);
    }
    CheckContext exitctx = ctx.getTryExitContext();
    if (exitctx != null) {
      exitctx.vsTryExit = exitctx.vsTryExit.join(vset);
    }
    if (expr != null) {
      // see if we are returning a value out of a try or synchronized
      // statement.  If so, find the outermost one. . . .
      Node outerFinallyNode = null;
      for (Context c = ctx; c != null; c = c.prev) {
        if (c.node == null) {
          continue;
        }
        if (c.node.op == METHOD) {
          // Don't search outside current method. Fixes 4084230.
          break;
        }
        if (c.node.op == SYNCHRONIZED) {
          outerFinallyNode = c.node;
          break;
        } else if (c.node.op == FINALLY && ((CheckContext) c).vsContinue != null) {
          outerFinallyNode = c.node;
        }
      }
      if (outerFinallyNode != null) {
        if (outerFinallyNode.op == FINALLY) {
          ((FinallyStatement) outerFinallyNode).needReturnSlot = true;
        } else {
          ((SynchronizedStatement) outerFinallyNode).needReturnSlot = true;
        }
      }
    }
    return DEAD_END;
  }
示例#11
0
 /** The cost of inlining this statement */
 public int costInline(int thresh, Environment env, Context ctx) {
   return 1 + ((expr != null) ? expr.costInline(thresh, env, ctx) : 0);
 }
示例#12
0
 /** Inline */
 public Statement inline(Environment env, Context ctx) {
   if (expr != null) {
     expr = expr.inlineValue(env, ctx);
   }
   return this;
 }