Index: src/hydrogen.cc |
diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
index 57220e0de1e5cf77641235343b45aba12249cb8a..fc3d1453e0120b0781fa9ca86e45d3eb05772f3a 100644 |
--- a/src/hydrogen.cc |
+++ b/src/hydrogen.cc |
@@ -3112,7 +3112,7 @@ void HGraph::RestoreActualValues() { |
} |
-void HOptimizedGraphBuilder::PushAndAdd(HInstruction* instr) { |
+void HGraphBuilder::PushAndAdd(HInstruction* instr) { |
Push(instr); |
AddInstruction(instr); |
} |
@@ -7460,8 +7460,8 @@ void HOptimizedGraphBuilder::VisitTypeof(UnaryOperation* expr) { |
void HOptimizedGraphBuilder::VisitSub(UnaryOperation* expr) { |
CHECK_ALIVE(VisitForValue(expr->expression())); |
- HValue* value = Pop(); |
Handle<Type> operand_type = expr->expression()->bounds().lower; |
+ HValue* value = TruncateToNumber(Pop(), &operand_type); |
HInstruction* instr = BuildUnaryMathOp(value, operand_type, Token::SUB); |
return ast_context()->ReturnInstruction(instr, expr->id()); |
} |
@@ -7469,8 +7469,8 @@ void HOptimizedGraphBuilder::VisitSub(UnaryOperation* expr) { |
void HOptimizedGraphBuilder::VisitBitNot(UnaryOperation* expr) { |
CHECK_ALIVE(VisitForValue(expr->expression())); |
- HValue* value = Pop(); |
Handle<Type> operand_type = expr->expression()->bounds().lower; |
+ HValue* value = TruncateToNumber(Pop(), &operand_type); |
HInstruction* instr = BuildUnaryMathOp(value, operand_type, Token::BIT_NOT); |
return ast_context()->ReturnInstruction(instr, expr->id()); |
} |
@@ -7800,6 +7800,40 @@ bool CanBeZero(HValue* right) { |
} |
+HValue* HGraphBuilder::TruncateToNumber(HValue* value, Handle<Type>* expected) { |
+ if (value->IsConstant()) { |
+ HConstant* constant = HConstant::cast(value); |
+ Maybe<HConstant*> number = constant->CopyToTruncatedNumber(zone()); |
+ if (number.has_value) { |
+ *expected = handle(Type::Number(), isolate()); |
+ return AddInstruction(number.value); |
+ } |
+ return value; |
+ } |
+ |
+ Handle<Type> expected_type = *expected; |
+ Representation rep = Representation::FromType(expected_type); |
+ if (!rep.IsTagged()) return value; |
+ |
+ // If our type feedback suggests that we can non-observably truncate to number |
+ // we introduce the appropriate check here. This avoids 'value' having a |
+ // tagged representation later on. |
+ if (expected_type->Is(Type::Oddball())) { |
+ // TODO(olivf) The BinaryOpStub only records undefined. It might pay off to |
+ // also record booleans and convert them to 0/1 here. |
+ IfBuilder if_nan(this); |
+ if_nan.If<HCompareObjectEqAndBranch>(value, |
+ graph()->GetConstantUndefined()); |
+ if_nan.Then(); |
+ if_nan.ElseDeopt(); |
+ if_nan.End(); |
+ return Add<HConstant>(OS::nan_value(), Representation::Double()); |
+ } |
+ |
+ return value; |
+} |
+ |
+ |
HInstruction* HOptimizedGraphBuilder::BuildBinaryOperation( |
BinaryOperation* expr, |
HValue* left, |
@@ -7813,6 +7847,14 @@ HInstruction* HOptimizedGraphBuilder::BuildBinaryOperation( |
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())) { |
AddSoftDeoptimize(); |
// TODO(rossberg): we should be able to get rid of non-continuous defaults. |