/** 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);
 }
 /** 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;
 }
 /** 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;
 }
  /** 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);
  }
Exemplo n.º 6
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(";");
 }
  /** 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;
  }