Reland "[bigint] Fix early-return in asIntN"

For "top digit" (of the result) comparison to be applicable, we must
also check that there are no further digits in the source.

The included regression test flushes out another bug in "TruncateToNBits",
so that gets fixed here too (in contrast to the first landing attempt).

This reverts commit cb9e7af4e5.

Bug: v8:7150
Change-Id: Id631b1ae79e60b8e85ed4667e246a64c46765f2b
Reviewed-on: https://chromium-review.googlesource.com/807348
Reviewed-by: Georg Neis <neis@chromium.org>
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49877}
This commit is contained in:
Jakob Kummerow 2017-12-04 16:21:58 -08:00 committed by Commit Bot
parent 4d95c4b0c9
commit b4470ea4cf
2 changed files with 10 additions and 4 deletions

View File

@ -1928,12 +1928,13 @@ Handle<BigInt> BigInt::AsIntN(uint64_t n, Handle<BigInt> x) {
if (x->is_zero()) return x;
if (n == 0) return MutableBigInt::Zero(x->GetIsolate());
uint64_t needed_length = (n + kDigitBits - 1) / kDigitBits;
uint64_t x_length = static_cast<uint64_t>(x->length());
// If {x} has less than {n} bits, return it directly.
if (static_cast<uint64_t>(x->length()) < needed_length) return x;
if (x_length < needed_length) return x;
DCHECK_LE(needed_length, kMaxInt);
digit_t top_digit = x->digit(static_cast<int>(needed_length) - 1);
digit_t compare_digit = static_cast<digit_t>(1) << ((n - 1) % kDigitBits);
if (top_digit < compare_digit) return x;
if (x_length == needed_length && top_digit < compare_digit) return x;
// Otherwise we have to truncate (which is a no-op in the special case
// of x == -2^(n-1)), and determine the right sign. We also might have
// to subtract from 2^n to simulate having two's complement representation.
@ -2010,8 +2011,11 @@ Handle<BigInt> MutableBigInt::TruncateToNBits(int n, Handle<BigInt> x) {
// The MSD might contain extra bits that we don't want.
digit_t msd = x->digit(last);
int drop = kDigitBits - (n % kDigitBits);
result->set_digit(last, (msd << drop) >> drop);
if (n % kDigitBits != 0) {
int drop = kDigitBits - (n % kDigitBits);
msd = (msd << drop) >> drop;
}
result->set_digit(last, msd);
result->set_sign(x->sign());
return MakeImmutable(result);
}

View File

@ -145,6 +145,8 @@
}{
assertThrows(() => BigInt.asIntN(3, 12), TypeError);
assertEquals(-4n, BigInt.asIntN(3, "12"));
assertEquals(0x123456789abcdefn,
BigInt.asIntN(64, 0xabcdef0123456789abcdefn));
}
// BigInt.asUintN