Chromium Code Reviews| Index: src/hydrogen.cc |
| diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
| index bb2b08984d4ace32f9fa3fab0ca1efd762913218..2c8bac9e8c64a596bac92595786ab69fd1af9164 100644 |
| --- a/src/hydrogen.cc |
| +++ b/src/hydrogen.cc |
| @@ -4136,8 +4136,7 @@ void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { |
| ASSERT(current_block() != NULL); |
| ASSERT(current_block()->HasPredecessor()); |
| - // We only optimize switch statements with smi-literal smi comparisons, |
| - // with a bounded number of clauses. |
| + // We only optimize switch statements with a bounded number of clauses. |
| const int kCaseClauseLimit = 128; |
| ZoneList<CaseClause*>* clauses = stmt->cases(); |
| int clause_count = clauses->length(); |
| @@ -4146,28 +4145,10 @@ void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { |
| return Bailout(kSwitchStatementTooManyClauses); |
| } |
| - ASSERT(stmt->switch_type() != SwitchStatement::UNKNOWN_SWITCH); |
| - |
| CHECK_ALIVE(VisitForValue(stmt->tag())); |
| Add<HSimulate>(stmt->EntryId()); |
| 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) { |
| - 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); |
| - } |
| + Handle<Type> tag_type = stmt->tag()->bounds().lower; |
| // 1. Build all the tests, with dangling true branches |
| BailoutId default_id = BailoutId::None(); |
| @@ -4183,35 +4164,12 @@ void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { |
| CHECK_ALIVE(VisitForValue(clause->label())); |
| HValue* label_value = Pop(); |
| - HControlInstruction* compare; |
| - |
| - if (stmt->switch_type() == SwitchStatement::SMI_SWITCH) { |
| - if (!clause->compare_type()->Is(Type::Smi())) { |
| - Add<HDeoptimize>("Non-smi switch type", Deoptimizer::SOFT); |
| - } |
| - |
| - HCompareNumericAndBranch* compare_ = |
| - New<HCompareNumericAndBranch>(tag_value, |
| - label_value, |
| - Token::EQ_STRICT); |
| - compare_->set_observed_input_representation( |
| - Representation::Smi(), Representation::Smi()); |
| - compare = compare_; |
| - } 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); |
| - } |
| + Handle<Type> label_type = clause->label()->bounds().lower; |
| + Handle<Type> combined_type = clause->compare_type(); |
| + HControlInstruction* compare = BuildCompareInstruction( |
| + Token::EQ_STRICT, tag_value, label_value, tag_type, label_type, |
| + combined_type, stmt->tag()->position(), clause->label()->position(), |
| + clause->id()); |
| HBasicBlock* next_test_block = graph()->CreateBasicBlock(); |
| HBasicBlock* body_block = graph()->CreateBasicBlock(); |
| @@ -4231,11 +4189,6 @@ void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { |
| HBasicBlock* last_block = current_block(); |
| Drop(1); // tag_value |
| - if (not_string_block != NULL) { |
| - BailoutId join_id = !default_id.IsNone() ? default_id : stmt->ExitId(); |
| - last_block = CreateJoin(last_block, not_string_block, join_id); |
| - } |
| - |
| // 2. Loop over the clauses and the linked list of tests in lockstep, |
| // translating the clause bodies. |
| HBasicBlock* fall_through_block = NULL; |
| @@ -9142,9 +9095,6 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) { |
| Handle<Type> left_type = expr->left()->bounds().lower; |
| Handle<Type> right_type = expr->right()->bounds().lower; |
| Handle<Type> combined_type = expr->combined_type(); |
| - Representation combined_rep = Representation::FromType(combined_type); |
|
rossberg
2013/12/11 09:41:34
Not sure this matters, but deferring the conversio
Jakob Kummerow
2013/12/11 10:00:01
Nope, doesn't matter.
The only change we'd do to
rossberg
2013/12/11 11:35:27
Yes, I assumed as much. Though I still wonder why
|
| - Representation left_rep = Representation::FromType(left_type); |
| - Representation right_rep = Representation::FromType(right_type); |
| CHECK_ALIVE(VisitForValue(expr->left())); |
| CHECK_ALIVE(VisitForValue(expr->right())); |
| @@ -9218,34 +9168,54 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) { |
| combined_type = left_type = right_type = handle(Type::Any(), isolate()); |
| } |
| + HControlInstruction* compare = BuildCompareInstruction( |
| + op, left, right, left_type, right_type, combined_type, |
| + expr->left()->position(), expr->right()->position(), expr->id()); |
| + if (compare == NULL) return; // Bailed out. |
| + return ast_context()->ReturnControl(compare, expr->id()); |
| +} |
| + |
| + |
| +HControlInstruction* HOptimizedGraphBuilder::BuildCompareInstruction( |
| + Token::Value op, |
| + HValue* left, |
| + HValue* right, |
| + Handle<Type> left_type, |
| + Handle<Type> right_type, |
| + Handle<Type> combined_type, |
| + int left_position, |
| + int right_position, |
| + BailoutId bailout_id) { |
| + Representation left_rep = Representation::FromType(left_type); |
| + Representation right_rep = Representation::FromType(right_type); |
| + Representation combined_rep = Representation::FromType(combined_type); |
| + |
| if (combined_type->Is(Type::Receiver())) { |
| - switch (op) { |
| - case Token::EQ: |
| - case Token::EQ_STRICT: { |
| - // Can we get away with map check and not instance type check? |
| - if (combined_type->IsClass()) { |
| - Handle<Map> map = combined_type->AsClass(); |
| - AddCheckMap(left, map); |
| - AddCheckMap(right, map); |
| - HCompareObjectEqAndBranch* result = |
| - New<HCompareObjectEqAndBranch>(left, right); |
| - if (FLAG_emit_opt_code_positions) { |
| - result->set_operand_position(zone(), 0, expr->left()->position()); |
| - result->set_operand_position(zone(), 1, expr->right()->position()); |
| - } |
| - return ast_context()->ReturnControl(result, expr->id()); |
| - } else { |
| - BuildCheckHeapObject(left); |
| - Add<HCheckInstanceType>(left, HCheckInstanceType::IS_SPEC_OBJECT); |
| - BuildCheckHeapObject(right); |
| - Add<HCheckInstanceType>(right, HCheckInstanceType::IS_SPEC_OBJECT); |
| - HCompareObjectEqAndBranch* result = |
| - New<HCompareObjectEqAndBranch>(left, right); |
| - return ast_context()->ReturnControl(result, expr->id()); |
| + if (Token::IsEqualityOp(op)) { |
| + // Can we get away with map check and not instance type check? |
| + if (combined_type->IsClass()) { |
| + Handle<Map> map = combined_type->AsClass(); |
| + AddCheckMap(left, map); |
| + AddCheckMap(right, map); |
| + HCompareObjectEqAndBranch* result = |
| + New<HCompareObjectEqAndBranch>(left, right); |
| + if (FLAG_emit_opt_code_positions) { |
| + result->set_operand_position(zone(), 0, left_position); |
| + result->set_operand_position(zone(), 1, right_position); |
| } |
| + return result; |
| + } else { |
| + BuildCheckHeapObject(left); |
| + Add<HCheckInstanceType>(left, HCheckInstanceType::IS_SPEC_OBJECT); |
| + BuildCheckHeapObject(right); |
| + Add<HCheckInstanceType>(right, HCheckInstanceType::IS_SPEC_OBJECT); |
| + HCompareObjectEqAndBranch* result = |
| + New<HCompareObjectEqAndBranch>(left, right); |
| + return result; |
| } |
| - default: |
| - return Bailout(kUnsupportedNonPrimitiveCompare); |
| + } else { |
| + Bailout(kUnsupportedNonPrimitiveCompare); |
| + return NULL; |
| } |
| } else if (combined_type->Is(Type::InternalizedString()) && |
| Token::IsEqualityOp(op)) { |
| @@ -9255,7 +9225,7 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) { |
| Add<HCheckInstanceType>(right, HCheckInstanceType::IS_INTERNALIZED_STRING); |
| HCompareObjectEqAndBranch* result = |
| New<HCompareObjectEqAndBranch>(left, right); |
| - return ast_context()->ReturnControl(result, expr->id()); |
| + return result; |
| } else if (combined_type->Is(Type::String())) { |
| BuildCheckHeapObject(left); |
| Add<HCheckInstanceType>(left, HCheckInstanceType::IS_STRING); |
| @@ -9263,23 +9233,28 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) { |
| Add<HCheckInstanceType>(right, HCheckInstanceType::IS_STRING); |
| HStringCompareAndBranch* result = |
| New<HStringCompareAndBranch>(left, right, op); |
| - return ast_context()->ReturnControl(result, expr->id()); |
| + return result; |
| } else { |
| if (combined_rep.IsTagged() || combined_rep.IsNone()) { |
| - HCompareGeneric* result = New<HCompareGeneric>(left, right, op); |
| + HCompareGeneric* result = Add<HCompareGeneric>(left, right, op); |
| result->set_observed_input_representation(1, left_rep); |
| result->set_observed_input_representation(2, right_rep); |
| - return ast_context()->ReturnInstruction(result, expr->id()); |
| + if (result->HasObservableSideEffects()) { |
| + Push(result); |
| + AddSimulate(bailout_id, REMOVABLE_SIMULATE); |
| + Drop(1); |
| + } |
| + // TODO(jkummerow): Can we make this more efficient? |
| + HBranch* branch = New<HBranch>(result); |
| + return branch; |
| } else { |
| HCompareNumericAndBranch* result = |
| New<HCompareNumericAndBranch>(left, right, op); |
| result->set_observed_input_representation(left_rep, right_rep); |
| if (FLAG_emit_opt_code_positions) { |
| - result->SetOperandPositions(zone(), |
| - expr->left()->position(), |
| - expr->right()->position()); |
| + result->SetOperandPositions(zone(), left_position, right_position); |
| } |
| - return ast_context()->ReturnControl(result, expr->id()); |
| + return result; |
| } |
| } |
| } |