| Index: src/hydrogen.cc
 | 
| diff --git a/src/hydrogen.cc b/src/hydrogen.cc
 | 
| index 99beda097bbea97a5d537c982dcfb3c96decdfc2..b9ad8af529d82a9f078d61c0d88af6594b61ac64 100644
 | 
| --- a/src/hydrogen.cc
 | 
| +++ b/src/hydrogen.cc
 | 
| @@ -1709,23 +1709,23 @@ void HGlobalValueNumberer::ProcessLoopBlock(
 | 
|        bool can_hoist = !instr->gvn_flags().ContainsAnyOf(depends_flags);
 | 
|        if (instr->IsTransitionElementsKind()) {
 | 
|          // It's possible to hoist transitions out of a loop as long as the
 | 
| -        // hoisting wouldn't move the transition past a DependsOn of one of it's
 | 
| -        // changes or any instructions that might change an objects map or
 | 
| -        // elements contents.
 | 
| -        GVNFlagSet changes = instr->ChangesFlags();
 | 
| +        // hoisting wouldn't move the transition past an instruction that has a
 | 
| +        // DependsOn flag for anything it changes.
 | 
|          GVNFlagSet hoist_depends_blockers =
 | 
| -            HValue::ConvertChangesToDependsFlags(changes);
 | 
| -        // In addition to not hoisting transitions above other instructions that
 | 
| -        // change dependencies that the transition changes, it must not be
 | 
| -        // hoisted above map changes and stores to an elements backing store
 | 
| -        // that the transition might change.
 | 
| -        GVNFlagSet hoist_change_blockers = changes;
 | 
| -        hoist_change_blockers.Add(kChangesMaps);
 | 
| +            HValue::ConvertChangesToDependsFlags(instr->ChangesFlags());
 | 
| +
 | 
| +        // In addition, the transition must not be hoisted above elements kind
 | 
| +        // changes, or if the transition is destructive to the elements buffer,
 | 
| +        // changes to array pointer or array contents.
 | 
| +        GVNFlagSet hoist_change_blockers;
 | 
| +        hoist_change_blockers.Add(kChangesElementsKind);
 | 
|          HTransitionElementsKind* trans = HTransitionElementsKind::cast(instr);
 | 
|          if (trans->original_map()->has_fast_double_elements()) {
 | 
| +          hoist_change_blockers.Add(kChangesElementsPointer);
 | 
|            hoist_change_blockers.Add(kChangesDoubleArrayElements);
 | 
|          }
 | 
|          if (trans->transitioned_map()->has_fast_double_elements()) {
 | 
| +          hoist_change_blockers.Add(kChangesElementsPointer);
 | 
|            hoist_change_blockers.Add(kChangesArrayElements);
 | 
|          }
 | 
|          if (FLAG_trace_gvn) {
 | 
| @@ -3966,7 +3966,7 @@ void HGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
 | 
|        new(zone()) HLoadKeyedFastElement(
 | 
|            environment()->ExpressionStackAt(2),  // Enum cache.
 | 
|            environment()->ExpressionStackAt(0),  // Iteration index.
 | 
| -          HLoadKeyedFastElement::OMIT_HOLE_CHECK));
 | 
| +          OMIT_HOLE_CHECK));
 | 
|  
 | 
|    // Check if the expected map still matches that of the enumerable.
 | 
|    // If not just deoptimize.
 | 
