v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
tostring.cc
Go to the documentation of this file.
1// Copyright 2021 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <cstring>
6#include <limits>
7
11#include "src/bigint/util.h"
13
14namespace v8 {
15namespace bigint {
16
17namespace {
18
19// Lookup table for the maximum number of bits required per character of a
20// base-N string representation of a number. To increase accuracy, the array
21// value is the actual value multiplied by 32. To generate this table:
22// for (var i = 0; i <= 36; i++) { print(Math.ceil(Math.log2(i) * 32) + ","); }
23constexpr uint8_t kMaxBitsPerChar[] = {
24 0, 0, 32, 51, 64, 75, 83, 90, 96, // 0..8
25 102, 107, 111, 115, 119, 122, 126, 128, // 9..16
26 131, 134, 136, 139, 141, 143, 145, 147, // 17..24
27 149, 151, 153, 154, 156, 158, 159, 160, // 25..32
28 162, 163, 165, 166, // 33..36
29};
30
31static const int kBitsPerCharTableShift = 5;
32static const size_t kBitsPerCharTableMultiplier = 1u << kBitsPerCharTableShift;
33
34static const char kConversionChars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
35
36// Raises {base} to the power of {exponent}. Does not check for overflow.
37digit_t digit_pow(digit_t base, digit_t exponent) {
38 digit_t result = 1ull;
39 while (exponent > 0) {
40 if (exponent & 1) {
41 result *= base;
42 }
43 exponent >>= 1;
44 base *= base;
45 }
46 return result;
47}
48
49// Compile-time version of the above.
50constexpr digit_t digit_pow_rec(digit_t base, digit_t exponent) {
51 return exponent == 1 ? base : base * digit_pow_rec(base, exponent - 1);
52}
53
54// A variant of ToStringFormatter::BasecaseLast, specialized for a radix
55// known at compile-time.
56template <int radix>
57char* BasecaseFixedLast(digit_t chunk, char* out) {
58 while (chunk != 0) {
59 DCHECK(*(out - 1) == kStringZapValue);
60 if (radix <= 10) {
61 *(--out) = '0' + (chunk % radix);
62 } else {
63 *(--out) = kConversionChars[chunk % radix];
64 }
65 chunk /= radix;
66 }
67 return out;
68}
69
70// By making {radix} a compile-time constant and computing {chunk_divisor}
71// as another compile-time constant from it, we allow the compiler to emit
72// an optimized instruction sequence based on multiplications with "magic"
73// numbers (modular multiplicative inverses) instead of actual divisions.
74// The price we pay is having to work on half digits; the technique doesn't
75// work with twodigit_t-by-digit_t divisions.
76// Includes an equivalent of ToStringFormatter::BasecaseMiddle, accordingly
77// specialized for a radix known at compile time.
78template <digit_t radix>
79char* DivideByMagic(RWDigits rest, Digits input, char* output) {
80 constexpr uint8_t max_bits_per_char = kMaxBitsPerChar[radix];
81 constexpr int chunk_chars =
82 kHalfDigitBits * kBitsPerCharTableMultiplier / max_bits_per_char;
83 constexpr digit_t chunk_divisor = digit_pow_rec(radix, chunk_chars);
85 for (int i = input.len() - 1; i >= 0; i--) {
86 digit_t d = input[i];
87 digit_t upper = (remainder << kHalfDigitBits) | (d >> kHalfDigitBits);
88 digit_t u_result = upper / chunk_divisor;
89 remainder = upper % chunk_divisor;
91 digit_t l_result = lower / chunk_divisor;
92 remainder = lower % chunk_divisor;
93 rest[i] = (u_result << kHalfDigitBits) | l_result;
94 }
95 // {remainder} is now the current chunk to be written out.
96 for (int i = 0; i < chunk_chars; i++) {
97 DCHECK(*(output - 1) == kStringZapValue);
98 if (radix <= 10) {
99 *(--output) = '0' + (remainder % radix);
100 } else {
101 *(--output) = kConversionChars[remainder % radix];
102 }
103 remainder /= radix;
104 }
105 DCHECK(remainder == 0);
106 return output;
107}
108
109class RecursionLevel;
110
111// The classic algorithm must check for interrupt requests if no faster
112// algorithm is available.
113#if V8_ADVANCED_BIGINT_ALGORITHMS
114#define MAYBE_INTERRUPT(code) ((void)0)
115#else
116#define MAYBE_INTERRUPT(code) code
117#endif
118
119class ToStringFormatter {
120 public:
121 ToStringFormatter(Digits X, int radix, bool sign, char* out,
122 uint32_t chars_available, ProcessorImpl* processor)
123 : digits_(X),
124 radix_(radix),
125 sign_(sign),
126 out_start_(out),
127 out_end_(out + chars_available),
128 out_(out_end_),
129 processor_(processor) {
130 digits_.Normalize();
131 DCHECK(chars_available >= ToStringResultLength(digits_, radix_, sign_));
132 }
133
134 void Start();
135 int Finish();
136
137 void Classic() {
138 if (digits_.len() == 0) {
139 *(--out_) = '0';
140 return;
141 }
142 if (digits_.len() == 1) {
143 out_ = BasecaseLast(digits_[0], out_);
144 return;
145 }
146 // {rest} holds the part of the BigInt that we haven't looked at yet.
147 // Not to be confused with "remainder"!
148 ScratchDigits rest(digits_.len());
149 // In the first round, divide the input, allocating a new BigInt for
150 // the result == rest; from then on divide the rest in-place.
151 Digits dividend = digits_;
152 do {
153 if (radix_ == 10) {
154 // Faster but costs binary size, so we optimize the most common case.
155 out_ = DivideByMagic<10>(rest, dividend, out_);
156 MAYBE_INTERRUPT(processor_->AddWorkEstimate(rest.len() * 2));
157 } else {
158 digit_t chunk;
159 processor_->DivideSingle(rest, &chunk, dividend, chunk_divisor_);
160 out_ = BasecaseMiddle(chunk, out_);
161 // Assume that a division is about ten times as expensive as a
162 // multiplication.
163 MAYBE_INTERRUPT(processor_->AddWorkEstimate(rest.len() * 10));
164 }
165 MAYBE_INTERRUPT(if (processor_->should_terminate()) return );
166 rest.Normalize();
167 dividend = rest;
168 } while (rest.len() > 1);
169 out_ = BasecaseLast(rest[0], out_);
170 }
171
172 void BasePowerOfTwo();
173
174 void Fast();
175 char* FillWithZeros(RecursionLevel* level, char* prev_cursor, char* out,
176 bool is_last_on_level);
177 char* ProcessLevel(RecursionLevel* level, Digits chunk, char* out,
178 bool is_last_on_level);
179
180 private:
181 // When processing the last (most significant) digit, don't write leading
182 // zeros.
183 char* BasecaseLast(digit_t digit, char* out) {
184 if (radix_ == 10) return BasecaseFixedLast<10>(digit, out);
185 do {
186 DCHECK(*(out - 1) == kStringZapValue);
187 *(--out) = kConversionChars[digit % radix_];
188 digit /= radix_;
189 } while (digit > 0);
190 return out;
191 }
192
193 // When processing a middle (non-most significant) digit, always write the
194 // same number of characters (as many '0' as necessary).
195 char* BasecaseMiddle(digit_t digit, char* out) {
196 for (int i = 0; i < chunk_chars_; i++) {
197 DCHECK(*(out - 1) == kStringZapValue);
198 *(--out) = kConversionChars[digit % radix_];
199 digit /= radix_;
200 }
201 DCHECK(digit == 0);
202 return out;
203 }
204
205 Digits digits_;
209 bool sign_;
211 char* out_end_;
212 char* out_;
214 ProcessorImpl* processor_;
215};
216
217#undef MAYBE_INTERRUPT
218
219// Prepares data for {Classic}. Not needed for {BasePowerOfTwo}.
220void ToStringFormatter::Start() {
221 max_bits_per_char_ = kMaxBitsPerChar[radix_];
222 chunk_chars_ = kDigitBits * kBitsPerCharTableMultiplier / max_bits_per_char_;
223 chunk_divisor_ = digit_pow(radix_, chunk_chars_);
224 // By construction of chunk_chars_, there can't have been overflow.
226}
227
228int ToStringFormatter::Finish() {
230 DCHECK(out_ < out_end_); // At least one character was written.
231 while (out_ < out_end_ && *out_ == '0') out_++;
232 if (sign_) *(--out_) = '-';
233 int excess = 0;
234 if (out_ > out_start_) {
235 size_t actual_length = out_end_ - out_;
236 excess = static_cast<int>(out_ - out_start_);
237 std::memmove(out_start_, out_, actual_length);
238 }
239 return excess;
240}
241
242void ToStringFormatter::BasePowerOfTwo() {
243 const int bits_per_char = CountTrailingZeros(radix_);
244 const int char_mask = radix_ - 1;
245 digit_t digit = 0;
246 // Keeps track of how many unprocessed bits there are in {digit}.
247 int available_bits = 0;
248 for (int i = 0; i < digits_.len() - 1; i++) {
249 digit_t new_digit = digits_[i];
250 // Take any leftover bits from the last iteration into account.
251 int current = (digit | (new_digit << available_bits)) & char_mask;
252 *(--out_) = kConversionChars[current];
253 int consumed_bits = bits_per_char - available_bits;
254 digit = new_digit >> consumed_bits;
255 available_bits = kDigitBits - consumed_bits;
256 while (available_bits >= bits_per_char) {
257 *(--out_) = kConversionChars[digit & char_mask];
258 digit >>= bits_per_char;
259 available_bits -= bits_per_char;
260 }
261 }
262 // Take any leftover bits from the last iteration into account.
263 digit_t msd = digits_.msd();
264 int current = (digit | (msd << available_bits)) & char_mask;
265 *(--out_) = kConversionChars[current];
266 digit = msd >> (bits_per_char - available_bits);
267 while (digit != 0) {
268 *(--out_) = kConversionChars[digit & char_mask];
269 digit >>= bits_per_char;
270 }
271}
272
273#if V8_ADVANCED_BIGINT_ALGORITHMS
274
275// "Fast" divide-and-conquer conversion to string. The basic idea is to
276// recursively cut the BigInt in half (using a division with remainder,
277// the divisor being ~half as large (in bits) as the current dividend).
278//
279// As preparation, we build up a linked list of metadata for each recursion
280// level. We do this bottom-up, i.e. start with the level that will produce
281// two halves that are register-sized and bail out to the base case.
282// Each higher level (executed earlier, prepared later) uses a divisor that is
283// the square of the previously-created "next" level's divisor. Preparation
284// terminates when the current divisor is at least half as large as the bigint.
285// We also precompute each level's divisor's inverse, so we can use
286// Barrett division later.
287//
288// Example: say we want to format 1234567890123, and we can fit two decimal
289// digits into a register for the base case.
290//
291// 1234567890123
292// ↓
293// %100000000 (a) // RecursionLevel 2,
294// / \ // is_toplevel_ == true.
295// 12345 67890123
296// ↓ ↓
297// (e) %10000 %10000 (b) // RecursionLevel 1
298// / \ / \
299// 1 2345 6789 0123
300// ↓ (f) ↓ ↓ (d) ↓
301// (g) %100 %100 %100 %100 (c) // RecursionLevel 0
302// / \ / \ / \ / \
303// 00 01 23 45 67 89 01 23
304// ↓ ↓ ↓ ↓ ↓ ↓ ↓ // Base case.
305// "1" "23" "45" "67" "89" "01" "23"
306//
307// We start building RecursionLevels in order 0 -> 1 -> 2, performing the
308// squarings 100² = 10000 and 10000² = 100000000 each only once. Execution
309// then happens in order (a) through (g); lower-level divisors are used
310// repeatedly. We build the string from right to left.
311// Note that we can skip the division at (g) and fall through directly.
312// Also, note that there are two chunks with value 1: one of them must produce
313// a leading "0" in its string representation, the other must not.
314//
315// In this example, {base_divisor} is 100 and {base_char_count} is 2.
316
317// TODO(jkummerow): Investigate whether it is beneficial to build one or two
318// fewer RecursionLevels, and use the topmost level for more than one division.
319
320class RecursionLevel {
321 public:
322 static RecursionLevel* CreateLevels(digit_t base_divisor, int base_char_count,
323 int target_bit_length,
324 ProcessorImpl* processor);
325 ~RecursionLevel() { delete next_; }
326
327 void ComputeInverse(ProcessorImpl* proc, int dividend_length = 0);
328 Digits GetInverse(int dividend_length);
329
330 private:
331 friend class ToStringFormatter;
332 RecursionLevel(digit_t base_divisor, int base_char_count)
333 : char_count_(base_char_count), divisor_(1) {
334 divisor_[0] = base_divisor;
335 }
336 explicit RecursionLevel(RecursionLevel* next)
337 : char_count_(next->char_count_ * 2),
338 next_(next),
339 divisor_(next->divisor_.len() * 2) {
340 next->is_toplevel_ = false;
341 }
342
343 void LeftShiftDivisor() {
344 leading_zero_shift_ = CountLeadingZeros(divisor_.msd());
345 LeftShift(divisor_, divisor_, leading_zero_shift_);
346 }
347
348 int leading_zero_shift_{0};
349 // The number of characters generated by *each half* of this level.
350 int char_count_;
351 bool is_toplevel_{true};
352 RecursionLevel* next_{nullptr};
353 ScratchDigits divisor_;
354 std::unique_ptr<Storage> inverse_storage_;
355 Digits inverse_;
356};
357
358// static
359RecursionLevel* RecursionLevel::CreateLevels(digit_t base_divisor,
360 int base_char_count,
361 int target_bit_length,
362 ProcessorImpl* processor) {
363 RecursionLevel* level = new RecursionLevel(base_divisor, base_char_count);
364 // We can stop creating levels when the next level's divisor, which is the
365 // square of the current level's divisor, would be strictly bigger (in terms
366 // of its numeric value) than the input we're formatting. Since computing that
367 // next divisor is expensive, we want to predict the necessity based on bit
368 // lengths. Bit lengths are an imperfect predictor of numeric value, so we
369 // have to be careful:
370 // - since we can't estimate which one of two numbers of equal bit length
371 // is bigger, we have to aim for a strictly bigger bit length.
372 // - when squaring, the bit length sometimes doubles (e.g. 0b11² == 0b1001),
373 // but usually we "lose" a bit (e.g. 0b10² == 0b100).
374 while (BitLength(level->divisor_) * 2 - 1 <= target_bit_length) {
375 RecursionLevel* prev = level;
376 level = new RecursionLevel(prev);
377 processor->Multiply(level->divisor_, prev->divisor_, prev->divisor_);
378 if (processor->should_terminate()) {
379 delete level;
380 return nullptr;
381 }
382 level->divisor_.Normalize();
383 // Left-shifting the divisor must only happen after it's been used to
384 // compute the next divisor.
385 prev->LeftShiftDivisor();
386 prev->ComputeInverse(processor);
387 }
388 level->LeftShiftDivisor();
389 // Not calling info->ComputeInverse here so that it can take the input's
390 // length into account to save some effort on inverse generation.
391 return level;
392}
393
394// The top level might get by with a smaller inverse than we could maximally
395// compute, so the caller should provide the dividend length.
396void RecursionLevel::ComputeInverse(ProcessorImpl* processor,
397 int dividend_length) {
398 int inverse_len = divisor_.len();
399 if (dividend_length != 0) {
400 inverse_len = dividend_length - divisor_.len();
401 DCHECK(inverse_len <= divisor_.len());
402 }
403 int scratch_len = InvertScratchSpace(inverse_len);
404 ScratchDigits scratch(scratch_len);
405 Storage* inv_storage = new Storage(inverse_len + 1);
406 inverse_storage_.reset(inv_storage);
407 RWDigits inverse_initializer(inv_storage->get(), inverse_len + 1);
408 Digits input(divisor_, divisor_.len() - inverse_len, inverse_len);
409 processor->Invert(inverse_initializer, input, scratch);
410 inverse_initializer.TrimOne();
411 inverse_ = inverse_initializer;
412}
413
414Digits RecursionLevel::GetInverse(int dividend_length) {
415 DCHECK(inverse_.len() != 0);
416 int inverse_len = dividend_length - divisor_.len();
417 // If the bits in memory are reliable, then we always have enough digits
418 // in the inverse available. This is a Release-mode CHECK because malicious
419 // concurrent heap mutation can throw off the decisions made by the recursive
420 // procedure, and this is a good bottleneck to catch them.
421 CHECK(inverse_len <= inverse_.len());
422 return inverse_ + (inverse_.len() - inverse_len);
423}
424
425void ToStringFormatter::Fast() {
426 // As a sandbox proofing measure, we round up here. Using {BitLength(digits_)}
427 // would be technically optimal, but vulnerable to a malicious worker that
428 // uses an in-sandbox corruption primitive to concurrently toggle the MSD bits
429 // between the invocations of {CreateLevels} and {ProcessLevel}.
430 int target_bit_length = digits_.len() * kDigitBits;
431 std::unique_ptr<RecursionLevel> recursion_levels(RecursionLevel::CreateLevels(
432 chunk_divisor_, chunk_chars_, target_bit_length, processor_));
433 if (processor_->should_terminate()) return;
434 out_ = ProcessLevel(recursion_levels.get(), digits_, out_, true);
435}
436
437// Writes '0' characters right-to-left, starting at {out}-1, until the distance
438// from {right_boundary} to {out} equals the number of characters that {level}
439// is supposed to produce.
440char* ToStringFormatter::FillWithZeros(RecursionLevel* level,
441 char* right_boundary, char* out,
442 bool is_last_on_level) {
443 // Fill up with zeros up to the character count expected to be generated
444 // on this level; unless this is the left edge of the result.
445 if (is_last_on_level) return out;
446 int chunk_chars = level == nullptr ? chunk_chars_ : level->char_count_ * 2;
447 char* end = right_boundary - chunk_chars;
448 DCHECK(out >= end);
449 while (out > end) {
450 *(--out) = '0';
451 }
452 return out;
453}
454
455char* ToStringFormatter::ProcessLevel(RecursionLevel* level, Digits chunk,
456 char* out, bool is_last_on_level) {
457 // Step 0: if only one digit is left, bail out to the base case.
458 Digits normalized = chunk;
459 normalized.Normalize();
460 if (normalized.len() <= 1) {
461 char* right_boundary = out;
462 if (normalized.len() == 1) {
463 out = BasecaseLast(normalized[0], out);
464 }
465 return FillWithZeros(level, right_boundary, out, is_last_on_level);
466 }
467
468 // Step 1: If the chunk is guaranteed to remain smaller than the divisor
469 // even after left-shifting, fall through to the next level immediately.
470 if (normalized.len() < level->divisor_.len()) {
471 char* right_boundary = out;
472 out = ProcessLevel(level->next_, chunk, out, is_last_on_level);
473 return FillWithZeros(level, right_boundary, out, is_last_on_level);
474 }
475 // Step 2: Prepare the chunk.
476 bool allow_inplace_modification = chunk.digits() != digits_.digits();
477 Digits original_chunk = chunk;
478 ShiftedDigits chunk_shifted(chunk, level->leading_zero_shift_,
479 allow_inplace_modification);
480 chunk = chunk_shifted;
481 chunk.Normalize();
482 // Check (now precisely) if the chunk is smaller than the divisor.
483 int comparison = Compare(chunk, level->divisor_);
484 if (comparison <= 0) {
485 char* right_boundary = out;
486 if (comparison < 0) {
487 // If the chunk is strictly smaller than the divisor, we can process
488 // it directly on the next level as the right half, and know that the
489 // left half is all '0'.
490 // In case we shifted {chunk} in-place, we must undo that
491 // before the call...
492 chunk_shifted.Reset();
493 // ...and otherwise undo the {chunk = chunk_shifted} assignment above.
494 chunk = original_chunk;
495 out = ProcessLevel(level->next_, chunk, out, is_last_on_level);
496 } else {
497 DCHECK(comparison == 0);
498 // If the chunk is equal to the divisor, we know that the right half
499 // is all '0', and the left half is '...0001'.
500 // Handling this case specially is an optimization; we could also
501 // fall through to the generic "chunk > divisor" path below.
502 out = FillWithZeros(level->next_, right_boundary, out, false);
503 *(--out) = '1';
504 }
505 // In both cases, make sure the left half is fully written.
506 return FillWithZeros(level, right_boundary, out, is_last_on_level);
507 }
508 // Step 3: Allocate space for the results.
509 // Allocate one extra digit so the next level can left-shift in-place.
510 ScratchDigits right(level->divisor_.len() + 1);
511 // Allocate one extra digit because DivideBarrett requires it.
512 ScratchDigits left(chunk.len() - level->divisor_.len() + 1);
513
514 // Step 4: Divide to split {chunk} into {left} and {right}.
515 int inverse_len = chunk.len() - level->divisor_.len();
516 if (inverse_len == 0) {
517 processor_->DivideSchoolbook(left, right, chunk, level->divisor_);
518 } else if (level->divisor_.len() == 1) {
519 processor_->DivideSingle(left, right.digits(), chunk, level->divisor_[0]);
520 for (int i = 1; i < right.len(); i++) right[i] = 0;
521 } else {
522 ScratchDigits scratch(DivideBarrettScratchSpace(chunk.len()));
523 // The top level only computes its inverse when {chunk.len()} is
524 // available. Other levels have precomputed theirs.
525 if (level->is_toplevel_) {
526 level->ComputeInverse(processor_, chunk.len());
527 if (processor_->should_terminate()) return out;
528 }
529 Digits inverse = level->GetInverse(chunk.len());
530 processor_->DivideBarrett(left, right, chunk, level->divisor_, inverse,
531 scratch);
532 if (processor_->should_terminate()) return out;
533 }
534 RightShift(right, right, level->leading_zero_shift_);
535#if DEBUG
536 Digits left_test = left;
537 left_test.Normalize();
538 DCHECK(left_test.len() <= level->divisor_.len());
539#endif
540
541 // Step 5: Recurse.
542 char* end_of_right_part = ProcessLevel(level->next_, right, out, false);
543 if (processor_->should_terminate()) return out;
544 // The recursive calls are required and hence designed to write exactly as
545 // many characters as their level is responsible for.
546 DCHECK(end_of_right_part == out - level->char_count_);
547 USE(end_of_right_part);
548 // We intentionally don't use {end_of_right_part} here to be prepared for
549 // potential future multi-threaded execution.
550 return ProcessLevel(level->next_, left, out - level->char_count_,
551 is_last_on_level);
552}
553
554#endif // V8_ADVANCED_BIGINT_ALGORITHMS
555
556} // namespace
557
558void ProcessorImpl::ToString(char* out, uint32_t* out_length, Digits X,
559 int radix, bool sign) {
560 const bool use_fast_algorithm = X.len() >= kToStringFastThreshold;
561 ToStringImpl(out, out_length, X, radix, sign, use_fast_algorithm);
562}
563
564// Factored out so that tests can call it.
565void ProcessorImpl::ToStringImpl(char* out, uint32_t* out_length, Digits X,
566 int radix, bool sign, bool fast) {
567#if DEBUG
568 for (uint32_t i = 0; i < *out_length; i++) out[i] = kStringZapValue;
569#endif
570 ToStringFormatter formatter(X, radix, sign, out, *out_length, this);
571 if (IsPowerOfTwo(radix)) {
572 formatter.BasePowerOfTwo();
573#if V8_ADVANCED_BIGINT_ALGORITHMS
574 } else if (fast) {
575 formatter.Start();
576 formatter.Fast();
577 if (should_terminate()) return;
578#else
579 USE(fast);
580#endif // V8_ADVANCED_BIGINT_ALGORITHMS
581 } else {
582 formatter.Start();
583 formatter.Classic();
584 }
585 int excess = formatter.Finish();
586 *out_length -= excess;
587 memset(out + *out_length, 0, excess);
588}
589
590Status Processor::ToString(char* out, uint32_t* out_length, Digits X, int radix,
591 bool sign) {
592 ProcessorImpl* impl = static_cast<ProcessorImpl*>(this);
593 impl->ToString(out, out_length, X, radix, sign);
594 return impl->get_and_clear_status();
595}
596
597uint32_t ToStringResultLength(Digits X, int radix, bool sign) {
598 const uint32_t bit_length = BitLength(X);
599 uint32_t result;
600 if (IsPowerOfTwo(radix)) {
601 const uint32_t bits_per_char = CountTrailingZeros(radix);
602 result = DIV_CEIL(bit_length, bits_per_char) + sign;
603 } else {
604 // Maximum number of bits we can represent with one character.
605 const uint8_t max_bits_per_char = kMaxBitsPerChar[radix];
606 // For estimating the result length, we have to be pessimistic and work with
607 // the minimum number of bits one character can represent.
608 const uint8_t min_bits_per_char = max_bits_per_char - 1;
609 // Perform the following computation with uint64_t to avoid overflows.
610 uint64_t chars_required = bit_length;
611 chars_required *= kBitsPerCharTableMultiplier;
612 chars_required = DIV_CEIL(chars_required, min_bits_per_char);
613 DCHECK(chars_required <
614 static_cast<uint64_t>(std::numeric_limits<uint32_t>::max()));
615 result = static_cast<uint32_t>(chars_required);
616 }
617 result += sign;
618 return result;
619}
620
621} // namespace bigint
622} // namespace v8
void ToString(char *out, uint32_t *out_length, Digits X, int radix, bool sign)
Definition tostring.cc:558
void ToStringImpl(char *out, uint32_t *out_length, Digits X, int radix, bool sign, bool use_fast_algorithm)
Definition tostring.cc:565
Status ToString(char *out, uint32_t *out_length, Digits X, int radix, bool sign)
Definition tostring.cc:590
int end
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in allocation gc speed threshold for starting incremental marking via a task in percent of available threshold for starting incremental marking immediately in percent of available Use a single schedule for determining a marking schedule between JS and C objects schedules the minor GC task with kUserVisible priority max worker number of concurrent for NumberOfWorkerThreads start background threads that allocate memory concurrent_array_buffer_sweeping use parallel threads to clear weak refs in the atomic pause trace progress of the incremental marking trace object counts and memory usage report a tick only when allocated zone memory changes by this amount TracingFlags::gc_stats TracingFlags::gc_stats track native contexts that are expected to be garbage collected verify heap pointers before and after GC memory reducer runs GC with ReduceMemoryFootprint flag Maximum number of memory reducer GCs scheduled Old gen GC speed is computed directly from gc tracer counters Perform compaction on full GCs based on V8 s default heuristics Perform compaction on every full GC Perform code space compaction when finalizing a full GC with stack Stress GC compaction to flush out bugs with moving objects flush of baseline code when it has not been executed recently Use time base code flushing instead of age Use a progress bar to scan large objects in increments when incremental marking is active force incremental marking for small heaps and run it more often force marking at random points between and X(inclusive) percent " "of the regular marking start limit") DEFINE_INT(stress_scavenge
double remainder
ZoneVector< RpoNumber > & result
ProcessorImpl * processor_
Definition mul-fft.cc:474
constexpr unsigned CountLeadingZeros(T value)
Definition bits.h:100
constexpr unsigned CountTrailingZeros(T value)
Definition bits.h:144
uint32_t ToStringResultLength(Digits X, int radix, bool sign)
Definition tostring.cc:597
constexpr int BitLength(int n)
Definition util.h:65
void LeftShift(RWDigits Z, Digits X, digit_t shift)
Definition bitwise.cc:136
static constexpr int kHalfDigitBits
constexpr char kStringZapValue
Definition bigint.h:355
static constexpr digit_t kHalfDigitMask
constexpr int CountTrailingZeros(uint32_t value)
Definition util.h:54
constexpr bool IsPowerOfTwo(int value)
Definition util.h:69
void RightShift(RWDigits Z, Digits X, digit_t shift, const RightShiftState &state)
Definition bitwise.cc:195
constexpr int InvertScratchSpace(int n)
constexpr int DivideBarrettScratchSpace(int n)
constexpr int kToStringFastThreshold
uintptr_t digit_t
Definition bigint.h:34
int Compare(const T &a, const T &b)
#define CHECK(condition)
Definition logging.h:124
#define DCHECK(condition)
Definition logging.h:482
#define USE(...)
Definition macros.h:293
#define MAYBE_INTERRUPT(code)
Definition tostring.cc:116
char * out_
Definition tostring.cc:212
int chunk_chars_
Definition tostring.cc:208
int max_bits_per_char_
Definition tostring.cc:207
int radix_
Definition tostring.cc:206
char * out_end_
Definition tostring.cc:211
Digits digits_
Definition tostring.cc:205
bool sign_
Definition tostring.cc:209
char * out_start_
Definition tostring.cc:210
digit_t chunk_divisor_
Definition tostring.cc:213
#define DIV_CEIL(x, y)
Definition util.h:19