| Index: runtime/vm/flow_graph_optimizer.cc
 | 
| diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
 | 
| index 45a2670e554bbd70d2ba864751c7bc3f2ffae6ff..9f67fa2ca1f0785be8960a591f57a520f01f2df3 100644
 | 
| --- a/runtime/vm/flow_graph_optimizer.cc
 | 
| +++ b/runtime/vm/flow_graph_optimizer.cc
 | 
| @@ -54,6 +54,107 @@ void FlowGraphOptimizer::OptimizeComputations() {
 | 
|  }
 | 
|  
 | 
|  
 | 
| +static Computation* CreateConversion(Representation from,
 | 
| +                                     Representation to,
 | 
| +                                     Definition* def,
 | 
| +                                     Instruction* deopt_target) {
 | 
| +  if ((from == kUnboxedDouble) && (to == kTagged)) {
 | 
| +    return new BoxDoubleComp(new Value(def), NULL);
 | 
| +  } else if ((from == kTagged) && (to == kUnboxedDouble)) {
 | 
| +    const intptr_t deopt_id = (deopt_target != NULL) ?
 | 
| +        deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId;
 | 
| +    ASSERT((deopt_target != NULL) || (def->GetPropagatedCid() == kDoubleCid));
 | 
| +    return new UnboxDoubleComp(new Value(def), deopt_id);
 | 
| +  } else {
 | 
| +    UNREACHABLE();
 | 
| +    return NULL;
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void FlowGraphOptimizer::InsertConversionsFor(Definition* def) {
 | 
| +  const Representation from_rep = def->representation();
 | 
| +
 | 
| +  for (Value* use = def->input_use_list();
 | 
| +       use != NULL;
 | 
| +       use = use->next_use()) {
 | 
| +    const Representation to_rep =
 | 
| +        use->instruction()->RequiredInputRepresentation(use->use_index());
 | 
| +    if (from_rep == to_rep) {
 | 
| +      continue;
 | 
| +    }
 | 
| +
 | 
| +    Instruction* deopt_target = NULL;
 | 
| +    Instruction* instr = use->instruction();
 | 
| +    if (instr->IsPhi()) {
 | 
| +      if (!instr->AsPhi()->is_alive()) continue;
 | 
| +
 | 
| +      // For phis conversions have to be inserted in the predecessor.
 | 
| +      const BlockEntryInstr* pred =
 | 
| +          instr->AsPhi()->block()->PredecessorAt(use->use_index());
 | 
| +      instr = pred->last_instruction();
 | 
| +    } else {
 | 
| +      deopt_target = instr;
 | 
| +    }
 | 
| +
 | 
| +    BindInstr* converted = InsertBefore(
 | 
| +      instr,
 | 
| +      CreateConversion(from_rep, to_rep, def, deopt_target),
 | 
| +      use->instruction()->env(),
 | 
| +      BindInstr::kUsed);
 | 
| +
 | 
| +    use->set_definition(converted);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +void FlowGraphOptimizer::SelectRepresentations() {
 | 
| +  // Convervatively unbox all phis that were proven to be of type Double.
 | 
| +  for (intptr_t i = 0; i < block_order_.length(); ++i) {
 | 
| +    JoinEntryInstr* join_entry = block_order_[i]->AsJoinEntry();
 | 
| +    if (join_entry == NULL) continue;
 | 
| +
 | 
| +    if (join_entry->phis() != NULL) {
 | 
| +      for (intptr_t i = 0; i < join_entry->phis()->length(); ++i) {
 | 
| +        PhiInstr* phi = (*join_entry->phis())[i];
 | 
| +        if ((phi != NULL) && (phi->GetPropagatedCid() == kDoubleCid)) {
 | 
| +          phi->set_representation(kUnboxedDouble);
 | 
| +        }
 | 
| +      }
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  // Process all instructions and insert conversions where needed.
 | 
| +  GraphEntryInstr* graph_entry = block_order_[0]->AsGraphEntry();
 | 
| +
 | 
| +  // Visit incoming parameters.
 | 
| +  for (intptr_t i = 0; i < graph_entry->start_env()->values().length(); i++) {
 | 
| +    Value* val = graph_entry->start_env()->values()[i];
 | 
| +    InsertConversionsFor(val->definition());
 | 
| +  }
 | 
| +
 | 
| +  for (intptr_t i = 0; i < block_order_.length(); ++i) {
 | 
| +    BlockEntryInstr* entry = block_order_[i];
 | 
| +
 | 
| +    JoinEntryInstr* join_entry = entry->AsJoinEntry();
 | 
| +    if ((join_entry != NULL) && (join_entry->phis() != NULL)) {
 | 
| +      for (intptr_t i = 0; i < join_entry->phis()->length(); ++i) {
 | 
| +        PhiInstr* phi = (*join_entry->phis())[i];
 | 
| +        if ((phi != NULL) && (phi->is_alive())) {
 | 
| +          InsertConversionsFor(phi);
 | 
| +        }
 | 
| +      }
 | 
| +    }
 | 
| +
 | 
| +    for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) {
 | 
| +      Definition* def = it.Current()->AsDefinition();
 | 
| +      if (def != NULL) {
 | 
| +        InsertConversionsFor(def);
 | 
| +      }
 | 
| +    }
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
|  static bool ICDataHasReceiverClassId(const ICData& ic_data, intptr_t class_id) {
 | 
|    ASSERT(ic_data.num_args_tested() > 0);
 | 
|    for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) {
 | 
| @@ -341,39 +442,20 @@ bool FlowGraphOptimizer::TryReplaceWithBinaryOp(BindInstr* instr,
 | 
|        // Check that either left or right are not a smi.  Result or a
 | 
|        // binary operation with two smis is a smi not a double.
 | 
|        InsertBefore(instr,
 | 
| -                   new CheckEitherNonSmiComp(left, right, comp),
 | 
| +                   new CheckEitherNonSmiComp(left->Copy(),
 | 
| +                                             right->Copy(),
 | 
| +                                             comp),
 | 
|                     instr->env(),
 | 
|                     BindInstr::kUnused);
 | 
|  
 | 
| -      // Unbox operands.
 | 
| -      BindInstr* unbox_left = InsertBefore(
 | 
| -          instr,
 | 
| -          new UnboxDoubleComp(left->Copy(), comp),
 | 
| -          instr->env(),
 | 
| -          BindInstr::kUsed);
 | 
| -      BindInstr* unbox_right = InsertBefore(
 | 
| -          instr,
 | 
| -          new UnboxDoubleComp(right->Copy(), comp),
 | 
| -          instr->env(),
 | 
| -          BindInstr::kUsed);
 | 
| -
 | 
|        UnboxedDoubleBinaryOpComp* double_bin_op =
 | 
|            new UnboxedDoubleBinaryOpComp(op_kind,
 | 
| -                                        new Value(unbox_left),
 | 
| -                                        new Value(unbox_right));
 | 
| +                                        left->Copy(),
 | 
| +                                        right->Copy(),
 | 
| +                                        comp);
 | 
|        double_bin_op->set_ic_data(comp->ic_data());
 | 
|        instr->set_computation(double_bin_op);
 | 
|  
 | 
| -      if (instr->is_used()) {
 | 
| -        // Box result.
 | 
| -        Value* value = new Value(instr);
 | 
| -        BindInstr* bind = InsertAfter(instr,
 | 
| -                                      new BoxDoubleComp(value, comp),
 | 
| -                                      NULL,
 | 
| -                                      BindInstr::kUsed);
 | 
| -        instr->ReplaceUsesWith(bind);
 | 
| -      }
 | 
| -
 | 
|        RemovePushArguments(comp);
 | 
|      } else {
 | 
|        BinaryDoubleOpComp* double_bin_op = new BinaryDoubleOpComp(op_kind, comp);
 | 
| 
 |