| @@ -4257,7 +4257,7 @@ static bool IsFastLiteral(Handle<JSObject> boilerplate,
 | 
|        elements->map() != boilerplate->GetHeap()->fixed_cow_array_map()) {
 | 
|      if (boilerplate->HasFastDoubleElements()) {
 | 
|        *total_size += FixedDoubleArray::SizeFor(elements->length());
 | 
| -    } else if (boilerplate->HasFastElements()) {
 | 
| +    } else if (boilerplate->HasFastObjectElements()) {
 | 
|        Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
 | 
|        int length = elements->length();
 | 
|        for (int i = 0; i < length; i++) {
 | 
| @@ -4464,11 +4464,13 @@ void HGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
 | 
|                                Representation::Integer32()));
 | 
|  
 | 
|      switch (boilerplate_elements_kind) {
 | 
| -      case FAST_SMI_ONLY_ELEMENTS:
 | 
| +      case FAST_SMI_ELEMENTS:
 | 
| +      case FAST_HOLEY_SMI_ELEMENTS:
 | 
|          // Smi-only arrays need a smi check.
 | 
|          AddInstruction(new(zone()) HCheckSmi(value));
 | 
|          // Fall through.
 | 
|        case FAST_ELEMENTS:
 | 
| +      case FAST_HOLEY_ELEMENTS:
 | 
|          AddInstruction(new(zone()) HStoreKeyedFastElement(
 | 
|              elements,
 | 
|              key,
 | 
| @@ -4476,6 +4478,7 @@ void HGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
 | 
|              boilerplate_elements_kind));
 | 
|          break;
 | 
|        case FAST_DOUBLE_ELEMENTS:
 | 
| +      case FAST_HOLEY_DOUBLE_ELEMENTS:
 | 
|          AddInstruction(new(zone()) HStoreKeyedFastDoubleElement(elements,
 | 
|                                                                  key,
 | 
|                                                                  value));
 | 
| @@ -5233,9 +5236,12 @@ HInstruction* HGraphBuilder::BuildExternalArrayElementAccess(
 | 
|        case EXTERNAL_FLOAT_ELEMENTS:
 | 
|        case EXTERNAL_DOUBLE_ELEMENTS:
 | 
|          break;
 | 
| -      case FAST_SMI_ONLY_ELEMENTS:
 | 
| +      case FAST_SMI_ELEMENTS:
 | 
|        case FAST_ELEMENTS:
 | 
|        case FAST_DOUBLE_ELEMENTS:
 | 
| +      case FAST_HOLEY_SMI_ELEMENTS:
 | 
| +      case FAST_HOLEY_ELEMENTS:
 | 
| +      case FAST_HOLEY_DOUBLE_ELEMENTS:
 | 
|        case DICTIONARY_ELEMENTS:
 | 
|        case NON_STRICT_ARGUMENTS_ELEMENTS:
 | 
|          UNREACHABLE();
 | 
| @@ -5260,13 +5266,16 @@ HInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements,
 | 
|      ASSERT(val != NULL);
 | 
|      switch (elements_kind) {
 | 
|        case FAST_DOUBLE_ELEMENTS:
 | 
| +      case FAST_HOLEY_DOUBLE_ELEMENTS:
 | 
|          return new(zone()) HStoreKeyedFastDoubleElement(
 | 
|              elements, checked_key, val);
 | 
| -      case FAST_SMI_ONLY_ELEMENTS:
 | 
| +      case FAST_SMI_ELEMENTS:
 | 
| +      case FAST_HOLEY_SMI_ELEMENTS:
 | 
|          // Smi-only arrays need a smi check.
 | 
|          AddInstruction(new(zone()) HCheckSmi(val));
 | 
|          // Fall through.
 | 
|        case FAST_ELEMENTS:
 | 
| +      case FAST_HOLEY_ELEMENTS:
 | 
|          return new(zone()) HStoreKeyedFastElement(
 | 
|              elements, checked_key, val, elements_kind);
 | 
|        default:
 | 
| @@ -5275,10 +5284,13 @@ HInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements,
 | 
|      }
 | 
|    }
 | 
|    // It's an element load (!is_store).
 | 
| -  if (elements_kind == FAST_DOUBLE_ELEMENTS) {
 | 
| -    return new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key);
 | 
| -  } else {  // FAST_ELEMENTS or FAST_SMI_ONLY_ELEMENTS.
 | 
| -    return new(zone()) HLoadKeyedFastElement(elements, checked_key);
 | 
| +  HoleCheckMode mode = IsFastPackedElementsKind(elements_kind) ?
 | 
| +      OMIT_HOLE_CHECK :
 | 
| +      PERFORM_HOLE_CHECK;
 | 
| +  if (IsFastDoubleElementsKind(elements_kind)) {
 | 
| +    return new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key, mode);
 | 
| +  } else {  // Smi or Object elements.
 | 
| +    return new(zone()) HLoadKeyedFastElement(elements, checked_key, mode);
 | 
|    }
 | 
|  }
 | 
