Chromium Code Reviews| Index: src/hydrogen.cc | 
| diff --git a/src/hydrogen.cc b/src/hydrogen.cc | 
| index 0b843bd45b32eb6d57c1efa86ee784c59290c817..aeb3d150d0f1362e5d0c609e422734fe6d547dcb 100644 | 
| --- a/src/hydrogen.cc | 
| +++ b/src/hydrogen.cc | 
| @@ -2690,38 +2690,74 @@ void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { | 
| HValue* tag_value = Pop(); | 
| HBasicBlock* first_test_block = current_block(); | 
| - // 1. Build all the tests, with dangling true branches. Unconditionally | 
| - // deoptimize if we encounter a non-smi comparison. | 
| + SwitchType switch_type = UNKNOWN_SWITCH; | 
| + | 
| + // 1. Extract clause type | 
| for (int i = 0; i < clause_count; ++i) { | 
| CaseClause* clause = clauses->at(i); | 
| if (clause->is_default()) continue; | 
| - if (!clause->label()->IsSmiLiteral()) { | 
| - return Bailout("SwitchStatement: non-literal switch label"); | 
| + | 
| + if (switch_type == UNKNOWN_SWITCH) { | 
| + if (clause->label()->IsSmiLiteral()) { | 
| + switch_type = SMI_SWITCH; | 
| + } else if (clause->label()->IsStringLiteral()) { | 
| + switch_type = STRING_SWITCH; | 
| + } else { | 
| + return Bailout("SwitchStatement: non-literal switch label"); | 
| + } | 
| + } else if ((switch_type == STRING_SWITCH && | 
| + !clause->label()->IsStringLiteral()) || | 
| + (switch_type == SMI_SWITCH && | 
| + !clause->label()->IsSmiLiteral())) { | 
| + return Bailout("SwitchStatemnt: mixed label types are not supported"); | 
| } | 
| + } | 
| + | 
| + // Test switch's tag value if all clauses are string literals | 
| + if (switch_type == STRING_SWITCH) { | 
| + AddInstruction(HCheckInstanceType::NewIsSymbol(tag_value)); | 
| + AddInstruction(new(zone()) HCheckNonSmi(tag_value)); | 
| 
 
Vyacheslav Egorov (Chromium)
2011/10/24 12:27:29
Checking that tag_value is non-smi after is-symbol
 
 | 
| + } | 
| + | 
| + // 2. Build all the tests, with dangling true branches | 
| + for (int i = 0; i < clause_count; ++i) { | 
| + CaseClause* clause = clauses->at(i); | 
| + if (clause->is_default()) continue; | 
| - // Unconditionally deoptimize on the first non-smi compare. | 
| clause->RecordTypeFeedback(oracle()); | 
| - if (!clause->IsSmiCompare()) { | 
| - // Finish with deoptimize and add uses of enviroment values to | 
| - // account for invisible uses. | 
| - current_block()->FinishExitWithDeoptimization(HDeoptimize::kUseAll); | 
| - set_current_block(NULL); | 
| - break; | 
| - } | 
| - // Otherwise generate a compare and branch. | 
| + // Generate a compare and branch. | 
| CHECK_ALIVE(VisitForValue(clause->label())); | 
| HValue* label_value = Pop(); | 
| - HCompareIDAndBranch* compare = | 
| - new(zone()) HCompareIDAndBranch(tag_value, | 
| - label_value, | 
| - Token::EQ_STRICT); | 
| - compare->SetInputRepresentation(Representation::Integer32()); | 
| - HBasicBlock* body_block = graph()->CreateBasicBlock(); | 
| + | 
| HBasicBlock* next_test_block = graph()->CreateBasicBlock(); | 
| + HBasicBlock* body_block = graph()->CreateBasicBlock(); | 
| + | 
| + HControlInstruction* compare; | 
| + | 
| + if (switch_type == SMI_SWITCH) { | 
| + if (!clause->IsSmiCompare()) { | 
| + // Finish with deoptimize and add uses of enviroment values to | 
| + // account for invisible uses. | 
| + current_block()->FinishExitWithDeoptimization(HDeoptimize::kUseAll); | 
| + set_current_block(NULL); | 
| + break; | 
| + } | 
| + | 
| + HCompareIDAndBranch* compare_ = | 
| + new(zone()) HCompareIDAndBranch(tag_value, | 
| + label_value, | 
| + Token::EQ_STRICT); | 
| + compare_->SetInputRepresentation(Representation::Integer32()); | 
| + compare = compare_; | 
| + } else { | 
| + compare = new(zone()) HCompareObjectEqAndBranch(tag_value, label_value); | 
| + } | 
| + | 
| compare->SetSuccessorAt(0, body_block); | 
| compare->SetSuccessorAt(1, next_test_block); | 
| current_block()->Finish(compare); | 
| + | 
| set_current_block(next_test_block); | 
| } | 
| @@ -2729,7 +2765,7 @@ void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { | 
| // exit. This block is NULL if we deoptimized. | 
| HBasicBlock* last_block = current_block(); | 
| - // 2. Loop over the clauses and the linked list of tests in lockstep, | 
| + // 3. 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; |