| Index: runtime/vm/flow_graph_optimizer.cc
 | 
| ===================================================================
 | 
| --- runtime/vm/flow_graph_optimizer.cc	(revision 42566)
 | 
| +++ runtime/vm/flow_graph_optimizer.cc	(working copy)
 | 
| @@ -33,9 +33,6 @@
 | 
|  DEFINE_FLAG(int, max_equality_polymorphic_checks, 32,
 | 
|      "Maximum number of polymorphic checks in equality operator,"
 | 
|      " otherwise use megamorphic dispatch.");
 | 
| -DEFINE_FLAG(bool, remove_redundant_phis, true, "Remove redundant phis.");
 | 
| -DEFINE_FLAG(bool, trace_constant_propagation, false,
 | 
| -    "Print constant propagation and useless code elimination.");
 | 
|  DEFINE_FLAG(bool, trace_load_optimization, false,
 | 
|      "Print live sets for load optimization pass.");
 | 
|  DEFINE_FLAG(bool, trace_optimization, false, "Print optimization details.");
 | 
| @@ -7500,1619 +7497,6 @@
 | 
|  }
 | 
|  
 | 
|  
 | 
| -ConstantPropagator::ConstantPropagator(
 | 
| -    FlowGraph* graph,
 | 
| -    const GrowableArray<BlockEntryInstr*>& ignored)
 | 
| -    : FlowGraphVisitor(ignored),
 | 
| -      graph_(graph),
 | 
| -      unknown_(Object::unknown_constant()),
 | 
| -      non_constant_(Object::non_constant()),
 | 
| -      reachable_(new(graph->isolate()) BitVector(
 | 
| -          graph->isolate(), graph->preorder().length())),
 | 
| -      marked_phis_(new(graph->isolate()) BitVector(
 | 
| -          graph->isolate(), graph->max_virtual_register_number())),
 | 
| -      block_worklist_(),
 | 
