Index: src/hydrogen.cc |
diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
index 05a59d26d3dc139ae3ec5aded1c79fb3bda7cfc4..6236f7849d6dc4a62a824ab671c02b9e60f15851 100644 |
--- a/src/hydrogen.cc |
+++ b/src/hydrogen.cc |
@@ -2574,6 +2574,8 @@ HCompare* HGraphBuilder::BuildSwitchCompare(HSubgraph* subgraph, |
void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { |
VISIT_FOR_VALUE(stmt->tag()); |
+ // TODO(3168478): simulate added for tag should be enough. |
+ AddSimulate(stmt->EntryId()); |
HValue* switch_value = Pop(); |
ZoneList<CaseClause*>* clauses = stmt->cases(); |
@@ -2581,11 +2583,16 @@ void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { |
if (num_clauses == 0) return; |
if (num_clauses > 128) BAILOUT("SwitchStatement: too many clauses"); |
+ int num_smi_clauses = num_clauses; |
for (int i = 0; i < num_clauses; i++) { |
CaseClause* clause = clauses->at(i); |
if (clause->is_default()) continue; |
clause->RecordTypeFeedback(oracle()); |
- if (!clause->IsSmiCompare()) BAILOUT("SwitchStatement: non-smi compare"); |
+ if (!clause->IsSmiCompare()) { |
+ // We will deoptimize if the first non-smi compare is reached. |
+ num_smi_clauses = i; |
+ break; |
+ } |
fschneider
2010/12/15 16:12:13
Does it make sense to check if all clauses have a
|
if (!clause->label()->IsSmiLiteral()) { |
BAILOUT("SwitchStatement: non-literal switch label"); |
} |
@@ -2596,17 +2603,18 @@ void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { |
// Build a series of empty subgraphs for the comparisons. |
// The default clause does not have a comparison subgraph. |
- ZoneList<HSubgraph*> compare_graphs(num_clauses); |
- for (int i = 0; i < num_clauses; i++) { |
- HSubgraph* subgraph = !clauses->at(i)->is_default() |
- ? CreateEmptySubgraph() |
- : NULL; |
- compare_graphs.Add(subgraph); |
+ ZoneList<HSubgraph*> compare_graphs(num_smi_clauses); |
+ for (int i = 0; i < num_smi_clauses; i++) { |
+ if (clauses->at(i)->is_default()) { |
+ compare_graphs.Add(NULL); |
+ } else { |
+ compare_graphs.Add(CreateEmptySubgraph()); |
+ } |
} |
HSubgraph* prev_graph = current_subgraph_; |
HCompare* prev_compare_inst = NULL; |
- for (int i = 0; i < num_clauses; i++) { |
+ for (int i = 0; i < num_smi_clauses; i++) { |
CaseClause* clause = clauses->at(i); |
if (clause->is_default()) continue; |
@@ -2623,6 +2631,7 @@ void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { |
} |
// Build instructions for current subgraph. |
+ ASSERT(clause->IsSmiCompare()); |
prev_compare_inst = BuildSwitchCompare(subgraph, switch_value, clause); |
if (HasStackOverflow()) return; |
@@ -2642,33 +2651,52 @@ void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { |
prev_compare_inst)); |
} |
+ // If we have a non-smi compare clause, we deoptimize after trying |
+ // all the previous compares. |
+ if (num_smi_clauses < num_clauses) { |
+ last_false_block->Finish(new HDeoptimize); |
+ } |
+ |
// Build statement blocks, connect them to their comparison block and |
// to the previous statement block, if there is a fall-through. |
HSubgraph* previous_subgraph = NULL; |
for (int i = 0; i < num_clauses; i++) { |
CaseClause* clause = clauses->at(i); |
- HSubgraph* subgraph = CreateEmptySubgraph(); |
- |
- if (clause->is_default()) { |
- // Default clause: Connect it to the last false block. |
- last_false_block->Finish(new HGoto(subgraph->entry_block())); |
- } else { |
- // Connect with the corresponding comparison. |
- HBasicBlock* empty = |
- compare_graphs.at(i)->exit_block()->end()->FirstSuccessor(); |
- empty->Finish(new HGoto(subgraph->entry_block())); |
+ // Subgraph for the statements of the clause is only created when |
+ // it's reachable either from the corresponding compare or as a |
+ // fall-through from previous statements. |
+ HSubgraph* subgraph = NULL; |
+ |
+ if (i < num_smi_clauses) { |
+ if (clause->is_default()) { |
+ if (!last_false_block->IsFinished()) { |
+ // Default clause: Connect it to the last false block. |
+ subgraph = CreateEmptySubgraph(); |
+ last_false_block->Finish(new HGoto(subgraph->entry_block())); |
+ } |
+ } else { |
+ ASSERT(clause->IsSmiCompare()); |
+ // Connect with the corresponding comparison. |
+ subgraph = CreateEmptySubgraph(); |
+ HBasicBlock* empty = |
+ compare_graphs.at(i)->exit_block()->end()->FirstSuccessor(); |
+ empty->Finish(new HGoto(subgraph->entry_block())); |
+ } |
} |
// Check for fall-through from previous statement block. |
if (previous_subgraph != NULL && previous_subgraph->HasExit()) { |
+ if (subgraph == NULL) subgraph = CreateEmptySubgraph(); |
previous_subgraph->exit_block()-> |
Finish(new HGoto(subgraph->entry_block())); |
} |
- ADD_TO_SUBGRAPH(subgraph, clause->statements()); |
- HBasicBlock* break_block = subgraph->BundleBreak(stmt); |
- if (break_block != NULL) { |
- break_block->Finish(new HGoto(single_exit_block)); |
+ if (subgraph != NULL) { |
+ ADD_TO_SUBGRAPH(subgraph, clause->statements()); |
+ HBasicBlock* break_block = subgraph->BundleBreak(stmt); |
+ if (break_block != NULL) { |
+ break_block->Finish(new HGoto(single_exit_block)); |
+ } |
} |
previous_subgraph = subgraph; |
@@ -2676,7 +2704,7 @@ void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { |
// If the last statement block has a fall-through, connect it to the |
// single exit block. |
- if (previous_subgraph->HasExit()) { |
+ if (previous_subgraph != NULL && previous_subgraph->HasExit()) { |
previous_subgraph->exit_block()->Finish(new HGoto(single_exit_block)); |
} |