Index: runtime/vm/flow_graph_optimizer.cc |
=================================================================== |
--- runtime/vm/flow_graph_optimizer.cc (revision 23072) |
+++ runtime/vm/flow_graph_optimizer.cc (working copy) |
@@ -3415,8 +3415,6 @@ |
void LICM::Hoist(ForwardInstructionIterator* it, |
BlockEntryInstr* pre_header, |
Instruction* current) { |
- // TODO(fschneider): Avoid repeated deoptimization when |
- // speculatively hoisting checks. |
if (FLAG_trace_optimization) { |
OS::Print("Hoisting instruction %s:%"Pd" from B%"Pd" to B%"Pd"\n", |
current->DebugName(), |
@@ -3472,7 +3470,7 @@ |
} |
// Host CheckSmi instruction and make this phi smi one. |
- Hoist(it, pre_header, current); |
+ if (MayHoist(current, pre_header)) Hoist(it, pre_header, current); |
// Replace value we are checking with phi's input. |
current->value()->BindTo(phi->InputAt(non_smi_input)->definition()); |
@@ -3491,6 +3489,31 @@ |
} |
+bool LICM::MayHoist(Instruction* instr, BlockEntryInstr* pre_header) { |
+ // TODO(fschneider): Enable hoisting of Assert-instructions |
+ // if it safe to do. |
+ if (instr->IsAssertAssignable()) return false; |
+ if (instr->IsAssertBoolean()) return false; |
+ |
+ if (instr->CanDeoptimize()) { |
+ intptr_t target_deopt_id = |
+ pre_header->last_instruction()->AsGoto()->GetDeoptId(); |
+ const Function& function = flow_graph_->parsed_function().function(); |
+ const Array& deopt_history = Array::Handle(function.deopt_history()); |
+ if (deopt_history.IsNull()) return true; |
+ |
+ Smi& deopt_id = Smi::Handle(); |
+ for (intptr_t i = 0; i < deopt_history.Length(); ++i) { |
+ deopt_id ^= deopt_history.At(i); |
+ if (!deopt_id.IsNull() && (deopt_id.Value() == target_deopt_id)) { |
+ return false; |
+ } |
+ } |
+ } |
+ return true; |
+} |
+ |
+ |
void LICM::Optimize() { |
const ZoneGrowableArray<BlockEntryInstr*>& loop_headers = |
flow_graph()->loop_headers(); |
@@ -3525,11 +3548,7 @@ |
break; |
} |
} |
- if (inputs_loop_invariant && |
- !current->IsAssertAssignable() && |
- !current->IsAssertBoolean()) { |
- // TODO(fschneider): Enable hoisting of Assert-instructions |
- // if it safe to do. |
+ if (inputs_loop_invariant && MayHoist(current, pre_header)) { |
Hoist(&it, pre_header, current); |
} else if (current->IsCheckSmi() && |
current->InputAt(0)->definition()->IsPhi()) { |