[bigint] Avoid some allocations in BigInt.asIntN and BigInt.asUintN.

Bug: v8:6791
Change-Id: I05c8be6ac880c5ab5451db24dd0ad57b74bde8ba
Reviewed-on: https://chromium-review.googlesource.com/757137
Commit-Queue: Georg Neis <neis@chromium.org>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49232}
This commit is contained in:
Georg Neis 2017-11-08 09:52:00 +01:00 committed by Commit Bot
parent d16520127f
commit 1817199c18
2 changed files with 50 additions and 18 deletions

View File

@ -736,6 +736,23 @@ Handle<BigInt> BigInt::AbsoluteSub(Handle<BigInt> x, Handle<BigInt> y,
return result;
}
// Computes 2^n - abs(y), assuming 2^n >= abs(y).
Handle<BigInt> BigInt::AbsoluteSubFromPowerOfTwo(uint64_t n, Handle<BigInt> y,
bool result_sign) {
Handle<BigInt> x = PowerOfTwo(y->GetIsolate(), n);
digit_t borrow = x->InplaceSub(*y, 0);
for (int i = y->length(); borrow != 0; ++i) {
DCHECK_LT(i, x->length());
digit_t new_borrow = 0;
digit_t new_digit = digit_sub(x->digit(i), borrow, &new_borrow);
x->set_digit(i, new_digit);
borrow = new_borrow;
}
x->set_sign(result_sign);
x->RightTrim();
return x;
}
// Adds 1 to the absolute value of {x} and sets the result's sign to {sign}.
// {result_storage} is optional; if present, it will be used to store the
// result, otherwise a new BigInt will be allocated for the result.
@ -901,6 +918,32 @@ int BigInt::AbsoluteCompare(Handle<BigInt> x, Handle<BigInt> y) {
return x->digit(i) > y->digit(i) ? 1 : -1;
}
// Like AbsoluteCompare but only for y = 2^n.
int BigInt::AbsoluteCompareToPowerOfTwo(Handle<BigInt> x, uint64_t n) {
DCHECK_LE(n, kMaxSafeInteger);
int x_length = x->length();
uint64_t y_length = (n + kDigitBits) / kDigitBits;
if (static_cast<uint64_t>(x_length) < y_length) return -1;
if (static_cast<uint64_t>(x_length) > y_length) return +1;
DCHECK_NE(x_length, 0);
digit_t x_msd = x->digit(x_length - 1);
digit_t y_msd = static_cast<digit_t>(1) << (n % kDigitBits);
if (x_msd < y_msd) {
return -1;
} else if (x_msd > y_msd) {
return +1;
}
for (int i = 0; i < x_length - 1; ++i) {
if (x->digit(i) != 0) return 1;
}
return 0;
}
// Multiplies {multiplicand} with {multiplier} and adds the result to
// {accumulator}, starting at {accumulator_index} for the least-significant
// digit.
@ -1590,33 +1633,19 @@ MaybeHandle<String> BigInt::ToStringGeneric(Handle<BigInt> x, int radix) {
Handle<BigInt> BigInt::AsIntN(uint64_t n, Handle<BigInt> x) {
DCHECK_LE(n, kMaxSafeInteger);
Isolate* isolate = x->GetIsolate();
Handle<BigInt> result = AbsoluteAsUintN(n, x);
if (result->is_zero()) return result;
DCHECK_NE(n, 0);
DCHECK(!x->is_zero());
// Compare abs(result) against 2^(n-1).
int comparison;
{
// 2^(n-1) needs n bits.
uint64_t power_length = (n + kDigitBits - 1) / kDigitBits;
if (static_cast<uint64_t>(result->length()) < power_length) {
comparison = -1;
} else {
DCHECK_EQ(result->length(), power_length);
DCHECK_LE(n, kMaxInt);
// TODO(neis): Ideally we shouldn't allocate here at all.
comparison = AbsoluteCompare(result, PowerOfTwo(isolate, n - 1));
}
}
int comparison = AbsoluteCompareToPowerOfTwo(result, n - 1);
if (!x->sign()) {
// x is positive. Note that result == x mod 2^n.
if (comparison < 0) return result;
// Return (x mod 2^n) - 2^n, which is -(2^n - x mod 2^n).
return AbsoluteSub(PowerOfTwo(isolate, n), result, true);
return AbsoluteSubFromPowerOfTwo(n, result, true);
}
// x is negative. Note that abs(result) == -x mod 2^n.
@ -1631,7 +1660,7 @@ Handle<BigInt> BigInt::AsIntN(uint64_t n, Handle<BigInt> x) {
return result->sign() ? result : UnaryMinus(result);
}
// Return x mod 2^n.
return AbsoluteSub(PowerOfTwo(isolate, n), result, false);
return AbsoluteSubFromPowerOfTwo(n, result, false);
}
Handle<BigInt> BigInt::AsUintN(uint64_t n, Handle<BigInt> x) {
@ -1644,7 +1673,7 @@ Handle<BigInt> BigInt::AsUintN(uint64_t n, Handle<BigInt> x) {
// a) If result == 0, then (x mod 2^n) == 0.
// b) If result != 0, then (x mod 2^n) == 2^n - abs(result).
if (result->is_zero()) return result;
return AbsoluteSub(PowerOfTwo(x->GetIsolate(), n), result, false);
return AbsoluteSubFromPowerOfTwo(n, result, false);
}
Handle<BigInt> BigInt::AbsoluteAsUintN(uint64_t n, Handle<BigInt> x) {

View File

@ -131,6 +131,8 @@ class V8_EXPORT_PRIVATE BigInt : public HeapObject {
bool result_sign);
static Handle<BigInt> AbsoluteSub(Handle<BigInt> x, Handle<BigInt> y,
bool result_sign);
static Handle<BigInt> AbsoluteSubFromPowerOfTwo(uint64_t n, Handle<BigInt> y,
bool result_sign);
static Handle<BigInt> AbsoluteAddOne(Handle<BigInt> x, bool sign,
BigInt* result_storage = nullptr);
static Handle<BigInt> AbsoluteSubOne(Handle<BigInt> x, int result_length);
@ -151,6 +153,7 @@ class V8_EXPORT_PRIVATE BigInt : public HeapObject {
BigInt* result_storage = nullptr);
static int AbsoluteCompare(Handle<BigInt> x, Handle<BigInt> y);
static int AbsoluteCompareToPowerOfTwo(Handle<BigInt> x, uint64_t n);
static void MultiplyAccumulate(Handle<BigInt> multiplicand,
digit_t multiplier, Handle<BigInt> accumulator,