Commit 03035038 authored by Georg Neis's avatar Georg Neis Committed by Commit Bot

[bigint] Implement ToBigInt and NumberToBigInt.

... and use them to complete the BigInt function.

Bug: v8:6791
Change-Id: Ia36db86b92d1a0cfcb783516e04d6c0e3750f194
Reviewed-on: https://chromium-review.googlesource.com/737643
Commit-Queue: Georg Neis <neis@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48993}
parent 13802c8b
......@@ -15,12 +15,18 @@ BUILTIN(BigIntConstructor) {
HandleScope scope(isolate);
Handle<Object> value = args.atOrUndefined(isolate, 1);
// TODO(jkummerow): Implement properly.
if (value->IsJSReceiver()) {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, value,
JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(value),
ToPrimitiveHint::kNumber));
}
// Dummy implementation only takes Smi args.
if (!value->IsSmi()) return isolate->heap()->undefined_value();
int num = Smi::ToInt(*value);
return *isolate->factory()->NewBigIntFromInt(num);
if (value->IsNumber()) {
RETURN_RESULT_OR_FAILURE(isolate, BigInt::FromNumber(isolate, value));
} else {
RETURN_RESULT_OR_FAILURE(isolate, BigInt::FromObject(isolate, value));
}
}
BUILTIN(BigIntConstructor_ConstructStub) {
......
......@@ -1423,6 +1423,29 @@ Handle<BigInt> Factory::NewBigIntRaw(int length, PretenureFlag pretenure) {
BigInt);
}
Handle<BigInt> Factory::NewBigIntFromSafeInteger(double value,
PretenureFlag pretenure) {
if (value == 0) return NewBigInt(0);
uint64_t absolute = std::abs(value);
#if V8_TARGET_ARCH_64_BIT
static_assert(sizeof(BigInt::digit_t) == sizeof(uint64_t),
"unexpected BigInt digit size");
Handle<BigInt> result = NewBigIntRaw(1);
result->set_digit(0, absolute);
#else
static_assert(sizeof(BigInt::digit_t) == sizeof(uint32_t),
"unexpected BigInt digit size");
Handle<BigInt> result = NewBigIntRaw(2);
result->set_digit(0, absolute);
result->set_digit(1, absolute >> 32);
#endif
result->set_sign(value < 0); // Treats -0 like 0.
return result;
}
Handle<BigInt> Factory::NewBigIntFromInt(int value, PretenureFlag pretenure) {
if (value == 0) return NewBigInt(0);
Handle<BigInt> result = NewBigIntRaw(1);
......
......@@ -491,6 +491,8 @@ class V8_EXPORT_PRIVATE Factory final {
PretenureFlag pretenure = NOT_TENURED);
Handle<BigInt> NewBigIntFromInt(int value,
PretenureFlag pretenure = NOT_TENURED);
Handle<BigInt> NewBigIntFromSafeInteger(
double value, PretenureFlag pretenure = NOT_TENURED);
Handle<JSWeakMap> NewJSWeakMap();
......
......@@ -273,6 +273,10 @@ class ErrorUtils : public AllStatic {
T(AtomicsWaitNotAllowed, "Atomics.wait cannot be called in this context") \
T(BadSortComparisonFunction, \
"The comparison function must be either a function or undefined") \
T(BigIntFromNumber, \
"The number % is not a safe integer and thus cannot be converted to a " \
"BigInt") \
T(BigIntFromObject, "Cannot convert % to a BigInt") \
T(BigIntMixedTypes, \
"Cannot mix BigInt and other types, use explicit conversions") \
T(BigIntSerializeJSON, "Do not know how to serialize a BigInt") \
......
......@@ -483,6 +483,63 @@ MaybeHandle<String> BigInt::ToString(Handle<BigInt> bigint, int radix) {
return ToStringGeneric(bigint, radix);
}
namespace {
bool IsSafeInteger(Handle<HeapNumber> number) {
double value = number->value();
if (std::isnan(value) || std::isinf(value)) return false;
// Let integer be ! ToInteger(value).
// If ! SameValueZero(integer, value) is false, return false.
if (DoubleToInteger(value) != value) return false;
return std::abs(value) <= kMaxSafeInteger;
}
} // anonymous namespace
MaybeHandle<BigInt> BigInt::FromNumber(Isolate* isolate,
Handle<Object> number) {
DCHECK(number->IsNumber());
if (number->IsSmi()) {
return isolate->factory()->NewBigIntFromInt(Smi::cast(*number)->value());
}
if (!IsSafeInteger(Handle<HeapNumber>::cast(number))) {
THROW_NEW_ERROR(isolate,
NewRangeError(MessageTemplate::kBigIntFromNumber, number),
BigInt);
}
return isolate->factory()->NewBigIntFromSafeInteger(
Handle<HeapNumber>::cast(number)->value());
}
MaybeHandle<BigInt> BigInt::FromObject(Isolate* isolate, Handle<Object> obj) {
if (obj->IsJSReceiver()) {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, obj,
JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(obj),
ToPrimitiveHint::kNumber),
BigInt);
}
if (obj->IsBoolean()) {
return isolate->factory()->NewBigIntFromInt(obj->BooleanValue());
}
if (obj->IsBigInt()) {
return Handle<BigInt>::cast(obj);
}
if (obj->IsString()) {
Handle<BigInt> n;
if (StringToBigInt(isolate, Handle<String>::cast(obj)).ToHandle(&n)) {
return n;
}
// ... else fall through.
}
THROW_NEW_ERROR(
isolate, NewSyntaxError(MessageTemplate::kBigIntFromObject, obj), BigInt);
}
void BigInt::Initialize(int length, bool zero_initialize) {
set_length(length);
set_sign(false);
......
......@@ -74,6 +74,13 @@ class V8_EXPORT_PRIVATE BigInt : public HeapObject {
static MaybeHandle<String> ToString(Handle<BigInt> bigint, int radix = 10);
// ECMAScript's NumberToBigInt
static MaybeHandle<BigInt> FromNumber(Isolate* isolate,
Handle<Object> number);
// ECMAScript's ToBigInt (throws for Number input)
static MaybeHandle<BigInt> FromObject(Isolate* isolate, Handle<Object> obj);
// The maximum length that the current implementation supports would be
// kMaxInt / kDigitBits. However, we use a lower limit for now, because
// raising it later is easier than lowering it.
......
......@@ -428,7 +428,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(139),
B(Wide), B(LdaSmi), I16(141),
B(Star), R(18),
B(LdaConstant), U8(16),
B(Star), R(19),
......
......@@ -143,7 +143,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(139),
B(Wide), B(LdaSmi), I16(141),
B(Star), R(19),
B(LdaConstant), U8(13),
B(Star), R(20),
......@@ -432,7 +432,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(139),
B(Wide), B(LdaSmi), I16(141),
B(Star), R(19),
B(LdaConstant), U8(13),
B(Star), R(20),
......@@ -743,7 +743,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(139),
B(Wide), B(LdaSmi), I16(141),
B(Star), R(19),
B(LdaConstant), U8(13),
B(Star), R(20),
......@@ -991,7 +991,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(139),
B(Wide), B(LdaSmi), I16(141),
B(Star), R(16),
B(LdaConstant), U8(10),
B(Star), R(17),
......
......@@ -86,7 +86,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(139),
B(Wide), B(LdaSmi), I16(141),
B(Star), R(11),
B(LdaConstant), U8(8),
B(Star), R(12),
......@@ -227,7 +227,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(139),
B(Wide), B(LdaSmi), I16(141),
B(Star), R(12),
B(LdaConstant), U8(8),
B(Star), R(13),
......@@ -380,7 +380,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(139),
B(Wide), B(LdaSmi), I16(141),
B(Star), R(11),
B(LdaConstant), U8(8),
B(Star), R(12),
......@@ -523,7 +523,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(139),
B(Wide), B(LdaSmi), I16(141),
B(Star), R(10),
B(LdaConstant), U8(10),
B(Star), R(11),
......
......@@ -90,7 +90,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(139),
B(Wide), B(LdaSmi), I16(141),
B(Star), R(13),
B(LdaConstant), U8(7),
B(Star), R(14),
......@@ -268,7 +268,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(139),
B(Wide), B(LdaSmi), I16(141),
B(Star), R(13),
B(LdaConstant), U8(11),
B(Star), R(14),
......@@ -422,7 +422,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(139),
B(Wide), B(LdaSmi), I16(141),
B(Star), R(11),
B(LdaConstant), U8(9),
B(Star), R(12),
......@@ -524,7 +524,7 @@ bytecodes: [
B(JumpIfUndefined), U8(6),
B(Ldar), R(6),
B(JumpIfNotNull), U8(16),
B(LdaSmi), I8(69),
B(LdaSmi), I8(71),
B(Star), R(17),
B(LdaConstant), U8(4),
B(Star), R(18),
......@@ -580,7 +580,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(139),
B(Wide), B(LdaSmi), I16(141),
B(Star), R(16),
B(LdaConstant), U8(9),
B(Star), R(17),
......@@ -754,7 +754,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(139),
B(Wide), B(LdaSmi), I16(141),
B(Star), R(16),
B(LdaConstant), U8(10),
B(Star), R(17),
......@@ -953,7 +953,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(139),
B(Wide), B(LdaSmi), I16(141),
B(Star), R(15),
B(LdaConstant), U8(14),
B(Star), R(16),
......@@ -1116,7 +1116,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(139),
B(Wide), B(LdaSmi), I16(141),
B(Star), R(20),
B(LdaConstant), U8(7),
B(Star), R(21),
......@@ -1358,7 +1358,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(139),
B(Wide), B(LdaSmi), I16(141),
B(Star), R(20),
B(LdaConstant), U8(9),
B(Star), R(21),
......
......@@ -257,7 +257,7 @@ bytecodes: [
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(139),
B(Wide), B(LdaSmi), I16(141),
B(Star), R(14),
B(LdaConstant), U8(15),
B(Star), R(15),
......
......@@ -231,7 +231,7 @@ bytecodes: [
B(JumpIfUndefined), U8(6),
B(Ldar), R(3),
B(JumpIfNotNull), U8(16),
B(LdaSmi), I8(69),
B(LdaSmi), I8(71),
B(Star), R(4),
B(LdaConstant), U8(1),
B(Star), R(5),
......
......@@ -20,6 +20,34 @@ const six = BigInt(6);
assertSame(BigInt, BigInt.prototype.constructor)
}
// ToBigInt, NumberToBigInt, BigInt
{
assertThrows(() => BigInt(undefined), SyntaxError);
assertThrows(() => BigInt(null), SyntaxError);
assertThrows(() => BigInt({}), SyntaxError);
assertThrows(() => BigInt("foo"), SyntaxError);
}{
assertSame(BigInt(true), 1n);
assertSame(BigInt(false), 0n);
assertSame(BigInt(""), 0n);
assertSame(BigInt(" 42"), 42n);
assertSame(BigInt(-0), 0n);
assertSame(BigInt(42), 42n);
assertSame(BigInt(42n), 42n);
assertSame(BigInt(Object(42n)), 42n);
assertSame(BigInt(2**53 - 1), 9007199254740991n);
assertSame(BigInt(Object(2**53 - 1)), 9007199254740991n);
assertSame(BigInt([]), 0n);
}{
assertThrows(() => BigInt(NaN), RangeError);
assertThrows(() => BigInt(-Infinity), RangeError);
assertThrows(() => BigInt(+Infinity), RangeError);
assertThrows(() => BigInt(4.00000001), RangeError);
assertThrows(() => BigInt(Object(4.00000001)), RangeError);
assertThrows(() => BigInt(2**53), RangeError);
assertThrows(() => BigInt(2**1000), RangeError);
}
// BigInt.prototype[Symbol.toStringTag]
{
const toStringTag = Object.getOwnPropertyDescriptor(
......
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