Index: src/hydrogen.cc |
diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
index bf51aa7f3a5aefd9ff345b53eb855563f1265b7e..3984c9ad88aaf24bf3c1fe5c15e3265202aefd99 100644 |
--- a/src/hydrogen.cc |
+++ b/src/hydrogen.cc |
@@ -7652,10 +7652,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()) { |
@@ -7691,6 +7691,18 @@ bool CanBeZero(HValue* right) { |
} |
+HValue* HGraphBuilder::EnforceNumberType(HValue* number, |
+ Handle<Type> expected) { |
+ if (expected->Is(Type::Smi())) { |
+ return Add<HForceRepresentation>(number, Representation::Smi()); |
+ } else if (expected->Is(Type::Signed32())) { |
Sven Panne
2013/09/16 13:38:09
Just drop the "else", it's cleaner... :-)
|
+ return Add<HForceRepresentation>(number, Representation::Integer32()); |
+ } |
+ |
+ return number; |
+} |
+ |
+ |
HValue* HGraphBuilder::TruncateToNumber(HValue* value, Handle<Type>* expected) { |
if (value->IsConstant()) { |
HConstant* constant = HConstant::cast(value); |
@@ -7701,6 +7713,64 @@ HValue* HGraphBuilder::TruncateToNumber(HValue* value, Handle<Type>* expected) { |
} |
} |
+ NoObservableSideEffectsScope no_effects(this); |
+ 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; |
} |
@@ -7714,38 +7784,75 @@ 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); |
- } |
+ if (left_type->Is(Type::None()) || right_type->Is(Type::None())) { |
+ 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. |
+ left_type = handle(Type::Any(), isolate()); |
+ } else { |
+ Add<HDeoptimize>("Insufficient type feedback for RHS of binary operation", |
+ Deoptimizer::SOFT); |
+ right_type = handle(Type::Any(), isolate()); |
+ } |
+ } else { |
+ 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. |
- left_type = handle(Type::Any(), isolate()); |
- } |
- if (right_type->Is(Type::None())) { |
- Add<HDeoptimize>("Insufficient type feedback for RHS of binary operation", |
- Deoptimizer::SOFT); |
- right_type = handle(Type::Any(), isolate()); |
+ if (!maybe_string_add) { |
+ left = TruncateToNumber(left, &left_type); |
+ right = TruncateToNumber(right, &right_type); |
+ } |
+ |
+ left_rep = Representation::FromType(left_type); |
+ right_rep = Representation::FromType(right_type); |
} |
+ |
+ Representation result_rep = Representation::FromType(result_type); |
+ |
+ bool is_tagged = left_rep.IsTagged() || right_rep.IsTagged(); |
+ bool is_string_add = op == Token::ADD && is_tagged && |
+ (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); |
} |
@@ -7764,7 +7871,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; |
@@ -7773,7 +7880,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; |
} |