| -      definition_worklist_(graph, 10) {}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::Optimize(FlowGraph* graph) {
 | 
| -  GrowableArray<BlockEntryInstr*> ignored;
 | 
| -  ConstantPropagator cp(graph, ignored);
 | 
| -  cp.Analyze();
 | 
| -  cp.Transform();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::OptimizeBranches(FlowGraph* graph) {
 | 
| -  GrowableArray<BlockEntryInstr*> ignored;
 | 
| -  ConstantPropagator cp(graph, ignored);
 | 
| -  cp.Analyze();
 | 
| -  cp.Transform();
 | 
| -  cp.EliminateRedundantBranches();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::SetReachable(BlockEntryInstr* block) {
 | 
| -  if (!reachable_->Contains(block->preorder_number())) {
 | 
| -    reachable_->Add(block->preorder_number());
 | 
| -    block_worklist_.Add(block);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -bool ConstantPropagator::SetValue(Definition* definition, const Object& value) {
 | 
| -  // We would like to assert we only go up (toward non-constant) in the lattice.
 | 
| -  //
 | 
| -  // ASSERT(IsUnknown(definition->constant_value()) ||
 | 
| -  //        IsNonConstant(value) ||
 | 
| -  //        (definition->constant_value().raw() == value.raw()));
 | 
| -  //
 | 
| -  // But the final disjunct is not true (e.g., mint or double constants are
 | 
| -  // heap-allocated and so not necessarily pointer-equal on each iteration).
 | 
| -  if (definition->constant_value().raw() != value.raw()) {
 | 
| -    definition->constant_value() = value.raw();
 | 
| -    if (definition->input_use_list() != NULL) {
 | 
| -      definition_worklist_.Add(definition);
 | 
| -    }
 | 
| -    return true;
 | 
| -  }
 | 
| -  return false;
 | 
| -}
 | 
| -
 | 
| -
 | 
| -// Compute the join of two values in the lattice, assign it to the first.
 | 
| -void ConstantPropagator::Join(Object* left, const Object& right) {
 | 
| -  // Join(non-constant, X) = non-constant
 | 
| -  // Join(X, unknown)      = X
 | 
| -  if (IsNonConstant(*left) || IsUnknown(right)) return;
 | 
| -
 | 
| -  // Join(unknown, X)      = X
 | 
| -  // Join(X, non-constant) = non-constant
 | 
| -  if (IsUnknown(*left) || IsNonConstant(right)) {
 | 
| -    *left = right.raw();
 | 
| -    return;
 | 
| -  }
 | 
| -
 | 
| -  // Join(X, X) = X
 | 
| -  // TODO(kmillikin): support equality for doubles, mints, etc.
 | 
| -  if (left->raw() == right.raw()) return;
 | 
| -
 | 
| -  // Join(X, Y) = non-constant
 | 
| -  *left = non_constant_.raw();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -// --------------------------------------------------------------------------
 | 
| -// Analysis of blocks.  Called at most once per block.  The block is already
 | 
| -// marked as reachable.  All instructions in the block are analyzed.
 | 
| -void ConstantPropagator::VisitGraphEntry(GraphEntryInstr* block) {
 | 
| -  const GrowableArray<Definition*>& defs = *block->initial_definitions();
 | 
| -  for (intptr_t i = 0; i < defs.length(); ++i) {
 | 
| -    defs[i]->Accept(this);
 | 
| -  }
 | 
| -  ASSERT(ForwardInstructionIterator(block).Done());
 | 
| -
 | 
| -  // TODO(fschneider): Improve this approximation. The catch entry is only
 | 
| -  // reachable if a call in the try-block is reachable.
 | 
| -  for (intptr_t i = 0; i < block->SuccessorCount(); ++i) {
 | 
| -    SetReachable(block->SuccessorAt(i));
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitJoinEntry(JoinEntryInstr* block) {
 | 
| -  // Phis are visited when visiting Goto at a predecessor. See VisitGoto.
 | 
| -  for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
 | 
| -    it.Current()->Accept(this);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitTargetEntry(TargetEntryInstr* block) {
 | 
| -  for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
 | 
| -    it.Current()->Accept(this);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitIndirectEntry(IndirectEntryInstr* block) {
 | 
| -  for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
 | 
| -    it.Current()->Accept(this);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitCatchBlockEntry(CatchBlockEntryInstr* block) {
 | 
| -  const GrowableArray<Definition*>& defs = *block->initial_definitions();
 | 
| -  for (intptr_t i = 0; i < defs.length(); ++i) {
 | 
| -    defs[i]->Accept(this);
 | 
| -  }
 | 
| -  for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
 | 
| -    it.Current()->Accept(this);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitParallelMove(ParallelMoveInstr* instr) {
 | 
| -  // Parallel moves have not yet been inserted in the graph.
 | 
| -  UNREACHABLE();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -// --------------------------------------------------------------------------
 | 
| -// Analysis of control instructions.  Unconditional successors are
 | 
| -// reachable.  Conditional successors are reachable depending on the
 | 
| -// constant value of the condition.
 | 
| -void ConstantPropagator::VisitReturn(ReturnInstr* instr) {
 | 
| -  // Nothing to do.
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitThrow(ThrowInstr* instr) {
 | 
| -  // Nothing to do.
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitReThrow(ReThrowInstr* instr) {
 | 
| -  // Nothing to do.
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitGoto(GotoInstr* instr) {
 | 
| -  SetReachable(instr->successor());
 | 
| -
 | 
| -  // Phi value depends on the reachability of a predecessor. We have
 | 
| -  // to revisit phis every time a predecessor becomes reachable.
 | 
| -  for (PhiIterator it(instr->successor()); !it.Done(); it.Advance()) {
 | 
| -    it.Current()->Accept(this);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitIndirectGoto(IndirectGotoInstr* instr) {
 | 
| -  for (intptr_t i = 0; i < instr->SuccessorCount(); i++) {
 | 
| -    SetReachable(instr->SuccessorAt(i));
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitBranch(BranchInstr* instr) {
 | 
| -  instr->comparison()->Accept(this);
 | 
| -
 | 
| -  // The successors may be reachable, but only if this instruction is.  (We
 | 
| -  // might be analyzing it because the constant value of one of its inputs
 | 
| -  // has changed.)
 | 
| -  if (reachable_->Contains(instr->GetBlock()->preorder_number())) {
 | 
| -    if (instr->constant_target() != NULL) {
 | 
| -      ASSERT((instr->constant_target() == instr->true_successor()) ||
 | 
| -             (instr->constant_target() == instr->false_successor()));
 | 
| -      SetReachable(instr->constant_target());
 | 
| -    } else {
 | 
| -      const Object& value = instr->comparison()->constant_value();
 | 
| -      if (IsNonConstant(value)) {
 | 
| -        SetReachable(instr->true_successor());
 | 
| -        SetReachable(instr->false_successor());
 | 
| -      } else if (value.raw() == Bool::True().raw()) {
 | 
| -        SetReachable(instr->true_successor());
 | 
| -      } else if (!IsUnknown(value)) {  // Any other constant.
 | 
| -        SetReachable(instr->false_successor());
 | 
| -      }
 | 
| -    }
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -// --------------------------------------------------------------------------
 | 
| -// Analysis of non-definition instructions.  They do not have values so they
 | 
| -// cannot have constant values.
 | 
| -void ConstantPropagator::VisitCheckStackOverflow(
 | 
| -    CheckStackOverflowInstr* instr) { }
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitCheckClass(CheckClassInstr* instr) { }
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitCheckClassId(CheckClassIdInstr* instr) { }
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitGuardFieldClass(GuardFieldClassInstr* instr) { }
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitGuardFieldLength(GuardFieldLengthInstr* instr) { }
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitCheckSmi(CheckSmiInstr* instr) { }
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitCheckEitherNonSmi(
 | 
| -    CheckEitherNonSmiInstr* instr) { }
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitCheckArrayBound(CheckArrayBoundInstr* instr) { }
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitDeoptimize(DeoptimizeInstr* instr) {
 | 
| -  // TODO(vegorov) remove all code after DeoptimizeInstr as dead.
 | 
| -}
 | 
| -
 | 
| -
 | 
| -Definition* ConstantPropagator::UnwrapPhi(Definition* defn) {
 | 
| -  if (defn->IsPhi()) {
 | 
| -    JoinEntryInstr* block = defn->AsPhi()->block();
 | 
| -
 | 
| -    Definition* input = NULL;
 | 
| -    for (intptr_t i = 0; i < defn->InputCount(); ++i) {
 | 
| -      if (reachable_->Contains(block->PredecessorAt(i)->preorder_number())) {
 | 
| -        if (input == NULL) {
 | 
| -          input = defn->InputAt(i)->definition();
 | 
| -        } else {
 | 
| -          return defn;
 | 
| -        }
 | 
| -      }
 | 
| -    }
 | 
| -
 | 
| -    return input;
 | 
| -  }
 | 
| -
 | 
| -  return defn;
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::MarkPhi(Definition* phi) {
 | 
| -  ASSERT(phi->IsPhi());
 | 
| -  marked_phis_->Add(phi->ssa_temp_index());
 | 
| -}
 | 
| -
 | 
| -
 | 
| -// --------------------------------------------------------------------------
 | 
| -// Analysis of definitions.  Compute the constant value.  If it has changed
 | 
| -// and the definition has input uses, add the definition to the definition
 | 
| -// worklist so that the used can be processed.
 | 
| -void ConstantPropagator::VisitPhi(PhiInstr* instr) {
 | 
| -  // Compute the join over all the reachable predecessor values.
 | 
| -  JoinEntryInstr* block = instr->block();
 | 
| -  Object& value = Object::ZoneHandle(I, Unknown());
 | 
| -  for (intptr_t pred_idx = 0; pred_idx < instr->InputCount(); ++pred_idx) {
 | 
| -    if (reachable_->Contains(
 | 
| -            block->PredecessorAt(pred_idx)->preorder_number())) {
 | 
| -      Join(&value,
 | 
| -           instr->InputAt(pred_idx)->definition()->constant_value());
 | 
| -    }
 | 
| -  }
 | 
| -  if (!SetValue(instr, value) &&
 | 
| -      marked_phis_->Contains(instr->ssa_temp_index())) {
 | 
| -    marked_phis_->Remove(instr->ssa_temp_index());
 | 
| -    definition_worklist_.Add(instr);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitRedefinition(RedefinitionInstr* instr) {
 | 
| -  SetValue(instr, instr->value()->definition()->constant_value());
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitParameter(ParameterInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitPushArgument(PushArgumentInstr* instr) {
 | 
| -  SetValue(instr, instr->value()->definition()->constant_value());
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitAssertAssignable(AssertAssignableInstr* instr) {
 | 
| -  const Object& value = instr->value()->definition()->constant_value();
 | 
| -  if (IsNonConstant(value)) {
 | 
| -    SetValue(instr, non_constant_);
 | 
| -  } else if (IsConstant(value)) {
 | 
| -    // We are ignoring the instantiator and instantiator_type_arguments, but
 | 
| -    // still monotonic and safe.
 | 
| -    if (instr->value()->Type()->IsAssignableTo(instr->dst_type())) {
 | 
| -      SetValue(instr, value);
 | 
| -    } else {
 | 
| -      SetValue(instr, non_constant_);
 | 
| -    }
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitAssertBoolean(AssertBooleanInstr* instr) {
 | 
| -  const Object& value = instr->value()->definition()->constant_value();
 | 
| -  if (IsNonConstant(value)) {
 | 
| -    SetValue(instr, non_constant_);
 | 
| -  } else if (IsConstant(value)) {
 | 
| -    if (value.IsBool()) {
 | 
| -      SetValue(instr, value);
 | 
| -    } else {
 | 
| -      SetValue(instr, non_constant_);
 | 
| -    }
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitCurrentContext(CurrentContextInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitClosureCall(ClosureCallInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitInstanceCall(InstanceCallInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitPolymorphicInstanceCall(
 | 
| -    PolymorphicInstanceCallInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitStaticCall(StaticCallInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitLoadLocal(LoadLocalInstr* instr) {
 | 
| -  // Instruction is eliminated when translating to SSA.
 | 
| -  UNREACHABLE();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitPushTemp(PushTempInstr* instr) {
 | 
| -  // Instruction is eliminated when translating to SSA.
 | 
| -  UNREACHABLE();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitDropTemps(DropTempsInstr* instr) {
 | 
| -  // Instruction is eliminated when translating to SSA.
 | 
| -  UNREACHABLE();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitStoreLocal(StoreLocalInstr* instr) {
 | 
| -  // Instruction is eliminated when translating to SSA.
 | 
| -  UNREACHABLE();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitIfThenElse(IfThenElseInstr* instr) {
 | 
| -  instr->comparison()->Accept(this);
 | 
| -  const Object& value = instr->comparison()->constant_value();
 | 
| -  if (IsNonConstant(value)) {
 | 
| -    SetValue(instr, non_constant_);
 | 
| -  } else if (IsConstant(value)) {
 | 
| -    ASSERT(!value.IsNull());
 | 
| -    ASSERT(value.IsBool());
 | 
| -    bool result = Bool::Cast(value).value();
 | 
| -    SetValue(instr,
 | 
| -             Smi::Handle(I, Smi::New(
 | 
| -                 result ? instr->if_true() : instr->if_false())));
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitStrictCompare(StrictCompareInstr* instr) {
 | 
| -  Definition* left_defn = instr->left()->definition();
 | 
| -  Definition* right_defn = instr->right()->definition();
 | 
| -
 | 
| -  Definition* unwrapped_left_defn = UnwrapPhi(left_defn);
 | 
| -  Definition* unwrapped_right_defn = UnwrapPhi(right_defn);
 | 
| -  if (unwrapped_left_defn == unwrapped_right_defn) {
 | 
| -    // Fold x === x, and x !== x to true/false.
 | 
| -    SetValue(instr, Bool::Get(instr->kind() == Token::kEQ_STRICT));
 | 
| -    if (unwrapped_left_defn != left_defn) {
 | 
| -      MarkPhi(left_defn);
 | 
| -    }
 | 
| -    if (unwrapped_right_defn != right_defn) {
 | 
| -      MarkPhi(right_defn);
 | 
| -    }
 | 
| -    return;
 | 
| -  }
 | 
| -
 | 
| -  const Object& left = left_defn->constant_value();
 | 
| -  const Object& right = right_defn->constant_value();
 | 
| -  if (IsNonConstant(left) || IsNonConstant(right)) {
 | 
| -    // TODO(vegorov): incorporate nullability information into the lattice.
 | 
| -    if ((left.IsNull() && instr->right()->Type()->HasDecidableNullability()) ||
 | 
| -        (right.IsNull() && instr->left()->Type()->HasDecidableNullability())) {
 | 
| -      bool result = left.IsNull() ? instr->right()->Type()->IsNull()
 | 
| -                                  : instr->left()->Type()->IsNull();
 | 
| -      if (instr->kind() == Token::kNE_STRICT) {
 | 
| -        result = !result;
 | 
| -      }
 | 
| -      SetValue(instr, Bool::Get(result));
 | 
| -    } else {
 | 
| -      const intptr_t left_cid = instr->left()->Type()->ToCid();
 | 
| -      const intptr_t right_cid = instr->right()->Type()->ToCid();
 | 
| -      // If exact classes (cids) are known and they differ, the result
 | 
| -      // of strict compare can be computed.
 | 
| -      if ((left_cid != kDynamicCid) && (right_cid != kDynamicCid) &&
 | 
| -          (left_cid != right_cid)) {
 | 
| -        const bool result = (instr->kind() != Token::kEQ_STRICT);
 | 
| -        SetValue(instr, Bool::Get(result));
 | 
| -      } else {
 | 
| -        SetValue(instr, non_constant_);
 | 
| -      }
 | 
| -    }
 | 
| -  } else if (IsConstant(left) && IsConstant(right)) {
 | 
| -    bool result = (left.raw() == right.raw());
 | 
| -    if (instr->kind() == Token::kNE_STRICT) {
 | 
| -      result = !result;
 | 
| -    }
 | 
| -    SetValue(instr, Bool::Get(result));
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -static bool CompareIntegers(Token::Kind kind,
 | 
| -                            const Integer& left,
 | 
| -                            const Integer& right) {
 | 
| -  const int result = left.CompareWith(right);
 | 
| -  switch (kind) {
 | 
| -    case Token::kEQ: return (result == 0);
 | 
| -    case Token::kNE: return (result != 0);
 | 
| -    case Token::kLT: return (result < 0);
 | 
| -    case Token::kGT: return (result > 0);
 | 
| -    case Token::kLTE: return (result <= 0);
 | 
| -    case Token::kGTE: return (result >= 0);
 | 
| -    default:
 | 
| -      UNREACHABLE();
 | 
| -      return false;
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitTestSmi(TestSmiInstr* instr) {
 | 
| -  const Object& left = instr->left()->definition()->constant_value();
 | 
| -  const Object& right = instr->right()->definition()->constant_value();
 | 
| -  if (IsNonConstant(left) || IsNonConstant(right)) {
 | 
| -    SetValue(instr, non_constant_);
 | 
| -  } else if (IsConstant(left) && IsConstant(right)) {
 | 
| -    if (left.IsInteger() && right.IsInteger()) {
 | 
| -      const bool result = CompareIntegers(
 | 
| -          instr->kind(),
 | 
| -          Integer::Handle(I, Integer::Cast(left).BitOp(Token::kBIT_AND,
 | 
| -                                                       Integer::Cast(right))),
 | 
| -          Smi::Handle(I, Smi::New(0)));
 | 
| -      SetValue(instr, result ? Bool::True() : Bool::False());
 | 
| -    } else {
 | 
| -      SetValue(instr, non_constant_);
 | 
| -    }
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitTestCids(TestCidsInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitEqualityCompare(EqualityCompareInstr* instr) {
 | 
| -  Definition* left_defn = instr->left()->definition();
 | 
| -  Definition* right_defn = instr->right()->definition();
 | 
| -
 | 
| -  if (RawObject::IsIntegerClassId(instr->operation_cid())) {
 | 
| -    // Fold x == x, and x != x to true/false for numbers comparisons.
 | 
| -    Definition* unwrapped_left_defn = UnwrapPhi(left_defn);
 | 
| -    Definition* unwrapped_right_defn = UnwrapPhi(right_defn);
 | 
| -    if (unwrapped_left_defn == unwrapped_right_defn) {
 | 
| -      // Fold x === x, and x !== x to true/false.
 | 
| -      SetValue(instr, Bool::Get(instr->kind() == Token::kEQ));
 | 
| -      if (unwrapped_left_defn != left_defn) {
 | 
| -        MarkPhi(left_defn);
 | 
| -      }
 | 
| -      if (unwrapped_right_defn != right_defn) {
 | 
| -        MarkPhi(right_defn);
 | 
| -      }
 | 
| -      return;
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  const Object& left = left_defn->constant_value();
 | 
| -  const Object& right = right_defn->constant_value();
 | 
| -  if (IsNonConstant(left) || IsNonConstant(right)) {
 | 
| -    SetValue(instr, non_constant_);
 | 
| -  } else if (IsConstant(left) && IsConstant(right)) {
 | 
| -    if (left.IsInteger() && right.IsInteger()) {
 | 
| -      const bool result = CompareIntegers(instr->kind(),
 | 
| -                                          Integer::Cast(left),
 | 
| -                                          Integer::Cast(right));
 | 
| -      SetValue(instr, Bool::Get(result));
 | 
| -    } else if (left.IsString() && right.IsString()) {
 | 
| -      const bool result = String::Cast(left).Equals(String::Cast(right));
 | 
| -      SetValue(instr, Bool::Get((instr->kind() == Token::kEQ) == result));
 | 
| -    } else {
 | 
| -      SetValue(instr, non_constant_);
 | 
| -    }
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitRelationalOp(RelationalOpInstr* instr) {
 | 
| -  const Object& left = instr->left()->definition()->constant_value();
 | 
| -  const Object& right = instr->right()->definition()->constant_value();
 | 
| -  if (IsNonConstant(left) || IsNonConstant(right)) {
 | 
| -    SetValue(instr, non_constant_);
 | 
| -  } else if (IsConstant(left) && IsConstant(right)) {
 | 
| -    if (left.IsInteger() && right.IsInteger()) {
 | 
| -      const bool result = CompareIntegers(instr->kind(),
 | 
| -                                          Integer::Cast(left),
 | 
| -                                          Integer::Cast(right));
 | 
| -      SetValue(instr, Bool::Get(result));
 | 
| -    } else if (left.IsDouble() && right.IsDouble()) {
 | 
| -      // TODO(srdjan): Implement.
 | 
| -      SetValue(instr, non_constant_);
 | 
| -    } else {
 | 
| -      SetValue(instr, non_constant_);
 | 
| -    }
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitNativeCall(NativeCallInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitDebugStepCheck(DebugStepCheckInstr* instr) {
 | 
| -  // Nothing to do.
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitStringFromCharCode(
 | 
| -    StringFromCharCodeInstr* instr) {
 | 
| -  const Object& o = instr->char_code()->definition()->constant_value();
 | 
| -  if (o.IsNull() || IsNonConstant(o)) {
 | 
| -    SetValue(instr, non_constant_);
 | 
| -  } else if (IsConstant(o)) {
 | 
| -    const intptr_t ch_code = Smi::Cast(o).Value();
 | 
| -    ASSERT(ch_code >= 0);
 | 
| -    if (ch_code < Symbols::kMaxOneCharCodeSymbol) {
 | 
| -      RawString** table = Symbols::PredefinedAddress();
 | 
| -      SetValue(instr, String::ZoneHandle(I, table[ch_code]));
 | 
| -    } else {
 | 
| -      SetValue(instr, non_constant_);
 | 
| -    }
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitStringToCharCode(StringToCharCodeInstr* instr) {
 | 
| -  const Object& o = instr->str()->definition()->constant_value();
 | 
| -  if (o.IsNull() || IsNonConstant(o)) {
 | 
| -    SetValue(instr, non_constant_);
 | 
| -  } else if (IsConstant(o)) {
 | 
| -    const String& str = String::Cast(o);
 | 
| -    const intptr_t result =
 | 
| -        (str.Length() == 1) ? static_cast<intptr_t>(str.CharAt(0)) : -1;
 | 
| -    SetValue(instr, Smi::ZoneHandle(I, Smi::New(result)));
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitStringInterpolate(StringInterpolateInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitLoadIndexed(LoadIndexedInstr* instr) {
 | 
| -  const Object& array_obj = instr->array()->definition()->constant_value();
 | 
| -  const Object& index_obj = instr->index()->definition()->constant_value();
 | 
| -  if (IsNonConstant(array_obj) || IsNonConstant(index_obj)) {
 | 
| -    SetValue(instr, non_constant_);
 | 
| -  } else if (IsConstant(array_obj) && IsConstant(index_obj)) {
 | 
| -    // Need index to be Smi and array to be either String or an immutable array.
 | 
| -    if (!index_obj.IsSmi()) {
 | 
| -      // Should not occur.
 | 
| -      SetValue(instr, non_constant_);
 | 
| -      return;
 | 
| -    }
 | 
| -    const intptr_t index = Smi::Cast(index_obj).Value();
 | 
| -    if (index >= 0) {
 | 
| -      if (array_obj.IsString()) {
 | 
| -        const String& str = String::Cast(array_obj);
 | 
| -        if (str.Length() > index) {
 | 
| -          SetValue(instr, Smi::Handle(I,
 | 
| -              Smi::New(static_cast<intptr_t>(str.CharAt(index)))));
 | 
| -          return;
 | 
| -        }
 | 
| -      } else if (array_obj.IsArray()) {
 | 
| -        const Array& a = Array::Cast(array_obj);
 | 
| -        if ((a.Length() > index) && a.IsImmutable()) {
 | 
| -          Instance& result = Instance::Handle(I);
 | 
| -          result ^= a.At(index);
 | 
| -          SetValue(instr, result);
 | 
| -          return;
 | 
| -        }
 | 
| -      }
 | 
| -    }
 | 
| -    SetValue(instr, non_constant_);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) {
 | 
| -  // TODO(zerny): Implement constant propagation.
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitStoreIndexed(StoreIndexedInstr* instr) {
 | 
| -  SetValue(instr, instr->value()->definition()->constant_value());
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitStoreInstanceField(
 | 
| -    StoreInstanceFieldInstr* instr) {
 | 
| -  SetValue(instr, instr->value()->definition()->constant_value());
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitInitStaticField(InitStaticFieldInstr* instr) {
 | 
| -  // Nothing to do.
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitLoadStaticField(LoadStaticFieldInstr* instr) {
 | 
| -  const Field& field = instr->StaticField();
 | 
| -  ASSERT(field.is_static());
 | 
| -  if (field.is_final()) {
 | 
| -    Instance& obj = Instance::Handle(I, field.value());
 | 
| -    ASSERT(obj.raw() != Object::sentinel().raw());
 | 
| -    ASSERT(obj.raw() != Object::transition_sentinel().raw());
 | 
| -    if (obj.IsSmi() || obj.IsOld()) {
 | 
| -      SetValue(instr, obj);
 | 
| -      return;
 | 
| -    }
 | 
| -  }
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitStoreStaticField(StoreStaticFieldInstr* instr) {
 | 
| -  SetValue(instr, instr->value()->definition()->constant_value());
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitBooleanNegate(BooleanNegateInstr* instr) {
 | 
| -  const Object& value = instr->value()->definition()->constant_value();
 | 
| -  if (IsNonConstant(value)) {
 | 
| -    SetValue(instr, non_constant_);
 | 
| -  } else if (IsConstant(value)) {
 | 
| -    bool val = value.raw() != Bool::True().raw();
 | 
| -    SetValue(instr, Bool::Get(val));
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitInstanceOf(InstanceOfInstr* instr) {
 | 
| -  const Definition* def = instr->value()->definition();
 | 
| -  const Object& value = def->constant_value();
 | 
| -  if (IsNonConstant(value)) {
 | 
| -    const AbstractType& checked_type = instr->type();
 | 
| -    intptr_t value_cid = instr->value()->Type()->ToCid();
 | 
| -    Representation rep = def->representation();
 | 
| -    if ((checked_type.IsFloat32x4Type() && (rep == kUnboxedFloat32x4)) ||
 | 
| -        (checked_type.IsInt32x4Type() && (rep == kUnboxedInt32x4)) ||
 | 
| -        (checked_type.IsDoubleType() && (rep == kUnboxedDouble) &&
 | 
| -         CanUnboxDouble()) ||
 | 
| -        (checked_type.IsIntType() && (rep == kUnboxedMint))) {
 | 
| -      // Ensure that compile time type matches representation.
 | 
| -      ASSERT(((rep == kUnboxedFloat32x4) && (value_cid == kFloat32x4Cid)) ||
 | 
| -             ((rep == kUnboxedInt32x4) && (value_cid == kInt32x4Cid)) ||
 | 
| -             ((rep == kUnboxedDouble) && (value_cid == kDoubleCid)) ||
 | 
| -             ((rep == kUnboxedMint) && (value_cid == kMintCid)));
 | 
| -      // The representation guarantees the type check to be true.
 | 
| -      SetValue(instr, instr->negate_result() ? Bool::False() : Bool::True());
 | 
| -    } else {
 | 
| -      SetValue(instr, non_constant_);
 | 
| -    }
 | 
| -  } else if (IsConstant(value)) {
 | 
| -    // TODO(kmillikin): Handle instanceof on constants.
 | 
| -    SetValue(instr, non_constant_);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitCreateArray(CreateArrayInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitAllocateObject(AllocateObjectInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitLoadUntagged(LoadUntaggedInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitLoadClassId(LoadClassIdInstr* instr) {
 | 
| -  intptr_t cid = instr->object()->Type()->ToCid();
 | 
| -  if (cid != kDynamicCid) {
 | 
| -    SetValue(instr, Smi::ZoneHandle(I, Smi::New(cid)));
 | 
| -    return;
 | 
| -  }
 | 
| -  const Object& object = instr->object()->definition()->constant_value();
 | 
| -  if (IsConstant(object)) {
 | 
| -    SetValue(instr, Smi::ZoneHandle(I, Smi::New(object.GetClassId())));
 | 
| -    return;
 | 
| -  }
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitLoadField(LoadFieldInstr* instr) {
 | 
| -  Value* instance = instr->instance();
 | 
| -  if ((instr->recognized_kind() == MethodRecognizer::kObjectArrayLength) &&
 | 
| -      instance->definition()->OriginalDefinition()->IsCreateArray()) {
 | 
| -    Value* num_elements = instance->definition()->OriginalDefinition()
 | 
| -        ->AsCreateArray()->num_elements();
 | 
| -    if (num_elements->BindsToConstant() &&
 | 
| -        num_elements->BoundConstant().IsSmi()) {
 | 
| -      intptr_t length = Smi::Cast(num_elements->BoundConstant()).Value();
 | 
| -      const Object& result = Smi::ZoneHandle(I, Smi::New(length));
 | 
| -      SetValue(instr, result);
 | 
| -      return;
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  if (instr->IsImmutableLengthLoad()) {
 | 
| -    ConstantInstr* constant =
 | 
| -        instance->definition()->OriginalDefinition()->AsConstant();
 | 
| -    if (constant != NULL) {
 | 
| -      if (constant->value().IsString()) {
 | 
| -        SetValue(instr, Smi::ZoneHandle(I,
 | 
| -            Smi::New(String::Cast(constant->value()).Length())));
 | 
| -        return;
 | 
| -      }
 | 
| -      if (constant->value().IsArray()) {
 | 
| -        SetValue(instr, Smi::ZoneHandle(I,
 | 
| -            Smi::New(Array::Cast(constant->value()).Length())));
 | 
| -        return;
 | 
| -      }
 | 
| -    }
 | 
| -  }
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitInstantiateType(InstantiateTypeInstr* instr) {
 | 
| -  const Object& object =
 | 
| -      instr->instantiator()->definition()->constant_value();
 | 
| -  if (IsNonConstant(object)) {
 | 
| -    SetValue(instr, non_constant_);
 | 
| -    return;
 | 
| -  }
 | 
| -  if (IsConstant(object)) {
 | 
| -    if (instr->type().IsTypeParameter()) {
 | 
| -      if (object.IsNull()) {
 | 
| -        SetValue(instr, Type::ZoneHandle(I, Type::DynamicType()));
 | 
| -        return;
 | 
| -      }
 | 
| -      // We could try to instantiate the type parameter and return it if no
 | 
| -      // malformed error is reported.
 | 
| -    }
 | 
| -    SetValue(instr, non_constant_);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitInstantiateTypeArguments(
 | 
| -    InstantiateTypeArgumentsInstr* instr) {
 | 
| -  const Object& object =
 | 
| -      instr->instantiator()->definition()->constant_value();
 | 
| -  if (IsNonConstant(object)) {
 | 
| -    SetValue(instr, non_constant_);
 | 
| -    return;
 | 
| -  }
 | 
| -  if (IsConstant(object)) {
 | 
| -    const intptr_t len = instr->type_arguments().Length();
 | 
| -    if (instr->type_arguments().IsRawInstantiatedRaw(len) &&
 | 
| -        object.IsNull()) {
 | 
| -      SetValue(instr, object);
 | 
| -      return;
 | 
| -    }
 | 
| -    if (instr->type_arguments().IsUninstantiatedIdentity() ||
 | 
| -        instr->type_arguments().CanShareInstantiatorTypeArguments(
 | 
| -            instr->instantiator_class())) {
 | 
| -      SetValue(instr, object);
 | 
| -      return;
 | 
| -    }
 | 
| -    SetValue(instr, non_constant_);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitAllocateContext(AllocateContextInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitAllocateUninitializedContext(
 | 
| -    AllocateUninitializedContextInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitCloneContext(CloneContextInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitBinaryIntegerOp(BinaryIntegerOpInstr* binary_op) {
 | 
| -  const Object& left = binary_op->left()->definition()->constant_value();
 | 
| -  const Object& right = binary_op->right()->definition()->constant_value();
 | 
| -  if (IsConstant(left) && IsConstant(right)) {
 | 
| -    if (left.IsInteger() && right.IsInteger()) {
 | 
| -      const Integer& left_int = Integer::Cast(left);
 | 
| -      const Integer& right_int = Integer::Cast(right);
 | 
| -      const Integer& result =
 | 
| -          Integer::Handle(I, binary_op->Evaluate(left_int, right_int));
 | 
| -      if (!result.IsNull()) {
 | 
| -        SetValue(binary_op, Integer::ZoneHandle(I, result.raw()));
 | 
| -        return;
 | 
| -      }
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  SetValue(binary_op, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitBinarySmiOp(BinarySmiOpInstr* instr) {
 | 
| -  VisitBinaryIntegerOp(instr);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitBinaryInt32Op(BinaryInt32OpInstr* instr) {
 | 
| -  VisitBinaryIntegerOp(instr);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitBinaryUint32Op(BinaryUint32OpInstr* instr) {
 | 
| -  VisitBinaryIntegerOp(instr);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitShiftUint32Op(ShiftUint32OpInstr* instr) {
 | 
| -  VisitBinaryIntegerOp(instr);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitBinaryMintOp(BinaryMintOpInstr* instr) {
 | 
| -  VisitBinaryIntegerOp(instr);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitShiftMintOp(ShiftMintOpInstr* instr) {
 | 
| -  VisitBinaryIntegerOp(instr);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitBoxInt64(BoxInt64Instr* instr) {
 | 
| -  // TODO(kmillikin): Handle box operation.
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitUnboxInt64(UnboxInt64Instr* instr) {
 | 
| -  // TODO(kmillikin): Handle unbox operation.
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitUnaryMintOp(UnaryMintOpInstr* instr) {
 | 
| -  // TODO(kmillikin): Handle unary operations.
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitUnarySmiOp(UnarySmiOpInstr* instr) {
 | 
| -  const Object& value = instr->value()->definition()->constant_value();
 | 
| -  if (IsNonConstant(value)) {
 | 
| -    SetValue(instr, non_constant_);
 | 
| -  } else if (IsConstant(value)) {
 | 
| -    // TODO(kmillikin): Handle unary operations.
 | 
| -    SetValue(instr, non_constant_);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitUnaryDoubleOp(UnaryDoubleOpInstr* instr) {
 | 
| -  const Object& value = instr->value()->definition()->constant_value();
 | 
| -  if (IsNonConstant(value)) {
 | 
| -    SetValue(instr, non_constant_);
 | 
| -  } else if (IsConstant(value)) {
 | 
| -    // TODO(kmillikin): Handle unary operations.
 | 
| -    SetValue(instr, non_constant_);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitSmiToDouble(SmiToDoubleInstr* instr) {
 | 
| -  const Object& value = instr->value()->definition()->constant_value();
 | 
| -  if (IsConstant(value) && value.IsInteger()) {
 | 
| -    SetValue(instr, Double::Handle(I,
 | 
| -        Double::New(Integer::Cast(value).AsDoubleValue(), Heap::kOld)));
 | 
| -  } else if (IsNonConstant(value)) {
 | 
| -    SetValue(instr, non_constant_);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitMintToDouble(MintToDoubleInstr* instr) {
 | 
| -  const Object& value = instr->value()->definition()->constant_value();
 | 
| -  if (IsConstant(value) && value.IsInteger()) {
 | 
| -    SetValue(instr, Double::Handle(I,
 | 
| -        Double::New(Integer::Cast(value).AsDoubleValue(), Heap::kOld)));
 | 
| -  } else if (IsNonConstant(value)) {
 | 
| -    SetValue(instr, non_constant_);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitInt32ToDouble(Int32ToDoubleInstr* instr) {
 | 
| -  const Object& value = instr->value()->definition()->constant_value();
 | 
| -  if (IsConstant(value) && value.IsInteger()) {
 | 
| -    SetValue(instr, Double::Handle(I,
 | 
| -        Double::New(Integer::Cast(value).AsDoubleValue(), Heap::kOld)));
 | 
| -  } else if (IsNonConstant(value)) {
 | 
| -    SetValue(instr, non_constant_);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitDoubleToInteger(DoubleToIntegerInstr* instr) {
 | 
| -  // TODO(kmillikin): Handle conversion.
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitDoubleToSmi(DoubleToSmiInstr* instr) {
 | 
| -  // TODO(kmillikin): Handle conversion.
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitDoubleToDouble(DoubleToDoubleInstr* instr) {
 | 
| -  // TODO(kmillikin): Handle conversion.
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitDoubleToFloat(DoubleToFloatInstr* instr) {
 | 
| -  // TODO(kmillikin): Handle conversion.
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitFloatToDouble(FloatToDoubleInstr* instr) {
 | 
| -  // TODO(kmillikin): Handle conversion.
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitInvokeMathCFunction(
 | 
| -    InvokeMathCFunctionInstr* instr) {
 | 
| -  // TODO(kmillikin): Handle conversion.
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitMergedMath(MergedMathInstr* instr) {
 | 
| -  // TODO(srdjan): Handle merged instruction.
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitExtractNthOutput(ExtractNthOutputInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitConstant(ConstantInstr* instr) {
 | 
| -  SetValue(instr, instr->value());
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitUnboxedConstant(UnboxedConstantInstr* instr) {
 | 
| -  SetValue(instr, instr->value());
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitConstraint(ConstraintInstr* instr) {
 | 
| -  // Should not be used outside of range analysis.
 | 
| -  UNREACHABLE();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitMaterializeObject(MaterializeObjectInstr* instr) {
 | 
| -  // Should not be used outside of allocation elimination pass.
 | 
| -  UNREACHABLE();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -static bool IsIntegerOrDouble(const Object& value) {
 | 
| -  return value.IsInteger() || value.IsDouble();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -static double ToDouble(const Object& value) {
 | 
| -  return value.IsInteger() ? Integer::Cast(value).AsDoubleValue()
 | 
| -                           : Double::Cast(value).value();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitBinaryDoubleOp(
 | 
| -    BinaryDoubleOpInstr* instr) {
 | 
| -  const Object& left = instr->left()->definition()->constant_value();
 | 
| -  const Object& right = instr->right()->definition()->constant_value();
 | 
| -  if (IsNonConstant(left) || IsNonConstant(right)) {
 | 
| -    SetValue(instr, non_constant_);
 | 
| -  } else if (left.IsInteger() && right.IsInteger()) {
 | 
| -    SetValue(instr, non_constant_);
 | 
| -  } else if (IsIntegerOrDouble(left) && IsIntegerOrDouble(right)) {
 | 
| -    const double left_val = ToDouble(left);
 | 
| -    const double right_val = ToDouble(right);
 | 
| -    double result_val = 0.0;
 | 
| -    switch (instr->op_kind()) {
 | 
| -      case Token::kADD:
 | 
| -        result_val = left_val + right_val;
 | 
| -        break;
 | 
| -      case Token::kSUB:
 | 
| -        result_val = left_val - right_val;
 | 
| -        break;
 | 
| -      case Token::kMUL:
 | 
| -        result_val = left_val * right_val;
 | 
| -        break;
 | 
| -      case Token::kDIV:
 | 
| -        result_val = left_val / right_val;
 | 
| -        break;
 | 
| -      default:
 | 
| -        UNREACHABLE();
 | 
| -    }
 | 
| -    const Double& result = Double::ZoneHandle(Double::NewCanonical(result_val));
 | 
| -    SetValue(instr, result);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitBinaryFloat32x4Op(
 | 
| -    BinaryFloat32x4OpInstr* instr) {
 | 
| -  const Object& left = instr->left()->definition()->constant_value();
 | 
| -  const Object& right = instr->right()->definition()->constant_value();
 | 
| -  if (IsNonConstant(left) || IsNonConstant(right)) {
 | 
| -    SetValue(instr, non_constant_);
 | 
| -  } else if (IsConstant(left) && IsConstant(right)) {
 | 
| -    // TODO(kmillikin): Handle binary operation.
 | 
| -    SetValue(instr, non_constant_);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitFloat32x4Constructor(
 | 
| -    Float32x4ConstructorInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitSimd32x4Shuffle(Simd32x4ShuffleInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitSimd32x4ShuffleMix(
 | 
| -    Simd32x4ShuffleMixInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitSimd32x4GetSignMask(
 | 
| -    Simd32x4GetSignMaskInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitFloat32x4Zero(Float32x4ZeroInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitFloat32x4Splat(Float32x4SplatInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitFloat32x4Comparison(
 | 
| -    Float32x4ComparisonInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitFloat32x4MinMax(Float32x4MinMaxInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitFloat32x4Scale(Float32x4ScaleInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitFloat32x4Sqrt(Float32x4SqrtInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitFloat32x4ZeroArg(Float32x4ZeroArgInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitFloat32x4Clamp(Float32x4ClampInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitFloat32x4With(Float32x4WithInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitFloat32x4ToInt32x4(
 | 
| -    Float32x4ToInt32x4Instr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitInt32x4Constructor(
 | 
| -    Int32x4ConstructorInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitInt32x4BoolConstructor(
 | 
| -    Int32x4BoolConstructorInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitInt32x4GetFlag(Int32x4GetFlagInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitInt32x4SetFlag(Int32x4SetFlagInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitInt32x4Select(Int32x4SelectInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitInt32x4ToFloat32x4(
 | 
| -    Int32x4ToFloat32x4Instr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitBinaryInt32x4Op(BinaryInt32x4OpInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitSimd64x2Shuffle(Simd64x2ShuffleInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitBinaryFloat64x2Op(BinaryFloat64x2OpInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitFloat32x4ToFloat64x2(
 | 
| -    Float32x4ToFloat64x2Instr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitFloat64x2ToFloat32x4(
 | 
| -    Float64x2ToFloat32x4Instr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitFloat64x2Zero(
 | 
| -    Float64x2ZeroInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitFloat64x2Splat(
 | 
| -    Float64x2SplatInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitFloat64x2Constructor(
 | 
| -    Float64x2ConstructorInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitFloat64x2ZeroArg(Float64x2ZeroArgInstr* instr) {
 | 
| -  // TODO(johnmccutchan): Implement constant propagation.
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitFloat64x2OneArg(Float64x2OneArgInstr* instr) {
 | 
| -  // TODO(johnmccutchan): Implement constant propagation.
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitMathUnary(MathUnaryInstr* instr) {
 | 
| -  const Object& value = instr->value()->definition()->constant_value();
 | 
| -  if (IsNonConstant(value)) {
 | 
| -    SetValue(instr, non_constant_);
 | 
| -  } else if (IsConstant(value)) {
 | 
| -    // TODO(kmillikin): Handle Math's unary operations (sqrt, cos, sin).
 | 
| -    SetValue(instr, non_constant_);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitMathMinMax(MathMinMaxInstr* instr) {
 | 
| -  const Object& left = instr->left()->definition()->constant_value();
 | 
| -  const Object& right = instr->right()->definition()->constant_value();
 | 
| -  if (IsNonConstant(left) || IsNonConstant(right)) {
 | 
| -    SetValue(instr, non_constant_);
 | 
| -  } else if (IsConstant(left) && IsConstant(right)) {
 | 
| -    // TODO(srdjan): Handle min and max.
 | 
| -    SetValue(instr, non_constant_);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitCaseInsensitiveCompareUC16(
 | 
| -    CaseInsensitiveCompareUC16Instr *instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitUnbox(UnboxInstr* instr) {
 | 
| -  const Object& value = instr->value()->definition()->constant_value();
 | 
| -  if (IsNonConstant(value)) {
 | 
| -    SetValue(instr, non_constant_);
 | 
| -  } else if (IsConstant(value)) {
 | 
| -    // TODO(kmillikin): Handle conversion.
 | 
| -    SetValue(instr, non_constant_);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitBox(BoxInstr* instr) {
 | 
| -  const Object& value = instr->value()->definition()->constant_value();
 | 
| -  if (IsNonConstant(value)) {
 | 
| -    SetValue(instr, non_constant_);
 | 
| -  } else if (IsConstant(value)) {
 | 
| -    // TODO(kmillikin): Handle conversion.
 | 
| -    SetValue(instr, non_constant_);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitBoxUint32(BoxUint32Instr* instr) {
 | 
| -  // TODO(kmillikin): Handle box operation.
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitUnboxUint32(UnboxUint32Instr* instr) {
 | 
| -  // TODO(kmillikin): Handle unbox operation.
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitBoxInt32(BoxInt32Instr* instr) {
 | 
| -  // TODO(kmillikin): Handle box operation.
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitUnboxInt32(UnboxInt32Instr* instr) {
 | 
| -  // TODO(kmillikin): Handle unbox operation.
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitUnboxedIntConverter(
 | 
| -    UnboxedIntConverterInstr* instr) {
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::VisitUnaryUint32Op(UnaryUint32OpInstr* instr) {
 | 
| -  // TODO(kmillikin): Handle unary operations.
 | 
| -  SetValue(instr, non_constant_);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::Analyze() {
 | 
| -  GraphEntryInstr* entry = graph_->graph_entry();
 | 
| -  reachable_->Add(entry->preorder_number());
 | 
| -  block_worklist_.Add(entry);
 | 
| -
 | 
| -  while (true) {
 | 
| -    if (block_worklist_.is_empty()) {
 | 
| -      if (definition_worklist_.IsEmpty()) break;
 | 
| -      Definition* definition = definition_worklist_.RemoveLast();
 | 
| -      Value* use = definition->input_use_list();
 | 
| -      while (use != NULL) {
 | 
| -        use->instruction()->Accept(this);
 | 
| -        use = use->next_use();
 | 
| -      }
 | 
| -    } else {
 | 
| -      BlockEntryInstr* block = block_worklist_.RemoveLast();
 | 
| -      block->Accept(this);
 | 
| -    }
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -static bool IsEmptyBlock(BlockEntryInstr* block) {
 | 
| -  return block->next()->IsGoto() &&
 | 
| -      (!block->IsJoinEntry() || (block->AsJoinEntry()->phis() == NULL)) &&
 | 
| -      !block->IsIndirectEntry();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -// Traverses a chain of empty blocks and returns the first reachable non-empty
 | 
| -// block that is not dominated by the start block. The empty blocks are added
 | 
| -// to the supplied bit vector.
 | 
| -static BlockEntryInstr* FindFirstNonEmptySuccessor(
 | 
| -    TargetEntryInstr* block,
 | 
| -    BitVector* empty_blocks) {
 | 
| -  BlockEntryInstr* current = block;
 | 
| -  while (IsEmptyBlock(current) && block->Dominates(current)) {
 | 
| -    ASSERT(!block->IsJoinEntry() || (block->AsJoinEntry()->phis() == NULL));
 | 
| -    empty_blocks->Add(current->preorder_number());
 | 
| -    current = current->next()->AsGoto()->successor();
 | 
| -  }
 | 
| -  return current;
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::EliminateRedundantBranches() {
 | 
| -  // Canonicalize branches that have no side-effects and where true- and
 | 
| -  // false-targets are the same.
 | 
| -  bool changed = false;
 | 
| -  BitVector* empty_blocks = new(I) BitVector(I, graph_->preorder().length());
 | 
| -  for (BlockIterator b = graph_->postorder_iterator();
 | 
| -       !b.Done();
 | 
| -       b.Advance()) {
 | 
| -    BlockEntryInstr* block = b.Current();
 | 
| -    BranchInstr* branch = block->last_instruction()->AsBranch();
 | 
| -    empty_blocks->Clear();
 | 
| -    if ((branch != NULL) && branch->Effects().IsNone()) {
 | 
| -      ASSERT(branch->previous() != NULL);  // Not already eliminated.
 | 
| -      BlockEntryInstr* if_true =
 | 
| -          FindFirstNonEmptySuccessor(branch->true_successor(), empty_blocks);
 | 
| -      BlockEntryInstr* if_false =
 | 
| -          FindFirstNonEmptySuccessor(branch->false_successor(), empty_blocks);
 | 
| -      if (if_true == if_false) {
 | 
| -        // Replace the branch with a jump to the common successor.
 | 
| -        // Drop the comparison, which does not have side effects
 | 
| -        JoinEntryInstr* join = if_true->AsJoinEntry();
 | 
| -        if (join->phis() == NULL) {
 | 
| -          GotoInstr* jump = new(I) GotoInstr(if_true->AsJoinEntry());
 | 
| -          jump->InheritDeoptTarget(I, branch);
 | 
| -
 | 
| -          Instruction* previous = branch->previous();
 | 
| -          branch->set_previous(NULL);
 | 
| -          previous->LinkTo(jump);
 | 
| -
 | 
| -          // Remove uses from branch and all the empty blocks that
 | 
| -          // are now unreachable.
 | 
| -          branch->UnuseAllInputs();
 | 
| -          for (BitVector::Iterator it(empty_blocks); !it.Done(); it.Advance()) {
 | 
| -            BlockEntryInstr* empty_block = graph_->preorder()[it.Current()];
 | 
| -            empty_block->ClearAllInstructions();
 | 
| -          }
 | 
| -
 | 
| -          changed = true;
 | 
| -
 | 
| -          if (FLAG_trace_constant_propagation) {
 | 
| -            OS::Print("Eliminated branch in B%" Pd " common target B%" Pd "\n",
 | 
| -                      block->block_id(), join->block_id());
 | 
| -          }
 | 
| -        }
 | 
| -      }
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  if (changed) {
 | 
| -    graph_->DiscoverBlocks();
 | 
| -    // TODO(fschneider): Update dominator tree in place instead of recomputing.
 | 
| -    GrowableArray<BitVector*> dominance_frontier;
 | 
| -    graph_->ComputeDominators(&dominance_frontier);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void ConstantPropagator::Transform() {
 | 
| -  if (FLAG_trace_constant_propagation) {
 | 
| -    OS::Print("\n==== Before constant propagation ====\n");
 | 
| -    FlowGraphPrinter printer(*graph_);
 | 
| -    printer.PrintBlocks();
 | 
| -  }
 | 
| -
 | 
| -  // We will recompute dominators, block ordering, block ids, block last
 | 
| -  // instructions, previous pointers, predecessors, etc. after eliminating
 | 
| -  // unreachable code.  We do not maintain those properties during the
 | 
| -  // transformation.
 | 
| -  for (BlockIterator b = graph_->reverse_postorder_iterator();
 | 
| -       !b.Done();
 | 
| -       b.Advance()) {
 | 
| -    BlockEntryInstr* block = b.Current();
 | 
| -    if (!reachable_->Contains(block->preorder_number())) {
 | 
| -      if (FLAG_trace_constant_propagation) {
 | 
| -        OS::Print("Unreachable B%" Pd "\n", block->block_id());
 | 
| -      }
 | 
| -      // Remove all uses in unreachable blocks.
 | 
| -      block->ClearAllInstructions();
 | 
| -      continue;
 | 
| -    }
 | 
| -
 | 
| -    JoinEntryInstr* join = block->AsJoinEntry();
 | 
| -    if (join != NULL) {
 | 
| -      // Remove phi inputs corresponding to unreachable predecessor blocks.
 | 
| -      // Predecessors will be recomputed (in block id order) after removing
 | 
| -      // unreachable code so we merely have to keep the phi inputs in order.
 | 
| -      ZoneGrowableArray<PhiInstr*>* phis = join->phis();
 | 
| -      if ((phis != NULL) && !phis->is_empty()) {
 | 
| -        intptr_t pred_count = join->PredecessorCount();
 | 
| -        intptr_t live_count = 0;
 | 
| -        for (intptr_t pred_idx = 0; pred_idx < pred_count; ++pred_idx) {
 | 
| -          if (reachable_->Contains(
 | 
| -                  join->PredecessorAt(pred_idx)->preorder_number())) {
 | 
| -            if (live_count < pred_idx) {
 | 
| -              for (PhiIterator it(join); !it.Done(); it.Advance()) {
 | 
| -                PhiInstr* phi = it.Current();
 | 
| -                ASSERT(phi != NULL);
 | 
| -                phi->SetInputAt(live_count, phi->InputAt(pred_idx));
 | 
| -              }
 | 
| -            }
 | 
| -            ++live_count;
 | 
| -          } else {
 | 
| -            for (PhiIterator it(join); !it.Done(); it.Advance()) {
 | 
| -              PhiInstr* phi = it.Current();
 | 
| -              ASSERT(phi != NULL);
 | 
| -              phi->InputAt(pred_idx)->RemoveFromUseList();
 | 
| -            }
 | 
| -          }
 | 
| -        }
 | 
| -        if (live_count < pred_count) {
 | 
| -          intptr_t to_idx = 0;
 | 
| -          for (intptr_t from_idx = 0; from_idx < phis->length(); ++from_idx) {
 | 
| -            PhiInstr* phi = (*phis)[from_idx];
 | 
| -            ASSERT(phi != NULL);
 | 
| -            if (FLAG_remove_redundant_phis && (live_count == 1)) {
 | 
| -              Value* input = phi->InputAt(0);
 | 
| -              phi->ReplaceUsesWith(input->definition());
 | 
| -              input->RemoveFromUseList();
 | 
| -            } else {
 | 
| -              phi->inputs_.TruncateTo(live_count);
 | 
| -              (*phis)[to_idx++] = phi;
 | 
| -            }
 | 
| -          }
 | 
| -          if (to_idx == 0) {
 | 
| -            join->phis_ = NULL;
 | 
| -          } else {
 | 
| -            phis->TruncateTo(to_idx);
 | 
| -          }
 | 
| -        }
 | 
| -      }
 | 
| -    }
 | 
| -
 | 
| -    for (ForwardInstructionIterator i(block); !i.Done(); i.Advance()) {
 | 
| -      Definition* defn = i.Current()->AsDefinition();
 | 
| -      // Replace constant-valued instructions without observable side
 | 
| -      // effects.  Do this for smis only to avoid having to copy other
 | 
| -      // objects into the heap's old generation.
 | 
| -      if ((defn != NULL) &&
 | 
| -          IsConstant(defn->constant_value()) &&
 | 
| -          (defn->constant_value().IsSmi() || defn->constant_value().IsOld()) &&
 | 
| -          !defn->IsConstant() &&
 | 
| -          !defn->IsPushArgument() &&
 | 
| -          !defn->IsStoreIndexed() &&
 | 
| -          !defn->IsStoreInstanceField() &&
 | 
| -          !defn->IsStoreStaticField()) {
 | 
| -        if (FLAG_trace_constant_propagation) {
 | 
| -          OS::Print("Constant v%" Pd " = %s\n",
 | 
| -                    defn->ssa_temp_index(),
 | 
| -                    defn->constant_value().ToCString());
 | 
| -        }
 | 
| -        ConstantInstr* constant = graph_->GetConstant(defn->constant_value());
 | 
| -        defn->ReplaceUsesWith(constant);
 | 
| -        i.RemoveCurrentFromGraph();
 | 
| -      }
 | 
| -    }
 | 
| -
 | 
| -    // Replace branches where one target is unreachable with jumps.
 | 
| -    BranchInstr* branch = block->last_instruction()->AsBranch();
 | 
| -    if (branch != NULL) {
 | 
| -      TargetEntryInstr* if_true = branch->true_successor();
 | 
| -      TargetEntryInstr* if_false = branch->false_successor();
 | 
| -      JoinEntryInstr* join = NULL;
 | 
| -      Instruction* next = NULL;
 | 
| -
 | 
| -      if (!reachable_->Contains(if_true->preorder_number())) {
 | 
| -        ASSERT(reachable_->Contains(if_false->preorder_number()));
 | 
| -        ASSERT(if_false->parallel_move() == NULL);
 | 
| -        ASSERT(if_false->loop_info() == NULL);
 | 
| -        join = new(I) JoinEntryInstr(if_false->block_id(),
 | 
| -                                     if_false->try_index());
 | 
| -        join->InheritDeoptTarget(I, if_false);
 | 
| -        if_false->UnuseAllInputs();
 | 
| -        next = if_false->next();
 | 
| -      } else if (!reachable_->Contains(if_false->preorder_number())) {
 | 
| -        ASSERT(if_true->parallel_move() == NULL);
 | 
| -        ASSERT(if_true->loop_info() == NULL);
 | 
| -        join = new(I) JoinEntryInstr(if_true->block_id(),
 | 
| -                                     if_true->try_index());
 | 
| -        join->InheritDeoptTarget(I, if_true);
 | 
| -        if_true->UnuseAllInputs();
 | 
| -        next = if_true->next();
 | 
| -      }
 | 
| -
 | 
| -      if (join != NULL) {
 | 
| -        // Replace the branch with a jump to the reachable successor.
 | 
| -        // Drop the comparison, which does not have side effects as long
 | 
| -        // as it is a strict compare (the only one we can determine is
 | 
| -        // constant with the current analysis).
 | 
| -        GotoInstr* jump = new(I) GotoInstr(join);
 | 
| -        jump->InheritDeoptTarget(I, branch);
 | 
| -
 | 
| -        Instruction* previous = branch->previous();
 | 
| -        branch->set_previous(NULL);
 | 
| -        previous->LinkTo(jump);
 | 
| -
 | 
| -        // Replace the false target entry with the new join entry. We will
 | 
| -        // recompute the dominators after this pass.
 | 
| -        join->LinkTo(next);
 | 
| -        branch->UnuseAllInputs();
 | 
| -      }
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  graph_->DiscoverBlocks();
 | 
| -  graph_->MergeBlocks();
 | 
| -  GrowableArray<BitVector*> dominance_frontier;
 | 
| -  graph_->ComputeDominators(&dominance_frontier);
 | 
| -
 | 
| -  if (FLAG_trace_constant_propagation) {
 | 
| -    OS::Print("\n==== After constant propagation ====\n");
 | 
| -    FlowGraphPrinter printer(*graph_);
 | 
| -    printer.PrintBlocks();
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
|  // Returns true if the given phi has a single input use and
 | 
|  // is used in the environments either at the corresponding block entry or
 | 
|  // at the same instruction where input use is.
 | 
| 
 |