Index: src/hydrogen.cc |
diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
index b5cebbe327e10f9612bfd8cdee581ed7fc80b0d2..3ece7bd8e69b32691a9d57b6dec4821c6bbe12df 100644 |
--- a/src/hydrogen.cc |
+++ b/src/hydrogen.cc |
@@ -737,7 +737,8 @@ HGraphBuilder::IfBuilder::IfBuilder( |
} |
-void HGraphBuilder::IfBuilder::AddCompare(HControlInstruction* compare) { |
+HControlInstruction* HGraphBuilder::IfBuilder::AddCompare( |
+ HControlInstruction* compare) { |
if (split_edge_merge_block_ != NULL) { |
HEnvironment* env = first_false_block_->last_environment(); |
HBasicBlock* split_edge = |
@@ -756,6 +757,7 @@ void HGraphBuilder::IfBuilder::AddCompare(HControlInstruction* compare) { |
} |
builder_->current_block()->Finish(compare); |
needs_compare_ = false; |
+ return compare; |
} |
@@ -7581,10 +7583,10 @@ static bool ShiftAmountsAllowReplaceByRotate(HValue* sa, |
// directions that can be replaced by one rotate right instruction or not. |
// Returns the operand and the shift amount for the rotate instruction in the |
// former case. |
-bool HOptimizedGraphBuilder::MatchRotateRight(HValue* left, |
- HValue* right, |
- HValue** operand, |
- HValue** shift_amount) { |
+bool HGraphBuilder::MatchRotateRight(HValue* left, |
+ HValue* right, |
+ HValue** operand, |
+ HValue** shift_amount) { |
HShl* shl; |
HShr* shr; |
if (left->IsShl() && right->IsShr()) { |
@@ -7620,6 +7622,18 @@ bool CanBeZero(HValue* right) { |
} |
+HValue* HGraphBuilder::EnforceNumberType(HValue* number, |
+ Handle<Type> expected) { |
+ if (expected->Is(Type::Smi())) { |
+ return Add<HForceRepresentation>(number, Representation::Smi()); |
+ } |
+ if (expected->Is(Type::Signed32())) { |
+ return Add<HForceRepresentation>(number, Representation::Integer32()); |
+ } |
+ return number; |
+} |
+ |
+ |
HValue* HGraphBuilder::TruncateToNumber(HValue* value, Handle<Type>* expected) { |
if (value->IsConstant()) { |
HConstant* constant = HConstant::cast(value); |
@@ -7630,6 +7644,63 @@ HValue* HGraphBuilder::TruncateToNumber(HValue* value, Handle<Type>* expected) { |
} |
} |
+ Handle<Type> expected_type = *expected; |
+ |
+ // Separate the number type from the rest. |
+ Handle<Type> expected_obj = handle(Type::Intersect( |
+ expected_type, handle(Type::NonNumber(), isolate())), isolate()); |
+ Handle<Type> expected_number = handle(Type::Intersect( |
+ expected_type, handle(Type::Number(), isolate())), isolate()); |
+ |
+ // We expect to get a number. |
+ // (We need to check first, since Type::None->Is(Type::Any()) == true. |
+ if (expected_obj->Is(Type::None())) { |
+ ASSERT(!expected_number->Is(Type::None())); |
+ return value; |
+ } |
+ |
+ if (expected_obj->Is(Type::Undefined())) { |
+ // This is already done by HChange. |
+ *expected = handle(Type::Union( |
+ expected_number, handle(Type::Double(), isolate())), isolate()); |
+ return value; |
+ } |
+ |
+ if (expected_obj->Is(Type::Null())) { |
+ *expected = handle(Type::Union( |
+ expected_number, handle(Type::Smi(), isolate())), isolate()); |
+ IfBuilder if_null(this); |
+ if_null.If<HCompareObjectEqAndBranch>(value, |
+ graph()->GetConstantNull()); |
+ if_null.Then(); |
+ Push(graph()->GetConstant0()); |
+ if_null.Else(); |
+ Push(value); |
+ if_null.End(); |
+ return Pop(); |
+ } |
+ |
+ if (expected_obj->Is(Type::Boolean())) { |
+ *expected = handle(Type::Union( |
+ expected_number, handle(Type::Smi(), isolate())), isolate()); |
+ IfBuilder if_true(this); |
+ if_true.If<HCompareObjectEqAndBranch>(value, |
+ graph()->GetConstantTrue()); |
+ if_true.Then(); |
+ Push(graph()->GetConstant1()); |
+ if_true.Else(); |
+ IfBuilder if_false(this); |
+ if_false.If<HCompareObjectEqAndBranch>(value, |
+ graph()->GetConstantFalse()); |
+ if_false.Then(); |
+ Push(graph()->GetConstant0()); |
+ if_false.Else(); |
+ Push(value); |
+ if_false.End(); |
+ if_true.End(); |
+ return Pop(); |
+ } |
+ |
return value; |
} |
@@ -7643,38 +7714,72 @@ HInstruction* HOptimizedGraphBuilder::BuildBinaryOperation( |
Handle<Type> right_type = expr->right()->bounds().lower; |
Handle<Type> result_type = expr->bounds().lower; |
Maybe<int> fixed_right_arg = expr->fixed_right_arg(); |
+ |
+ return HGraphBuilder::BuildBinaryOperation(expr->op(), left, right, |
+ left_type, right_type, result_type, fixed_right_arg, context); |
+} |
+ |
+ |
+HInstruction* HGraphBuilder::BuildBinaryOperation( |
+ Token::Value op, |
+ HValue* left, |
+ HValue* right, |
+ Handle<Type> left_type, |
+ Handle<Type> right_type, |
+ Handle<Type> result_type, |
+ Maybe<int> fixed_right_arg, |
+ HValue* context) { |
+ |
Representation left_rep = Representation::FromType(left_type); |
Representation right_rep = Representation::FromType(right_type); |
- Representation result_rep = Representation::FromType(result_type); |
- if (expr->op() != Token::ADD || |
- (left->type().IsNonString() && right->type().IsNonString())) { |
- // For addition we can only truncate the arguments to number if we can |
- // prove that we will not end up in string concatenation mode. |
- left = TruncateToNumber(left, &left_type); |
- right = TruncateToNumber(right, &right_type); |
- } |
+ bool maybe_string_add = op == Token::ADD && |
+ (left_type->Maybe(Type::String()) || |
+ right_type->Maybe(Type::String())); |
if (left_type->Is(Type::None())) { |
Add<HDeoptimize>("Insufficient type feedback for LHS of binary operation", |
Deoptimizer::SOFT); |
- // TODO(rossberg): we should be able to get rid of non-continuous defaults. |
+ // TODO(rossberg): we should be able to get rid of non-continuous |
+ // defaults. |
left_type = handle(Type::Any(), isolate()); |
+ } else { |
+ if (!maybe_string_add) left = TruncateToNumber(left, &left_type); |
+ left_rep = Representation::FromType(left_type); |
} |
+ |
if (right_type->Is(Type::None())) { |
Add<HDeoptimize>("Insufficient type feedback for RHS of binary operation", |
Deoptimizer::SOFT); |
right_type = handle(Type::Any(), isolate()); |
+ } else { |
+ if (!maybe_string_add) right = TruncateToNumber(right, &right_type); |
+ right_rep = Representation::FromType(right_type); |
} |
+ |
+ Representation result_rep = Representation::FromType(result_type); |
+ |
+ bool is_string_add = op == Token::ADD && |
+ (left_type->Is(Type::String()) || |
+ right_type->Is(Type::String())); |
+ |
HInstruction* instr = NULL; |
- switch (expr->op()) { |
+ switch (op) { |
case Token::ADD: |
- if (left_type->Is(Type::String()) && right_type->Is(Type::String())) { |
- BuildCheckHeapObject(left); |
- AddInstruction(HCheckInstanceType::NewIsString(left, zone())); |
- BuildCheckHeapObject(right); |
- AddInstruction(HCheckInstanceType::NewIsString(right, zone())); |
- instr = HStringAdd::New(zone(), context, left, right); |
+ if (is_string_add) { |
+ StringAddFlags flags = STRING_ADD_CHECK_BOTH; |
+ if (left_type->Is(Type::String())) { |
+ BuildCheckHeapObject(left); |
+ AddInstruction(HCheckInstanceType::NewIsString(left, zone())); |
+ flags = STRING_ADD_CHECK_RIGHT; |
+ } |
+ if (right_type->Is(Type::String())) { |
+ BuildCheckHeapObject(right); |
+ AddInstruction(HCheckInstanceType::NewIsString(right, zone())); |
+ flags = (flags == STRING_ADD_CHECK_BOTH) |
+ ? STRING_ADD_CHECK_LEFT : STRING_ADD_CHECK_NONE; |
+ } |
+ instr = HStringAdd::New(zone(), context, left, right, flags); |
} else { |
instr = HAdd::New(zone(), context, left, right); |
} |
@@ -7693,7 +7798,7 @@ HInstruction* HOptimizedGraphBuilder::BuildBinaryOperation( |
break; |
case Token::BIT_XOR: |
case Token::BIT_AND: |
- instr = NewUncasted<HBitwise>(expr->op(), left, right); |
+ instr = NewUncasted<HBitwise>(op, left, right); |
break; |
case Token::BIT_OR: { |
HValue* operand, *shift_amount; |
@@ -7702,7 +7807,7 @@ HInstruction* HOptimizedGraphBuilder::BuildBinaryOperation( |
MatchRotateRight(left, right, &operand, &shift_amount)) { |
instr = new(zone()) HRor(context, operand, shift_amount); |
} else { |
- instr = NewUncasted<HBitwise>(expr->op(), left, right); |
+ instr = NewUncasted<HBitwise>(op, left, right); |
} |
break; |
} |