|  
 | 
| @@ -5286,15 +5298,30 @@ HInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements,
 | 
|  HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object,
 | 
|                                                             HValue* key,
 | 
|                                                             HValue* val,
 | 
| +                                                           HValue* dependency,
 | 
|                                                             Handle<Map> map,
 | 
|                                                             bool is_store) {
 | 
| -  HInstruction* mapcheck = AddInstruction(new(zone()) HCheckMaps(object, map));
 | 
| -  bool fast_smi_only_elements = map->has_fast_smi_only_elements();
 | 
| -  bool fast_elements = map->has_fast_elements();
 | 
| +  HInstruction* mapcheck =
 | 
| +      AddInstruction(new(zone()) HCheckMaps(object, map, dependency));
 | 
| +  // No GVNFlag is necessary for ElementsKind if there is an explicit dependency
 | 
| +  // on a HElementsTransition instruction. The flag can also be removed if the
 | 
| +  // map to check has FAST_HOLEY_ELEMENTS, since there can be no further
 | 
| +  // ElementsKind transitions. Finally, the dependency can be removed for stores
 | 
| +  // for FAST_ELEMENTS, since a transition to HOLEY elements won't change the
 | 
| +  // generated store code.
 | 
| +  if (dependency ||
 | 
| +      (map->elements_kind() == FAST_HOLEY_ELEMENTS) ||
 | 
| +      (map->elements_kind() == FAST_ELEMENTS && is_store)) {
 | 
| +    mapcheck->ClearGVNFlag(kDependsOnElementsKind);
 | 
| +  }
 | 
| +  bool fast_smi_only_elements = map->has_fast_smi_elements();
 | 
| +  bool fast_elements = map->has_fast_object_elements();
 | 
|    HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object));
 | 
|    if (is_store && (fast_elements || fast_smi_only_elements)) {
 | 
| -    AddInstruction(new(zone()) HCheckMaps(
 | 
| -        elements, isolate()->factory()->fixed_array_map()));
 | 
| +    HCheckMaps* check_cow_map = new(zone()) HCheckMaps(
 | 
| +        elements, isolate()->factory()->fixed_array_map());
 | 
| +    check_cow_map->ClearGVNFlag(kDependsOnElementsKind);
 | 
| +    AddInstruction(check_cow_map);
 | 
|    }
 | 
|    HInstruction* length = NULL;
 | 
|    HInstruction* checked_key = NULL;
 | 
| @@ -5347,8 +5374,8 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object,
 | 
|    for (int i = 0; i < maps->length(); ++i) {
 | 
|      Handle<Map> map = maps->at(i);
 | 
|      ElementsKind elements_kind = map->elements_kind();
 | 
| -    if (elements_kind == FAST_DOUBLE_ELEMENTS ||
 | 
| -        elements_kind == FAST_ELEMENTS) {
 | 
| +    if (IsFastElementsKind(elements_kind) &&
 | 
| +        elements_kind != GetInitialFastElementsKind()) {
 | 
|        possible_transitioned_maps.Add(map);
 | 
|      }
 | 
|    }
 | 
| @@ -5362,12 +5389,17 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object,
 | 
|  
 | 
|    int num_untransitionable_maps = 0;
 | 
|    Handle<Map> untransitionable_map;
 | 
| +  HTransitionElementsKind* transition = NULL;
 | 
|    for (int i = 0; i < maps->length(); ++i) {
 | 
|      Handle<Map> map = maps->at(i);
 | 
|      ASSERT(map->IsMap());
 | 
|      if (!transition_target.at(i).is_null()) {
 | 
| -      AddInstruction(new(zone()) HTransitionElementsKind(
 | 
| -          object, map, transition_target.at(i)));
 | 
| +      ASSERT(Map::IsValidElementsTransition(
 | 
| +          map->elements_kind(),
 | 
| +          transition_target.at(i)->elements_kind()));
 | 
| +      transition = new(zone()) HTransitionElementsKind(
 | 
| +          object, map, transition_target.at(i));
 | 
| +      AddInstruction(transition);
 | 
|      } else {
 | 
|        type_todo[map->elements_kind()] = true;
 | 
|        if (map->elements_kind() >= FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND) {
 | 
| @@ -5387,7 +5419,7 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object,
 | 
|                                        : BuildLoadKeyedGeneric(object, key));
 | 
|      } else {
 | 
|        instr = AddInstruction(BuildMonomorphicElementAccess(
 | 
| -          object, key, val, untransitionable_map, is_store));
 | 
| +          object, key, val, transition, untransitionable_map, is_store));
 | 
|      }
 | 
