Commit 3b57e96c authored by Jakob Kummerow's avatar Jakob Kummerow Committed by Commit Bot

[bigint] Support BigInts in +,-,*,/,% binary ops.

This CL teaches the respective bytecode handlers and standalone stubs
about BigInts, and collects "kBigInt" feedback for them. However,
Turbofan does not yet care about such feedback, so it is simply converted
to "any" for now (making TF emit stub calls for BigInt operations).

Bug: v8:6791
Change-Id: I6440c108ccd79058d77adc2a6041251db9d5f81d
Reviewed-on: https://chromium-review.googlesource.com/683758Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48173}
parent 3faea676
...@@ -57,7 +57,7 @@ class NumberBuiltinsAssembler : public CodeStubAssembler { ...@@ -57,7 +57,7 @@ class NumberBuiltinsAssembler : public CodeStubAssembler {
template <typename Descriptor> template <typename Descriptor>
void BinaryOp(Label* smis, Variable* var_left, Variable* var_right, void BinaryOp(Label* smis, Variable* var_left, Variable* var_right,
Label* doubles, Variable* var_left_double, Label* doubles, Variable* var_left_double,
Variable* var_right_double); Variable* var_right_double, Label* bigints);
}; };
// ES6 #sec-number.isfinite // ES6 #sec-number.isfinite
...@@ -401,7 +401,8 @@ TF_BUILTIN(Add, AddStubAssembler) { ...@@ -401,7 +401,8 @@ TF_BUILTIN(Add, AddStubAssembler) {
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),
string_add_convert_left(this, Label::kDeferred), string_add_convert_left(this, Label::kDeferred),
string_add_convert_right(this, Label::kDeferred); string_add_convert_right(this, Label::kDeferred),
do_bigint_add(this, Label::kDeferred);
Goto(&loop); Goto(&loop);
BIND(&loop); BIND(&loop);
{ {
...@@ -451,6 +452,7 @@ TF_BUILTIN(Add, AddStubAssembler) { ...@@ -451,6 +452,7 @@ TF_BUILTIN(Add, AddStubAssembler) {
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(right_instance_type), &do_bigint_add);
ConvertAndLoop(&var_right, right_instance_type, &loop, context); ConvertAndLoop(&var_right, right_instance_type, &loop, context);
} }
} // if_right_heapobject } // if_right_heapobject
...@@ -477,6 +479,7 @@ TF_BUILTIN(Add, AddStubAssembler) { ...@@ -477,6 +479,7 @@ TF_BUILTIN(Add, AddStubAssembler) {
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);
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 Number nor a String, and {right} is a Smi.
ConvertAndLoop(&var_left, left_instance_type, &loop, context); ConvertAndLoop(&var_left, left_instance_type, &loop, context);
} }
...@@ -504,6 +507,7 @@ TF_BUILTIN(Add, AddStubAssembler) { ...@@ -504,6 +507,7 @@ TF_BUILTIN(Add, AddStubAssembler) {
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(right_instance_type), &do_bigint_add);
// {left} is a HeapNumber, {right} is neither Number nor String. // {left} is a HeapNumber, {right} is neither Number nor String.
ConvertAndLoop(&var_right, right_instance_type, &loop, context); ConvertAndLoop(&var_right, right_instance_type, &loop, context);
} }
...@@ -517,6 +521,8 @@ TF_BUILTIN(Add, AddStubAssembler) { ...@@ -517,6 +521,8 @@ TF_BUILTIN(Add, AddStubAssembler) {
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(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),
...@@ -554,6 +560,12 @@ TF_BUILTIN(Add, AddStubAssembler) { ...@@ -554,6 +560,12 @@ TF_BUILTIN(Add, AddStubAssembler) {
Return(CallStub(callable, context, var_left.value(), var_right.value())); Return(CallStub(callable, context, var_left.value(), var_right.value()));
} }
BIND(&do_bigint_add);
{
Return(CallRuntime(Runtime::kBigIntBinaryOp, context, var_left.value(),
var_right.value(), SmiConstant(Token::ADD)));
}
BIND(&do_double_add); BIND(&do_double_add);
{ {
Node* value = Float64Add(var_left_double.value(), var_right_double.value()); Node* value = Float64Add(var_left_double.value(), var_right_double.value());
...@@ -565,7 +577,8 @@ template <typename Descriptor> ...@@ -565,7 +577,8 @@ template <typename Descriptor>
void NumberBuiltinsAssembler::BinaryOp(Label* smis, Variable* var_left, void NumberBuiltinsAssembler::BinaryOp(Label* smis, Variable* var_left,
Variable* var_right, Label* doubles, Variable* var_right, Label* doubles,
Variable* var_left_double, Variable* var_left_double,
Variable* var_right_double) { Variable* var_right_double,
Label* bigints) {
DCHECK(var_left->rep() == MachineRepresentation::kTagged); DCHECK(var_left->rep() == MachineRepresentation::kTagged);
DCHECK(var_right->rep() == MachineRepresentation::kTagged); DCHECK(var_right->rep() == MachineRepresentation::kTagged);
...@@ -610,6 +623,8 @@ void NumberBuiltinsAssembler::BinaryOp(Label* smis, Variable* var_left, ...@@ -610,6 +623,8 @@ void NumberBuiltinsAssembler::BinaryOp(Label* smis, Variable* var_left,
BIND(&left_not_number); BIND(&left_not_number);
{ {
GotoIf(IsBigInt(var_left->value()), bigints);
// TODO(jkummerow): Here and below, this should call NonNumericToNumeric.
var_left->Bind( var_left->Bind(
CallBuiltin(Builtins::kNonNumberToNumber, context, var_left->value())); CallBuiltin(Builtins::kNonNumberToNumber, context, var_left->value()));
Goto(&loop); Goto(&loop);
...@@ -617,6 +632,7 @@ void NumberBuiltinsAssembler::BinaryOp(Label* smis, Variable* var_left, ...@@ -617,6 +632,7 @@ void NumberBuiltinsAssembler::BinaryOp(Label* smis, Variable* var_left,
BIND(&right_not_number); BIND(&right_not_number);
{ {
GotoIf(IsBigInt(var_right->value()), bigints);
var_right->Bind( var_right->Bind(
CallBuiltin(Builtins::kNonNumberToNumber, context, var_right->value())); CallBuiltin(Builtins::kNonNumberToNumber, context, var_right->value()));
Goto(&loop); Goto(&loop);
...@@ -628,10 +644,10 @@ TF_BUILTIN(Subtract, NumberBuiltinsAssembler) { ...@@ -628,10 +644,10 @@ TF_BUILTIN(Subtract, NumberBuiltinsAssembler) {
VARIABLE(var_right, MachineRepresentation::kTagged); VARIABLE(var_right, MachineRepresentation::kTagged);
VARIABLE(var_left_double, MachineRepresentation::kFloat64); VARIABLE(var_left_double, MachineRepresentation::kFloat64);
VARIABLE(var_right_double, MachineRepresentation::kFloat64); VARIABLE(var_right_double, MachineRepresentation::kFloat64);
Label do_smi_sub(this), do_double_sub(this); Label do_smi_sub(this), do_double_sub(this), do_bigint_sub(this);
BinaryOp<Descriptor>(&do_smi_sub, &var_left, &var_right, &do_double_sub, BinaryOp<Descriptor>(&do_smi_sub, &var_left, &var_right, &do_double_sub,
&var_left_double, &var_right_double); &var_left_double, &var_right_double, &do_bigint_sub);
BIND(&do_smi_sub); BIND(&do_smi_sub);
{ {
...@@ -658,6 +674,13 @@ TF_BUILTIN(Subtract, NumberBuiltinsAssembler) { ...@@ -658,6 +674,13 @@ TF_BUILTIN(Subtract, NumberBuiltinsAssembler) {
Node* value = Float64Sub(var_left_double.value(), var_right_double.value()); Node* value = Float64Sub(var_left_double.value(), var_right_double.value());
Return(AllocateHeapNumberWithValue(value)); Return(AllocateHeapNumberWithValue(value));
} }
BIND(&do_bigint_sub);
{
Node* context = Parameter(Descriptor::kContext);
Return(CallRuntime(Runtime::kBigIntBinaryOp, context, var_left.value(),
var_right.value(), SmiConstant(Token::SUB)));
}
} }
TF_BUILTIN(Multiply, NumberBuiltinsAssembler) { TF_BUILTIN(Multiply, NumberBuiltinsAssembler) {
...@@ -665,10 +688,10 @@ TF_BUILTIN(Multiply, NumberBuiltinsAssembler) { ...@@ -665,10 +688,10 @@ TF_BUILTIN(Multiply, NumberBuiltinsAssembler) {
VARIABLE(var_right, MachineRepresentation::kTagged); VARIABLE(var_right, MachineRepresentation::kTagged);
VARIABLE(var_left_double, MachineRepresentation::kFloat64); VARIABLE(var_left_double, MachineRepresentation::kFloat64);
VARIABLE(var_right_double, MachineRepresentation::kFloat64); VARIABLE(var_right_double, MachineRepresentation::kFloat64);
Label do_smi_mul(this), do_double_mul(this); Label do_smi_mul(this), do_double_mul(this), do_bigint_mul(this);
BinaryOp<Descriptor>(&do_smi_mul, &var_left, &var_right, &do_double_mul, BinaryOp<Descriptor>(&do_smi_mul, &var_left, &var_right, &do_double_mul,
&var_left_double, &var_right_double); &var_left_double, &var_right_double, &do_bigint_mul);
BIND(&do_smi_mul); BIND(&do_smi_mul);
// The result is not necessarily a smi, in case of overflow. // The result is not necessarily a smi, in case of overflow.
...@@ -677,6 +700,13 @@ TF_BUILTIN(Multiply, NumberBuiltinsAssembler) { ...@@ -677,6 +700,13 @@ TF_BUILTIN(Multiply, NumberBuiltinsAssembler) {
BIND(&do_double_mul); BIND(&do_double_mul);
Node* value = Float64Mul(var_left_double.value(), var_right_double.value()); Node* value = Float64Mul(var_left_double.value(), var_right_double.value());
Return(AllocateHeapNumberWithValue(value)); Return(AllocateHeapNumberWithValue(value));
BIND(&do_bigint_mul);
{
Node* context = Parameter(Descriptor::kContext);
Return(CallRuntime(Runtime::kBigIntBinaryOp, context, var_left.value(),
var_right.value(), SmiConstant(Token::MUL)));
}
} }
TF_BUILTIN(Divide, NumberBuiltinsAssembler) { TF_BUILTIN(Divide, NumberBuiltinsAssembler) {
...@@ -684,10 +714,10 @@ TF_BUILTIN(Divide, NumberBuiltinsAssembler) { ...@@ -684,10 +714,10 @@ TF_BUILTIN(Divide, NumberBuiltinsAssembler) {
VARIABLE(var_right, MachineRepresentation::kTagged); VARIABLE(var_right, MachineRepresentation::kTagged);
VARIABLE(var_left_double, MachineRepresentation::kFloat64); VARIABLE(var_left_double, MachineRepresentation::kFloat64);
VARIABLE(var_right_double, MachineRepresentation::kFloat64); VARIABLE(var_right_double, MachineRepresentation::kFloat64);
Label do_smi_div(this), do_double_div(this); Label do_smi_div(this), do_double_div(this), do_bigint_div(this);
BinaryOp<Descriptor>(&do_smi_div, &var_left, &var_right, &do_double_div, BinaryOp<Descriptor>(&do_smi_div, &var_left, &var_right, &do_double_div,
&var_left_double, &var_right_double); &var_left_double, &var_right_double, &do_bigint_div);
BIND(&do_smi_div); BIND(&do_smi_div);
{ {
...@@ -754,6 +784,13 @@ TF_BUILTIN(Divide, NumberBuiltinsAssembler) { ...@@ -754,6 +784,13 @@ TF_BUILTIN(Divide, NumberBuiltinsAssembler) {
Node* value = Float64Div(var_left_double.value(), var_right_double.value()); Node* value = Float64Div(var_left_double.value(), var_right_double.value());
Return(AllocateHeapNumberWithValue(value)); Return(AllocateHeapNumberWithValue(value));
} }
BIND(&do_bigint_div);
{
Node* context = Parameter(Descriptor::kContext);
Return(CallRuntime(Runtime::kBigIntBinaryOp, context, var_left.value(),
var_right.value(), SmiConstant(Token::DIV)));
}
} }
TF_BUILTIN(Modulus, NumberBuiltinsAssembler) { TF_BUILTIN(Modulus, NumberBuiltinsAssembler) {
...@@ -761,10 +798,10 @@ TF_BUILTIN(Modulus, NumberBuiltinsAssembler) { ...@@ -761,10 +798,10 @@ TF_BUILTIN(Modulus, NumberBuiltinsAssembler) {
VARIABLE(var_right, MachineRepresentation::kTagged); VARIABLE(var_right, MachineRepresentation::kTagged);
VARIABLE(var_left_double, MachineRepresentation::kFloat64); VARIABLE(var_left_double, MachineRepresentation::kFloat64);
VARIABLE(var_right_double, MachineRepresentation::kFloat64); VARIABLE(var_right_double, MachineRepresentation::kFloat64);
Label do_smi_mod(this), do_double_mod(this); Label do_smi_mod(this), do_double_mod(this), do_bigint_mod(this);
BinaryOp<Descriptor>(&do_smi_mod, &var_left, &var_right, &do_double_mod, BinaryOp<Descriptor>(&do_smi_mod, &var_left, &var_right, &do_double_mod,
&var_left_double, &var_right_double); &var_left_double, &var_right_double, &do_bigint_mod);
BIND(&do_smi_mod); BIND(&do_smi_mod);
Return(SmiMod(var_left.value(), var_right.value())); Return(SmiMod(var_left.value(), var_right.value()));
...@@ -772,6 +809,13 @@ TF_BUILTIN(Modulus, NumberBuiltinsAssembler) { ...@@ -772,6 +809,13 @@ TF_BUILTIN(Modulus, NumberBuiltinsAssembler) {
BIND(&do_double_mod); BIND(&do_double_mod);
Node* value = Float64Mod(var_left_double.value(), var_right_double.value()); Node* value = Float64Mod(var_left_double.value(), var_right_double.value());
Return(AllocateHeapNumberWithValue(value)); Return(AllocateHeapNumberWithValue(value));
BIND(&do_bigint_mod);
{
Node* context = Parameter(Descriptor::kContext);
Return(CallRuntime(Runtime::kBigIntBinaryOp, context, var_left.value(),
var_right.value(), SmiConstant(Token::MOD)));
}
} }
TF_BUILTIN(ShiftLeft, NumberBuiltinsAssembler) { TF_BUILTIN(ShiftLeft, NumberBuiltinsAssembler) {
......
...@@ -169,6 +169,9 @@ BinaryOperationHint BinaryOperationHintFromFeedback(int type_feedback) { ...@@ -169,6 +169,9 @@ BinaryOperationHint BinaryOperationHintFromFeedback(int type_feedback) {
return BinaryOperationHint::kNumberOrOddball; return BinaryOperationHint::kNumberOrOddball;
case BinaryOperationFeedback::kString: case BinaryOperationFeedback::kString:
return BinaryOperationHint::kString; return BinaryOperationHint::kString;
case BinaryOperationFeedback::kBigInt:
// TODO(jarin/jkummerow/neis): Support BigInts in TF.
// Fall through for now.
case BinaryOperationFeedback::kAny: case BinaryOperationFeedback::kAny:
default: default:
return BinaryOperationHint::kAny; return BinaryOperationHint::kAny;
......
...@@ -1256,6 +1256,7 @@ inline uint32_t ObjectHash(Address address) { ...@@ -1256,6 +1256,7 @@ inline uint32_t ObjectHash(Address address) {
// to a more generic type when we combine feedback. // to a more generic type when we combine feedback.
// kSignedSmall -> kSignedSmallInputs -> kNumber -> kNumberOrOddball -> kAny // kSignedSmall -> kSignedSmallInputs -> kNumber -> kNumberOrOddball -> kAny
// kString -> kAny // kString -> kAny
// kBigInt -> kAny
// TODO(mythria): Remove kNumber type when crankshaft can handle Oddballs // TODO(mythria): Remove kNumber type when crankshaft can handle Oddballs
// similar to Numbers. We don't need kNumber feedback for Turbofan. Extra // similar to Numbers. We don't need kNumber feedback for Turbofan. Extra
// information about Number might reduce few instructions but causes more // information about Number might reduce few instructions but causes more
...@@ -1270,7 +1271,8 @@ class BinaryOperationFeedback { ...@@ -1270,7 +1271,8 @@ class BinaryOperationFeedback {
kNumber = 0x7, kNumber = 0x7,
kNumberOrOddball = 0xF, kNumberOrOddball = 0xF,
kString = 0x10, kString = 0x10,
kAny = 0x3F kBigInt = 0x20,
kAny = 0x7F
}; };
}; };
......
...@@ -19,7 +19,7 @@ Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs, ...@@ -19,7 +19,7 @@ Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs,
Label do_fadd(this), if_lhsisnotnumber(this, Label::kDeferred), Label do_fadd(this), if_lhsisnotnumber(this, Label::kDeferred),
check_rhsisoddball(this, Label::kDeferred), check_rhsisoddball(this, Label::kDeferred),
call_with_oddball_feedback(this), call_with_any_feedback(this), call_with_oddball_feedback(this), call_with_any_feedback(this),
call_add_stub(this), end(this); call_add_stub(this), end(this), bigint(this, Label::kDeferred);
VARIABLE(var_fadd_lhs, MachineRepresentation::kFloat64); VARIABLE(var_fadd_lhs, MachineRepresentation::kFloat64);
VARIABLE(var_fadd_rhs, MachineRepresentation::kFloat64); VARIABLE(var_fadd_rhs, MachineRepresentation::kFloat64);
VARIABLE(var_type_feedback, MachineRepresentation::kTaggedSigned); VARIABLE(var_type_feedback, MachineRepresentation::kTaggedSigned);
...@@ -148,10 +148,20 @@ Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs, ...@@ -148,10 +148,20 @@ Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs,
BIND(&if_lhsisnotoddball); BIND(&if_lhsisnotoddball);
{ {
// Exit unless {lhs} is a string Label lhs_is_string(this), lhs_is_bigint(this);
GotoIfNot(IsStringInstanceType(lhs_instance_type), GotoIf(IsStringInstanceType(lhs_instance_type), &lhs_is_string);
&call_with_any_feedback); GotoIf(IsBigIntInstanceType(lhs_instance_type), &lhs_is_bigint);
Goto(&call_with_any_feedback);
BIND(&lhs_is_bigint);
{
// Label "bigint" handles BigInt + {anything except string}.
GotoIf(TaggedIsSmi(rhs), &bigint);
Branch(IsStringInstanceType(LoadInstanceType(rhs)),
&call_with_any_feedback, &bigint);
}
BIND(&lhs_is_string);
// Check if the {rhs} is a smi, and exit the string check early if it is. // Check if the {rhs} is a smi, and exit the string check early if it is.
GotoIf(TaggedIsSmi(rhs), &call_with_any_feedback); GotoIf(TaggedIsSmi(rhs), &call_with_any_feedback);
...@@ -178,10 +188,19 @@ Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs, ...@@ -178,10 +188,19 @@ Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs,
Node* rhs_instance_type = LoadInstanceType(rhs); Node* rhs_instance_type = LoadInstanceType(rhs);
Node* rhs_is_oddball = Node* rhs_is_oddball =
Word32Equal(rhs_instance_type, Int32Constant(ODDBALL_TYPE)); Word32Equal(rhs_instance_type, Int32Constant(ODDBALL_TYPE));
Branch(rhs_is_oddball, &call_with_oddball_feedback, GotoIf(rhs_is_oddball, &call_with_oddball_feedback);
Branch(IsBigIntInstanceType(rhs_instance_type), &bigint,
&call_with_any_feedback); &call_with_any_feedback);
} }
BIND(&bigint);
{
var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kBigInt));
var_result.Bind(CallRuntime(Runtime::kBigIntBinaryOp, context, lhs, rhs,
SmiConstant(Token::ADD)));
Goto(&end);
}
BIND(&call_with_oddball_feedback); BIND(&call_with_oddball_feedback);
{ {
var_type_feedback.Bind( var_type_feedback.Bind(
...@@ -212,7 +231,8 @@ Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback( ...@@ -212,7 +231,8 @@ Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback(
Token::Value opcode, bool rhs_is_smi) { Token::Value opcode, bool rhs_is_smi) {
Label do_float_operation(this), end(this), call_stub(this), Label do_float_operation(this), end(this), call_stub(this),
check_rhsisoddball(this, Label::kDeferred), call_with_any_feedback(this), check_rhsisoddball(this, Label::kDeferred), call_with_any_feedback(this),
if_lhsisnotnumber(this, Label::kDeferred); if_lhsisnotnumber(this, Label::kDeferred),
if_bigint(this, Label::kDeferred);
VARIABLE(var_float_lhs, MachineRepresentation::kFloat64); VARIABLE(var_float_lhs, MachineRepresentation::kFloat64);
VARIABLE(var_float_rhs, MachineRepresentation::kFloat64); VARIABLE(var_float_rhs, MachineRepresentation::kFloat64);
VARIABLE(var_type_feedback, MachineRepresentation::kTaggedSigned); VARIABLE(var_type_feedback, MachineRepresentation::kTaggedSigned);
...@@ -282,7 +302,7 @@ Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback( ...@@ -282,7 +302,7 @@ Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback(
} }
{ {
// Perform a floating point subtraction. // Perform floating point operation.
var_float_lhs.Bind(LoadHeapNumberValue(lhs)); var_float_lhs.Bind(LoadHeapNumberValue(lhs));
var_float_rhs.Bind(SmiToFloat64(rhs)); var_float_rhs.Bind(SmiToFloat64(rhs));
Goto(&do_float_operation); Goto(&do_float_operation);
...@@ -304,6 +324,7 @@ Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback( ...@@ -304,6 +324,7 @@ Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback(
// 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. // Check if lhs is an oddball.
Node* lhs_instance_type = LoadInstanceType(lhs); Node* lhs_instance_type = LoadInstanceType(lhs);
GotoIf(IsBigIntInstanceType(lhs_instance_type), &if_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); GotoIfNot(lhs_is_oddball, &call_with_any_feedback);
...@@ -334,6 +355,7 @@ Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback( ...@@ -334,6 +355,7 @@ Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback(
// Check if rhs is an oddball. At this point we know lhs is either a // Check if rhs is an oddball. At this point we know lhs is either a
// Smi or number or oddball and rhs is not a number or Smi. // Smi or number or oddball and rhs is not a number or Smi.
Node* rhs_instance_type = LoadInstanceType(rhs); Node* rhs_instance_type = LoadInstanceType(rhs);
GotoIf(IsBigIntInstanceType(rhs_instance_type), &if_bigint);
Node* rhs_is_oddball = Node* rhs_is_oddball =
Word32Equal(rhs_instance_type, Int32Constant(ODDBALL_TYPE)); Word32Equal(rhs_instance_type, Int32Constant(ODDBALL_TYPE));
GotoIfNot(rhs_is_oddball, &call_with_any_feedback); GotoIfNot(rhs_is_oddball, &call_with_any_feedback);
...@@ -343,6 +365,15 @@ Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback( ...@@ -343,6 +365,15 @@ Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback(
Goto(&call_stub); Goto(&call_stub);
} }
// This handles the case where at least one input is a BigInt.
BIND(&if_bigint);
{
var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kBigInt));
var_result.Bind(CallRuntime(Runtime::kBigIntBinaryOp, context, lhs, rhs,
SmiConstant(opcode)));
Goto(&end);
}
BIND(&call_with_any_feedback); BIND(&call_with_any_feedback);
{ {
var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny)); var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny));
......
...@@ -273,6 +273,8 @@ class ErrorUtils : public AllStatic { ...@@ -273,6 +273,8 @@ class ErrorUtils : public AllStatic {
T(AtomicsWaitNotAllowed, "Atomics.wait cannot be called in this context") \ T(AtomicsWaitNotAllowed, "Atomics.wait cannot be called in this context") \
T(BadSortComparisonFunction, \ T(BadSortComparisonFunction, \
"The comparison function must be either a function or undefined") \ "The comparison function must be either a function or undefined") \
T(BigIntMixedTypes, \
"Cannot mix BigInt and other types, use explicit conversions") \
T(CalledNonCallable, "% is not a function") \ T(CalledNonCallable, "% is not a function") \
T(CalledOnNonObject, "% called on non-object") \ T(CalledOnNonObject, "% called on non-object") \
T(CalledOnNullOrUndefined, "% called on null or undefined") \ T(CalledOnNullOrUndefined, "% called on null or undefined") \
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "src/counters.h" #include "src/counters.h"
#include "src/objects-inl.h" #include "src/objects-inl.h"
#include "src/objects/bigint.h" #include "src/objects/bigint.h"
#include "src/parsing/token.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -29,5 +30,41 @@ RUNTIME_FUNCTION(Runtime_BigIntToBoolean) { ...@@ -29,5 +30,41 @@ RUNTIME_FUNCTION(Runtime_BigIntToBoolean) {
return *isolate->factory()->ToBoolean(bigint->ToBoolean()); return *isolate->factory()->ToBoolean(bigint->ToBoolean());
} }
RUNTIME_FUNCTION(Runtime_BigIntBinaryOp) {
HandleScope scope(isolate);
DCHECK_EQ(3, args.length());
CONVERT_ARG_HANDLE_CHECKED(Object, left_obj, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, right_obj, 1);
CONVERT_SMI_ARG_CHECKED(opcode, 2);
if (!left_obj->IsBigInt() || !right_obj->IsBigInt()) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kBigIntMixedTypes));
}
Handle<BigInt> left(Handle<BigInt>::cast(left_obj));
Handle<BigInt> right(Handle<BigInt>::cast(right_obj));
MaybeHandle<BigInt> result;
switch (opcode) {
case Token::ADD:
result = BigInt::Add(left, right);
break;
case Token::SUB:
result = BigInt::Subtract(left, right);
break;
case Token::MUL:
result = BigInt::Multiply(left, right);
break;
case Token::DIV:
result = BigInt::Divide(left, right);
break;
case Token::MOD:
result = BigInt::Remainder(left, right);
break;
default:
UNREACHABLE();
}
RETURN_RESULT_OR_FAILURE(isolate, result);
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -70,7 +70,8 @@ namespace internal { ...@@ -70,7 +70,8 @@ namespace internal {
#define FOR_EACH_INTRINSIC_BIGINT(F) \ #define FOR_EACH_INTRINSIC_BIGINT(F) \
F(BigIntEqual, 2, 1) \ F(BigIntEqual, 2, 1) \
F(BigIntToBoolean, 1, 1) F(BigIntToBoolean, 1, 1) \
F(BigIntBinaryOp, 3, 1)
#define FOR_EACH_INTRINSIC_CLASSES(F) \ #define FOR_EACH_INTRINSIC_CLASSES(F) \
F(ThrowUnsupportedSuperError, 0, 1) \ F(ThrowUnsupportedSuperError, 0, 1) \
......
...@@ -428,7 +428,7 @@ bytecodes: [ ...@@ -428,7 +428,7 @@ bytecodes: [
B(TestTypeOf), U8(5), B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4), B(JumpIfFalse), U8(4),
B(Jump), U8(18), B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(135), B(Wide), B(LdaSmi), I16(136),
B(Star), R(18), B(Star), R(18),
B(LdaConstant), U8(16), B(LdaConstant), U8(16),
B(Star), R(19), B(Star), R(19),
......
...@@ -143,7 +143,7 @@ bytecodes: [ ...@@ -143,7 +143,7 @@ bytecodes: [
B(TestTypeOf), U8(5), B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4), B(JumpIfFalse), U8(4),
B(Jump), U8(18), B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(135), B(Wide), B(LdaSmi), I16(136),
B(Star), R(19), B(Star), R(19),
B(LdaConstant), U8(13), B(LdaConstant), U8(13),
B(Star), R(20), B(Star), R(20),
...@@ -432,7 +432,7 @@ bytecodes: [ ...@@ -432,7 +432,7 @@ bytecodes: [
B(TestTypeOf), U8(5), B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4), B(JumpIfFalse), U8(4),
B(Jump), U8(18), B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(135), B(Wide), B(LdaSmi), I16(136),
B(Star), R(19), B(Star), R(19),
B(LdaConstant), U8(13), B(LdaConstant), U8(13),
B(Star), R(20), B(Star), R(20),
...@@ -743,7 +743,7 @@ bytecodes: [ ...@@ -743,7 +743,7 @@ bytecodes: [
B(TestTypeOf), U8(5), B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4), B(JumpIfFalse), U8(4),
B(Jump), U8(18), B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(135), B(Wide), B(LdaSmi), I16(136),
B(Star), R(19), B(Star), R(19),
B(LdaConstant), U8(13), B(LdaConstant), U8(13),
B(Star), R(20), B(Star), R(20),
...@@ -991,7 +991,7 @@ bytecodes: [ ...@@ -991,7 +991,7 @@ bytecodes: [
B(TestTypeOf), U8(5), B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4), B(JumpIfFalse), U8(4),
B(Jump), U8(18), B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(135), B(Wide), B(LdaSmi), I16(136),
B(Star), R(16), B(Star), R(16),
B(LdaConstant), U8(10), B(LdaConstant), U8(10),
B(Star), R(17), B(Star), R(17),
......
...@@ -86,7 +86,7 @@ bytecodes: [ ...@@ -86,7 +86,7 @@ bytecodes: [
B(TestTypeOf), U8(5), B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4), B(JumpIfFalse), U8(4),
B(Jump), U8(18), B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(135), B(Wide), B(LdaSmi), I16(136),
B(Star), R(11), B(Star), R(11),
B(LdaConstant), U8(8), B(LdaConstant), U8(8),
B(Star), R(12), B(Star), R(12),
...@@ -227,7 +227,7 @@ bytecodes: [ ...@@ -227,7 +227,7 @@ bytecodes: [
B(TestTypeOf), U8(5), B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4), B(JumpIfFalse), U8(4),
B(Jump), U8(18), B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(135), B(Wide), B(LdaSmi), I16(136),
B(Star), R(12), B(Star), R(12),
B(LdaConstant), U8(8), B(LdaConstant), U8(8),
B(Star), R(13), B(Star), R(13),
...@@ -380,7 +380,7 @@ bytecodes: [ ...@@ -380,7 +380,7 @@ bytecodes: [
B(TestTypeOf), U8(5), B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4), B(JumpIfFalse), U8(4),
B(Jump), U8(18), B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(135), B(Wide), B(LdaSmi), I16(136),
B(Star), R(11), B(Star), R(11),
B(LdaConstant), U8(8), B(LdaConstant), U8(8),
B(Star), R(12), B(Star), R(12),
...@@ -523,7 +523,7 @@ bytecodes: [ ...@@ -523,7 +523,7 @@ bytecodes: [
B(TestTypeOf), U8(5), B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4), B(JumpIfFalse), U8(4),
B(Jump), U8(18), B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(135), B(Wide), B(LdaSmi), I16(136),
B(Star), R(10), B(Star), R(10),
B(LdaConstant), U8(10), B(LdaConstant), U8(10),
B(Star), R(11), B(Star), R(11),
......
...@@ -90,7 +90,7 @@ bytecodes: [ ...@@ -90,7 +90,7 @@ bytecodes: [
B(TestTypeOf), U8(5), B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4), B(JumpIfFalse), U8(4),
B(Jump), U8(18), B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(135), B(Wide), B(LdaSmi), I16(136),
B(Star), R(13), B(Star), R(13),
B(LdaConstant), U8(7), B(LdaConstant), U8(7),
B(Star), R(14), B(Star), R(14),
...@@ -268,7 +268,7 @@ bytecodes: [ ...@@ -268,7 +268,7 @@ bytecodes: [
B(TestTypeOf), U8(5), B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4), B(JumpIfFalse), U8(4),
B(Jump), U8(18), B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(135), B(Wide), B(LdaSmi), I16(136),
B(Star), R(13), B(Star), R(13),
B(LdaConstant), U8(11), B(LdaConstant), U8(11),
B(Star), R(14), B(Star), R(14),
...@@ -422,7 +422,7 @@ bytecodes: [ ...@@ -422,7 +422,7 @@ bytecodes: [
B(TestTypeOf), U8(5), B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4), B(JumpIfFalse), U8(4),
B(Jump), U8(18), B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(135), B(Wide), B(LdaSmi), I16(136),
B(Star), R(11), B(Star), R(11),
B(LdaConstant), U8(9), B(LdaConstant), U8(9),
B(Star), R(12), B(Star), R(12),
...@@ -524,7 +524,7 @@ bytecodes: [ ...@@ -524,7 +524,7 @@ bytecodes: [
B(JumpIfUndefined), U8(6), B(JumpIfUndefined), U8(6),
B(Ldar), R(6), B(Ldar), R(6),
B(JumpIfNotNull), U8(16), B(JumpIfNotNull), U8(16),
B(LdaSmi), I8(64), B(LdaSmi), I8(65),
B(Star), R(17), B(Star), R(17),
B(LdaConstant), U8(4), B(LdaConstant), U8(4),
B(Star), R(18), B(Star), R(18),
...@@ -580,7 +580,7 @@ bytecodes: [ ...@@ -580,7 +580,7 @@ bytecodes: [
B(TestTypeOf), U8(5), B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4), B(JumpIfFalse), U8(4),
B(Jump), U8(18), B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(135), B(Wide), B(LdaSmi), I16(136),
B(Star), R(16), B(Star), R(16),
B(LdaConstant), U8(9), B(LdaConstant), U8(9),
B(Star), R(17), B(Star), R(17),
...@@ -754,7 +754,7 @@ bytecodes: [ ...@@ -754,7 +754,7 @@ bytecodes: [
B(TestTypeOf), U8(5), B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4), B(JumpIfFalse), U8(4),
B(Jump), U8(18), B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(135), B(Wide), B(LdaSmi), I16(136),
B(Star), R(16), B(Star), R(16),
B(LdaConstant), U8(10), B(LdaConstant), U8(10),
B(Star), R(17), B(Star), R(17),
...@@ -953,7 +953,7 @@ bytecodes: [ ...@@ -953,7 +953,7 @@ bytecodes: [
B(TestTypeOf), U8(5), B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4), B(JumpIfFalse), U8(4),
B(Jump), U8(18), B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(135), B(Wide), B(LdaSmi), I16(136),
B(Star), R(15), B(Star), R(15),
B(LdaConstant), U8(14), B(LdaConstant), U8(14),
B(Star), R(16), B(Star), R(16),
...@@ -1116,7 +1116,7 @@ bytecodes: [ ...@@ -1116,7 +1116,7 @@ bytecodes: [
B(TestTypeOf), U8(5), B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4), B(JumpIfFalse), U8(4),
B(Jump), U8(18), B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(135), B(Wide), B(LdaSmi), I16(136),
B(Star), R(20), B(Star), R(20),
B(LdaConstant), U8(7), B(LdaConstant), U8(7),
B(Star), R(21), B(Star), R(21),
...@@ -1358,7 +1358,7 @@ bytecodes: [ ...@@ -1358,7 +1358,7 @@ bytecodes: [
B(TestTypeOf), U8(5), B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4), B(JumpIfFalse), U8(4),
B(Jump), U8(18), B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(135), B(Wide), B(LdaSmi), I16(136),
B(Star), R(20), B(Star), R(20),
B(LdaConstant), U8(9), B(LdaConstant), U8(9),
B(Star), R(21), B(Star), R(21),
......
...@@ -257,7 +257,7 @@ bytecodes: [ ...@@ -257,7 +257,7 @@ bytecodes: [
B(TestTypeOf), U8(5), B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4), B(JumpIfFalse), U8(4),
B(Jump), U8(18), B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(135), B(Wide), B(LdaSmi), I16(136),
B(Star), R(14), B(Star), R(14),
B(LdaConstant), U8(15), B(LdaConstant), U8(15),
B(Star), R(15), B(Star), R(15),
......
...@@ -231,7 +231,7 @@ bytecodes: [ ...@@ -231,7 +231,7 @@ bytecodes: [
B(JumpIfUndefined), U8(6), B(JumpIfUndefined), U8(6),
B(Ldar), R(3), B(Ldar), R(3),
B(JumpIfNotNull), U8(16), B(JumpIfNotNull), U8(16),
B(LdaSmi), I8(64), B(LdaSmi), I8(65),
B(Star), R(4), B(Star), R(4),
B(LdaConstant), U8(1), B(LdaConstant), U8(1),
B(Star), R(5), B(Star), R(5),
......
...@@ -10,6 +10,9 @@ const zero = BigInt(0); ...@@ -10,6 +10,9 @@ const zero = BigInt(0);
const another_zero = BigInt(0); const another_zero = BigInt(0);
const one = BigInt(1); const one = BigInt(1);
const another_one = BigInt(1); const another_one = BigInt(1);
const two = BigInt(2);
const three = BigInt(3);
const six = BigInt(6);
// BigInt // BigInt
{ {
...@@ -143,3 +146,44 @@ const another_one = BigInt(1); ...@@ -143,3 +146,44 @@ const another_one = BigInt(1);
assertTrue(new Map([[one, 42]]).has(one)); assertTrue(new Map([[one, 42]]).has(one));
assertTrue(new Map([[one, 42]]).has(another_one)); assertTrue(new Map([[one, 42]]).has(another_one));
} }
// Binary ops.
{
assertTrue(one + two === three);
assertEquals("hello1", "hello" + one);
assertEquals("2hello", two + "hello");
assertThrows("one + 2", TypeError);
assertThrows("2 + one", TypeError);
assertThrows("one + 0.5", TypeError);
assertThrows("0.5 + one", TypeError);
assertThrows("one + null", TypeError);
assertThrows("null + one", TypeError);
assertTrue(three - two === one);
assertThrows("two - 1", TypeError);
assertThrows("2 - one", TypeError);
assertThrows("two - 0.5", TypeError);
assertThrows("2.5 - one", TypeError);
assertTrue(two * three === six);
assertThrows("two * 1", TypeError);
assertThrows("1 * two", TypeError);
assertThrows("two * 1.5", TypeError);
assertThrows("1.5 * two", TypeError);
assertTrue(six / three === two);
assertThrows("six / 3", TypeError);
assertThrows("3 / three", TypeError);
assertThrows("six / 0.5", TypeError);
assertThrows("0.5 / six", TypeError);
assertThrows("zero / zero", RangeError);
assertThrows("zero / 0", TypeError);
assertTrue(three % two === one);
assertThrows("three % 2", TypeError);
assertThrows("3 % two", TypeError);
assertThrows("three % 2.5", TypeError);
assertThrows("3.5 % two", TypeError);
assertThrows("three % zero", RangeError);
assertThrows("three % 0", TypeError);
}
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