• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifndef V8_BIGINT_BIGINT_H_
6 #define V8_BIGINT_BIGINT_H_
7 
8 #include <stdint.h>
9 
10 #include <algorithm>
11 #include <cstring>
12 #include <iostream>
13 #include <vector>
14 
15 namespace v8 {
16 namespace bigint {
17 
18 // To play nice with embedders' macros, we define our own DCHECK here.
19 // It's only used in this file, and undef'ed at the end.
20 #ifdef DEBUG
21 #define BIGINT_H_DCHECK(cond)                         \
22   if (!(cond)) {                                      \
23     std::cerr << __FILE__ << ":" << __LINE__ << ": "; \
24     std::cerr << "Assertion failed: " #cond "\n";     \
25     abort();                                          \
26   }
27 
28 extern bool kAdvancedAlgorithmsEnabledInLibrary;
29 #else
30 #define BIGINT_H_DCHECK(cond) (void(0))
31 #endif
32 
33 // The type of a digit: a register-width unsigned integer.
34 using digit_t = uintptr_t;
35 using signed_digit_t = intptr_t;
36 #if UINTPTR_MAX == 0xFFFFFFFF
37 // 32-bit platform.
38 using twodigit_t = uint64_t;
39 #define HAVE_TWODIGIT_T 1
40 static constexpr int kLog2DigitBits = 5;
41 #elif UINTPTR_MAX == 0xFFFFFFFFFFFFFFFF
42 // 64-bit platform.
43 static constexpr int kLog2DigitBits = 6;
44 #if defined(__SIZEOF_INT128__)
45 using twodigit_t = __uint128_t;
46 #define HAVE_TWODIGIT_T 1
47 #endif  // defined(__SIZEOF_INT128__)
48 #else
49 #error Unsupported platform.
50 #endif
51 static constexpr int kDigitBits = 1 << kLog2DigitBits;
52 static_assert(kDigitBits == 8 * sizeof(digit_t), "inconsistent type sizes");
53 
54 // Describes an array of digits, also known as a BigInt. Unsigned.
55 // Does not own the memory it points at, and only gives read-only access to it.
56 // Digits are stored in little-endian order.
57 class Digits {
58  public:
59   // This is the constructor intended for public consumption.
Digits(digit_t * mem,int len)60   Digits(digit_t* mem, int len) : digits_(mem), len_(len) {
61     // Require 4-byte alignment (even on 64-bit platforms).
62     // TODO(jkummerow): See if we can tighten BigInt alignment in V8 to
63     // system pointer size, and raise this requirement to that.
64     BIGINT_H_DCHECK((reinterpret_cast<uintptr_t>(mem) & 3) == 0);
65   }
66   // Provides a "slice" view into another Digits object.
Digits(Digits src,int offset,int len)67   Digits(Digits src, int offset, int len)
68       : digits_(src.digits_ + offset),
69         len_(std::max(0, std::min(src.len_ - offset, len))) {
70     BIGINT_H_DCHECK(offset >= 0);
71   }
72   // Alternative way to get a "slice" view into another Digits object.
73   Digits operator+(int i) {
74     BIGINT_H_DCHECK(i >= 0 && i <= len_);
75     return Digits(digits_ + i, len_ - i);
76   }
77 
78   // Provides access to individual digits.
79   digit_t operator[](int i) {
80     BIGINT_H_DCHECK(i >= 0 && i < len_);
81     return read_4byte_aligned(i);
82   }
83   // Convenience accessor for the most significant digit.
msd()84   digit_t msd() {
85     BIGINT_H_DCHECK(len_ > 0);
86     return read_4byte_aligned(len_ - 1);
87   }
88   // Checks "pointer equality" (does not compare digits contents).
89   bool operator==(const Digits& other) const {
90     return digits_ == other.digits_ && len_ == other.len_;
91   }
92 
93   // Decrements {len_} until there are no leading zero digits left.
Normalize()94   void Normalize() {
95     while (len_ > 0 && msd() == 0) len_--;
96   }
97   // Unconditionally drops exactly one leading zero digit.
TrimOne()98   void TrimOne() {
99     BIGINT_H_DCHECK(len_ > 0 && msd() == 0);
100     len_--;
101   }
102 
len()103   int len() { return len_; }
digits()104   const digit_t* digits() const { return digits_; }
105 
106  protected:
107   friend class ShiftedDigits;
108   digit_t* digits_;
109   int len_;
110 
111  private:
112   // We require externally-provided digits arrays to be 4-byte aligned, but
113   // not necessarily 8-byte aligned; so on 64-bit platforms we use memcpy
114   // to allow unaligned reads.
read_4byte_aligned(int i)115   digit_t read_4byte_aligned(int i) {
116     if (sizeof(digit_t) == 4) {
117       return digits_[i];
118     } else {
119       digit_t result;
120       memcpy(&result, digits_ + i, sizeof(result));
121       return result;
122     }
123   }
124 };
125 
126 // Writable version of a Digits array.
127 // Does not own the memory it points at.
128 class RWDigits : public Digits {
129  public:
RWDigits(digit_t * mem,int len)130   RWDigits(digit_t* mem, int len) : Digits(mem, len) {}
RWDigits(RWDigits src,int offset,int len)131   RWDigits(RWDigits src, int offset, int len) : Digits(src, offset, len) {}
132   RWDigits operator+(int i) {
133     BIGINT_H_DCHECK(i >= 0 && i <= len_);
134     return RWDigits(digits_ + i, len_ - i);
135   }
136 
137 #if UINTPTR_MAX == 0xFFFFFFFF
138   digit_t& operator[](int i) {
139     BIGINT_H_DCHECK(i >= 0 && i < len_);
140     return digits_[i];
141   }
142 #else
143   // 64-bit platform. We only require digits arrays to be 4-byte aligned,
144   // so we use a wrapper class to allow regular array syntax while
145   // performing unaligned memory accesses under the hood.
146   class WritableDigitReference {
147    public:
148     // Support "X[i] = x" notation.
149     void operator=(digit_t digit) { memcpy(ptr_, &digit, sizeof(digit)); }
150     // Support "X[i] = Y[j]" notation.
151     WritableDigitReference& operator=(const WritableDigitReference& src) {
152       memcpy(ptr_, src.ptr_, sizeof(digit_t));
153       return *this;
154     }
155     // Support "x = X[i]" notation.
digit_t()156     operator digit_t() {
157       digit_t result;
158       memcpy(&result, ptr_, sizeof(result));
159       return result;
160     }
161 
162    private:
163     // This class is not for public consumption.
164     friend class RWDigits;
165     // Primary constructor.
WritableDigitReference(digit_t * ptr)166     explicit WritableDigitReference(digit_t* ptr)
167         : ptr_(reinterpret_cast<uint32_t*>(ptr)) {}
168     // Required for returning WDR instances from "operator[]" below.
169     WritableDigitReference(const WritableDigitReference& src) = default;
170 
171     uint32_t* ptr_;
172   };
173 
174   WritableDigitReference operator[](int i) {
175     BIGINT_H_DCHECK(i >= 0 && i < len_);
176     return WritableDigitReference(digits_ + i);
177   }
178 #endif
179 
digits()180   digit_t* digits() { return digits_; }
set_len(int len)181   void set_len(int len) { len_ = len; }
182 
Clear()183   void Clear() { memset(digits_, 0, len_ * sizeof(digit_t)); }
184 };
185 
186 class Platform {
187  public:
188   virtual ~Platform() = default;
189 
190   // If you want the ability to interrupt long-running operations, implement
191   // a Platform subclass that overrides this method. It will be queried
192   // every now and then by long-running operations.
InterruptRequested()193   virtual bool InterruptRequested() { return false; }
194 };
195 
196 // These are the operations that this library supports.
197 // The signatures follow the convention:
198 //
199 //   void Operation(RWDigits results, Digits inputs);
200 //
201 // You must preallocate the result; use the respective {OperationResultLength}
202 // function to determine its minimum required length. The actual result may
203 // be smaller, so you should call result.Normalize() on the result.
204 //
205 // The operations are divided into two groups: "fast" (O(n) with small
206 // coefficient) operations are exposed directly as free functions, "slow"
207 // operations are methods on a {Processor} object, which provides
208 // support for interrupting execution via the {Platform}'s {InterruptRequested}
209 // mechanism when it takes too long. These functions return a {Status} value.
210 
211 // Returns r such that r < 0 if A < B; r > 0 if A > B; r == 0 if A == B.
212 // Defined here to be inlineable, which helps ia32 a lot (64-bit platforms
213 // don't care).
Compare(Digits A,Digits B)214 inline int Compare(Digits A, Digits B) {
215   A.Normalize();
216   B.Normalize();
217   int diff = A.len() - B.len();
218   if (diff != 0) return diff;
219   int i = A.len() - 1;
220   while (i >= 0 && A[i] == B[i]) i--;
221   if (i < 0) return 0;
222   return A[i] > B[i] ? 1 : -1;
223 }
224 
225 // Z := X + Y
226 void Add(RWDigits Z, Digits X, Digits Y);
227 // Addition of signed integers. Returns true if the result is negative.
228 bool AddSigned(RWDigits Z, Digits X, bool x_negative, Digits Y,
229                bool y_negative);
230 // Z := X + 1
231 void AddOne(RWDigits Z, Digits X);
232 
233 // Z := X - Y. Requires X >= Y.
234 void Subtract(RWDigits Z, Digits X, Digits Y);
235 // Subtraction of signed integers. Returns true if the result is negative.
236 bool SubtractSigned(RWDigits Z, Digits X, bool x_negative, Digits Y,
237                     bool y_negative);
238 // Z := X - 1
239 void SubtractOne(RWDigits Z, Digits X);
240 
241 // The bitwise operations assume that negative BigInts are represented as
242 // sign+magnitude. Their behavior depends on the sign of the inputs: negative
243 // inputs perform an implicit conversion to two's complement representation.
244 // Z := X & Y
245 void BitwiseAnd_PosPos(RWDigits Z, Digits X, Digits Y);
246 // Call this for a BigInt x = (magnitude=X, negative=true).
247 void BitwiseAnd_NegNeg(RWDigits Z, Digits X, Digits Y);
248 // Positive X, negative Y. Callers must swap arguments as needed.
249 void BitwiseAnd_PosNeg(RWDigits Z, Digits X, Digits Y);
250 void BitwiseOr_PosPos(RWDigits Z, Digits X, Digits Y);
251 void BitwiseOr_NegNeg(RWDigits Z, Digits X, Digits Y);
252 void BitwiseOr_PosNeg(RWDigits Z, Digits X, Digits Y);
253 void BitwiseXor_PosPos(RWDigits Z, Digits X, Digits Y);
254 void BitwiseXor_NegNeg(RWDigits Z, Digits X, Digits Y);
255 void BitwiseXor_PosNeg(RWDigits Z, Digits X, Digits Y);
256 void LeftShift(RWDigits Z, Digits X, digit_t shift);
257 // RightShiftState is provided by RightShift_ResultLength and used by the actual
258 // RightShift to avoid some recomputation.
259 struct RightShiftState {
260   bool must_round_down = false;
261 };
262 void RightShift(RWDigits Z, Digits X, digit_t shift,
263                 const RightShiftState& state);
264 
265 // Z := (least significant n bits of X, interpreted as a signed n-bit integer).
266 // Returns true if the result is negative; Z will hold the absolute value.
267 bool AsIntN(RWDigits Z, Digits X, bool x_negative, int n);
268 // Z := (least significant n bits of X).
269 void AsUintN_Pos(RWDigits Z, Digits X, int n);
270 // Same, but X is the absolute value of a negative BigInt.
271 void AsUintN_Neg(RWDigits Z, Digits X, int n);
272 
273 enum class Status { kOk, kInterrupted };
274 
275 class FromStringAccumulator;
276 
277 class Processor {
278  public:
279   // Takes ownership of {platform}.
280   static Processor* New(Platform* platform);
281 
282   // Use this for any std::unique_ptr holding an instance of {Processor}.
283   class Destroyer {
284    public:
operator()285     void operator()(Processor* proc) { proc->Destroy(); }
286   };
287   // When not using std::unique_ptr, call this to delete the instance.
288   void Destroy();
289 
290   // Z := X * Y
291   Status Multiply(RWDigits Z, Digits X, Digits Y);
292   // Q := A / B
293   Status Divide(RWDigits Q, Digits A, Digits B);
294   // R := A % B
295   Status Modulo(RWDigits R, Digits A, Digits B);
296 
297   // {out_length} initially contains the allocated capacity of {out}, and
298   // upon return will be set to the actual length of the result string.
299   Status ToString(char* out, int* out_length, Digits X, int radix, bool sign);
300 
301   // Z := the contents of {accumulator}.
302   // Assume that this leaves {accumulator} in unusable state.
303   Status FromString(RWDigits Z, FromStringAccumulator* accumulator);
304 
305  protected:
306   // Use {Destroy} or {Destroyer} instead of the destructor directly.
307   ~Processor() = default;
308 };
309 
AddResultLength(int x_length,int y_length)310 inline int AddResultLength(int x_length, int y_length) {
311   return std::max(x_length, y_length) + 1;
312 }
AddSignedResultLength(int x_length,int y_length,bool same_sign)313 inline int AddSignedResultLength(int x_length, int y_length, bool same_sign) {
314   return same_sign ? AddResultLength(x_length, y_length)
315                    : std::max(x_length, y_length);
316 }
SubtractResultLength(int x_length,int y_length)317 inline int SubtractResultLength(int x_length, int y_length) { return x_length; }
SubtractSignedResultLength(int x_length,int y_length,bool same_sign)318 inline int SubtractSignedResultLength(int x_length, int y_length,
319                                       bool same_sign) {
320   return same_sign ? std::max(x_length, y_length)
321                    : AddResultLength(x_length, y_length);
322 }
MultiplyResultLength(Digits X,Digits Y)323 inline int MultiplyResultLength(Digits X, Digits Y) {
324   return X.len() + Y.len();
325 }
326 constexpr int kBarrettThreshold = 13310;
DivideResultLength(Digits A,Digits B)327 inline int DivideResultLength(Digits A, Digits B) {
328 #if V8_ADVANCED_BIGINT_ALGORITHMS
329   BIGINT_H_DCHECK(kAdvancedAlgorithmsEnabledInLibrary);
330   // The Barrett division algorithm needs one extra digit for temporary use.
331   int kBarrettExtraScratch = B.len() >= kBarrettThreshold ? 1 : 0;
332 #else
333   // If this fails, set -DV8_ADVANCED_BIGINT_ALGORITHMS in any compilation unit
334   // that #includes this header.
335   BIGINT_H_DCHECK(!kAdvancedAlgorithmsEnabledInLibrary);
336   constexpr int kBarrettExtraScratch = 0;
337 #endif
338   return A.len() - B.len() + 1 + kBarrettExtraScratch;
339 }
ModuloResultLength(Digits B)340 inline int ModuloResultLength(Digits B) { return B.len(); }
341 
342 int ToStringResultLength(Digits X, int radix, bool sign);
343 // In DEBUG builds, the result of {ToString} will be initialized to this value.
344 constexpr char kStringZapValue = '?';
345 
BitwiseAnd_PosPos_ResultLength(int x_length,int y_length)346 inline int BitwiseAnd_PosPos_ResultLength(int x_length, int y_length) {
347   return std::min(x_length, y_length);
348 }
BitwiseAnd_NegNeg_ResultLength(int x_length,int y_length)349 inline int BitwiseAnd_NegNeg_ResultLength(int x_length, int y_length) {
350   // Result length growth example: -2 & -3 = -4 (2-bit inputs, 3-bit result).
351   return std::max(x_length, y_length) + 1;
352 }
BitwiseAnd_PosNeg_ResultLength(int x_length)353 inline int BitwiseAnd_PosNeg_ResultLength(int x_length) { return x_length; }
BitwiseOrResultLength(int x_length,int y_length)354 inline int BitwiseOrResultLength(int x_length, int y_length) {
355   return std::max(x_length, y_length);
356 }
BitwiseXor_PosPos_ResultLength(int x_length,int y_length)357 inline int BitwiseXor_PosPos_ResultLength(int x_length, int y_length) {
358   return std::max(x_length, y_length);
359 }
BitwiseXor_NegNeg_ResultLength(int x_length,int y_length)360 inline int BitwiseXor_NegNeg_ResultLength(int x_length, int y_length) {
361   return std::max(x_length, y_length);
362 }
BitwiseXor_PosNeg_ResultLength(int x_length,int y_length)363 inline int BitwiseXor_PosNeg_ResultLength(int x_length, int y_length) {
364   // Result length growth example: 3 ^ -1 == -4 (2-bit inputs, 3-bit result).
365   return std::max(x_length, y_length) + 1;
366 }
LeftShift_ResultLength(int x_length,digit_t x_most_significant_digit,digit_t shift)367 inline int LeftShift_ResultLength(int x_length,
368                                   digit_t x_most_significant_digit,
369                                   digit_t shift) {
370   int digit_shift = static_cast<int>(shift / kDigitBits);
371   int bits_shift = static_cast<int>(shift % kDigitBits);
372   bool grow = bits_shift != 0 &&
373               (x_most_significant_digit >> (kDigitBits - bits_shift)) != 0;
374   return x_length + digit_shift + grow;
375 }
376 int RightShift_ResultLength(Digits X, bool x_sign, digit_t shift,
377                             RightShiftState* state);
378 
379 // Returns -1 if this "asIntN" operation would be a no-op.
380 int AsIntNResultLength(Digits X, bool x_negative, int n);
381 // Returns -1 if this "asUintN" operation would be a no-op.
382 int AsUintN_Pos_ResultLength(Digits X, int n);
AsUintN_Neg_ResultLength(int n)383 inline int AsUintN_Neg_ResultLength(int n) {
384   return ((n - 1) / kDigitBits) + 1;
385 }
386 
387 // Support for parsing BigInts from Strings, using an Accumulator object
388 // for intermediate state.
389 
390 class ProcessorImpl;
391 
392 #if !defined(DEBUG) && (defined(__GNUC__) || defined(__clang__))
393 // Clang supports this since 3.9, GCC since 4.x.
394 #define ALWAYS_INLINE inline __attribute__((always_inline))
395 #elif !defined(DEBUG) && defined(_MSC_VER)
396 #define ALWAYS_INLINE __forceinline
397 #else
398 #define ALWAYS_INLINE inline
399 #endif
400 
401 static constexpr int kStackParts = 8;
402 
403 // A container object for all metadata required for parsing a BigInt from
404 // a string.
405 // Aggressively optimized not to waste instructions for small cases, while
406 // also scaling transparently to huge cases.
407 // Defined here in the header so that it can be inlined.
408 class FromStringAccumulator {
409  public:
410   enum class Result { kOk, kMaxSizeExceeded };
411 
412   // Step 1: Create a FromStringAccumulator instance. For best performance,
413   // stack allocation is recommended.
414   // {max_digits} is only used for refusing to grow beyond a given size
415   // (see "Step 2" below). It does not cause pre-allocation, so feel free to
416   // specify a large maximum.
417   // TODO(jkummerow): The limit applies to the number of intermediate chunks,
418   // whereas the final result will be slightly smaller (depending on {radix}).
419   // So for sufficiently large N, setting max_digits=N here will not actually
420   // allow parsing BigInts with N digits. We can fix that if/when anyone cares.
FromStringAccumulator(int max_digits)421   explicit FromStringAccumulator(int max_digits)
422       : max_digits_(std::max(max_digits, kStackParts)) {}
423 
424   // Step 2: Call this method to read all characters.
425   // {CharIt} should be a forward iterator and
426   // std::iterator_traits<CharIt>::value_type shall be a character type, such as
427   // uint8_t or uint16_t. {end} should be one past the last character (i.e.
428   // {start == end} would indicate an empty string). Returns the current
429   // position when an invalid character is encountered.
430   template <class CharIt>
431   ALWAYS_INLINE CharIt Parse(CharIt start, CharIt end, digit_t radix);
432 
433   // Step 3: Check if a result is available, and determine its required
434   // allocation size (guaranteed to be <= max_digits passed to the constructor).
result()435   Result result() { return result_; }
ResultLength()436   int ResultLength() {
437     return std::max(stack_parts_used_, static_cast<int>(heap_parts_.size()));
438   }
439 
440   // Step 4: Use BigIntProcessor::FromString() to retrieve the result into an
441   // {RWDigits} struct allocated for the size returned by step 3.
442 
443  private:
444   friend class ProcessorImpl;
445 
446   template <class CharIt>
447   ALWAYS_INLINE CharIt ParsePowerTwo(CharIt start, CharIt end, digit_t radix);
448 
449   ALWAYS_INLINE bool AddPart(digit_t multiplier, digit_t part, bool is_last);
450   ALWAYS_INLINE bool AddPart(digit_t part);
451 
452   digit_t stack_parts_[kStackParts];
453   std::vector<digit_t> heap_parts_;
454   digit_t max_multiplier_{0};
455   digit_t last_multiplier_;
456   const int max_digits_;
457   Result result_{Result::kOk};
458   int stack_parts_used_{0};
459   bool inline_everything_{false};
460   uint8_t radix_{0};
461 };
462 
463 // The rest of this file is the inlineable implementation of
464 // FromStringAccumulator methods.
465 
466 #if defined(__GNUC__) || defined(__clang__)
467 // Clang supports this since 3.9, GCC since 5.x.
468 #define HAVE_BUILTIN_MUL_OVERFLOW 1
469 #else
470 #define HAVE_BUILTIN_MUL_OVERFLOW 0
471 #endif
472 
473 // Numerical value of the first 127 ASCII characters, using 255 as sentinel
474 // for "invalid".
475 static constexpr uint8_t kCharValue[] = {
476     255, 255, 255, 255, 255, 255, 255, 255,  // 0..7
477     255, 255, 255, 255, 255, 255, 255, 255,  // 8..15
478     255, 255, 255, 255, 255, 255, 255, 255,  // 16..23
479     255, 255, 255, 255, 255, 255, 255, 255,  // 24..31
480     255, 255, 255, 255, 255, 255, 255, 255,  // 32..39
481     255, 255, 255, 255, 255, 255, 255, 255,  // 40..47
482     0,   1,   2,   3,   4,   5,   6,   7,    // 48..55    '0' == 48
483     8,   9,   255, 255, 255, 255, 255, 255,  // 56..63    '9' == 57
484     255, 10,  11,  12,  13,  14,  15,  16,   // 64..71    'A' == 65
485     17,  18,  19,  20,  21,  22,  23,  24,   // 72..79
486     25,  26,  27,  28,  29,  30,  31,  32,   // 80..87
487     33,  34,  35,  255, 255, 255, 255, 255,  // 88..95    'Z' == 90
488     255, 10,  11,  12,  13,  14,  15,  16,   // 96..103   'a' == 97
489     17,  18,  19,  20,  21,  22,  23,  24,   // 104..111
490     25,  26,  27,  28,  29,  30,  31,  32,   // 112..119
491     33,  34,  35,  255, 255, 255, 255, 255,  // 120..127  'z' == 122
492 };
493 
494 // A space- and time-efficient way to map {2,4,8,16,32} to {1,2,3,4,5}.
495 static constexpr uint8_t kCharBits[] = {1, 2, 3, 0, 4, 0, 0, 0, 5};
496 
497 template <class CharIt>
ParsePowerTwo(CharIt current,CharIt end,digit_t radix)498 CharIt FromStringAccumulator::ParsePowerTwo(CharIt current, CharIt end,
499                                             digit_t radix) {
500   radix_ = static_cast<uint8_t>(radix);
501   const int char_bits = kCharBits[radix >> 2];
502   int bits_left;
503   bool done = false;
504   do {
505     digit_t part = 0;
506     bits_left = kDigitBits;
507     while (true) {
508       digit_t d;  // Numeric value of the current character {c}.
509       uint32_t c = *current;
510       if (c > 127 || (d = bigint::kCharValue[c]) >= radix) {
511         done = true;
512         break;
513       }
514 
515       if (bits_left < char_bits) break;
516       bits_left -= char_bits;
517       part = (part << char_bits) | d;
518 
519       ++current;
520       if (current == end) {
521         done = true;
522         break;
523       }
524     }
525     if (!AddPart(part)) return current;
526   } while (!done);
527   // We use the unused {last_multiplier_} field to
528   // communicate how many bits are unused in the last part.
529   last_multiplier_ = bits_left;
530   return current;
531 }
532 
533 template <class CharIt>
Parse(CharIt start,CharIt end,digit_t radix)534 CharIt FromStringAccumulator::Parse(CharIt start, CharIt end, digit_t radix) {
535   BIGINT_H_DCHECK(2 <= radix && radix <= 36);
536   CharIt current = start;
537 #if !HAVE_BUILTIN_MUL_OVERFLOW
538   const digit_t kMaxMultiplier = (~digit_t{0}) / radix;
539 #endif
540 #if HAVE_TWODIGIT_T  // The inlined path requires twodigit_t availability.
541   // The max supported radix is 36, and Math.log2(36) == 5.169..., so we
542   // need at most 5.17 bits per char.
543   static constexpr int kInlineThreshold = kStackParts * kDigitBits * 100 / 517;
544   inline_everything_ = (end - start) <= kInlineThreshold;
545 #endif
546   if (!inline_everything_ && (radix & (radix - 1)) == 0) {
547     return ParsePowerTwo(start, end, radix);
548   }
549   bool done = false;
550   do {
551     digit_t multiplier = 1;
552     digit_t part = 0;
553     while (true) {
554       digit_t d;  // Numeric value of the current character {c}.
555       uint32_t c = *current;
556       if (c > 127 || (d = bigint::kCharValue[c]) >= radix) {
557         done = true;
558         break;
559       }
560 
561 #if HAVE_BUILTIN_MUL_OVERFLOW
562       digit_t new_multiplier;
563       if (__builtin_mul_overflow(multiplier, radix, &new_multiplier)) break;
564       multiplier = new_multiplier;
565 #else
566       if (multiplier > kMaxMultiplier) break;
567       multiplier *= radix;
568 #endif
569       part = part * radix + d;
570 
571       ++current;
572       if (current == end) {
573         done = true;
574         break;
575       }
576     }
577     if (!AddPart(multiplier, part, done)) return current;
578   } while (!done);
579   return current;
580 }
581 
AddPart(digit_t multiplier,digit_t part,bool is_last)582 bool FromStringAccumulator::AddPart(digit_t multiplier, digit_t part,
583                                     bool is_last) {
584 #if HAVE_TWODIGIT_T
585   if (inline_everything_) {
586     // Inlined version of {MultiplySingle}.
587     digit_t carry = part;
588     digit_t high = 0;
589     for (int i = 0; i < stack_parts_used_; i++) {
590       twodigit_t result = twodigit_t{stack_parts_[i]} * multiplier;
591       digit_t new_high = result >> bigint::kDigitBits;
592       digit_t low = static_cast<digit_t>(result);
593       result = twodigit_t{low} + high + carry;
594       carry = result >> bigint::kDigitBits;
595       stack_parts_[i] = static_cast<digit_t>(result);
596       high = new_high;
597     }
598     stack_parts_[stack_parts_used_++] = carry + high;
599     return true;
600   }
601 #else
602   BIGINT_H_DCHECK(!inline_everything_);
603 #endif
604   if (is_last) {
605     last_multiplier_ = multiplier;
606   } else {
607     BIGINT_H_DCHECK(max_multiplier_ == 0 || max_multiplier_ == multiplier);
608     max_multiplier_ = multiplier;
609   }
610   return AddPart(part);
611 }
612 
AddPart(digit_t part)613 bool FromStringAccumulator::AddPart(digit_t part) {
614   if (stack_parts_used_ < kStackParts) {
615     stack_parts_[stack_parts_used_++] = part;
616     return true;
617   }
618   if (heap_parts_.size() == 0) {
619     // Initialize heap storage. Copy the stack part to make things easier later.
620     heap_parts_.reserve(kStackParts * 2);
621     for (int i = 0; i < kStackParts; i++) {
622       heap_parts_.push_back(stack_parts_[i]);
623     }
624   }
625   if (static_cast<int>(heap_parts_.size()) >= max_digits_) {
626     result_ = Result::kMaxSizeExceeded;
627     return false;
628   }
629   heap_parts_.push_back(part);
630   return true;
631 }
632 
633 }  // namespace bigint
634 }  // namespace v8
635 
636 #undef BIGINT_H_DCHECK
637 #undef ALWAYS_INLINE
638 #undef HAVE_BUILTIN_MUL_OVERFLOW
639 
640 #endif  // V8_BIGINT_BIGINT_H_
641