|      *has_side_effects |= instr->HasObservableSideEffects();
 | 
|      instr->set_position(position);
 | 
| @@ -5404,20 +5436,18 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object,
 | 
|    HLoadExternalArrayPointer* external_elements = NULL;
 | 
|    HInstruction* checked_key = NULL;
 | 
|  
 | 
| -  // Generated code assumes that FAST_SMI_ONLY_ELEMENTS, FAST_ELEMENTS,
 | 
| -  // FAST_DOUBLE_ELEMENTS and DICTIONARY_ELEMENTS are handled before external
 | 
| -  // arrays.
 | 
| -  STATIC_ASSERT(FAST_SMI_ONLY_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND);
 | 
| -  STATIC_ASSERT(FAST_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND);
 | 
| +  // Generated code assumes that FAST_* and DICTIONARY_ELEMENTS ElementsKinds
 | 
| +  // are handled before external arrays.
 | 
| +  STATIC_ASSERT(FAST_SMI_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND);
 | 
| +  STATIC_ASSERT(FAST_HOLEY_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND);
 | 
|    STATIC_ASSERT(FAST_DOUBLE_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND);
 | 
|    STATIC_ASSERT(DICTIONARY_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND);
 | 
|  
 | 
|    for (ElementsKind elements_kind = FIRST_ELEMENTS_KIND;
 | 
|         elements_kind <= LAST_ELEMENTS_KIND;
 | 
|         elements_kind = ElementsKind(elements_kind + 1)) {
 | 
| -    // After having handled FAST_ELEMENTS, FAST_SMI_ONLY_ELEMENTS,
 | 
| -    // FAST_DOUBLE_ELEMENTS and DICTIONARY_ELEMENTS, we need to add some code
 | 
| -    // that's executed for all external array cases.
 | 
| +    // After having handled FAST_* and DICTIONARY_ELEMENTS, we need to add some
 | 
| +    // code that's executed for all external array cases.
 | 
|      STATIC_ASSERT(LAST_EXTERNAL_ARRAY_ELEMENTS_KIND ==
 | 
|                    LAST_ELEMENTS_KIND);
 | 
|      if (elements_kind == FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND
 | 
| @@ -5439,10 +5469,8 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object,
 | 
|  
 | 
|        set_current_block(if_true);
 | 
|        HInstruction* access;
 | 
| -      if (elements_kind == FAST_SMI_ONLY_ELEMENTS ||
 | 
| -          elements_kind == FAST_ELEMENTS ||
 | 
| -          elements_kind == FAST_DOUBLE_ELEMENTS) {
 | 
| -        if (is_store && elements_kind != FAST_DOUBLE_ELEMENTS) {
 | 
| +      if (IsFastElementsKind(elements_kind)) {
 | 
| +        if (is_store && !IsFastDoubleElementsKind(elements_kind)) {
 | 
|            AddInstruction(new(zone()) HCheckMaps(
 | 
|                elements, isolate()->factory()->fixed_array_map(),
 | 
|                elements_kind_branch));
 | 
| @@ -5529,7 +5557,7 @@ HValue* HGraphBuilder::HandleKeyedElementAccess(HValue* obj,
 | 
|                         : BuildLoadKeyedGeneric(obj, key);
 | 
|      } else {
 | 
|        AddInstruction(new(zone()) HCheckNonSmi(obj));
 | 
| -      instr = BuildMonomorphicElementAccess(obj, key, val, map, is_store);
 | 
| +      instr = BuildMonomorphicElementAccess(obj, key, val, NULL, map, is_store);
 | 
|      }
 | 
|    } else if (expr->GetReceiverTypes() != NULL &&
 | 
|               !expr->GetReceiverTypes()->is_empty()) {
 | 
| 
 |