[bigint] Fix corner-case bugs in fast .toString
Bug: v8:11515 Change-Id: Ieece676f2f4ae258db8b7e1783c796ff6c0fa6f4 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3055293 Reviewed-by: Maya Lekova <mslekova@chromium.org> Commit-Queue: Jakob Kummerow <jkummerow@chromium.org> Cr-Commit-Position: refs/heads/master@{#75956}
This commit is contained in:
parent
5404eaf159
commit
2d6ad4deb4
@ -124,6 +124,7 @@ void ProcessorImpl::InvertNewton(RWDigits Z, Digits V, RWDigits scratch) {
|
|||||||
|
|
||||||
// (3d): U = T * S, truncated so that at least 2k+1 fraction bits remain
|
// (3d): U = T * S, truncated so that at least 2k+1 fraction bits remain
|
||||||
// (U has one integer digit, which might be zero).
|
// (U has one integer digit, which might be zero).
|
||||||
|
fraction_digits = DIV_CEIL(2 * k + 1, kDigitBits);
|
||||||
RWDigits U(scratch, kUOffset, S.len() + T.len());
|
RWDigits U(scratch, kUOffset, S.len() + T.len());
|
||||||
DCHECK(U.len() > fraction_digits);
|
DCHECK(U.len() > fraction_digits);
|
||||||
Multiply(U, S, T);
|
Multiply(U, S, T);
|
||||||
@ -202,6 +203,7 @@ void ProcessorImpl::Invert(RWDigits Z, Digits V, RWDigits scratch) {
|
|||||||
InvertBasecase(Z, V, scratch);
|
InvertBasecase(Z, V, scratch);
|
||||||
if (Z[vn] == 1) {
|
if (Z[vn] == 1) {
|
||||||
for (int i = 0; i < vn; i++) Z[i] = ~digit_t{0};
|
for (int i = 0; i < vn; i++) Z[i] = ~digit_t{0};
|
||||||
|
Z[vn] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -358,7 +358,17 @@ RecursionLevel* RecursionLevel::CreateLevels(digit_t base_divisor,
|
|||||||
int target_bit_length,
|
int target_bit_length,
|
||||||
ProcessorImpl* processor) {
|
ProcessorImpl* processor) {
|
||||||
RecursionLevel* level = new RecursionLevel(base_divisor, base_char_count);
|
RecursionLevel* level = new RecursionLevel(base_divisor, base_char_count);
|
||||||
while (BitLength(level->divisor_) * 2 <= target_bit_length) {
|
// We can stop creating levels when the next level's divisor, which is the
|
||||||
|
// square of the current level's divisor, would be strictly bigger (in terms
|
||||||
|
// of its numeric value) than the input we're formatting. Since computing that
|
||||||
|
// next divisor is expensive, we want to predict the necessity based on bit
|
||||||
|
// lengths. Bit lengths are an imperfect predictor of numeric value, so we
|
||||||
|
// have to be careful:
|
||||||
|
// - since we can't estimate which one of two numbers of equal bit length
|
||||||
|
// is bigger, we have to aim for a strictly bigger bit length.
|
||||||
|
// - when squaring, the bit length sometimes doubles (e.g. 0b11² == 0b1001),
|
||||||
|
// but usually we "lose" a bit (e.g. 0b10² == 0b100).
|
||||||
|
while (BitLength(level->divisor_) * 2 - 1 <= target_bit_length) {
|
||||||
RecursionLevel* prev = level;
|
RecursionLevel* prev = level;
|
||||||
level = new RecursionLevel(prev);
|
level = new RecursionLevel(prev);
|
||||||
processor->Multiply(level->divisor_, prev->divisor_, prev->divisor_);
|
processor->Multiply(level->divisor_, prev->divisor_, prev->divisor_);
|
||||||
@ -439,15 +449,18 @@ char* ToStringFormatter::ProcessLevel(RecursionLevel* level, Digits chunk,
|
|||||||
return ProcessLevel(level->next_, chunk, out, is_last_on_level);
|
return ProcessLevel(level->next_, chunk, out, is_last_on_level);
|
||||||
}
|
}
|
||||||
// Step 2: Prepare the chunk.
|
// Step 2: Prepare the chunk.
|
||||||
bool allow_inplace_modification = !level->is_toplevel_;
|
bool allow_inplace_modification = chunk.digits() != digits_.digits();
|
||||||
|
Digits original_chunk = chunk;
|
||||||
ShiftedDigits chunk_shifted(chunk, level->leading_zero_shift_,
|
ShiftedDigits chunk_shifted(chunk, level->leading_zero_shift_,
|
||||||
allow_inplace_modification);
|
allow_inplace_modification);
|
||||||
chunk = chunk_shifted;
|
chunk = chunk_shifted;
|
||||||
chunk.Normalize();
|
chunk.Normalize();
|
||||||
// Check (now precisely) if the chunk is smaller than the divisor.
|
// Check (now precisely) if the chunk is smaller than the divisor.
|
||||||
if (Compare(chunk, level->divisor_) <= 0) {
|
if (Compare(chunk, level->divisor_) <= 0) {
|
||||||
// In case we shifted {chunk} in-place, we must undo that before the call.
|
// In case we shifted {chunk} in-place, we must undo that before the call...
|
||||||
chunk_shifted.Reset();
|
chunk_shifted.Reset();
|
||||||
|
// ...and otherwise undo the {chunk = chunk_shifted} assignment above.
|
||||||
|
chunk = original_chunk;
|
||||||
return ProcessLevel(level->next_, chunk, out, is_last_on_level);
|
return ProcessLevel(level->next_, chunk, out, is_last_on_level);
|
||||||
}
|
}
|
||||||
// Step 3: Allocate space for the results.
|
// Step 3: Allocate space for the results.
|
||||||
|
Loading…
Reference in New Issue
Block a user