Chromium Code Reviews| 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; |
| } |