| Index: src/hydrogen.cc
 | 
| diff --git a/src/hydrogen.cc b/src/hydrogen.cc
 | 
| index a6b60b1f77a8fc439409096fbd88cd6c7b79006c..076d5c2e591b725f5b52f9c5c466d0d30e79cafc 100644
 | 
| --- a/src/hydrogen.cc
 | 
| +++ b/src/hydrogen.cc
 | 
| @@ -1431,7 +1431,8 @@ class HGlobalValueNumberer BASE_EMBEDDED {
 | 
|    void ProcessLoopBlock(HBasicBlock* block,
 | 
|                          HBasicBlock* before_loop,
 | 
|                          GVNFlagSet loop_kills,
 | 
| -                        GVNFlagSet* accumulated_first_time_depends);
 | 
| +                        GVNFlagSet* accumulated_first_time_depends,
 | 
| +                        GVNFlagSet* accumulated_first_time_changes);
 | 
|    bool AllowCodeMotion();
 | 
|    bool ShouldMove(HInstruction* instr, HBasicBlock* loop_header);
 | 
|  
 | 
| @@ -1512,10 +1513,12 @@ void HGlobalValueNumberer::LoopInvariantCodeMotion() {
 | 
|                 side_effects.ToIntegral());
 | 
|  
 | 
|        GVNFlagSet accumulated_first_time_depends;
 | 
| +      GVNFlagSet accumulated_first_time_changes;
 | 
|        HBasicBlock* last = block->loop_information()->GetLastBackEdge();
 | 
|        for (int j = block->block_id(); j <= last->block_id(); ++j) {
 | 
|          ProcessLoopBlock(graph_->blocks()->at(j), block, side_effects,
 | 
| -                         &accumulated_first_time_depends);
 | 
| +                         &accumulated_first_time_depends,
 | 
| +                         &accumulated_first_time_changes);
 | 
|        }
 | 
|      }
 | 
|    }
 | 
| @@ -1526,7 +1529,8 @@ void HGlobalValueNumberer::ProcessLoopBlock(
 | 
|      HBasicBlock* block,
 | 
|      HBasicBlock* loop_header,
 | 
|      GVNFlagSet loop_kills,
 | 
| -    GVNFlagSet* accumulated_first_time_depends) {
 | 
| +    GVNFlagSet* first_time_depends,
 | 
| +    GVNFlagSet* first_time_changes) {
 | 
|    HBasicBlock* pre_header = loop_header->predecessors()->at(0);
 | 
|    GVNFlagSet depends_flags = HValue::ConvertChangesToDependsFlags(loop_kills);
 | 
|    TraceGVN("Loop invariant motion for B%d depends_flags=0x%x\n",
 | 
| @@ -1544,28 +1548,47 @@ void HGlobalValueNumberer::ProcessLoopBlock(
 | 
|                 instr->gvn_flags().ToIntegral(),
 | 
|                 depends_flags.ToIntegral());
 | 
|        bool can_hoist = !instr->gvn_flags().ContainsAnyOf(depends_flags);
 | 
| -      if (!can_hoist && instr->IsTransitionElementsKind()) {
 | 
| -        // It's only possible to hoist one time side effects if there are no
 | 
| -        // dependencies on their changes from the loop header to the current
 | 
| -        // instruction.
 | 
| -        GVNFlagSet converted_changes =
 | 
| -            HValue::ConvertChangesToDependsFlags(instr->ChangesFlags());
 | 
| -        TraceGVN("Checking dependencies on one-time instruction %d (%s) "
 | 
| -                 "converted changes 0x%X, accumulated depends 0x%X\n",
 | 
| +      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();
 | 
| +        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);
 | 
| +        HTransitionElementsKind* trans = HTransitionElementsKind::cast(instr);
 | 
| +        if (trans->original_map()->has_fast_double_elements()) {
 | 
| +          hoist_change_blockers.Add(kChangesDoubleArrayElements);
 | 
| +        }
 | 
| +        if (trans->transitioned_map()->has_fast_double_elements()) {
 | 
| +          hoist_change_blockers.Add(kChangesArrayElements);
 | 
| +        }
 | 
| +        TraceGVN("Checking dependencies on HTransitionElementsKind %d (%s) "
 | 
| +                 "hoist depends blockers 0x%X, hoist change blockers 0x%X, "
 | 
| +                 "accumulated depends 0x%X, accumulated changes 0x%X\n",
 | 
|                   instr->id(),
 | 
|                   instr->Mnemonic(),
 | 
| -                 converted_changes.ToIntegral(),
 | 
| -                 accumulated_first_time_depends->ToIntegral());
 | 
| -        // It's possible to hoist one-time side effects from the current loop
 | 
| -        // loop only if they dominate all of the successor blocks in the same
 | 
| -        // loop and there are not any instructions that have Changes/DependsOn
 | 
| -        // that intervene between it and the beginning of the loop header.
 | 
| +                 hoist_depends_blockers.ToIntegral(),
 | 
| +                 hoist_change_blockers.ToIntegral(),
 | 
| +                 first_time_depends->ToIntegral(),
 | 
| +                 first_time_changes->ToIntegral());
 | 
| +        // It's possible to hoist transition from the current loop loop only if
 | 
| +        // they dominate all of the successor blocks in the same loop and there
 | 
| +        // are not any instructions that have Changes/DependsOn that intervene
 | 
| +        // between it and the beginning of the loop header.
 | 
|          bool in_nested_loop = block != loop_header &&
 | 
|              ((block->parent_loop_header() != loop_header) ||
 | 
|               block->IsLoopHeader());
 | 
|          can_hoist = !in_nested_loop &&
 | 
|              block->IsLoopSuccessorDominator() &&
 | 
| -            !accumulated_first_time_depends->ContainsAnyOf(converted_changes);
 | 
| +            !first_time_depends->ContainsAnyOf(hoist_depends_blockers) &&
 | 
| +            !first_time_changes->ContainsAnyOf(hoist_change_blockers);
 | 
|        }
 | 
|  
 | 
|        if (can_hoist) {
 | 
| @@ -1589,10 +1612,8 @@ void HGlobalValueNumberer::ProcessLoopBlock(
 | 
|      if (!hoisted) {
 | 
|        // If an instruction is not hoisted, we have to account for its side
 | 
|        // effects when hoisting later HTransitionElementsKind instructions.
 | 
| -      accumulated_first_time_depends->Add(instr->DependsOnFlags());
 | 
| -      GVNFlagSet converted_changes =
 | 
| -          HValue::ConvertChangesToDependsFlags(instr->SideEffectFlags());
 | 
| -      accumulated_first_time_depends->Add(converted_changes);
 | 
| +      first_time_depends->Add(instr->DependsOnFlags());
 | 
| +      first_time_changes->Add(instr->ChangesFlags());
 | 
|      }
 | 
|      instr = next;
 | 
|    }
 | 
| @@ -4454,7 +4475,7 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object,
 | 
|      Handle<Map> map = maps->at(i);
 | 
|      ASSERT(map->IsMap());
 | 
|      if (!transition_target.at(i).is_null()) {
 | 
| -      object = AddInstruction(new(zone()) HTransitionElementsKind(
 | 
| +      AddInstruction(new(zone()) HTransitionElementsKind(
 | 
|            object, map, transition_target.at(i)));
 | 
|      } else {
 | 
|        type_todo[map->elements_kind()] = true;
 | 
| 
 |