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 {
GotoIf(IsHeapNumberMap(right_map), &do_bigint_op);
Node* right_type = LoadMapInstanceType(right_map);
GotoIf(IsBigIntInstanceType(right_type), &do_bigint_op);
// TODO(jkummerow): This should use kNonNumericToNumeric.
var_right_bigint.Bind(
CallBuiltin(Builtins::kNonNumberToNumber, context, right));
CallBuiltin(Builtins::kNonNumberToNumeric, context, right));
Goto(&do_bigint_op);
BIND(&do_bigint_op);
......@@ -120,8 +119,8 @@ class NumberBuiltinsAssembler : public CodeStubAssembler {
Node* instance_type = LoadMapInstanceType(map);
GotoIf(IsBigIntInstanceType(instance_type), &is_bigint);
// Neither HeapNumber nor BigInt -> convert to Numeric.
// TODO(jkummerow): This should call "NonNumericToNumeric".
var_value.Bind(CallBuiltin(Builtins::kNonNumberToNumber, context, value));
var_value.Bind(
CallBuiltin(Builtins::kNonNumberToNumeric, context, value));
Goto(&loop);
BIND(&is_heap_number);
......@@ -448,8 +447,8 @@ class AddStubAssembler : public CodeStubAssembler {
void ConvertNonReceiverAndLoop(Variable* var_value, Label* loop,
Node* context) {
var_value->Bind(
CallBuiltin(Builtins::kNonNumberToNumber, context, var_value->value()));
var_value->Bind(CallBuiltin(Builtins::kNonNumberToNumeric, context,
var_value->value()));
Goto(loop);
}
......@@ -478,7 +477,7 @@ TF_BUILTIN(Add, AddStubAssembler) {
VARIABLE(var_right_double, MachineRepresentation::kFloat64);
// We might need to loop several times due to ToPrimitive, ToString and/or
// ToNumber conversions.
// ToNumeric conversions.
VARIABLE(var_result, MachineRepresentation::kTagged);
Variable* loop_vars[2] = {&var_left, &var_right};
Label loop(this, 2, loop_vars),
......@@ -562,7 +561,7 @@ TF_BUILTIN(Add, AddStubAssembler) {
GotoIf(IsStringInstanceType(left_instance_type),
&string_add_convert_right);
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);
}
} // if_right_smi
......@@ -597,14 +596,14 @@ TF_BUILTIN(Add, AddStubAssembler) {
BIND(&if_left_not_number);
{
Label if_left_bigint(this);
Node* left_instance_type = LoadMapInstanceType(left_map);
GotoIf(IsStringInstanceType(left_instance_type),
&string_add_convert_right);
Node* right_instance_type = LoadMapInstanceType(right_map);
GotoIf(IsStringInstanceType(right_instance_type),
&string_add_convert_left);
GotoIf(IsBigIntInstanceType(left_instance_type), &do_bigint_add);
GotoIf(IsBigIntInstanceType(right_instance_type), &do_bigint_add);
GotoIf(IsBigIntInstanceType(left_instance_type), &if_left_bigint);
Label if_left_not_receiver(this, Label::kDeferred);
Label if_right_not_receiver(this, Label::kDeferred);
GotoIfNot(IsJSReceiverInstanceType(left_instance_type),
......@@ -612,6 +611,15 @@ TF_BUILTIN(Add, AddStubAssembler) {
// {left} is a JSReceiver, convert it first.
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);
GotoIfNot(IsJSReceiverInstanceType(right_instance_type),
&if_right_not_receiver);
......@@ -705,18 +713,29 @@ void NumberBuiltinsAssembler::BinaryOp(Label* smis, Variable* var_left,
BIND(&left_not_number);
{
GotoIf(IsBigInt(var_left->value()), bigints);
// TODO(jkummerow): Here and below, this should call NonNumericToNumeric.
Label left_bigint(this);
GotoIf(IsBigInt(var_left->value()), &left_bigint);
var_left->Bind(
CallBuiltin(Builtins::kNonNumberToNumber, context, var_left->value()));
CallBuiltin(Builtins::kNonNumberToNumeric, context, var_left->value()));
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);
{
GotoIf(IsBigInt(var_right->value()), bigints);
var_right->Bind(
CallBuiltin(Builtins::kNonNumberToNumber, context, var_right->value()));
var_right->Bind(CallBuiltin(Builtins::kNonNumberToNumeric, context,
var_right->value()));
Goto(&loop);
}
}
......
......@@ -155,10 +155,8 @@ Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs,
BIND(&lhs_is_bigint);
{
// Label "bigint" handles BigInt + {anything except string}.
GotoIf(TaggedIsSmi(rhs), &bigint);
Branch(IsStringInstanceType(LoadInstanceType(rhs)),
&call_with_any_feedback, &bigint);
GotoIf(TaggedIsSmi(rhs), &call_with_any_feedback);
Branch(IsBigInt(rhs), &bigint, &call_with_any_feedback);
}
BIND(&lhs_is_string);
......@@ -322,31 +320,40 @@ Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback(
BIND(&if_lhsisnotnumber);
{
// 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);
GotoIf(IsBigIntInstanceType(lhs_instance_type), &if_bigint);
GotoIf(IsBigIntInstanceType(lhs_instance_type), &if_left_bigint);
Node* lhs_is_oddball =
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);
Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
BIND(&if_rhsissmi);
BIND(&if_left_oddball);
{
var_type_feedback.Bind(
SmiConstant(BinaryOperationFeedback::kNumberOrOddball));
Goto(&call_stub);
Label if_rhsissmi(this), if_rhsisnotsmi(this);
Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
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.
GotoIfNot(IsHeapNumber(rhs), &check_rhsisoddball);
var_type_feedback.Bind(
SmiConstant(BinaryOperationFeedback::kNumberOrOddball));
Goto(&call_stub);
GotoIf(TaggedIsSmi(rhs), &call_with_any_feedback);
Branch(IsBigInt(rhs), &if_bigint, &call_with_any_feedback);
}
}
......
......@@ -1298,8 +1298,8 @@ Node* InterpreterAssembler::TaggedToWord32OrBigIntWithFeedback(
&is_oddball);
// Not an oddball either -> convert to Numeric.
// TODO(jkummerow): This should use "NonNumericToNumeric".
var_value.Bind(CallBuiltin(Builtins::kNonNumberToNumber, context, value));
var_value.Bind(
CallBuiltin(Builtins::kNonNumberToNumeric, context, value));
var_type_feedback->Bind(SmiConstant(BinaryOperationFeedback::kAny));
Goto(&loop);
......
......@@ -1252,9 +1252,8 @@ class UnaryNumericOpAssembler : public InterpreterAssembler {
CSA_ASSERT(this, SmiEqual(var_feedback.value(),
SmiConstant(BinaryOperationFeedback::kNone)));
var_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny));
// TODO(jkummerow): This should call kNonNumericToNumeric.
var_value.Bind(
CallBuiltin(Builtins::kNonNumberToNumber, GetContext(), value));
CallBuiltin(Builtins::kNonNumberToNumeric, GetContext(), value));
Goto(&start);
}
}
......
......@@ -421,7 +421,10 @@ const six = BigInt(6);
// Binary ops.
{
let One = {valueOf() { return one }};
assertTrue(one + two === three);
assertTrue(One + two === three);
assertTrue(two + One === three);
assertEquals("hello1", "hello" + one);
assertEquals("2hello", two + "hello");
assertThrows("one + 2", TypeError);
......@@ -438,6 +441,8 @@ const six = BigInt(6);
assertThrows("2.5 - one", TypeError);
assertTrue(two * three === six);
assertTrue(two * One === two);
assertTrue(One * two === two);
assertThrows("two * 1", TypeError);
assertThrows("1 * two", TypeError);
assertThrows("two * 1.5", TypeError);
......@@ -462,8 +467,11 @@ const six = BigInt(6);
// Bitwise binary ops.
{
let One = {valueOf() { return one }};
assertTrue((three & one) === one);
assertTrue((BigInt(-2) & zero) === zero);
assertTrue((three & One) === one);
assertTrue((One & three) === one);
assertThrows("three & 1", TypeError);
assertThrows("1 & three", TypeError);
assertThrows("three & true", TypeError);
......@@ -507,10 +515,13 @@ const six = BigInt(6);
// Unary ops.
{
let One = {valueOf() { return one }};
assertTrue(~minus_one === zero);
assertTrue(-minus_one === one);
assertTrue(-One === minus_one);
assertTrue(~~two === two);
assertTrue(-(-two) === two);
assertTrue(~One === BigInt(-2));
let 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