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; |