Index: src/hydrogen.cc |
diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
index 8dbecac1191d49440fd755860a559cd71b75e2a5..96de7922d8753b9b6c121a1372cc99804c4c9f0d 100644 |
--- a/src/hydrogen.cc |
+++ b/src/hydrogen.cc |
@@ -4141,31 +4141,31 @@ void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { |
const int kCaseClauseLimit = 128; |
ZoneList<CaseClause*>* clauses = stmt->cases(); |
int clause_count = clauses->length(); |
+ ZoneList<HBasicBlock*> body_blocks(clause_count, zone()); |
if (clause_count > kCaseClauseLimit) { |
return Bailout(kSwitchStatementTooManyClauses); |
} |
ASSERT(stmt->switch_type() != SwitchStatement::UNKNOWN_SWITCH); |
- if (stmt->switch_type() == SwitchStatement::GENERIC_SWITCH) { |
- return Bailout(kSwitchStatementMixedOrNonLiteralSwitchLabels); |
- } |
CHECK_ALIVE(VisitForValue(stmt->tag())); |
Add<HSimulate>(stmt->EntryId()); |
- HValue* tag_value = Pop(); |
- HBasicBlock* first_test_block = current_block(); |
+ HValue* tag_value = Top(); |
HUnaryControlInstruction* string_check = NULL; |
HBasicBlock* not_string_block = NULL; |
// Test switch's tag value if all clauses are string literals |
if (stmt->switch_type() == SwitchStatement::STRING_SWITCH) { |
- first_test_block = graph()->CreateBasicBlock(); |
+ HBasicBlock* first_test_block = graph()->CreateBasicBlock(); |
not_string_block = graph()->CreateBasicBlock(); |
string_check = New<HIsStringAndBranch>( |
tag_value, first_test_block, not_string_block); |
FinishCurrentBlock(string_check); |
+ set_current_block(not_string_block); |
+ Drop(1); // tag_value |
+ |
set_current_block(first_test_block); |
} |
@@ -4174,7 +4174,8 @@ void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { |
for (int i = 0; i < clause_count; ++i) { |
CaseClause* clause = clauses->at(i); |
if (clause->is_default()) { |
- default_id = clause->EntryId(); |
+ body_blocks.Add(NULL, zone()); |
+ if (default_id.IsNone()) default_id = clause->EntryId(); |
continue; |
} |
@@ -4182,9 +4183,6 @@ void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { |
CHECK_ALIVE(VisitForValue(clause->label())); |
HValue* label_value = Pop(); |
- HBasicBlock* next_test_block = graph()->CreateBasicBlock(); |
- HBasicBlock* body_block = graph()->CreateBasicBlock(); |
- |
HControlInstruction* compare; |
if (stmt->switch_type() == SwitchStatement::SMI_SWITCH) { |
@@ -4199,22 +4197,39 @@ void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { |
compare_->set_observed_input_representation( |
Representation::Smi(), Representation::Smi()); |
compare = compare_; |
- } else { |
+ } else if (stmt->switch_type() == SwitchStatement::STRING_SWITCH) { |
compare = New<HStringCompareAndBranch>(tag_value, |
label_value, |
Token::EQ_STRICT); |
+ } else { |
+ HValue* test = Add<HCompareGeneric>(tag_value, |
+ label_value, |
+ Token::EQ_STRICT); |
+ if (test->HasObservableSideEffects()) { |
+ Push(test); |
+ Add<HSimulate>(clause->id(), REMOVABLE_SIMULATE); |
+ Drop(1); |
+ } |
+ compare = New<HBranch>(test); |
} |
+ HBasicBlock* next_test_block = graph()->CreateBasicBlock(); |
+ HBasicBlock* body_block = graph()->CreateBasicBlock(); |
+ body_blocks.Add(body_block, zone()); |
compare->SetSuccessorAt(0, body_block); |
compare->SetSuccessorAt(1, next_test_block); |
FinishCurrentBlock(compare); |
+ set_current_block(body_block); |
+ Drop(1); // tag_value |
+ |
set_current_block(next_test_block); |
} |
// Save the current block to use for the default or to join with the |
// exit. |
HBasicBlock* last_block = current_block(); |
+ Drop(1); // tag_value |
if (not_string_block != NULL) { |
BailoutId join_id = !default_id.IsNone() ? default_id : stmt->ExitId(); |
@@ -4223,7 +4238,6 @@ void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { |
// 2. Loop over the clauses and the linked list of tests in lockstep, |
// translating the clause bodies. |
- HBasicBlock* curr_test_block = first_test_block; |
HBasicBlock* fall_through_block = NULL; |
BreakAndContinueInfo break_info(stmt); |
@@ -4235,40 +4249,16 @@ void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { |
// goes to. |
HBasicBlock* normal_block = NULL; |
if (clause->is_default()) { |
- if (last_block != NULL) { |
- normal_block = last_block; |
- last_block = NULL; // Cleared to indicate we've handled it. |
- } |
+ if (last_block == NULL) continue; |
+ normal_block = last_block; |
+ last_block = NULL; // Cleared to indicate we've handled it. |
} else { |
- // If the current test block is deoptimizing due to an unhandled clause |
- // of the switch, the test instruction is in the next block since the |
- // deopt must end the current block. |
- if (curr_test_block->IsDeoptimizing()) { |
- ASSERT(curr_test_block->end()->SecondSuccessor() == NULL); |
- curr_test_block = curr_test_block->end()->FirstSuccessor(); |
- } |
- normal_block = curr_test_block->end()->FirstSuccessor(); |
- curr_test_block = curr_test_block->end()->SecondSuccessor(); |
+ normal_block = body_blocks[i]; |
} |
- // Identify a block to emit the body into. |
- if (normal_block == NULL) { |
- if (fall_through_block == NULL) { |
- // (a) Unreachable. |
- if (clause->is_default()) { |
- continue; // Might still be reachable clause bodies. |
- } else { |
- break; |
- } |
- } else { |
- // (b) Reachable only as fall through. |
- set_current_block(fall_through_block); |
- } |
- } else if (fall_through_block == NULL) { |
- // (c) Reachable only normally. |
+ if (fall_through_block == NULL) { |
set_current_block(normal_block); |
} else { |
- // (d) Reachable both ways. |
HBasicBlock* join = CreateJoin(fall_through_block, |
normal_block, |
clause->EntryId()); |