Commit 6414e17d authored by Georg Neis's avatar Georg Neis Committed by Commit Bot

[bigint] Implement Bigint.asUintN.

R=jkummerow@chromium.org

Bug: v8:6791
Change-Id: I765790d8b163aff6725900f19e95a914c75a0fe9
Reviewed-on: https://chromium-review.googlesource.com/752521
Commit-Queue: Georg Neis <neis@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49132}
parent 8cf319fe
......@@ -79,11 +79,16 @@ BUILTIN(BigIntAsUintN) {
Handle<Object> bits_obj = args.atOrUndefined(isolate, 1);
Handle<Object> bigint_obj = args.atOrUndefined(isolate, 2);
// TODO(jkummerow): Implement.
USE(bits_obj);
USE(bigint_obj);
Handle<Object> bits;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, bits,
Object::ToIndex(isolate, bits_obj, MessageTemplate::kInvalidIndex));
UNIMPLEMENTED();
Handle<BigInt> bigint;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, bigint,
BigInt::FromObject(isolate, bigint_obj));
return *BigInt::AsUintN(bits->Number(), bigint);
}
BUILTIN(BigIntAsIntN) {
......
......@@ -533,6 +533,7 @@ class ErrorUtils : public AllStatic {
T(InvalidDataViewLength, "Invalid DataView length %") \
T(InvalidOffset, "Start offset % is outside the bounds of the buffer") \
T(InvalidHint, "Invalid hint: %") \
T(InvalidIndex, "Invalid value: not (convertible to) a safe integer") \
T(InvalidLanguageTag, "Invalid language tag: %") \
T(InvalidWeakMapKey, "Invalid value used as weak map key") \
T(InvalidWeakSetValue, "Invalid value used in weak set") \
......
......@@ -485,8 +485,7 @@ MaybeHandle<String> BigInt::ToString(Handle<BigInt> bigint, int radix) {
namespace {
bool IsSafeInteger(Handle<HeapNumber> number) {
double value = number->value();
bool IsSafeInteger(double value) {
if (std::isnan(value) || std::isinf(value)) return false;
// Let integer be ! ToInteger(value).
......@@ -504,7 +503,7 @@ MaybeHandle<BigInt> BigInt::FromNumber(Isolate* isolate,
if (number->IsSmi()) {
return isolate->factory()->NewBigIntFromInt(Smi::cast(*number)->value());
}
if (!IsSafeInteger(Handle<HeapNumber>::cast(number))) {
if (!IsSafeInteger(Handle<HeapNumber>::cast(number)->value())) {
THROW_NEW_ERROR(isolate,
NewRangeError(MessageTemplate::kBigIntFromNumber, number),
BigInt);
......@@ -1589,6 +1588,64 @@ MaybeHandle<String> BigInt::ToStringGeneric(Handle<BigInt> x, int radix) {
return result;
}
Handle<BigInt> BigInt::AsUintN(uint64_t n, Handle<BigInt> x) {
DCHECK_LE(n, kMaxSafeInteger);
Handle<BigInt> result = AbsoluteAsUintN(n, x);
if (!x->sign()) return result;
// x is negative.
// Note that result == -x % 2^n. We use the following facts:
// If result == 0, then x % 2^n == 0.
// If result != 0, then x % 2^n == 2^n - result.
if (result->is_zero()) return result;
return AbsoluteSub(PowerOfTwo(x->GetIsolate(), n), result, false);
}
Handle<BigInt> BigInt::AbsoluteAsUintN(uint64_t n, Handle<BigInt> x) {
DCHECK_LE(n, kMaxSafeInteger);
Isolate* isolate = x->GetIsolate();
if (n == 0) return isolate->factory()->NewBigIntFromInt(0);
uint64_t total_bits = x->length() * kDigitBits;
if (total_bits <= n) return x;
DCHECK_LE(n, kMaxInt);
int N = static_cast<int>(n);
int needed_digits = (N + (kDigitBits - 1)) / kDigitBits;
DCHECK_LE(needed_digits, x->length());
Handle<BigInt> result = isolate->factory()->NewBigIntRaw(needed_digits);
// Copy all digits except the MSD.
int last = needed_digits - 1;
for (int i = 0; i < last; i++) {
result->set_digit(i, x->digit(i));
}
// The MSD might contain extra bits that we don't want.
digit_t msd = x->digit(last);
digit_t mask = std::numeric_limits<digit_t>::max();
if (N % kDigitBits != 0) mask = mask >> (kDigitBits - (N % kDigitBits));
result->set_digit(last, msd & mask);
result->RightTrim();
return result;
}
Handle<BigInt> BigInt::PowerOfTwo(Isolate* isolate, uint64_t n) {
DCHECK_LE(n, kMaxSafeInteger);
STATIC_ASSERT(kMaxLengthBits < kMaxInt);
// Truncate n to (1 + kMaxLengthBits), such that it doesn't overflow int but
// still causes the allocation to fail if it was too large.
int needed_bits =
1 + static_cast<int>(std::min(n, static_cast<uint64_t>(kMaxLengthBits)));
int needed_digits = (needed_bits + (kDigitBits - 1)) / kDigitBits;
Handle<BigInt> result = isolate->factory()->NewBigInt(needed_digits);
// All bits are zero. Now set the "n-th" bit.
digit_t msd = static_cast<digit_t>(1) << (n % kDigitBits);
result->set_digit(needed_digits - 1, msd);
return result;
}
// Digit arithmetic helpers.
#if V8_TARGET_ARCH_32_BIT
......
......@@ -59,6 +59,8 @@ class V8_EXPORT_PRIVATE BigInt : public HeapObject {
// Exposed for tests, do not call directly. Use CompareToNumber() instead.
static ComparisonResult CompareToDouble(Handle<BigInt> x, double y);
static Handle<BigInt> AsUintN(uint64_t n, Handle<BigInt> x);
DECL_CAST(BigInt)
DECL_VERIFIER(BigInt)
DECL_PRINTER(BigInt)
......@@ -85,6 +87,9 @@ class V8_EXPORT_PRIVATE BigInt : public HeapObject {
// ECMAScript's ToBigInt (throws for Number input)
static MaybeHandle<BigInt> FromObject(Isolate* isolate, Handle<Object> obj);
// Specialized version of Exponentiate(FromNumber(2), n) for n >= 0.
static Handle<BigInt> PowerOfTwo(Isolate* isolate, uint64_t n);
// 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.
......@@ -118,6 +123,9 @@ class V8_EXPORT_PRIVATE BigInt : public HeapObject {
static Rounding DecideRounding(Handle<BigInt> x, int mantissa_bits_unset,
int digit_index, uint64_t current_digit);
// NOTE: If x is negative, don't rely on the sign of a non-zero result.
static Handle<BigInt> AbsoluteAsUintN(uint64_t n, Handle<BigInt> x);
static Handle<BigInt> AbsoluteAdd(Handle<BigInt> x, Handle<BigInt> y,
bool result_sign);
static Handle<BigInt> AbsoluteSub(Handle<BigInt> x, Handle<BigInt> y,
......
......@@ -263,6 +263,100 @@ const six = BigInt(6);
}
}
// .asUintN
{
assertEquals(2, BigInt.asUintN.length);
}{
assertEquals(0n, BigInt.asUintN(0, 0n));
assertEquals(0n, BigInt.asUintN(1, 0n));
assertEquals(0n, BigInt.asUintN(16, 0n));
assertEquals(0n, BigInt.asUintN(31, 0n));
assertEquals(0n, BigInt.asUintN(32, 0n));
assertEquals(0n, BigInt.asUintN(33, 0n));
assertEquals(0n, BigInt.asUintN(63, 0n));
assertEquals(0n, BigInt.asUintN(64, 0n));
assertEquals(0n, BigInt.asUintN(65, 0n));
assertEquals(0n, BigInt.asUintN(127, 0n));
assertEquals(0n, BigInt.asUintN(128, 0n));
assertEquals(0n, BigInt.asUintN(129, 0n));
}{
assertEquals(0n, BigInt.asUintN(0, 42n));
assertEquals(0n, BigInt.asUintN(1, 42n));
assertEquals(42n, BigInt.asUintN(16, 42n));
assertEquals(42n, BigInt.asUintN(31, 42n));
assertEquals(42n, BigInt.asUintN(32, 42n));
assertEquals(42n, BigInt.asUintN(33, 42n));
assertEquals(42n, BigInt.asUintN(63, 42n));
assertEquals(42n, BigInt.asUintN(64, 42n));
assertEquals(42n, BigInt.asUintN(65, 42n));
assertEquals(42n, BigInt.asUintN(127, 42n));
assertEquals(42n, BigInt.asUintN(128, 42n));
assertEquals(42n, BigInt.asUintN(129, 42n));
}{
assertEquals(0n, BigInt.asUintN(0, -42n));
assertEquals(0n, BigInt.asUintN(1, -42n));
assertEquals(65536n - 42n, BigInt.asUintN(16, -42n));
assertEquals(2147483648n - 42n, BigInt.asUintN(31, -42n));
assertEquals(4294967296n - 42n, BigInt.asUintN(32, -42n));
assertEquals(8589934592n - 42n, BigInt.asUintN(33, -42n));
assertEquals(9223372036854775808n - 42n, BigInt.asUintN(63, -42n));
assertEquals(18446744073709551616n - 42n, BigInt.asUintN(64, -42n));
assertEquals(36893488147419103232n - 42n, BigInt.asUintN(65, -42n));
// TODO(neis): Enable once we have exponentation.
// assertEquals(2n**127n - 42n, BigInt.asUintN(127, -42n));
// assertEquals(2n**128n - 42n, BigInt.asUintN(128, -42n));
// assertEquals(2n**129n - 42n, BigInt.asUintN(129, -42n));
}{
assertEquals(0n, BigInt.asUintN(0, 4294967295n));
assertEquals(1n, BigInt.asUintN(1, 4294967295n));
assertEquals(65535n, BigInt.asUintN(16, 4294967295n));
assertEquals(2147483647n, BigInt.asUintN(31, 4294967295n));
assertEquals(4294967295n, BigInt.asUintN(32, 4294967295n));
assertEquals(4294967295n, BigInt.asUintN(33, 4294967295n));
assertEquals(4294967295n, BigInt.asUintN(63, 4294967295n));
assertEquals(4294967295n, BigInt.asUintN(64, 4294967295n));
assertEquals(4294967295n, BigInt.asUintN(65, 4294967295n));
assertEquals(4294967295n, BigInt.asUintN(127, 4294967295n));
assertEquals(4294967295n, BigInt.asUintN(128, 4294967295n));
assertEquals(4294967295n, BigInt.asUintN(129, 4294967295n));
}{
assertEquals(0n, BigInt.asUintN(0, -4294967295n));
assertEquals(1n, BigInt.asUintN(1, -4294967295n));
assertEquals(1n, BigInt.asUintN(16, -4294967295n));
assertEquals(1n, BigInt.asUintN(31, -4294967295n));
assertEquals(1n, BigInt.asUintN(32, -4294967295n));
assertEquals(8589934592n - 4294967295n, BigInt.asUintN(33, -4294967295n));
assertEquals(9223372036854775808n - 4294967295n,
BigInt.asUintN(63, -4294967295n));
assertEquals(18446744073709551616n - 4294967295n,
BigInt.asUintN(64,-4294967295n));
assertEquals(36893488147419103232n - 4294967295n,
BigInt.asUintN(65, -4294967295n));
// TODO(neis): Enable once we have exponentation.
// assertEquals(2n**127n - 42n, BigInt.asUintN(127, -4294967295n));
// assertEquals(2n**128n - 42n, BigInt.asUintN(128, -4294967295n));
// assertEquals(2n**129n - 42n, BigInt.asUintN(129, -4294967295n));
}{
assertEquals(42n, BigInt.asUintN(2**32, 42n));
assertEquals(4294967295n, BigInt.asUintN(2**32, 4294967295n));
assertEquals(4294967296n, BigInt.asUintN(2**32, 4294967296n));
assertEquals(4294967297n, BigInt.asUintN(2**32, 4294967297n));
}{
assertEquals(
BigInt.parseInt("0x7234567812345678"),
BigInt.asUintN(63, BigInt.parseInt("0xf234567812345678")));
}{
assertThrows(() => BigInt.asUintN(2n, 12n), TypeError);
assertThrows(() => BigInt.asUintN(-1, 0n), RangeError);
assertThrows(() => BigInt.asUintN(2**53, 0n), RangeError);
assertEquals(0n, BigInt.asUintN({}, 12n));
assertEquals(0n, BigInt.asUintN(2.9999, 12n));
assertEquals(4n, BigInt.asUintN(3.1234, 12n));
}{
assertThrows(() => BigInt.asUintN(3, 12), TypeError);
assertEquals(4n, BigInt.asUintN(3, "12"));
}
// .parseInt
{
assertEquals("hellobigint", BigInt.parseInt("hellobigint", 32).toString(32));
......
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