[bigint] Fix ToStringBasePowerOfTwo for multi-digit BigInts
It was working fine for bases 2, 4, and 16; but not for 8 and 32. We have to take carryover from one digit to the next into account when bits_per_character is not a divisor of kDigitBits. Bug: v8:6791 Change-Id: Ia2cd13bdddb04b8abf1e4381e66ba4c88826fbf9 Reviewed-on: https://chromium-review.googlesource.com/685813 Reviewed-by: Jaroslav Sevcik <jarin@chromium.org> Commit-Queue: Jakob Kummerow <jkummerow@chromium.org> Cr-Commit-Position: refs/heads/master@{#48239}
This commit is contained in:
parent
f2414988ee
commit
4ff45e5120
@ -594,42 +594,57 @@ MaybeHandle<String> BigInt::ToStringBasePowerOfTwo(Handle<BigInt> x,
|
|||||||
STATIC_ASSERT(base::bits::IsPowerOfTwo(kDigitBits));
|
STATIC_ASSERT(base::bits::IsPowerOfTwo(kDigitBits));
|
||||||
DCHECK(base::bits::IsPowerOfTwo(radix));
|
DCHECK(base::bits::IsPowerOfTwo(radix));
|
||||||
DCHECK(radix >= 2 && radix <= 32);
|
DCHECK(radix >= 2 && radix <= 32);
|
||||||
Factory* factory = x->GetIsolate()->factory();
|
Isolate* isolate = x->GetIsolate();
|
||||||
// TODO(jkummerow): check in caller?
|
// TODO(jkummerow): check in caller?
|
||||||
if (x->is_zero()) return factory->NewStringFromStaticChars("0");
|
if (x->is_zero()) return isolate->factory()->NewStringFromStaticChars("0");
|
||||||
|
|
||||||
const int len = x->length();
|
const int length = x->length();
|
||||||
const bool sign = x->sign();
|
const bool sign = x->sign();
|
||||||
const int bits_per_char = base::bits::CountTrailingZeros32(radix);
|
const int bits_per_char = base::bits::CountTrailingZeros32(radix);
|
||||||
const int char_mask = radix - 1;
|
const int char_mask = radix - 1;
|
||||||
const int chars_per_digit = kDigitBits / bits_per_char;
|
// Compute the length of the resulting string: divide the bit length of the
|
||||||
// Compute the number of chars needed to represent the most significant
|
// BigInt by the number of bits representable per character (rounding up).
|
||||||
// bigint digit.
|
const digit_t msd = x->digit(length - 1);
|
||||||
int chars_for_msd = 0;
|
const int msd_leading_zeros = base::bits::CountLeadingZeros(msd);
|
||||||
for (digit_t msd = x->digit(len - 1); msd != 0; msd >>= bits_per_char) {
|
const size_t bit_length = length * kDigitBits - msd_leading_zeros;
|
||||||
chars_for_msd++;
|
const size_t chars_required =
|
||||||
|
(bit_length + bits_per_char - 1) / bits_per_char + sign;
|
||||||
|
|
||||||
|
if (chars_required > String::kMaxLength) {
|
||||||
|
THROW_NEW_ERROR(isolate, NewInvalidStringLengthError(), String);
|
||||||
}
|
}
|
||||||
// All other digits need chars_per_digit characters; a leading "-" needs one.
|
|
||||||
if ((String::kMaxLength - chars_for_msd - sign) / chars_per_digit < len - 1) {
|
|
||||||
CHECK(false); // TODO(jkummerow): Throw instead of crashing.
|
|
||||||
}
|
|
||||||
const int chars = chars_for_msd + (len - 1) * chars_per_digit + sign;
|
|
||||||
|
|
||||||
Handle<SeqOneByteString> result =
|
Handle<SeqOneByteString> result =
|
||||||
factory->NewRawOneByteString(chars).ToHandleChecked();
|
isolate->factory()
|
||||||
|
->NewRawOneByteString(static_cast<int>(chars_required))
|
||||||
|
.ToHandleChecked();
|
||||||
uint8_t* buffer = result->GetChars();
|
uint8_t* buffer = result->GetChars();
|
||||||
// Print the number into the string, starting from the last position.
|
// Print the number into the string, starting from the last position.
|
||||||
int pos = chars - 1;
|
int pos = static_cast<int>(chars_required - 1);
|
||||||
for (int i = 0; i < len - 1; i++) {
|
digit_t digit = 0;
|
||||||
digit_t digit = x->digit(i);
|
// Keeps track of how many unprocessed bits there are in {digit}.
|
||||||
for (int j = 0; j < chars_per_digit; j++) {
|
int available_bits = 0;
|
||||||
|
for (int i = 0; i < length - 1; i++) {
|
||||||
|
digit_t new_digit = x->digit(i);
|
||||||
|
// Take any leftover bits from the last iteration into account.
|
||||||
|
int current = (digit | (new_digit << available_bits)) & char_mask;
|
||||||
|
buffer[pos--] = kConversionChars[current];
|
||||||
|
int consumed_bits = bits_per_char - available_bits;
|
||||||
|
digit = new_digit >> consumed_bits;
|
||||||
|
available_bits = kDigitBits - consumed_bits;
|
||||||
|
while (available_bits >= bits_per_char) {
|
||||||
buffer[pos--] = kConversionChars[digit & char_mask];
|
buffer[pos--] = kConversionChars[digit & char_mask];
|
||||||
digit >>= bits_per_char;
|
digit >>= bits_per_char;
|
||||||
|
available_bits -= bits_per_char;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Print the most significant digit.
|
// Take any leftover bits from the last iteration into account.
|
||||||
for (digit_t msd = x->digit(len - 1); msd != 0; msd >>= bits_per_char) {
|
int current = (digit | (msd << available_bits)) & char_mask;
|
||||||
buffer[pos--] = kConversionChars[msd & char_mask];
|
buffer[pos--] = kConversionChars[current];
|
||||||
|
digit = msd >> (bits_per_char - available_bits);
|
||||||
|
while (digit != 0) {
|
||||||
|
buffer[pos--] = kConversionChars[digit & char_mask];
|
||||||
|
digit >>= bits_per_char;
|
||||||
}
|
}
|
||||||
if (sign) buffer[pos--] = '-';
|
if (sign) buffer[pos--] = '-';
|
||||||
DCHECK(pos == -1);
|
DCHECK(pos == -1);
|
||||||
|
Loading…
Reference in New Issue
Block a user