| Index: src/hydrogen-instructions.cc
 | 
| diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc
 | 
| index feac1be0bcfcdf45f6c435f7899acd645d24e4e8..ec23e1971b7923d14b11ca23622cb900dbcbcd24 100644
 | 
| --- a/src/hydrogen-instructions.cc
 | 
| +++ b/src/hydrogen-instructions.cc
 | 
| @@ -85,6 +85,81 @@ void HValue::AssumeRepresentation(Representation r) {
 | 
|  }
 | 
|  
 | 
|  
 | 
| +void HValue::InferRepresentation(HInferRepresentation* h_infer) {
 | 
| +  ASSERT(CheckFlag(kFlexibleRepresentation));
 | 
| +  Representation new_rep = RepresentationFromInputs();
 | 
| +  UpdateRepresentation(new_rep, h_infer, "inputs");
 | 
| +  new_rep = RepresentationFromUses();
 | 
| +  UpdateRepresentation(new_rep, h_infer, "uses");
 | 
| +}
 | 
| +
 | 
| +
 | 
| +Representation HValue::RepresentationFromUses() {
 | 
| +  if (HasNoUses()) return Representation::None();
 | 
| +
 | 
| +  // Array of use counts for each representation.
 | 
| +  int use_count[Representation::kNumRepresentations] = { 0 };
 | 
| +
 | 
| +  for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
 | 
| +    HValue* use = it.value();
 | 
| +    Representation rep = use->observed_input_representation(it.index());
 | 
| +    if (rep.IsNone()) continue;
 | 
| +    if (FLAG_trace_representation) {
 | 
| +      PrintF("#%d %s is used by #%d %s as %s%s\n",
 | 
| +             id(), Mnemonic(), use->id(), use->Mnemonic(), rep.Mnemonic(),
 | 
| +             (use->CheckFlag(kTruncatingToInt32) ? "-trunc" : ""));
 | 
| +    }
 | 
| +    use_count[rep.kind()] += use->LoopWeight();
 | 
| +  }
 | 
| +  if (IsPhi()) HPhi::cast(this)->AddIndirectUsesTo(&use_count[0]);
 | 
| +  int tagged_count = use_count[Representation::kTagged];
 | 
| +  int double_count = use_count[Representation::kDouble];
 | 
| +  int int32_count = use_count[Representation::kInteger32];
 | 
| +
 | 
| +  if (tagged_count > 0) return Representation::Tagged();
 | 
| +  if (double_count > 0) return Representation::Double();
 | 
| +  if (int32_count > 0) return Representation::Integer32();
 | 
| +
 | 
