Commit 6627b0aa authored by Jakob Kummerow's avatar Jakob Kummerow Committed by Commit Bot

[bigint] Call NonNumberToNumeric where applicable

This supports {valueOf() { return BigInt(...) }} objects as
operands in binary and unary operations.

Bug: v8:6791
Change-Id: I30ec9983ff611477742f9ea0bc6d04972fe21d3c
Reviewed-on: https://chromium-review.googlesource.com/716863
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48612}
parent 2d60b728
...@@ -70,9 +70,8 @@ class NumberBuiltinsAssembler : public CodeStubAssembler { ...@@ -70,9 +70,8 @@ class NumberBuiltinsAssembler : public CodeStubAssembler {
GotoIf(IsHeapNumberMap(right_map), &do_bigint_op); GotoIf(IsHeapNumberMap(right_map), &do_bigint_op);
Node* right_type = LoadMapInstanceType(right_map); Node* right_type = LoadMapInstanceType(right_map);
GotoIf(IsBigIntInstanceType(right_type), &do_bigint_op); GotoIf(IsBigIntInstanceType(right_type), &do_bigint_op);
// TODO(jkummerow): This should use kNonNumericToNumeric.
var_right_bigint.Bind( var_right_bigint.Bind(
CallBuiltin(Builtins::kNonNumberToNumber, context, right)); CallBuiltin(Builtins::kNonNumberToNumeric, context, right));
Goto(&do_bigint_op); Goto(&do_bigint_op);
BIND(&do_bigint_op); BIND(&do_bigint_op);
...@@ -120,8 +119,8 @@ class NumberBuiltinsAssembler : public CodeStubAssembler { ...@@ -120,8 +119,8 @@ class NumberBuiltinsAssembler : public CodeStubAssembler {
Node* instance_type = LoadMapInstanceType(map); Node* instance_type = LoadMapInstanceType(map);
GotoIf(IsBigIntInstanceType(instance_type), &is_bigint); GotoIf(IsBigIntInstanceType(instance_type), &is_bigint);
// Neither HeapNumber nor BigInt -> convert to Numeric. // Neither HeapNumber nor BigInt -> convert to Numeric.
// TODO(jkummerow): This should call "NonNumericToNumeric". var_value.Bind(
var_value.Bind(CallBuiltin(Builtins::kNonNumberToNumber, context, value)); CallBuiltin(Builtins::kNonNumberToNumeric, context, value));
Goto(&loop); Goto(&loop);
BIND(&is_heap_number); BIND(&is_heap_number);
...@@ -448,8 +447,8 @@ class AddStubAssembler : public CodeStubAssembler { ...@@ -448,8 +447,8 @@ class AddStubAssembler : public CodeStubAssembler {
void ConvertNonReceiverAndLoop(Variable* var_value, Label* loop, void ConvertNonReceiverAndLoop(Variable* var_value, Label* loop,
Node* context) { Node* context) {
var_value->Bind( var_value->Bind(CallBuiltin(Builtins::kNonNumberToNumeric, context,
CallBuiltin(Builtins::kNonNumberToNumber, context, var_value->value())); var_value->value()));
Goto(loop); Goto(loop);
} }
...@@ -478,7 +477,7 @@ TF_BUILTIN(Add, AddStubAssembler) { ...@@ -478,7 +477,7 @@ TF_BUILTIN(Add, AddStubAssembler) {
VARIABLE(var_right_double, MachineRepresentation::kFloat64); VARIABLE(var_right_double, MachineRepresentation::kFloat64);
// We might need to loop several times due to ToPrimitive, ToString and/or // We might need to loop several times due to ToPrimitive, ToString and/or
// ToNumber conversions. // ToNumeric conversions.
VARIABLE(var_result, MachineRepresentation::kTagged); VARIABLE(var_result, MachineRepresentation::kTagged);
Variable* loop_vars[2] = {&var_left, &var_right}; Variable* loop_vars[2] = {&var_left, &var_right};
Label loop(this, 2, loop_vars), Label loop(this, 2, loop_vars),
...@@ -562,7 +561,7 @@ TF_BUILTIN(Add, AddStubAssembler) { ...@@ -562,7 +561,7 @@ TF_BUILTIN(Add, AddStubAssembler) {
GotoIf(IsStringInstanceType(left_instance_type), GotoIf(IsStringInstanceType(left_instance_type),
&string_add_convert_right); &string_add_convert_right);
GotoIf(IsBigIntInstanceType(left_instance_type), &do_bigint_add); GotoIf(IsBigIntInstanceType(left_instance_type), &do_bigint_add);
// {left} is neither a Number nor a String, and {right} is a Smi. // {left} is neither a Numeric nor a String, and {right} is a Smi.
ConvertAndLoop(&var_left, left_instance_type, &loop, context); ConvertAndLoop(&var_left, left_instance_type, &loop, context);
} }
} // if_right_smi } // if_right_smi
...@@ -597,14 +596,14 @@ TF_BUILTIN(Add, AddStubAssembler) { ...@@ -597,14 +596,14 @@ TF_BUILTIN(Add, AddStubAssembler) {
BIND(&if_left_not_number); BIND(&if_left_not_number);
{ {
Label if_left_bigint(this);
Node* left_instance_type = LoadMapInstanceType(left_map); Node* left_instance_type = LoadMapInstanceType(left_map);
GotoIf(IsStringInstanceType(left_instance_type), GotoIf(IsStringInstanceType(left_instance_type),
&string_add_convert_right); &string_add_convert_right);
Node* right_instance_type = LoadMapInstanceType(right_map); Node* right_instance_type = LoadMapInstanceType(right_map);
GotoIf(IsStringInstanceType(right_instance_type), GotoIf(IsStringInstanceType(right_instance_type),
&string_add_convert_left); &string_add_convert_left);
GotoIf(IsBigIntInstanceType(left_instance_type), &do_bigint_add); GotoIf(IsBigIntInstanceType(left_instance_type), &if_left_bigint);
GotoIf(IsBigIntInstanceType(right_instance_type), &do_bigint_add);
Label if_left_not_receiver(this, Label::kDeferred); Label if_left_not_receiver(this, Label::kDeferred);
Label if_right_not_receiver(this, Label::kDeferred); Label if_right_not_receiver(this, Label::kDeferred);
GotoIfNot(IsJSReceiverInstanceType(left_instance_type), GotoIfNot(IsJSReceiverInstanceType(left_instance_type),
...@@ -612,6 +611,15 @@ TF_BUILTIN(Add, AddStubAssembler) { ...@@ -612,6 +611,15 @@ TF_BUILTIN(Add, AddStubAssembler) {
// {left} is a JSReceiver, convert it first. // {left} is a JSReceiver, convert it first.
ConvertReceiverAndLoop(&var_left, &loop, context); ConvertReceiverAndLoop(&var_left, &loop, context);
BIND(&if_left_bigint);
{
// {right} is a HeapObject, but not a String. Jump to
// {do_bigint_add} if {right} is already a Numeric.
GotoIf(IsBigIntInstanceType(right_instance_type), &do_bigint_add);
GotoIf(IsHeapNumberMap(right_map), &do_bigint_add);
ConvertAndLoop(&var_right, right_instance_type, &loop, context);
}
BIND(&if_left_not_receiver); BIND(&if_left_not_receiver);
GotoIfNot(IsJSReceiverInstanceType(right_instance_type), GotoIfNot(IsJSReceiverInstanceType(right_instance_type),
&if_right_not_receiver); &if_right_not_receiver);
...@@ -705,18 +713,29 @@ void NumberBuiltinsAssembler::BinaryOp(Label* smis, Variable* var_left, ...@@ -705,18 +713,29 @@ void NumberBuiltinsAssembler::BinaryOp(Label* smis, Variable* var_left,
BIND(&left_not_number); BIND(&left_not_number);
{ {
GotoIf(IsBigInt(var_left->value()), bigints); Label left_bigint(this);
// TODO(jkummerow): Here and below, this should call NonNumericToNumeric. GotoIf(IsBigInt(var_left->value()), &left_bigint);
var_left->Bind( var_left->Bind(
CallBuiltin(Builtins::kNonNumberToNumber, context, var_left->value())); CallBuiltin(Builtins::kNonNumberToNumeric, context, var_left->value()));
Goto(&loop); Goto(&loop);
BIND(&left_bigint);
{
// Jump to {bigints} if {var_right} is already a Numeric.
GotoIf(TaggedIsSmi(var_right->value()), bigints);
GotoIf(IsBigInt(var_right->value()), bigints);
GotoIf(IsHeapNumber(var_right->value()), bigints);
var_right->Bind(CallBuiltin(Builtins::kNonNumberToNumeric, context,
var_right->value()));
Goto(&loop);
}
} }
BIND(&right_not_number); BIND(&right_not_number);
{ {
GotoIf(IsBigInt(var_right->value()), bigints); GotoIf(IsBigInt(var_right->value()), bigints);
var_right->Bind( var_right->Bind(CallBuiltin(Builtins::kNonNumberToNumeric, context,
CallBuiltin(Builtins::kNonNumberToNumber, context, var_right->value())); var_right->value()));
Goto(&loop); Goto(&loop);
} }
} }
......
...@@ -155,10 +155,8 @@ Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs, ...@@ -155,10 +155,8 @@ Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs,
BIND(&lhs_is_bigint); BIND(&lhs_is_bigint);
{ {
// Label "bigint" handles BigInt + {anything except string}. GotoIf(TaggedIsSmi(rhs), &call_with_any_feedback);
GotoIf(TaggedIsSmi(rhs), &bigint); Branch(IsBigInt(rhs), &bigint, &call_with_any_feedback);
Branch(IsStringInstanceType(LoadInstanceType(rhs)),
&call_with_any_feedback, &bigint);
} }
BIND(&lhs_is_string); BIND(&lhs_is_string);
...@@ -322,31 +320,40 @@ Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback( ...@@ -322,31 +320,40 @@ Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback(
BIND(&if_lhsisnotnumber); BIND(&if_lhsisnotnumber);
{ {
// No checks on rhs are done yet. We just know lhs is not a number or Smi. // No checks on rhs are done yet. We just know lhs is not a number or Smi.
// Check if lhs is an oddball. Label if_left_bigint(this), if_left_oddball(this);
Node* lhs_instance_type = LoadInstanceType(lhs); Node* lhs_instance_type = LoadInstanceType(lhs);
GotoIf(IsBigIntInstanceType(lhs_instance_type), &if_bigint); GotoIf(IsBigIntInstanceType(lhs_instance_type), &if_left_bigint);
Node* lhs_is_oddball = Node* lhs_is_oddball =
Word32Equal(lhs_instance_type, Int32Constant(ODDBALL_TYPE)); Word32Equal(lhs_instance_type, Int32Constant(ODDBALL_TYPE));
GotoIfNot(lhs_is_oddball, &call_with_any_feedback); Branch(lhs_is_oddball, &if_left_oddball, &call_with_any_feedback);
Label if_rhsissmi(this), if_rhsisnotsmi(this); BIND(&if_left_oddball);
Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
BIND(&if_rhsissmi);
{ {
var_type_feedback.Bind( Label if_rhsissmi(this), if_rhsisnotsmi(this);
SmiConstant(BinaryOperationFeedback::kNumberOrOddball)); Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
Goto(&call_stub);
BIND(&if_rhsissmi);
{
var_type_feedback.Bind(
SmiConstant(BinaryOperationFeedback::kNumberOrOddball));
Goto(&call_stub);
}
BIND(&if_rhsisnotsmi);
{
// Check if {rhs} is a HeapNumber.
GotoIfNot(IsHeapNumber(rhs), &check_rhsisoddball);
var_type_feedback.Bind(
SmiConstant(BinaryOperationFeedback::kNumberOrOddball));
Goto(&call_stub);
}
} }
BIND(&if_rhsisnotsmi); BIND(&if_left_bigint);
{ {
// Check if {rhs} is a HeapNumber. GotoIf(TaggedIsSmi(rhs), &call_with_any_feedback);
GotoIfNot(IsHeapNumber(rhs), &check_rhsisoddball); Branch(IsBigInt(rhs), &if_bigint, &call_with_any_feedback);
var_type_feedback.Bind(
SmiConstant(BinaryOperationFeedback::kNumberOrOddball));
Goto(&call_stub);
} }
} }
......
...@@ -1298,8 +1298,8 @@ Node* InterpreterAssembler::TaggedToWord32OrBigIntWithFeedback( ...@@ -1298,8 +1298,8 @@ Node* InterpreterAssembler::TaggedToWord32OrBigIntWithFeedback(
&is_oddball); &is_oddball);
// Not an oddball either -> convert to Numeric. // Not an oddball either -> convert to Numeric.
// TODO(jkummerow): This should use "NonNumericToNumeric". var_value.Bind(
var_value.Bind(CallBuiltin(Builtins::kNonNumberToNumber, context, value)); CallBuiltin(Builtins::kNonNumberToNumeric, context, value));
var_type_feedback->Bind(SmiConstant(BinaryOperationFeedback::kAny)); var_type_feedback->Bind(SmiConstant(BinaryOperationFeedback::kAny));
Goto(&loop); Goto(&loop);
......
...@@ -1252,9 +1252,8 @@ class UnaryNumericOpAssembler : public InterpreterAssembler { ...@@ -1252,9 +1252,8 @@ class UnaryNumericOpAssembler : public InterpreterAssembler {
CSA_ASSERT(this, SmiEqual(var_feedback.value(), CSA_ASSERT(this, SmiEqual(var_feedback.value(),
SmiConstant(BinaryOperationFeedback::kNone))); SmiConstant(BinaryOperationFeedback::kNone)));
var_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny)); var_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny));
// TODO(jkummerow): This should call kNonNumericToNumeric.
var_value.Bind( var_value.Bind(
CallBuiltin(Builtins::kNonNumberToNumber, GetContext(), value)); CallBuiltin(Builtins::kNonNumberToNumeric, GetContext(), value));
Goto(&start); Goto(&start);
} }
} }
......
...@@ -421,7 +421,10 @@ const six = BigInt(6); ...@@ -421,7 +421,10 @@ const six = BigInt(6);
// Binary ops. // Binary ops.
{ {
let One = {valueOf() { return one }};
assertTrue(one + two === three); assertTrue(one + two === three);
assertTrue(One + two === three);
assertTrue(two + One === three);
assertEquals("hello1", "hello" + one); assertEquals("hello1", "hello" + one);
assertEquals("2hello", two + "hello"); assertEquals("2hello", two + "hello");
assertThrows("one + 2", TypeError); assertThrows("one + 2", TypeError);
...@@ -438,6 +441,8 @@ const six = BigInt(6); ...@@ -438,6 +441,8 @@ const six = BigInt(6);
assertThrows("2.5 - one", TypeError); assertThrows("2.5 - one", TypeError);
assertTrue(two * three === six); assertTrue(two * three === six);
assertTrue(two * One === two);
assertTrue(One * two === two);
assertThrows("two * 1", TypeError); assertThrows("two * 1", TypeError);
assertThrows("1 * two", TypeError); assertThrows("1 * two", TypeError);
assertThrows("two * 1.5", TypeError); assertThrows("two * 1.5", TypeError);
...@@ -462,8 +467,11 @@ const six = BigInt(6); ...@@ -462,8 +467,11 @@ const six = BigInt(6);
// Bitwise binary ops. // Bitwise binary ops.
{ {
let One = {valueOf() { return one }};
assertTrue((three & one) === one); assertTrue((three & one) === one);
assertTrue((BigInt(-2) & zero) === zero); assertTrue((BigInt(-2) & zero) === zero);
assertTrue((three & One) === one);
assertTrue((One & three) === one);
assertThrows("three & 1", TypeError); assertThrows("three & 1", TypeError);
assertThrows("1 & three", TypeError); assertThrows("1 & three", TypeError);
assertThrows("three & true", TypeError); assertThrows("three & true", TypeError);
...@@ -507,10 +515,13 @@ const six = BigInt(6); ...@@ -507,10 +515,13 @@ const six = BigInt(6);
// Unary ops. // Unary ops.
{ {
let One = {valueOf() { return one }};
assertTrue(~minus_one === zero); assertTrue(~minus_one === zero);
assertTrue(-minus_one === one); assertTrue(-minus_one === one);
assertTrue(-One === minus_one);
assertTrue(~~two === two); assertTrue(~~two === two);
assertTrue(-(-two) === two); assertTrue(-(-two) === two);
assertTrue(~One === BigInt(-2));
let a = minus_one; let a = minus_one;
assertTrue(a++ === minus_one); assertTrue(a++ === minus_one);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment