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