%PDF- %PDF-
| Direktori : /home2/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/bigint/ |
| Current File : //home2/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/bigint/tostring.cc |
// Copyright 2021 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <cstring>
#include <limits>
#include "src/bigint/bigint-internal.h"
#include "src/bigint/digit-arithmetic.h"
#include "src/bigint/div-helpers.h"
#include "src/bigint/util.h"
#include "src/bigint/vector-arithmetic.h"
namespace v8 {
namespace bigint {
namespace {
// Lookup table for the maximum number of bits required per character of a
// base-N string representation of a number. To increase accuracy, the array
// value is the actual value multiplied by 32. To generate this table:
// for (var i = 0; i <= 36; i++) { print(Math.ceil(Math.log2(i) * 32) + ","); }
constexpr uint8_t kMaxBitsPerChar[] = {
0, 0, 32, 51, 64, 75, 83, 90, 96, // 0..8
102, 107, 111, 115, 119, 122, 126, 128, // 9..16
131, 134, 136, 139, 141, 143, 145, 147, // 17..24
149, 151, 153, 154, 156, 158, 159, 160, // 25..32
162, 163, 165, 166, // 33..36
};
static const int kBitsPerCharTableShift = 5;
static const size_t kBitsPerCharTableMultiplier = 1u << kBitsPerCharTableShift;
static const char kConversionChars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
// Raises {base} to the power of {exponent}. Does not check for overflow.
digit_t digit_pow(digit_t base, digit_t exponent) {
digit_t result = 1ull;
while (exponent > 0) {
if (exponent & 1) {
result *= base;
}
exponent >>= 1;
base *= base;
}
return result;
}
// Compile-time version of the above.
constexpr digit_t digit_pow_rec(digit_t base, digit_t exponent) {
return exponent == 1 ? base : base * digit_pow_rec(base, exponent - 1);
}
// A variant of ToStringFormatter::BasecaseLast, specialized for a radix
// known at compile-time.
template <int radix>
char* BasecaseFixedLast(digit_t chunk, char* out) {
while (chunk != 0) {
DCHECK(*(out - 1) == kStringZapValue);
if (radix <= 10) {
*(--out) = '0' + (chunk % radix);
} else {
*(--out) = kConversionChars[chunk % radix];
}
chunk /= radix;
}
return out;
}
// By making {radix} a compile-time constant and computing {chunk_divisor}
// as another compile-time constant from it, we allow the compiler to emit
// an optimized instruction sequence based on multiplications with "magic"
// numbers (modular multiplicative inverses) instead of actual divisions.
// The price we pay is having to work on half digits; the technique doesn't
// work with twodigit_t-by-digit_t divisions.
// Includes an equivalent of ToStringFormatter::BasecaseMiddle, accordingly
// specialized for a radix known at compile time.
template <digit_t radix>
char* DivideByMagic(RWDigits rest, Digits input, char* output) {
constexpr uint8_t max_bits_per_char = kMaxBitsPerChar[radix];
constexpr int chunk_chars =
kHalfDigitBits * kBitsPerCharTableMultiplier / max_bits_per_char;
constexpr digit_t chunk_divisor = digit_pow_rec(radix, chunk_chars);
digit_t remainder = 0;
for (int i = input.len() - 1; i >= 0; i--) {
digit_t d = input[i];
digit_t upper = (remainder << kHalfDigitBits) | (d >> kHalfDigitBits);
digit_t u_result = upper / chunk_divisor;
remainder = upper % chunk_divisor;
digit_t lower = (remainder << kHalfDigitBits) | (d & kHalfDigitMask);
digit_t l_result = lower / chunk_divisor;
remainder = lower % chunk_divisor;
rest[i] = (u_result << kHalfDigitBits) | l_result;
}
// {remainder} is now the current chunk to be written out.
for (int i = 0; i < chunk_chars; i++) {
DCHECK(*(output - 1) == kStringZapValue);
if (radix <= 10) {
*(--output) = '0' + (remainder % radix);
} else {
*(--output) = kConversionChars[remainder % radix];
}
remainder /= radix;
}
DCHECK(remainder == 0);
return output;
}
class RecursionLevel;
// The classic algorithm must check for interrupt requests if no faster
// algorithm is available.
#if V8_ADVANCED_BIGINT_ALGORITHMS
#define MAYBE_INTERRUPT(code) ((void)0)
#else
#define MAYBE_INTERRUPT(code) code
#endif
class ToStringFormatter {
public:
ToStringFormatter(Digits X, int radix, bool sign, char* out,
int chars_available, ProcessorImpl* processor)
: digits_(X),
radix_(radix),
sign_(sign),
out_start_(out),
out_end_(out + chars_available),
out_(out_end_),
processor_(processor) {
digits_.Normalize();
DCHECK(chars_available >= ToStringResultLength(digits_, radix_, sign_));
}
void Start();
int Finish();
void Classic() {
if (digits_.len() == 0) {
*(--out_) = '0';
return;
}
if (digits_.len() == 1) {
out_ = BasecaseLast(digits_[0], out_);
return;
}
// {rest} holds the part of the BigInt that we haven't looked at yet.
// Not to be confused with "remainder"!
ScratchDigits rest(digits_.len());
// In the first round, divide the input, allocating a new BigInt for
// the result == rest; from then on divide the rest in-place.
Digits dividend = digits_;
do {
if (radix_ == 10) {
// Faster but costs binary size, so we optimize the most common case.
out_ = DivideByMagic<10>(rest, dividend, out_);
MAYBE_INTERRUPT(processor_->AddWorkEstimate(rest.len() * 2));
} else {
digit_t chunk;
processor_->DivideSingle(rest, &chunk, dividend, chunk_divisor_);
out_ = BasecaseMiddle(chunk, out_);
// Assume that a division is about ten times as expensive as a
// multiplication.
MAYBE_INTERRUPT(processor_->AddWorkEstimate(rest.len() * 10));
}
MAYBE_INTERRUPT(if (processor_->should_terminate()) return );
rest.Normalize();
dividend = rest;
} while (rest.len() > 1);
out_ = BasecaseLast(rest[0], out_);
}
void BasePowerOfTwo();
void Fast();
char* FillWithZeros(RecursionLevel* level, char* prev_cursor, char* out,
bool is_last_on_level);
char* ProcessLevel(RecursionLevel* level, Digits chunk, char* out,
bool is_last_on_level);
private:
// When processing the last (most significant) digit, don't write leading
// zeros.
char* BasecaseLast(digit_t digit, char* out) {
if (radix_ == 10) return BasecaseFixedLast<10>(digit, out);
do {
DCHECK(*(out - 1) == kStringZapValue);
*(--out) = kConversionChars[digit % radix_];
digit /= radix_;
} while (digit > 0);
return out;
}
// When processing a middle (non-most significant) digit, always write the
// same number of characters (as many '0' as necessary).
char* BasecaseMiddle(digit_t digit, char* out) {
for (int i = 0; i < chunk_chars_; i++) {
DCHECK(*(out - 1) == kStringZapValue);
*(--out) = kConversionChars[digit % radix_];
digit /= radix_;
}
DCHECK(digit == 0);
return out;
}
Digits digits_;
int radix_;
int max_bits_per_char_ = 0;
int chunk_chars_ = 0;
bool sign_;
char* out_start_;
char* out_end_;
char* out_;
digit_t chunk_divisor_ = 0;
ProcessorImpl* processor_;
};
#undef MAYBE_INTERRUPT
// Prepares data for {Classic}. Not needed for {BasePowerOfTwo}.
void ToStringFormatter::Start() {
max_bits_per_char_ = kMaxBitsPerChar[radix_];
chunk_chars_ = kDigitBits * kBitsPerCharTableMultiplier / max_bits_per_char_;
chunk_divisor_ = digit_pow(radix_, chunk_chars_);
// By construction of chunk_chars_, there can't have been overflow.
DCHECK(chunk_divisor_ != 0);
}
int ToStringFormatter::Finish() {
DCHECK(out_ >= out_start_);
DCHECK(out_ < out_end_); // At least one character was written.
while (out_ < out_end_ && *out_ == '0') out_++;
if (sign_) *(--out_) = '-';
int excess = 0;
if (out_ > out_start_) {
size_t actual_length = out_end_ - out_;
excess = static_cast<int>(out_ - out_start_);
std::memmove(out_start_, out_, actual_length);
}
return excess;
}
void ToStringFormatter::BasePowerOfTwo() {
const int bits_per_char = CountTrailingZeros(radix_);
const int char_mask = radix_ - 1;
digit_t digit = 0;
// Keeps track of how many unprocessed bits there are in {digit}.
int available_bits = 0;
for (int i = 0; i < digits_.len() - 1; i++) {
digit_t new_digit = digits_[i];
// Take any leftover bits from the last iteration into account.
int current = (digit | (new_digit << available_bits)) & char_mask;
*(--out_) = 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) {
*(--out_) = kConversionChars[digit & char_mask];
digit >>= bits_per_char;
available_bits -= bits_per_char;
}
}
// Take any leftover bits from the last iteration into account.
digit_t msd = digits_.msd();
int current = (digit | (msd << available_bits)) & char_mask;
*(--out_) = kConversionChars[current];
digit = msd >> (bits_per_char - available_bits);
while (digit != 0) {
*(--out_) = kConversionChars[digit & char_mask];
digit >>= bits_per_char;
}
}
#if V8_ADVANCED_BIGINT_ALGORITHMS
// "Fast" divide-and-conquer conversion to string. The basic idea is to
// recursively cut the BigInt in half (using a division with remainder,
// the divisor being ~half as large (in bits) as the current dividend).
//
// As preparation, we build up a linked list of metadata for each recursion
// level. We do this bottom-up, i.e. start with the level that will produce
// two halves that are register-sized and bail out to the base case.
// Each higher level (executed earlier, prepared later) uses a divisor that is
// the square of the previously-created "next" level's divisor. Preparation
// terminates when the current divisor is at least half as large as the bigint.
// We also precompute each level's divisor's inverse, so we can use
// Barrett division later.
//
// Example: say we want to format 1234567890123, and we can fit two decimal
// digits into a register for the base case.
//
// 1234567890123
// ↓
// %100000000 (a) // RecursionLevel 2,
// / \ // is_toplevel_ == true.
// 12345 67890123
// ↓ ↓
// (e) %10000 %10000 (b) // RecursionLevel 1
// / \ / \
// 1 2345 6789 0123
// ↓ (f) ↓ ↓ (d) ↓
// (g) %100 %100 %100 %100 (c) // RecursionLevel 0
// / \ / \ / \ / \
// 00 01 23 45 67 89 01 23
// ↓ ↓ ↓ ↓ ↓ ↓ ↓ // Base case.
// "1" "23" "45" "67" "89" "01" "23"
//
// We start building RecursionLevels in order 0 -> 1 -> 2, performing the
// squarings 100² = 10000 and 10000² = 100000000 each only once. Execution
// then happens in order (a) through (g); lower-level divisors are used
// repeatedly. We build the string from right to left.
// Note that we can skip the division at (g) and fall through directly.
// Also, note that there are two chunks with value 1: one of them must produce
// a leading "0" in its string representation, the other must not.
//
// In this example, {base_divisor} is 100 and {base_char_count} is 2.
// TODO(jkummerow): Investigate whether it is beneficial to build one or two
// fewer RecursionLevels, and use the topmost level for more than one division.
class RecursionLevel {
public:
static RecursionLevel* CreateLevels(digit_t base_divisor, int base_char_count,
int target_bit_length,
ProcessorImpl* processor);
~RecursionLevel() { delete next_; }
void ComputeInverse(ProcessorImpl* proc, int dividend_length = 0);
Digits GetInverse(int dividend_length);
private:
friend class ToStringFormatter;
RecursionLevel(digit_t base_divisor, int base_char_count)
: char_count_(base_char_count), divisor_(1) {
divisor_[0] = base_divisor;
}
explicit RecursionLevel(RecursionLevel* next)
: char_count_(next->char_count_ * 2),
next_(next),
divisor_(next->divisor_.len() * 2) {
next->is_toplevel_ = false;
}
void LeftShiftDivisor() {
leading_zero_shift_ = CountLeadingZeros(divisor_.msd());
LeftShift(divisor_, divisor_, leading_zero_shift_);
}
int leading_zero_shift_{0};
// The number of characters generated by *each half* of this level.
int char_count_;
bool is_toplevel_{true};
RecursionLevel* next_{nullptr};
ScratchDigits divisor_;
std::unique_ptr<Storage> inverse_storage_;
Digits inverse_{nullptr, 0};
};
// static
RecursionLevel* RecursionLevel::CreateLevels(digit_t base_divisor,
int base_char_count,
int target_bit_length,
ProcessorImpl* processor) {
RecursionLevel* level = new RecursionLevel(base_divisor, base_char_count);
// 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;
level = new RecursionLevel(prev);
processor->Multiply(level->divisor_, prev->divisor_, prev->divisor_);
if (processor->should_terminate()) {
delete level;
return nullptr;
}
level->divisor_.Normalize();
// Left-shifting the divisor must only happen after it's been used to
// compute the next divisor.
prev->LeftShiftDivisor();
prev->ComputeInverse(processor);
}
level->LeftShiftDivisor();
// Not calling info->ComputeInverse here so that it can take the input's
// length into account to save some effort on inverse generation.
return level;
}
// The top level might get by with a smaller inverse than we could maximally
// compute, so the caller should provide the dividend length.
void RecursionLevel::ComputeInverse(ProcessorImpl* processor,
int dividend_length) {
int inverse_len = divisor_.len();
if (dividend_length != 0) {
inverse_len = dividend_length - divisor_.len();
DCHECK(inverse_len <= divisor_.len());
}
int scratch_len = InvertScratchSpace(inverse_len);
ScratchDigits scratch(scratch_len);
Storage* inv_storage = new Storage(inverse_len + 1);
inverse_storage_.reset(inv_storage);
RWDigits inverse_initializer(inv_storage->get(), inverse_len + 1);
Digits input(divisor_, divisor_.len() - inverse_len, inverse_len);
processor->Invert(inverse_initializer, input, scratch);
inverse_initializer.TrimOne();
inverse_ = inverse_initializer;
}
Digits RecursionLevel::GetInverse(int dividend_length) {
DCHECK(inverse_.len() != 0);
int inverse_len = dividend_length - divisor_.len();
DCHECK(inverse_len <= inverse_.len());
return inverse_ + (inverse_.len() - inverse_len);
}
void ToStringFormatter::Fast() {
std::unique_ptr<RecursionLevel> recursion_levels(RecursionLevel::CreateLevels(
chunk_divisor_, chunk_chars_, BitLength(digits_), processor_));
if (processor_->should_terminate()) return;
out_ = ProcessLevel(recursion_levels.get(), digits_, out_, true);
}
// Writes '0' characters right-to-left, starting at {out}-1, until the distance
// from {right_boundary} to {out} equals the number of characters that {level}
// is supposed to produce.
char* ToStringFormatter::FillWithZeros(RecursionLevel* level,
char* right_boundary, char* out,
bool is_last_on_level) {
// Fill up with zeros up to the character count expected to be generated
// on this level; unless this is the left edge of the result.
if (is_last_on_level) return out;
int chunk_chars = level == nullptr ? chunk_chars_ : level->char_count_ * 2;
char* end = right_boundary - chunk_chars;
DCHECK(out >= end);
while (out > end) {
*(--out) = '0';
}
return out;
}
char* ToStringFormatter::ProcessLevel(RecursionLevel* level, Digits chunk,
char* out, bool is_last_on_level) {
// Step 0: if only one digit is left, bail out to the base case.
Digits normalized = chunk;
normalized.Normalize();
if (normalized.len() <= 1) {
char* right_boundary = out;
if (normalized.len() == 1) {
out = BasecaseLast(normalized[0], out);
}
return FillWithZeros(level, right_boundary, out, is_last_on_level);
}
// Step 1: If the chunk is guaranteed to remain smaller than the divisor
// even after left-shifting, fall through to the next level immediately.
if (normalized.len() < level->divisor_.len()) {
char* right_boundary = out;
out = ProcessLevel(level->next_, chunk, out, is_last_on_level);
return FillWithZeros(level, right_boundary, out, is_last_on_level);
}
// Step 2: Prepare the chunk.
bool allow_inplace_modification = chunk.digits() != digits_.digits();
Digits original_chunk = chunk;
ShiftedDigits chunk_shifted(chunk, level->leading_zero_shift_,
allow_inplace_modification);
chunk = chunk_shifted;
chunk.Normalize();
// Check (now precisely) if the chunk is smaller than the divisor.
int comparison = Compare(chunk, level->divisor_);
if (comparison <= 0) {
char* right_boundary = out;
if (comparison < 0) {
// If the chunk is strictly smaller than the divisor, we can process
// it directly on the next level as the right half, and know that the
// left half is all '0'.
// In case we shifted {chunk} in-place, we must undo that
// before the call...
chunk_shifted.Reset();
// ...and otherwise undo the {chunk = chunk_shifted} assignment above.
chunk = original_chunk;
out = ProcessLevel(level->next_, chunk, out, is_last_on_level);
} else {
DCHECK(comparison == 0);
// If the chunk is equal to the divisor, we know that the right half
// is all '0', and the left half is '...0001'.
// Handling this case specially is an optimization; we could also
// fall through to the generic "chunk > divisor" path below.
out = FillWithZeros(level->next_, right_boundary, out, false);
*(--out) = '1';
}
// In both cases, make sure the left half is fully written.
return FillWithZeros(level, right_boundary, out, is_last_on_level);
}
// Step 3: Allocate space for the results.
// Allocate one extra digit so the next level can left-shift in-place.
ScratchDigits right(level->divisor_.len() + 1);
// Allocate one extra digit because DivideBarrett requires it.
ScratchDigits left(chunk.len() - level->divisor_.len() + 1);
// Step 4: Divide to split {chunk} into {left} and {right}.
int inverse_len = chunk.len() - level->divisor_.len();
if (inverse_len == 0) {
processor_->DivideSchoolbook(left, right, chunk, level->divisor_);
} else if (level->divisor_.len() == 1) {
processor_->DivideSingle(left, right.digits(), chunk, level->divisor_[0]);
for (int i = 1; i < right.len(); i++) right[i] = 0;
} else {
ScratchDigits scratch(DivideBarrettScratchSpace(chunk.len()));
// The top level only computes its inverse when {chunk.len()} is
// available. Other levels have precomputed theirs.
if (level->is_toplevel_) {
level->ComputeInverse(processor_, chunk.len());
if (processor_->should_terminate()) return out;
}
Digits inverse = level->GetInverse(chunk.len());
processor_->DivideBarrett(left, right, chunk, level->divisor_, inverse,
scratch);
if (processor_->should_terminate()) return out;
}
RightShift(right, right, level->leading_zero_shift_);
#if DEBUG
Digits left_test = left;
left_test.Normalize();
DCHECK(left_test.len() <= level->divisor_.len());
#endif
// Step 5: Recurse.
char* end_of_right_part = ProcessLevel(level->next_, right, out, false);
if (processor_->should_terminate()) return out;
// The recursive calls are required and hence designed to write exactly as
// many characters as their level is responsible for.
DCHECK(end_of_right_part == out - level->char_count_);
USE(end_of_right_part);
// We intentionally don't use {end_of_right_part} here to be prepared for
// potential future multi-threaded execution.
return ProcessLevel(level->next_, left, out - level->char_count_,
is_last_on_level);
}
#endif // V8_ADVANCED_BIGINT_ALGORITHMS
} // namespace
void ProcessorImpl::ToString(char* out, int* out_length, Digits X, int radix,
bool sign) {
const bool use_fast_algorithm = X.len() >= kToStringFastThreshold;
ToStringImpl(out, out_length, X, radix, sign, use_fast_algorithm);
}
// Factored out so that tests can call it.
void ProcessorImpl::ToStringImpl(char* out, int* out_length, Digits X,
int radix, bool sign, bool fast) {
#if DEBUG
for (int i = 0; i < *out_length; i++) out[i] = kStringZapValue;
#endif
ToStringFormatter formatter(X, radix, sign, out, *out_length, this);
if (IsPowerOfTwo(radix)) {
formatter.BasePowerOfTwo();
#if V8_ADVANCED_BIGINT_ALGORITHMS
} else if (fast) {
formatter.Start();
formatter.Fast();
if (should_terminate()) return;
#else
USE(fast);
#endif // V8_ADVANCED_BIGINT_ALGORITHMS
} else {
formatter.Start();
formatter.Classic();
}
int excess = formatter.Finish();
*out_length -= excess;
memset(out + *out_length, 0, excess);
}
Status Processor::ToString(char* out, int* out_length, Digits X, int radix,
bool sign) {
ProcessorImpl* impl = static_cast<ProcessorImpl*>(this);
impl->ToString(out, out_length, X, radix, sign);
return impl->get_and_clear_status();
}
int ToStringResultLength(Digits X, int radix, bool sign) {
const int bit_length = BitLength(X);
int result;
if (IsPowerOfTwo(radix)) {
const int bits_per_char = CountTrailingZeros(radix);
result = DIV_CEIL(bit_length, bits_per_char) + sign;
} else {
// Maximum number of bits we can represent with one character.
const uint8_t max_bits_per_char = kMaxBitsPerChar[radix];
// For estimating the result length, we have to be pessimistic and work with
// the minimum number of bits one character can represent.
const uint8_t min_bits_per_char = max_bits_per_char - 1;
// Perform the following computation with uint64_t to avoid overflows.
uint64_t chars_required = bit_length;
chars_required *= kBitsPerCharTableMultiplier;
chars_required = DIV_CEIL(chars_required, min_bits_per_char);
DCHECK(chars_required <
static_cast<uint64_t>(std::numeric_limits<int>::max()));
result = static_cast<int>(chars_required);
}
result += sign;
return result;
}
} // namespace bigint
} // namespace v8