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