| +  return Representation::None();
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void HValue::UpdateRepresentation(Representation new_rep,
 | 
| +                                  HInferRepresentation* h_infer,
 | 
| +                                  const char* reason) {
 | 
| +  Representation r = representation();
 | 
| +  if (new_rep.is_more_general_than(r)) {
 | 
| +    // When an HConstant is marked "not convertible to integer", then
 | 
| +    // never try to represent it as an integer.
 | 
| +    if (new_rep.IsInteger32() && !IsConvertibleToInteger()) {
 | 
| +      new_rep = Representation::Tagged();
 | 
| +      if (FLAG_trace_representation) {
 | 
| +        PrintF("Changing #%d %s representation %s -> %s because it's NCTI"
 | 
| +               " (%s want i)\n",
 | 
| +               id(), Mnemonic(), r.Mnemonic(), new_rep.Mnemonic(), reason);
 | 
| +      }
 | 
| +    } else {
 | 
| +      if (FLAG_trace_representation) {
 | 
| +        PrintF("Changing #%d %s representation %s -> %s based on %s\n",
 | 
| +               id(), Mnemonic(), r.Mnemonic(), new_rep.Mnemonic(), reason);
 | 
| +      }
 | 
| +    }
 | 
| +    ChangeRepresentation(new_rep);
 | 
| +    AddDependantsToWorklist(h_infer);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void HValue::AddDependantsToWorklist(HInferRepresentation* h_infer) {
 | 
| +  for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
 | 
| +    h_infer->AddToWorklist(it.value());
 | 
| +  }
 | 
| +  for (int i = 0; i < OperandCount(); ++i) {
 | 
| +    h_infer->AddToWorklist(OperandAt(i));
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
|  static int32_t ConvertAndSetOverflow(int64_t result, bool* overflow) {
 | 
|    if (result > kMaxInt) {
 | 
|      *overflow = true;
 | 
| @@ -301,6 +376,7 @@ HUseListNode* HUseListNode::tail() {
 | 
|  
 | 
|  bool HValue::CheckUsesForFlag(Flag f) {
 | 
|    for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
 | 
| +    if (it.value()->IsSimulate()) continue;
 | 
|      if (!it.value()->CheckFlag(f)) return false;
 | 
|    }
 | 
|    return true;
 | 
| @@ -764,6 +840,24 @@ void HReturn::PrintDataTo(StringStream* stream) {
 | 
|  }
 | 
|  
 | 
|  
 | 
| +Representation HBranch::observed_input_representation(int index) {
 | 
| +  static const ToBooleanStub::Types tagged_types(
 | 
| +      ToBooleanStub::UNDEFINED |
 | 
| +      ToBooleanStub::NULL_TYPE |
 | 
| +      ToBooleanStub::SPEC_OBJECT |
 | 
| +      ToBooleanStub::STRING);
 | 
| +  if (expected_input_types_.ContainsAnyOf(tagged_types)) {
 | 
| +    return Representation::Tagged();
 | 
| +  } else if (expected_input_types_.Contains(ToBooleanStub::HEAP_NUMBER)) {
 | 
| +    return Representation::Double();
 | 
| +  } else if (expected_input_types_.Contains(ToBooleanStub::SMI)) {
 | 
| +    return Representation::Integer32();
 | 
| +  } else {
 | 
| +    return Representation::None();
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
|  void HCompareMap::PrintDataTo(StringStream* stream) {
 | 
|    value()->PrintNameTo(stream);
 | 
|    stream->Add(" (%p)", *map());
 | 
| @@ -1339,15 +1433,11 @@ void HPhi::InitRealUses(int phi_id) {
 | 
|    for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
 | 
|      HValue* value = it.value();
 | 
|      if (!value->IsPhi()) {
 | 
| -      Representation rep = value->ObservedInputRepresentation(it.index());
 | 
| +      Representation rep = value->observed_input_representation(it.index());
 | 
|        non_phi_uses_[rep.kind()] += value->LoopWeight();
 | 
|        if (FLAG_trace_representation) {
 | 
| -        PrintF("%d %s is used by %d %s as %s\n",
 | 
| -               this->id(),
 | 
| -               this->Mnemonic(),
 | 
| -               value->id(),
 | 
| -               value->Mnemonic(),
 | 
| -               rep.Mnemonic());
 | 
| +        PrintF("#%d Phi is used by real #%d %s as %s\n",
 | 
| +               id(), value->id(), value->Mnemonic(), rep.Mnemonic());
 | 
|        }
 | 
|      }
 | 
|    }
 | 
| @@ -1356,11 +1446,8 @@ void HPhi::InitRealUses(int phi_id) {
 | 
|  
 | 
|  void HPhi::AddNonPhiUsesFrom(HPhi* other) {
 | 
|    if (FLAG_trace_representation) {
 | 
| -    PrintF("adding to %d %s uses of %d %s: i%d d%d t%d\n",
 | 
| -           this->id(),
 | 
| -           this->Mnemonic(),
 | 
| -           other->id(),
 | 
| -           other->Mnemonic(),
 | 
| +    PrintF("adding to #%d Phi uses of #%d Phi: i%d d%d t%d\n",
 | 
| +           id(), other->id(),
 | 
|             other->non_phi_uses_[Representation::kInteger32],
 | 
|             other->non_phi_uses_[Representation::kDouble],
 | 
|             other->non_phi_uses_[Representation::kTagged]);
 | 
| @@ -1379,9 +1466,20 @@ void HPhi::AddIndirectUsesTo(int* dest) {
 | 
|  }
 | 
|  
 | 
|  
 | 
| -void HPhi::ResetInteger32Uses() {
 | 
| -  non_phi_uses_[Representation::kInteger32] = 0;
 | 
| -  indirect_uses_[Representation::kInteger32] = 0;
 | 
| +void HSimulate::MergeInto(HSimulate* other) {
 | 
| +  for (int i = 0; i < values_.length(); ++i) {
 | 
| +    HValue* value = values_[i];
 | 
| +    if (HasAssignedIndexAt(i)) {
 | 
| +      other->AddAssignedValue(GetAssignedIndexAt(i), value);
 | 
| +    } else {
 | 
| +      if (other->pop_count_ > 0) {
 | 
| +        other->pop_count_--;
 | 
| +      } else {
 | 
| +        other->AddPushedValue(value);
 | 
| +      }
 | 
| +    }
 | 
| +  }
 | 
| +  other->pop_count_ += pop_count();
 | 
|  }
 | 
|  
 | 
|  
 | 
| @@ -1390,7 +1488,7 @@ void HSimulate::PrintDataTo(StringStream* stream) {
 | 
|    if (pop_count_ > 0) stream->Add(" pop %d", pop_count_);
 | 
|    if (values_.length() > 0) {
 | 
|      if (pop_count_ > 0) stream->Add(" /");
 | 
| -    for (int i = 0; i < values_.length(); ++i) {
 | 
| +    for (int i = values_.length() - 1; i >= 0; --i) {
 | 
|        if (i > 0) stream->Add(",");
 | 
|        if (HasAssignedIndexAt(i)) {
 | 
|          stream->Add(" var[%d] = ", GetAssignedIndexAt(i));
 | 
| @@ -1429,7 +1527,6 @@ HConstant::HConstant(Handle<Object> handle, Representation r)
 | 
|      : handle_(handle),
 | 
|        has_int32_value_(false),
 | 
|        has_double_value_(false) {
 | 
| -  set_representation(r);
 | 
|    SetFlag(kUseGVN);
 | 
|    if (handle_->IsNumber()) {
 | 
|      double n = handle_->Number();
 | 
| @@ -1438,6 +1535,16 @@ HConstant::HConstant(Handle<Object> handle, Representation r)
 | 
|      double_value_ = n;
 | 
|      has_double_value_ = true;
 | 
|    }
 | 
| +  if (r.IsNone()) {
 | 
| +    if (has_int32_value_) {
 | 
| +      r = Representation::Integer32();
 | 
| +    } else if (has_double_value_) {
 | 
| +      r = Representation::Double();
 | 
| +    } else {
 | 
| +      r = Representation::Tagged();
 | 
| +    }
 | 
| +  }
 | 
| +  set_representation(r);
 | 
|  }
 | 
|  
 | 
|  
 | 
| @@ -1536,6 +1643,52 @@ void HBinaryOperation::PrintDataTo(StringStream* stream) {
 | 
|  }
 | 
|  
 | 
|  
 | 
| +void HBinaryOperation::InferRepresentation(HInferRepresentation* h_infer) {
 | 
| +  ASSERT(CheckFlag(kFlexibleRepresentation));
 | 
| +  Representation new_rep = RepresentationFromInputs();
 | 
| +  UpdateRepresentation(new_rep, h_infer, "inputs");
 | 
| +  // When the operation has information about its own output type, don't look
 | 
| +  // at uses.
 | 
| +  if (!observed_output_representation_.IsNone()) return;
 | 
| +  new_rep = RepresentationFromUses();
 | 
| +  UpdateRepresentation(new_rep, h_infer, "uses");
 | 
| +}
 | 
| +
 | 
| +
 | 
| +Representation HBinaryOperation::RepresentationFromInputs() {
 | 
| +  // Determine the worst case of observed input representations and
 | 
| +  // the currently assumed output representation.
 | 
| +  Representation rep = representation();
 | 
| +  if (observed_output_representation_.is_more_general_than(rep)) {
 | 
| +    rep = observed_output_representation_;
 | 
| +  }
 | 
| +  for (int i = 1; i <= 2; ++i) {
 | 
| +    Representation input_rep = observed_input_representation(i);
 | 
| +    if (input_rep.is_more_general_than(rep)) rep = input_rep;
 | 
| +  }
 | 
| +  // If any of the actual input representation is more general than what we
 | 
| +  // have so far but not Tagged, use that representation instead.
 | 
| +  Representation left_rep = left()->representation();
 | 
| +  Representation right_rep = right()->representation();
 | 
| +
 | 
| +  if (left_rep.is_more_general_than(rep) &&
 | 
| +      left()->CheckFlag(kFlexibleRepresentation)) {
 | 
| +    rep = left_rep;
 | 
| +  }
 | 
| +  if (right_rep.is_more_general_than(rep) &&
 | 
| +      right()->CheckFlag(kFlexibleRepresentation)) {
 | 
| +    rep = right_rep;
 | 
| +  }
 | 
| +  return rep;
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void HBinaryOperation::AssumeRepresentation(Representation r) {
 | 
| +  set_observed_input_representation(r, r);
 | 
| +  HValue::AssumeRepresentation(r);
 | 
| +}
 | 
| +
 | 
| +
 | 
|  Range* HBitwise::InferRange(Zone* zone) {
 | 
|    if (op() == Token::BIT_XOR) return HValue::InferRange(zone);
 | 
|    const int32_t kDefaultMask = static_cast<int32_t>(0xffffffff);
 | 
| @@ -1667,9 +1820,19 @@ void HGoto::PrintDataTo(StringStream* stream) {
 | 
|  }
 | 
|  
 | 
|  
 | 
| -void HCompareIDAndBranch::SetInputRepresentation(Representation r) {
 | 
| -  input_representation_ = r;
 | 
| -  if (r.IsDouble()) {
 | 
| +void HCompareIDAndBranch::InferRepresentation(HInferRepresentation* h_infer) {
 | 
| +  Representation rep = Representation::None();
 | 
| +  Representation left_rep = left()->representation();
 | 
| +  Representation right_rep = right()->representation();
 | 
| +  bool observed_integers =
 | 
| +      observed_input_representation(0).IsInteger32() &&
 | 
| +      observed_input_representation(1).IsInteger32();
 | 
| +  bool inputs_are_not_doubles =
 | 
| +      !left_rep.IsDouble() && !right_rep.IsDouble();
 | 
| +  if (observed_integers && inputs_are_not_doubles) {
 | 
| +    rep = Representation::Integer32();
 | 
| +  } else {
 | 
| +    rep = Representation::Double();
 | 
|      // According to the ES5 spec (11.9.3, 11.8.5), Equality comparisons (==, ===
 | 
|      // and !=) have special handling of undefined, e.g. undefined == undefined
 | 
|      // is 'true'. Relational comparisons have a different semantic, first
 | 
| @@ -1686,9 +1849,8 @@ void HCompareIDAndBranch::SetInputRepresentation(Representation r) {
 | 
|      if (!Token::IsOrderedRelationalCompareOp(token_)) {
 | 
|        SetFlag(kDeoptimizeOnUndefined);
 | 
|      }
 | 
| -  } else {
 | 
| -    ASSERT(r.IsInteger32());
 | 
|    }
 | 
| +  ChangeRepresentation(rep);
 | 
|  }
 | 
|  
 | 
|  
 | 
| @@ -2451,7 +2613,41 @@ void HBitwise::PrintDataTo(StringStream* stream) {
 | 
|  }
 | 
|  
 | 
|  
 | 
| -Representation HPhi::InferredRepresentation() {
 | 
| +void HPhi::InferRepresentation(HInferRepresentation* h_infer) {
 | 
| +  ASSERT(CheckFlag(kFlexibleRepresentation));
 | 
| +  // If there are non-Phi uses, and all of them have observed the same
 | 
| +  // representation, than that's what this Phi is going to use.
 | 
| +  Representation new_rep = RepresentationObservedByAllNonPhiUses();
 | 
| +  if (!new_rep.IsNone()) {
 | 
| +    UpdateRepresentation(new_rep, h_infer, "unanimous use observations");
 | 
| +    return;
 | 
| +  }
 | 
| +  new_rep = RepresentationFromInputs();
 | 
| +  UpdateRepresentation(new_rep, h_infer, "inputs");
 | 
| +  new_rep = RepresentationFromUses();
 | 
| +  UpdateRepresentation(new_rep, h_infer, "uses");
 | 
| +  new_rep = RepresentationFromUseRequirements();
 | 
| +  UpdateRepresentation(new_rep, h_infer, "use requirements");
 | 
| +}
 | 
| +
 | 
| +
 | 
| +Representation HPhi::RepresentationObservedByAllNonPhiUses() {
 | 
| +  int non_phi_use_count = 0;
 | 
| +  for (int i = Representation::kInteger32;
 | 
| +       i < Representation::kNumRepresentations; ++i) {
 | 
| +    non_phi_use_count += non_phi_uses_[i];
 | 
| +  }
 | 
| +  if (non_phi_use_count <= 1) return Representation::None();
 | 
| +  for (int i = 0; i < Representation::kNumRepresentations; ++i) {
 | 
| +    if (non_phi_uses_[i] == non_phi_use_count) {
 | 
| +      return Representation::FromKind(static_cast<Representation::Kind>(i));
 | 
| +    }
 | 
| +  }
 | 
| +  return Representation::None();
 | 
| +}
 | 
| +
 | 
| +
 | 
| +Representation HPhi::RepresentationFromInputs() {
 | 
|    bool double_occurred = false;
 | 
|    bool int32_occurred = false;
 | 
|    for (int i = 0; i < OperandCount(); ++i) {
 | 
| @@ -2460,6 +2656,7 @@ Representation HPhi::InferredRepresentation() {
 | 
|        HPhi* hint_value = HUnknownOSRValue::cast(value)->incoming_value();
 | 
|        if (hint_value != NULL) {
 | 
|          Representation hint = hint_value->representation();
 | 
| +        if (hint.IsTagged()) return hint;
 | 
|          if (hint.IsDouble()) double_occurred = true;
 | 
|          if (hint.IsInteger32()) int32_occurred = true;
 | 
|        }
 | 
| @@ -2478,7 +2675,9 @@ Representation HPhi::InferredRepresentation() {
 | 
|            return Representation::Tagged();
 | 
|          }
 | 
|        } else {
 | 
| -        return Representation::Tagged();
 | 
| +        if (value->IsPhi() && !IsConvertibleToInteger()) {
 | 
| +          return Representation::Tagged();
 | 
| +        }
 | 
|        }
 | 
|      }
 | 
|    }
 | 
| @@ -2491,6 +2690,37 @@ Representation HPhi::InferredRepresentation() {
 | 
|  }
 | 
|  
 | 
|  
 | 
| +Representation HPhi::RepresentationFromUseRequirements() {
 | 
| +  Representation all_uses_require = Representation::None();
 | 
| +  bool all_uses_require_the_same = true;
 | 
| +  for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
 | 
| +    // We check for observed_input_representation elsewhere.
 | 
| +    Representation use_rep =
 | 
| +        it.value()->RequiredInputRepresentation(it.index());
 | 
| +    // No useful info from this use -> look at the next one.
 | 
| +    if (use_rep.IsNone()) {
 | 
| +      continue;
 | 
| +    }
 | 
| +    if (use_rep.Equals(all_uses_require)) {
 | 
| +      continue;
 | 
| +    }
 | 
| +    // This use's representation contradicts what we've seen so far.
 | 
| +    if (!all_uses_require.IsNone()) {
 | 
| +      ASSERT(!use_rep.Equals(all_uses_require));
 | 
| +      all_uses_require_the_same = false;
 | 
| +      break;
 | 
| +    }
 | 
| +    // Otherwise, initialize observed representation.
 | 
| +    all_uses_require = use_rep;
 | 
| +  }
 | 
| +  if (all_uses_require_the_same) {
 | 
| +    return all_uses_require;
 | 
| +  }
 | 
| +
 | 
| +  return Representation::None();
 | 
| +}
 | 
| +
 | 
| +
 | 
|  // Node-specific verification code is only included in debug mode.
 | 
|  #ifdef DEBUG
 | 
|  
 | 
| 
 |