v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
conversions.cc
Go to the documentation of this file.
1// Copyright 2011 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
6
7#include <limits.h>
8#include <stdarg.h>
9
10#include <cmath>
11#include <optional>
12
13#include "src/base/fpu.h"
17#include "src/bigint/bigint.h"
19#include "src/handles/handles.h"
20#include "src/heap/factory.h"
21#include "src/objects/bigint.h"
26#include "third_party/fast_float/src/include/fast_float/fast_float.h"
27#include "third_party/fast_float/src/include/fast_float/float_common.h"
28
29#if defined(_STLP_VENDOR_CSTD)
30// STLPort doesn't import fpclassify into the std namespace.
31#define FPCLASSIFY_NAMESPACE
32#else
33#define FPCLASSIFY_NAMESPACE std
34#endif
35
36namespace v8 {
37namespace internal {
38
39// Helper class for building result strings in a character buffer. The
40// purpose of the class is to use safe operations that checks the
41// buffer bounds on all operations in debug mode.
42// This simple base class does not allow formatted output.
44 public:
45 // Create a string builder with a buffer of the given size. The
46 // buffer is allocated through NewArray<char> and must be
47 // deallocated by the caller of Finalize().
48 explicit SimpleStringBuilder(size_t size) {
51 }
52
53 SimpleStringBuilder(char* buffer, size_t size)
54 : buffer_(buffer, size), cursor_(buffer) {}
55
59
60 // Get the current position in the builder.
61 size_t position() const {
63 return cursor_ - buffer_.begin();
64 }
65
66 // Add a single character to the builder. It is not allowed to add
67 // 0-characters; use the Finalize() method to terminate the string
68 // instead.
69 V8_INLINE void AddCharacter(char c) {
70 DCHECK_NE(c, '\0');
73 *cursor_++ = c;
74 }
75
76 // Add an entire string to the builder. 'len' must be equal to strlen().
77 V8_INLINE void AddString(const char* s, size_t len) {
78 DCHECK_EQ(len, strlen(s));
79 AddSubstring(s, len);
80 }
81
82 // Add a string literal to the builder.
83 template <size_t N>
84 V8_INLINE void AddStringLiteral(const char (&s)[N]) {
85 AddSubstring(s, N - 1);
86 }
87
88 // Add the first 'n' characters of the given 0-terminated string 's' to the
89 // builder. The input string must have enough characters.
90 V8_INLINE void AddSubstring(const char* s, size_t n) {
93 DCHECK_LE(n, strlen(s));
94 MemCopy(cursor_, s, n * kCharSize);
95 cursor_ += n;
96 }
97
98 // Add character padding to the builder. If count is non-positive,
99 // nothing is added to the builder.
100 V8_INLINE void AddPadding(char c, int count) {
102 DCHECK_LE(position() + std::max(0, count), buffer_.size());
103 cursor_ = std::fill_n(cursor_, count, c);
104 }
105
106 // Add the decimal representation of the value.
107 void AddDecimalInteger(int value) {
108 uint32_t number = static_cast<uint32_t>(value);
109 if (value < 0) {
110 AddCharacter('-');
111 number = static_cast<uint32_t>(-value);
112 }
113 int digits = 1;
114 for (uint32_t factor = 10; digits < 10; digits++, factor *= 10) {
115 if (factor > number) break;
116 }
117 cursor_ += digits;
118 for (int i = 1; i <= digits; i++) {
119 *(cursor_ - i) = '0' + static_cast<char>(number % 10);
120 number /= 10;
121 }
122 }
123
124 // Finalize the string by, checking that there is no null-character in the
125 // content. Returns a pointer one past the last character.
126 char* Finalize() {
129#ifdef DEBUG
130 // Make sure nobody managed to add a 0-character to the
131 // buffer while building the string.
132 for (const char* buf = buffer_.begin(); buf != cursor_; buf++) {
133 DCHECK_NE(*buf, '\0');
134 }
135#endif
136 char* ret = cursor_;
137 cursor_ = nullptr;
139 return ret;
140 }
141
142 private:
144 char* cursor_;
145
146 bool is_finalized() const { return cursor_ == nullptr; }
147
149};
150
154
155inline double SignedZero(bool negative) {
157}
158
159inline bool isDigit(int x, int radix) {
160 return (x >= '0' && x <= '9' && x < '0' + radix) ||
161 (radix > 10 && x >= 'a' && x < 'a' + radix - 10) ||
162 (radix > 10 && x >= 'A' && x < 'A' + radix - 10);
163}
164
165inline bool isBinaryDigit(int x) { return x == '0' || x == '1'; }
166
167template <class Char>
168bool SubStringEquals(const Char** current, const Char* end,
169 const char* substring) {
170 DCHECK(**current == *substring);
171 for (substring++; *substring != '\0'; substring++) {
172 ++*current;
173 if (*current == end || **current != *substring) return false;
174 }
175 ++*current;
176 return true;
177}
178
179// Returns true if a nonspace character has been found and false if the
180// end was been reached before finding a nonspace character.
181template <class Char>
182inline bool AdvanceToNonspace(const Char** current, const Char* end) {
183 while (*current != end) {
184 if (!IsWhiteSpaceOrLineTerminator(**current)) return true;
185 ++*current;
186 }
187 return false;
188}
189
190// Parsing integers with radix 2, 4, 8, 16, 32. Assumes current != end.
191template <int radix_log_2, class Char>
192double InternalStringToIntDouble(const Char* start, const Char* end,
193 bool negative, bool allow_trailing_junk) {
194 const Char* current = start;
195 DCHECK_NE(current, end);
196
197 // Skip leading 0s.
198 while (*current == '0') {
199 ++current;
200 if (current == end) return SignedZero(negative);
201 }
202
203 int64_t number = 0;
204 int exponent = 0;
205 constexpr int radix = (1 << radix_log_2);
206
207 constexpr int lim_0 = '0' + (radix < 10 ? radix : 10);
208 constexpr int lim_a = 'a' + (radix - 10);
209 constexpr int lim_A = 'A' + (radix - 10);
210
211 do {
212 int digit;
213 if (*current >= '0' && *current < lim_0) {
214 digit = static_cast<char>(*current) - '0';
215 } else if (*current >= 'a' && *current < lim_a) {
216 digit = static_cast<char>(*current) - 'a' + 10;
217 } else if (*current >= 'A' && *current < lim_A) {
218 digit = static_cast<char>(*current) - 'A' + 10;
219 } else {
220 // We've not found any digits, this must be junk.
221 if (current == start) return JunkStringValue();
222 if (allow_trailing_junk || !AdvanceToNonspace(&current, end)) break;
223 return JunkStringValue();
224 }
225
226 number = number * radix + digit;
227 int overflow = static_cast<int>(number >> 53);
228 if (overflow != 0) {
229 // Overflow occurred. Need to determine which direction to round the
230 // result.
231 int overflow_bits_count = 1;
232 while (overflow > 1) {
233 overflow_bits_count++;
234 overflow >>= 1;
235 }
236
237 int dropped_bits_mask = ((1 << overflow_bits_count) - 1);
238 int dropped_bits = static_cast<int>(number) & dropped_bits_mask;
239 number >>= overflow_bits_count;
240 exponent = overflow_bits_count;
241
242 bool zero_tail = true;
243 while (true) {
244 ++current;
245 if (current == end || !isDigit(*current, radix)) break;
246 zero_tail = zero_tail && *current == '0';
247 exponent += radix_log_2;
248 }
249
250 if (!allow_trailing_junk && AdvanceToNonspace(&current, end)) {
251 return JunkStringValue();
252 }
253
254 int middle_value = (1 << (overflow_bits_count - 1));
255 if (dropped_bits > middle_value) {
256 number++; // Rounding up.
257 } else if (dropped_bits == middle_value) {
258 // Rounding to even to consistency with decimals: half-way case rounds
259 // up if significant part is odd and down otherwise.
260 if ((number & 1) != 0 || !zero_tail) {
261 number++; // Rounding up.
262 }
263 }
264
265 // Rounding up may cause overflow.
266 if ((number & (static_cast<int64_t>(1) << 53)) != 0) {
267 exponent++;
268 number >>= 1;
269 }
270 break;
271 }
272 ++current;
273 } while (current != end);
274
275 DCHECK(number < (int64_t{1} << 53));
276 DCHECK(static_cast<int64_t>(static_cast<double>(number)) == number);
277
278 if (exponent == 0) {
279 if (negative) {
280 if (number == 0) return -0.0;
281 number = -number;
282 }
283 return static_cast<double>(number);
284 }
285
286 DCHECK_NE(number, 0);
287 return std::ldexp(static_cast<double>(negative ? -number : number), exponent);
288}
289
290namespace {
291
292// Subclasses of StringToIntHelper get access to internal state:
293enum class State { kRunning, kError, kJunk, kEmpty, kZero, kDone };
294
295enum class Sign { kNegative, kPositive, kNone };
296
297} // namespace
298
299// ES6 18.2.5 parseInt(string, radix) (with NumberParseIntHelper subclass);
300// and BigInt parsing cases from https://tc39.github.io/proposal-bigint/
301// (with StringToBigIntHelper subclass).
303 public:
305 : subject_(subject), radix_(radix) {
306 DCHECK(subject->IsFlat());
307 }
308
309 // Used for the NumberParseInt operation
310 StringToIntHelper(const uint8_t* subject, int radix, size_t length)
311 : raw_one_byte_subject_(subject), radix_(radix), length_(length) {}
312
313 StringToIntHelper(const base::uc16* subject, int radix, size_t length)
314 : raw_two_byte_subject_(subject), radix_(radix), length_(length) {}
315
316 // Used for the StringToBigInt operation.
317 explicit StringToIntHelper(DirectHandle<String> subject) : subject_(subject) {
318 DCHECK(subject->IsFlat());
319 }
320
321 // Used for parsing BigInt literals, where the input is a Zone-allocated
322 // buffer of one-byte digits, along with an optional radix prefix.
323 StringToIntHelper(const uint8_t* subject, size_t length)
324 : raw_one_byte_subject_(subject), length_(length) {}
325 virtual ~StringToIntHelper() = default;
326
327 protected:
328 // Subclasses must implement these:
329 virtual void ParseOneByte(const uint8_t* start) = 0;
330 virtual void ParseTwoByte(const base::uc16* start) = 0;
331
332 // Subclasses must call this to do all the work.
333 void ParseInt();
334
335 // Subclass constructors should call these for configuration before calling
336 // ParseInt().
342
343 bool IsOneByte() const {
344 if (raw_two_byte_subject_ != nullptr) return false;
345 return raw_one_byte_subject_ != nullptr ||
347 }
348
350 const DisallowGarbageCollection& no_gc) {
351 if (raw_one_byte_subject_ != nullptr) {
353 }
354 return subject_->GetFlatContent(no_gc).ToOneByteVector();
355 }
356
358 const DisallowGarbageCollection& no_gc) {
359 if (raw_two_byte_subject_ != nullptr) {
361 }
362 return subject_->GetFlatContent(no_gc).ToUC16Vector();
363 }
364
365 int radix() { return radix_; }
366 size_t cursor() { return cursor_; }
367 size_t length() { return length_; }
368 bool negative() { return sign_ == Sign::kNegative; }
369 Sign sign() { return sign_; }
370 State state() { return state_; }
371 void set_state(State state) { state_ = state; }
372
373 private:
374 template <class Char>
375 void DetectRadixInternal(const Char* current, size_t length);
376
378 const uint8_t* raw_one_byte_subject_ = nullptr;
380 int radix_ = 0;
381 size_t cursor_ = 0;
382 size_t length_ = 0;
383 Sign sign_ = Sign::kNone;
384 bool leading_zero_ = false;
387 State state_ = State::kRunning;
388};
389
392 if (IsOneByte()) {
394 DetectRadixInternal(vector.begin(), vector.size());
395 if (state_ != State::kRunning) return;
396 ParseOneByte(vector.begin());
397 } else {
399 DetectRadixInternal(vector.begin(), vector.size());
400 if (state_ != State::kRunning) return;
401 ParseTwoByte(vector.begin());
402 }
403}
404
405template <class Char>
407 size_t length) {
408 const Char* start = current;
409 length_ = length;
410 const Char* end = start + length;
411
412 if (!AdvanceToNonspace(&current, end)) {
413 return set_state(State::kEmpty);
414 }
415
416 if (*current == '+') {
417 // Ignore leading sign; skip following spaces.
418 ++current;
419 if (current == end) {
420 return set_state(State::kJunk);
421 }
422 sign_ = Sign::kPositive;
423 } else if (*current == '-') {
424 ++current;
425 if (current == end) {
426 return set_state(State::kJunk);
427 }
428 sign_ = Sign::kNegative;
429 }
430
431 if (radix_ == 0) {
432 // Radix detection.
433 radix_ = 10;
434 if (*current == '0') {
435 ++current;
436 if (current == end) return set_state(State::kZero);
437 if (*current == 'x' || *current == 'X') {
438 radix_ = 16;
439 ++current;
440 if (current == end) return set_state(State::kJunk);
442 (*current == 'o' || *current == 'O')) {
443 radix_ = 8;
444 ++current;
445 if (current == end) return set_state(State::kJunk);
447 (*current == 'b' || *current == 'B')) {
448 radix_ = 2;
449 ++current;
450 if (current == end) return set_state(State::kJunk);
451 } else {
452 leading_zero_ = true;
453 }
454 }
455 } else if (radix_ == 16) {
456 if (*current == '0') {
457 // Allow "0x" prefix.
458 ++current;
459 if (current == end) return set_state(State::kZero);
460 if (*current == 'x' || *current == 'X') {
461 ++current;
462 if (current == end) return set_state(State::kJunk);
463 } else {
464 leading_zero_ = true;
465 }
466 }
467 }
468 // Skip leading zeros.
469 while (*current == '0') {
470 leading_zero_ = true;
471 ++current;
472 if (current == end) return set_state(State::kZero);
473 }
474 // Detect leading zeros with junk after them, if allowed.
475 if (leading_zero_ && allow_trailing_junk_ && !isDigit(*current, radix_)) {
476 return set_state(State::kZero);
477 }
478
479 if (!leading_zero_ && !isDigit(*current, radix_)) {
480 return set_state(State::kJunk);
481 }
482
483 DCHECK(radix_ >= 2 && radix_ <= 36);
484 cursor_ = current - start;
485}
486
488 public:
491
492 NumberParseIntHelper(const uint8_t* string, int radix, size_t length)
493 : StringToIntHelper(string, radix, length) {}
494
495 NumberParseIntHelper(const base::uc16* string, int radix, size_t length)
496 : StringToIntHelper(string, radix, length) {}
497
498 template <class Char>
499 void ParseInternal(const Char* start) {
500 const Char* current = start + cursor();
501 const Char* end = start + length();
502
503 if (radix() == 10) return HandleBaseTenCase(current, end);
505 result_ = HandlePowerOfTwoCase(current, end);
506 set_state(State::kDone);
507 return;
508 }
509 return HandleGenericCase(current, end);
510 }
511 void ParseOneByte(const uint8_t* start) final { return ParseInternal(start); }
512 void ParseTwoByte(const base::uc16* start) final {
513 return ParseInternal(start);
514 }
515
516 double GetResult() {
517 ParseInt();
518 switch (state()) {
519 case State::kJunk:
520 case State::kEmpty:
521 return JunkStringValue();
522 case State::kZero:
523 return SignedZero(negative());
524 case State::kDone:
525 return negative() ? -result_ : result_;
526 case State::kError:
527 case State::kRunning:
528 break;
529 }
530 UNREACHABLE();
531 }
532
533 private:
534 template <class Char>
535 void HandleGenericCase(const Char* current, const Char* end);
536
537 template <class Char>
538 double HandlePowerOfTwoCase(const Char* current, const Char* end) {
539 const bool allow_trailing_junk = true;
540 // GetResult() will take care of the sign bit, so ignore it for now.
541 const bool negative = false;
542 switch (radix()) {
543 case 2:
546 case 4:
549 case 8:
552
553 case 16:
556
557 case 32:
560 default:
561 UNREACHABLE();
562 }
563 }
564
565 template <class Char>
566 void HandleBaseTenCase(const Char* current, const Char* end) {
567 // Parsing with strtod.
568 // Doubles are less than 1.8e308.
569 constexpr size_t kMaxSignificantDigits = 309;
570 // The buffer may contain up to kMaxSignificantDigits + 1 digits and a zero
571 // end.
572 constexpr size_t kBufferSize = kMaxSignificantDigits + 2;
573 char buffer[kBufferSize];
574 size_t buffer_pos = 0;
575 while (*current >= '0' && *current <= '9') {
576 if (buffer_pos <= kMaxSignificantDigits) {
577 // If the number has more than kMaxSignificantDigits it will be parsed
578 // as infinity.
579 static_assert(kMaxSignificantDigits < kBufferSize);
580 buffer[buffer_pos++] = static_cast<char>(*current);
581 }
582 ++current;
583 if (current == end) break;
584 }
585
586 SLOW_DCHECK(buffer_pos < kBufferSize);
587 buffer[buffer_pos] = '\0';
588 base::Vector<const char> buffer_vector(buffer, buffer_pos);
589 result_ = Strtod(buffer_vector, 0);
590 set_state(State::kDone);
591 }
592
593 double result_ = 0;
594};
595
596template <class Char>
598 const Char* end) {
599 // The following code causes accumulating rounding error for numbers greater
600 // than ~2^56. It's explicitly allowed in the spec: "if R is not 2, 4, 8, 10,
601 // 16, or 32, then mathInt may be an implementation-dependent approximation to
602 // the mathematical integer value" (15.1.2.2).
603
604 int lim_0 = '0' + (radix() < 10 ? radix() : 10);
605 int lim_a = 'a' + (radix() - 10);
606 int lim_A = 'A' + (radix() - 10);
607
608 // NOTE: The code for computing the value may seem a bit complex at
609 // first glance. It is structured to use 32-bit multiply-and-add
610 // loops as long as possible to avoid losing precision.
611
612 bool done = false;
613 do {
614 // Parse the longest part of the string starting at {current}
615 // possible while keeping the multiplier, and thus the part
616 // itself, within 32 bits.
617 uint32_t part = 0, multiplier = 1;
618 while (true) {
619 uint32_t d;
620 if (*current >= '0' && *current < lim_0) {
621 d = *current - '0';
622 } else if (*current >= 'a' && *current < lim_a) {
623 d = *current - 'a' + 10;
624 } else if (*current >= 'A' && *current < lim_A) {
625 d = *current - 'A' + 10;
626 } else {
627 done = true;
628 break;
629 }
630
631 // Update the value of the part as long as the multiplier fits
632 // in 32 bits. When we can't guarantee that the next iteration
633 // will not overflow the multiplier, we stop parsing the part
634 // by leaving the loop.
635 const uint32_t kMaximumMultiplier = 0xFFFFFFFFU / 36;
636 uint32_t m = multiplier * static_cast<uint32_t>(radix());
637 if (m > kMaximumMultiplier) break;
638 part = part * radix() + d;
639 multiplier = m;
640 DCHECK(multiplier > part);
641
642 ++current;
643 if (current == end) {
644 done = true;
645 break;
646 }
647 }
648 result_ = result_ * multiplier + part;
649 } while (!done);
650
651 if (!allow_trailing_junk() && AdvanceToNonspace(&current, end)) {
652 return set_state(State::kJunk);
653 }
654 return set_state(State::kDone);
655}
656
657// Converts a string to a double value.
658template <class Char>
659double InternalStringToDouble(const Char* current, const Char* end,
660 ConversionFlag flag, double empty_string_val) {
661 // To make sure that iterator dereferencing is valid the following
662 // convention is used:
663 // 1. Each '++current' statement is followed by check for equality to 'end'.
664 // 2. If AdvanceToNonspace returned false then current == end.
665 // 3. If 'current' becomes be equal to 'end' the function returns or goes to
666 // 'parsing_done'.
667 // 4. 'current' is not dereferenced after the 'parsing_done' label.
668 // 5. Code before 'parsing_done' may rely on 'current != end'.
669 if (!AdvanceToNonspace(&current, end)) {
670 return empty_string_val;
671 }
672
673 // The non-decimal prefix has to be the first thing after any whitespace,
674 // so check for this first.
675 if (flag == ALLOW_NON_DECIMAL_PREFIX) {
676 // Copy the current iterator, so that on a failure to find the prefix, we
677 // rewind to the start.
678 const Char* prefixed = current;
679 if (*prefixed == '0') {
680 ++prefixed;
681 if (prefixed == end) return 0;
682
683 if (*prefixed == 'x' || *prefixed == 'X') {
684 ++prefixed;
685 if (prefixed == end) return JunkStringValue(); // "0x".
686 return InternalStringToIntDouble<4>(prefixed, end, false, false);
687 } else if (*prefixed == 'o' || *prefixed == 'O') {
688 ++prefixed;
689 if (prefixed == end) return JunkStringValue(); // "0o".
690 return InternalStringToIntDouble<3>(prefixed, end, false, false);
691 } else if (*prefixed == 'b' || *prefixed == 'B') {
692 ++prefixed;
693 if (prefixed == end) return JunkStringValue(); // "0b".
694 return InternalStringToIntDouble<1>(prefixed, end, false, false);
695 }
696 }
697 }
698
699 // From here we are parsing a StrDecimalLiteral, as per
700 // https://tc39.es/ecma262/#sec-tonumber-applied-to-the-string-type
701 const bool allow_trailing_junk = flag == ALLOW_TRAILING_JUNK;
702
703 double value;
704 // fast_float takes a char/char16_t instead of a uint8_t/uint16_t. Cast the
705 // pointers to match.
706 using UC = std::conditional_t<std::is_same_v<Char, uint8_t>, char, char16_t>;
707 static_assert(sizeof(UC) == sizeof(Char));
708 const UC* current_uc = reinterpret_cast<const UC*>(current);
709 const UC* end_uc = reinterpret_cast<const UC*>(end);
710 auto ret =
711 fast_float::from_chars(current_uc, end_uc, value,
712 static_cast<fast_float::chars_format>(
713 fast_float::chars_format::general |
714 fast_float::chars_format::no_infnan |
715 fast_float::chars_format::allow_leading_plus));
716 if (ret.ptr == end_uc) return value;
717 if (ret.ptr > current_uc) {
718 current = reinterpret_cast<const Char*>(ret.ptr);
719 if (!allow_trailing_junk && AdvanceToNonspace(&current, end)) {
720 return JunkStringValue();
721 }
722 return value;
723 }
724
725 // Failed to parse any number -- handle ±Infinity before giving up.
726 DCHECK_EQ(ret.ptr, current_uc);
727 DCHECK_NE(current, end);
728 static constexpr char kInfinityString[] = "Infinity";
729 switch (*current) {
730 case '+':
731 // Ignore leading plus sign.
732 ++current;
733 if (current == end) return JunkStringValue();
734 if (*current != kInfinityString[0]) return JunkStringValue();
735 [[fallthrough]];
736 case kInfinityString[0]:
737 if (!SubStringEquals(&current, end, kInfinityString)) {
738 return JunkStringValue();
739 }
740 if (!allow_trailing_junk && AdvanceToNonspace(&current, end)) {
741 return JunkStringValue();
742 }
743 return V8_INFINITY;
744
745 case '-':
746 ++current;
747 if (current == end) return JunkStringValue();
748 if (*current != kInfinityString[0]) return JunkStringValue();
749 if (!SubStringEquals(&current, end, kInfinityString)) {
750 return JunkStringValue();
751 }
752 if (!allow_trailing_junk && AdvanceToNonspace(&current, end)) {
753 return JunkStringValue();
754 }
755 return -V8_INFINITY;
756
757 default:
758 return JunkStringValue();
759 }
760}
761
762double StringToDouble(const char* str, ConversionFlag flags,
763 double empty_string_val) {
764 // We use {base::OneByteVector} instead of {base::CStrVector} to avoid
765 // instantiating the InternalStringToDouble() template for {const char*} as
766 // well.
767 return StringToDouble(base::OneByteVector(str), flags, empty_string_val);
768}
769
771 double empty_string_val) {
772 return InternalStringToDouble(str.begin(), str.end(), flags,
773 empty_string_val);
774}
775
777 double empty_string_val) {
778 return InternalStringToDouble(str.begin(), str.end(), flags,
779 empty_string_val);
780}
781
783 DCHECK_EQ(str[0], '0');
784 DCHECK_EQ(tolower(str[1]), 'b');
785 return InternalStringToIntDouble<1>(str.begin() + 2, str.end(), false, false);
786}
787
789 DCHECK_EQ(str[0], '0');
790 DCHECK_EQ(tolower(str[1]), 'o');
791 return InternalStringToIntDouble<3>(str.begin() + 2, str.end(), false, false);
792}
793
795 DCHECK_EQ(str[0], '0');
796 DCHECK_EQ(tolower(str[1]), 'x');
797 return InternalStringToIntDouble<4>(str.begin() + 2, str.end(), false, false);
798}
799
801 return InternalStringToIntDouble<3>(str.begin(), str.end(), false, false);
802}
803
804double StringToInt(Isolate* isolate, DirectHandle<String> string, int radix) {
805 NumberParseIntHelper helper(string, radix);
806 return helper.GetResult();
807}
808
809template <typename IsolateT>
811 public:
813
814 // Used for StringToBigInt operation (BigInt constructor and == operator).
822
823 // Used for parsing BigInt literals, where the input is a buffer of
824 // one-byte ASCII digits, along with an optional radix prefix.
825 StringToBigIntHelper(IsolateT* isolate, const uint8_t* string, size_t length)
826 : StringToIntHelper(string, length),
827 isolate_(isolate),
830 }
831
832 void ParseOneByte(const uint8_t* start) final { return ParseInternal(start); }
833 void ParseTwoByte(const base::uc16* start) final {
834 return ParseInternal(start);
835 }
836
838 ParseInt();
839 if (behavior_ == Behavior::kStringToBigInt && sign() != Sign::kNone &&
840 radix() != 10) {
841 return MaybeHandle<BigInt>();
842 }
843 if (state() == State::kEmpty) {
845 set_state(State::kZero);
846 } else {
847 UNREACHABLE();
848 }
849 }
850 switch (this->state()) {
851 case State::kJunk:
852 case State::kError:
853 return MaybeHandle<BigInt>();
854 case State::kZero:
856 case State::kDone:
859 case State::kEmpty:
860 case State::kRunning:
861 break;
862 }
863 UNREACHABLE();
864 }
865
866 // Used for converting BigInt literals. The scanner has already checked
867 // that the literal is valid and not too big, so this always succeeds.
868 std::unique_ptr<char[]> DecimalString(bigint::Processor* processor) {
870 ParseInt();
871 if (state() == State::kZero) {
872 // Input may have been "0x0" or similar.
873 return std::unique_ptr<char[]>(new char[2]{'0', '\0'});
874 }
875 DCHECK_EQ(state(), State::kDone);
876 int num_digits = accumulator_.ResultLength();
877 base::SmallVector<bigint::digit_t, 8> digit_storage(num_digits);
878 bigint::RWDigits digits(digit_storage.data(), num_digits);
879 processor->FromString(digits, &accumulator_);
880 uint32_t num_chars = bigint::ToStringResultLength(digits, 10, false);
881 std::unique_ptr<char[]> out(new char[num_chars + 1]);
882 processor->ToString(out.get(), &num_chars, digits, 10, false);
883 out[num_chars] = '\0';
884 return out;
885 }
886 IsolateT* isolate() { return isolate_; }
887
888 private:
889 template <class Char>
890 void ParseInternal(const Char* start) {
892 const Char* current = start + cursor();
893 const Char* end = start + length();
894 current = accumulator_.Parse(current, end, radix());
895
896 Result result = accumulator_.result();
897 if (result == Result::kMaxSizeExceeded) {
898 return set_state(State::kError);
899 }
900 if (!allow_trailing_junk() && AdvanceToNonspace(&current, end)) {
901 return set_state(State::kJunk);
902 }
903 return set_state(State::kDone);
904 }
905
907 // For literals, we pretenure the allocated BigInt, since it's about
908 // to be stored in the interpreter's constants array.
911 }
912
913 IsolateT* isolate_;
916};
917
919 DirectHandle<String> string) {
920 string = String::Flatten(isolate, string);
921 StringToBigIntHelper<Isolate> helper(isolate, string);
922 return helper.GetResult();
923}
924
925template <typename IsolateT>
926MaybeHandle<BigInt> BigIntLiteral(IsolateT* isolate, const char* string) {
928 isolate, reinterpret_cast<const uint8_t*>(string), strlen(string));
929 return helper.GetResult();
930}
932 MaybeHandle<BigInt> BigIntLiteral(Isolate* isolate, const char* string);
933template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
935 const char* string);
936
937std::unique_ptr<char[]> BigIntLiteralToDecimal(
938 LocalIsolate* isolate, base::Vector<const uint8_t> literal) {
939 StringToBigIntHelper<LocalIsolate> helper(nullptr, literal.begin(),
940 literal.size());
941 return helper.DecimalString(isolate->bigint_processor());
942}
943
944std::string_view DoubleToStringView(double v, base::Vector<char> buffer) {
945 switch (FPCLASSIFY_NAMESPACE::fpclassify(v)) {
946 case FP_NAN:
947 return "NaN";
948 case FP_INFINITE:
949 return (v < 0.0 ? "-Infinity" : "Infinity");
950 case FP_ZERO:
951 return "0";
952 default: {
953 if (IsInt32Double(v)) {
954 // This will trigger if v is -0 and -0.0 is stringified to "0".
955 // (see ES section 7.1.12.1 #sec-tostring-applied-to-the-number-type)
956 return IntToStringView(FastD2I(v), buffer);
957 }
958 SimpleStringBuilder builder(buffer.begin(), buffer.size());
959 int decimal_point;
960 int sign;
961 constexpr int kV8DtoaBufferCapacity = base::kBase10MaximalLength + 1;
962 char decimal_rep[kV8DtoaBufferCapacity];
963 int length;
964
967 base::Vector<char>(decimal_rep, kV8DtoaBufferCapacity), &sign,
968 &length, &decimal_point);
969
970 if (sign) builder.AddCharacter('-');
971
972 if (length <= decimal_point && decimal_point <= 21) {
973 // ECMA-262 section 9.8.1 step 6.
974 builder.AddString(decimal_rep, length);
975 builder.AddPadding('0', decimal_point - length);
976
977 } else if (0 < decimal_point && decimal_point <= 21) {
978 // ECMA-262 section 9.8.1 step 7.
979 builder.AddSubstring(decimal_rep, decimal_point);
980 builder.AddCharacter('.');
981 builder.AddString(decimal_rep + decimal_point, length - decimal_point);
982
983 } else if (decimal_point <= 0 && decimal_point > -6) {
984 // ECMA-262 section 9.8.1 step 8.
985 builder.AddStringLiteral("0.");
986 builder.AddPadding('0', -decimal_point);
987 builder.AddString(decimal_rep, length);
988
989 } else {
990 // ECMA-262 section 9.8.1 step 9 and 10 combined.
991 builder.AddCharacter(decimal_rep[0]);
992 if (length != 1) {
993 builder.AddCharacter('.');
994 builder.AddString(decimal_rep + 1, length - 1);
995 }
996 builder.AddCharacter('e');
997 builder.AddCharacter((decimal_point >= 0) ? '+' : '-');
998 int exponent = decimal_point - 1;
999 if (exponent < 0) exponent = -exponent;
1000 builder.AddDecimalInteger(exponent);
1001 }
1002 return {buffer.begin(), builder.Finalize()};
1003 }
1004 }
1005}
1006
1007std::string_view IntToStringView(int n, base::Vector<char> buffer) {
1008 bool negative = true;
1009 if (n >= 0) {
1010 n = -n;
1011 negative = false;
1012 }
1013 // Build the string backwards from the least significant digit.
1014 size_t i = buffer.size();
1015 do {
1016 // We ensured n <= 0, so the subtraction does the right addition.
1017 buffer[--i] = '0' - (n % 10);
1018 n /= 10;
1019 } while (n);
1020 if (negative) buffer[--i] = '-';
1021 return {buffer.begin() + i, buffer.end()};
1022}
1023
1024std::string_view DoubleToFixedStringView(double value, int f,
1025 base::Vector<char> buffer) {
1026 const double kFirstNonFixed = 1e21;
1027 DCHECK_GE(f, 0);
1029
1030 bool negative = false;
1031 double abs_value = value;
1032 if (value < 0) {
1033 abs_value = -value;
1034 negative = true;
1035 }
1036
1037 // If abs_value has more than kDoubleToFixedMaxDigitsBeforePoint digits before
1038 // the point use the non-fixed conversion routine.
1039 if (abs_value >= kFirstNonFixed) {
1040 return DoubleToStringView(value, buffer);
1041 }
1042
1043 // Find a sufficiently precise decimal representation of n.
1044 int decimal_point;
1045 int sign;
1046 // Add space for the '\0' byte.
1047 constexpr int kDecimalRepCapacity =
1049 char decimal_rep[kDecimalRepCapacity];
1050 int decimal_rep_length;
1052 base::Vector<char>(decimal_rep, kDecimalRepCapacity),
1053 &sign, &decimal_rep_length, &decimal_point);
1054
1055 // Create a representation that is padded with zeros if needed.
1056 int zero_prefix_length = 0;
1057 int zero_postfix_length = 0;
1058
1059 if (decimal_point <= 0) {
1060 zero_prefix_length = -decimal_point + 1;
1061 decimal_point = 1;
1062 }
1063
1064 if (zero_prefix_length + decimal_rep_length < decimal_point + f) {
1065 zero_postfix_length =
1066 decimal_point + f - decimal_rep_length - zero_prefix_length;
1067 }
1068
1069 unsigned rep_length =
1070 zero_prefix_length + decimal_rep_length + zero_postfix_length;
1071 // TODO(pthier): Get rid of this intermediate string builder.
1072 base::Vector<char> rep_buffer = base::Vector<char>::New(rep_length + 1);
1073 SimpleStringBuilder rep_builder(rep_buffer.begin(), rep_buffer.size());
1074 rep_builder.AddPadding('0', zero_prefix_length);
1075 rep_builder.AddString(decimal_rep, decimal_rep_length);
1076 rep_builder.AddPadding('0', zero_postfix_length);
1077 char* rep_end = rep_builder.Finalize();
1078 // AddSubstring requires a null-terminated string (for DCHECKs only).
1079 *rep_end = '\0';
1080
1081 // Create the result string by appending a minus and putting in a
1082 // decimal point if needed.
1083 SimpleStringBuilder builder(buffer.begin(), buffer.size());
1084 if (negative) builder.AddCharacter('-');
1085 builder.AddSubstring(rep_buffer.begin(), decimal_point);
1086 if (f > 0) {
1087 builder.AddCharacter('.');
1088 builder.AddSubstring(rep_buffer.begin() + decimal_point, f);
1089 }
1090 DeleteArray(rep_buffer.begin());
1091 return {buffer.begin(), builder.Finalize()};
1092}
1093
1094static std::string_view CreateExponentialRepresentation(
1095 char* decimal_rep, int rep_length, int exponent, bool negative,
1096 int significant_digits, base::Vector<char> buffer) {
1097 bool negative_exponent = false;
1098 if (exponent < 0) {
1099 negative_exponent = true;
1100 exponent = -exponent;
1101 }
1102
1103 SimpleStringBuilder builder(buffer.begin(), buffer.size());
1104
1105 if (negative) builder.AddCharacter('-');
1106 builder.AddCharacter(decimal_rep[0]);
1107 if (significant_digits != 1) {
1108 builder.AddCharacter('.');
1109 DCHECK_EQ(rep_length, strlen(decimal_rep));
1110 DCHECK_GE(significant_digits, rep_length);
1111 builder.AddString(decimal_rep + 1, rep_length - 1);
1112 builder.AddPadding('0', significant_digits - rep_length);
1113 }
1114
1115 builder.AddCharacter('e');
1116 builder.AddCharacter(negative_exponent ? '-' : '+');
1117 builder.AddDecimalInteger(exponent);
1118 return {buffer.begin(), builder.Finalize()};
1119}
1120
1121std::string_view DoubleToExponentialStringView(double value, int f,
1122 base::Vector<char> buffer) {
1123 // f might be -1 to signal that f was undefined in JavaScript.
1124 DCHECK(f >= -1 && f <= kMaxFractionDigits);
1125
1126 bool negative = false;
1127 if (value < 0) {
1128 value = -value;
1129 negative = true;
1130 }
1131
1132 // Find a sufficiently precise decimal representation of n.
1133 int decimal_point;
1134 int sign;
1135 // f corresponds to the digits after the point. There is always one digit
1136 // before the point. The number of requested_digits equals hence f + 1.
1137 // And we have to add one character for the null-terminator.
1138 constexpr int kV8DtoaBufferCapacity = kMaxFractionDigits + 1 + 1;
1139 // Make sure that the buffer is big enough, even if we fall back to the
1140 // shortest representation (which happens when f equals -1).
1142 char decimal_rep[kV8DtoaBufferCapacity];
1143 int decimal_rep_length;
1144
1145 if (f == -1) {
1147 base::Vector<char>(decimal_rep, kV8DtoaBufferCapacity),
1148 &sign, &decimal_rep_length, &decimal_point);
1149 f = decimal_rep_length - 1;
1150 } else {
1152 base::Vector<char>(decimal_rep, kV8DtoaBufferCapacity),
1153 &sign, &decimal_rep_length, &decimal_point);
1154 }
1155 DCHECK_GT(decimal_rep_length, 0);
1156 DCHECK(decimal_rep_length <= f + 1);
1157
1158 int exponent = decimal_point - 1;
1159 return CreateExponentialRepresentation(decimal_rep, decimal_rep_length,
1160 exponent, negative, f + 1, buffer);
1161}
1162
1163std::string_view DoubleToPrecisionStringView(double value, int p,
1164 base::Vector<char> buffer) {
1165 constexpr int kMinimalDigits = 1;
1166 DCHECK(p >= kMinimalDigits && p <= kMaxFractionDigits);
1167 USE(kMinimalDigits);
1168
1169 bool negative = false;
1170 if (value < 0) {
1171 value = -value;
1172 negative = true;
1173 }
1174
1175 // Find a sufficiently precise decimal representation of n.
1176 int decimal_point;
1177 int sign;
1178 // Add one for the terminating null character.
1179 constexpr int kV8DtoaBufferCapacity = kMaxFractionDigits + 1;
1180 char decimal_rep[kV8DtoaBufferCapacity];
1181 int decimal_rep_length;
1182
1184 base::Vector<char>(decimal_rep, kV8DtoaBufferCapacity),
1185 &sign, &decimal_rep_length, &decimal_point);
1186 DCHECK(decimal_rep_length <= p);
1187
1188 int exponent = decimal_point - 1;
1189
1190 std::string_view result;
1191
1192 if (exponent < -6 || exponent >= p) {
1193 result = CreateExponentialRepresentation(decimal_rep, decimal_rep_length,
1194 exponent, negative, p, buffer);
1195 } else {
1196 // Use fixed notation.
1197 SimpleStringBuilder builder(buffer.begin(), buffer.size());
1198 if (negative) builder.AddCharacter('-');
1199 if (decimal_point <= 0) {
1200 builder.AddStringLiteral("0.");
1201 builder.AddPadding('0', -decimal_point);
1202 builder.AddString(decimal_rep, decimal_rep_length);
1203 builder.AddPadding('0', p - decimal_rep_length);
1204 } else {
1205 const size_t m = std::min(decimal_rep_length, decimal_point);
1206 builder.AddSubstring(decimal_rep, m);
1207 builder.AddPadding('0', decimal_point - decimal_rep_length);
1208 if (decimal_point < p) {
1209 builder.AddCharacter('.');
1210 const int extra = negative ? 2 : 1;
1211 if (decimal_rep_length > decimal_point) {
1212 DCHECK_EQ(decimal_rep_length - decimal_point,
1213 strlen(decimal_rep + decimal_point));
1214 const int len = decimal_rep_length - decimal_point;
1215 DCHECK_LE(builder.position(), kMaxInt);
1216 const size_t n =
1217 std::min(len, p - static_cast<int>(builder.position() - extra));
1218 builder.AddSubstring(decimal_rep + decimal_point, n);
1219 }
1220 builder.AddPadding('0',
1221 extra + (p - static_cast<int>(builder.position())));
1222 }
1223 }
1224 result = {buffer.begin(), builder.Finalize()};
1225 }
1226
1227 return result;
1228}
1229
1230std::string_view DoubleToRadixStringView(double value, int radix,
1231 base::Vector<char> buffer) {
1232 // We don't expect to see zero here (callers should handle it).
1233 DCHECK_NE(0.0, value);
1234
1235 // Certain invalid inputs will cause this function to corrupt memory (write
1236 // out-of-bounds of the given buffer), so defend against that with CHECKs.
1237 CHECK(radix >= 2 && radix <= 36);
1238 CHECK(std::isfinite(value));
1239
1240 // Character array used for conversion.
1241 static const char chars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
1242
1243 size_t integer_cursor = buffer.size() / 2;
1244 size_t fraction_cursor = integer_cursor;
1245
1246 bool negative = value < 0;
1247 if (negative) value = -value;
1248
1249 // Split the value into an integer part and a fractional part.
1250 double integer = std::floor(value);
1251 double fraction = value - integer;
1252 // We only compute fractional digits up to the input double's precision.
1253 double delta = 0.5 * (base::Double(value).NextDouble() - value);
1254 bool delta_is_positive = true;
1255 // If the delta rounded down to zero, use the minimum (denormal) delta
1256 // value. Be careful around denormal flushing when doing so.
1257 if (delta <= 0) {
1259 // We're flushing the delta value to zero, so the loop below won't
1260 // make progress. Skip it instead.
1261 delta_is_positive = false;
1262 } else {
1263 static_assert(base::Double(0.0).NextDouble() > 0);
1264 delta = base::Double(0.0).NextDouble();
1265 }
1266 }
1267 if (delta_is_positive && fraction >= delta) {
1268 // Insert decimal point.
1269 buffer[fraction_cursor++] = '.';
1270 do {
1271 // Shift up by one digit.
1272 fraction *= radix;
1273 delta *= radix;
1274 // Write digit.
1275 int digit = static_cast<int>(fraction);
1276 buffer[fraction_cursor++] = chars[digit];
1277 // Calculate remainder.
1278 fraction -= digit;
1279 // Round to even.
1280 if (fraction > 0.5 || (fraction == 0.5 && (digit & 1))) {
1281 if (fraction + delta > 1) {
1282 // We need to back trace already written digits in case of carry-over.
1283 while (true) {
1284 fraction_cursor--;
1285 if (fraction_cursor == buffer.size() / 2) {
1286 CHECK_EQ('.', buffer[fraction_cursor]);
1287 // Carry over to the integer part.
1288 integer += 1;
1289 break;
1290 }
1291 char c = buffer[fraction_cursor];
1292 // Reconstruct digit.
1293 digit = c > '9' ? (c - 'a' + 10) : (c - '0');
1294 if (digit + 1 < radix) {
1295 buffer[fraction_cursor++] = chars[digit + 1];
1296 break;
1297 }
1298 }
1299 break;
1300 }
1301 }
1302 } while (fraction >= delta);
1303 }
1304
1305 // Compute integer digits. Fill unrepresented digits with zero.
1306 while (base::Double(integer / radix).Exponent() > 0) {
1307 integer /= radix;
1308 buffer[--integer_cursor] = '0';
1309 }
1310 do {
1311 double remainder = Modulo(integer, radix);
1312 buffer[--integer_cursor] = chars[static_cast<int>(remainder)];
1313 integer = (integer - remainder) / radix;
1314 } while (integer > 0);
1315
1316 // Add sign and terminate string.
1317 if (negative) buffer[--integer_cursor] = '-';
1318 DCHECK_LE(integer_cursor, 1u << 31); // Didn't underflow.
1319 DCHECK_GT(fraction_cursor, integer_cursor);
1320 return {buffer.begin() + integer_cursor, fraction_cursor - integer_cursor};
1321}
1322
1323// ES6 18.2.4 parseFloat(string)
1325 ConversionFlag flag, double empty_string_val) {
1326 DirectHandle<String> flattened = String::Flatten(isolate, string);
1327 return FlatStringToDouble(*flattened, flag, empty_string_val);
1328}
1329
1331 double empty_string_val) {
1333 DCHECK(string->IsFlat());
1334 String::FlatContent flat = string->GetFlatContent(no_gc);
1335 DCHECK(flat.IsFlat());
1336 if (flat.IsOneByte()) {
1337 return StringToDouble(flat.ToOneByteVector(), flag, empty_string_val);
1338 } else {
1339 return StringToDouble(flat.ToUC16Vector(), flag, empty_string_val);
1340 }
1341}
1342
1343std::optional<double> TryStringToDouble(LocalIsolate* isolate,
1344 DirectHandle<String> object,
1345 uint32_t max_length_for_conversion) {
1347 uint32_t length = object->length();
1348 if (length > max_length_for_conversion) {
1349 return std::nullopt;
1350 }
1351
1352 auto buffer = std::make_unique<base::uc16[]>(max_length_for_conversion);
1353 SharedStringAccessGuardIfNeeded access_guard(isolate);
1354 String::WriteToFlat(*object, buffer.get(), 0, length, access_guard);
1355 base::Vector<const base::uc16> v(buffer.get(), length);
1357}
1358
1359std::optional<double> TryStringToInt(LocalIsolate* isolate,
1360 DirectHandle<String> object, int radix) {
1362 const uint32_t kMaxLengthForConversion = 20;
1363 uint32_t length = object->length();
1364 if (length > kMaxLengthForConversion) {
1365 return std::nullopt;
1366 }
1367
1369 uint8_t buffer[kMaxLengthForConversion];
1370 SharedStringAccessGuardIfNeeded access_guard(isolate);
1371 String::WriteToFlat(*object, buffer, 0, length, access_guard);
1372 NumberParseIntHelper helper(buffer, radix, length);
1373 return helper.GetResult();
1374 } else {
1375 base::uc16 buffer[kMaxLengthForConversion];
1376 SharedStringAccessGuardIfNeeded access_guard(isolate);
1377 String::WriteToFlat(*object, buffer, 0, length, access_guard);
1378 NumberParseIntHelper helper(buffer, radix, length);
1379 return helper.GetResult();
1380 }
1381}
1382
1389
1391 SharedStringAccessGuardIfNeeded& access_guard) {
1392 // Max length of canonical double: -X.XXXXXXXXXXXXXXXXX-eXXX
1393 const uint32_t kBufferSize = 24;
1394 const uint32_t length = string->length();
1395 if (length == 0 || length > kBufferSize) return false;
1396 uint16_t buffer[kBufferSize];
1397 String::WriteToFlat(string, buffer, 0, length, access_guard);
1398 // If the first char is not a digit or a '-' or we can't match 'NaN' or
1399 // '(-)Infinity', bailout immediately.
1400 uint32_t offset = 0;
1401 if (!IsDecimalDigit(buffer[0])) {
1402 if (buffer[0] == '-') {
1403 if (length == 1) return false; // Just '-' is bad.
1404 if (!IsDecimalDigit(buffer[1])) {
1405 if (buffer[1] == 'I' && length == 9) {
1406 // Allow matching of '-Infinity' below.
1407 } else {
1408 return false;
1409 }
1410 }
1411 offset++;
1412 } else if (buffer[0] == 'I' && length == 8) {
1413 // Allow matching of 'Infinity' below.
1414 } else if (buffer[0] == 'N' && length == 3) {
1415 // Match NaN.
1416 return buffer[1] == 'a' && buffer[2] == 'N';
1417 } else {
1418 return false;
1419 }
1420 }
1421 // Expected fast path: key is an integer.
1422 static const uint32_t kRepresentableIntegerLength = 15; // (-)XXXXXXXXXXXXXXX
1423 if (length - offset <= kRepresentableIntegerLength) {
1424 const uint32_t initial_offset = offset;
1425 bool matches = true;
1426 for (; offset < length; offset++) {
1427 matches &= IsDecimalDigit(buffer[offset]);
1428 }
1429 if (matches) {
1430 // Match 0 and -0.
1431 if (buffer[initial_offset] == '0') return initial_offset == length - 1;
1432 return true;
1433 }
1434 }
1435 // Slow path: test DoubleToString(StringToDouble(string)) == string.
1436 base::Vector<const uint16_t> vector(buffer, length);
1437 double d = StringToDouble(vector, NO_CONVERSION_FLAG);
1438 if (std::isnan(d)) return false;
1439 // Compute reverse string.
1440 char reverse_buffer[kBufferSize + 1]; // Result will be /0 terminated.
1441 base::Vector<char> reverse_vector(reverse_buffer, arraysize(reverse_buffer));
1442 std::string_view reverse_string = DoubleToStringView(d, reverse_vector);
1443
1444 if (reverse_string.length() != length) return false;
1445 for (uint32_t i = 0; i < length; ++i) {
1446 if (static_cast<uint16_t>(reverse_string[i]) != buffer[i]) return false;
1447 }
1448 return true;
1449}
1450
1452
1453int32_t DoubleToInt32_NoInline(double x) { return DoubleToInt32(x); }
1454
1455} // namespace internal
1456} // namespace v8
1457
1458#undef FPCLASSIFY_NAMESPACE
#define SLOW_DCHECK(condition)
Definition checks.h:21
constexpr double NextDouble() const
Definition double.h:69
static constexpr uint64_t kSignMask
Definition double.h:27
static V8_BASE_EXPORT bool GetFlushDenormals()
Definition fpu.cc:96
constexpr size_t size() const
Definition vector.h:70
static Vector< T > New(size_t length)
Definition vector.h:35
constexpr T * begin() const
Definition vector.h:96
constexpr T * end() const
Definition vector.h:103
ALWAYS_INLINE CharIt Parse(CharIt start, CharIt end, digit_t radix)
static const uint32_t kMaxLength
Definition bigint.h:106
static Handle< BigInt > Zero(IsolateT *isolate, AllocationType allocation=AllocationType::kYoung)
Definition bigint.cc:333
static MaybeHandle< BigInt > Allocate(IsolateT *isolate, bigint::FromStringAccumulator *accumulator, bool negative, AllocationType allocation)
Definition bigint.cc:1192
void HandleGenericCase(const Char *current, const Char *end)
void HandleBaseTenCase(const Char *current, const Char *end)
NumberParseIntHelper(const base::uc16 *string, int radix, size_t length)
void ParseOneByte(const uint8_t *start) final
double HandlePowerOfTwoCase(const Char *current, const Char *end)
void ParseInternal(const Char *start)
void ParseTwoByte(const base::uc16 *start) final
NumberParseIntHelper(const uint8_t *string, int radix, size_t length)
NumberParseIntHelper(DirectHandle< String > string, int radix)
static bool IsNeeded(Tagged< String > str, LocalIsolate *local_isolate)
Definition string-inl.h:76
static SharedStringAccessGuardIfNeeded NotNeeded()
Definition string-inl.h:72
V8_INLINE void AddPadding(char c, int count)
V8_INLINE void AddStringLiteral(const char(&s)[N])
V8_INLINE void AddSubstring(const char *s, size_t n)
DISALLOW_IMPLICIT_CONSTRUCTORS(SimpleStringBuilder)
SimpleStringBuilder(char *buffer, size_t size)
V8_INLINE void AddString(const char *s, size_t len)
V8_INLINE void AddCharacter(char c)
void ParseTwoByte(const base::uc16 *start) final
std::unique_ptr< char[]> DecimalString(bigint::Processor *processor)
StringToBigIntHelper(IsolateT *isolate, const uint8_t *string, size_t length)
void ParseOneByte(const uint8_t *start) final
StringToBigIntHelper(IsolateT *isolate, DirectHandle< String > string)
bigint::FromStringAccumulator accumulator_
MaybeHandle< BigInt > GetResult()
void ParseInternal(const Char *start)
StringToIntHelper(const uint8_t *subject, size_t length)
base::Vector< const base::uc16 > GetTwoByteVector(const DisallowGarbageCollection &no_gc)
base::Vector< const uint8_t > GetOneByteVector(const DisallowGarbageCollection &no_gc)
virtual ~StringToIntHelper()=default
StringToIntHelper(DirectHandle< String > subject)
StringToIntHelper(const base::uc16 *subject, int radix, size_t length)
StringToIntHelper(DirectHandle< String > subject, int radix)
const base::uc16 * raw_two_byte_subject_
virtual void ParseOneByte(const uint8_t *start)=0
virtual void ParseTwoByte(const base::uc16 *start)=0
DirectHandle< String > subject_
StringToIntHelper(const uint8_t *subject, int radix, size_t length)
void DetectRadixInternal(const Char *current, size_t length)
const uint8_t * raw_one_byte_subject_
base::Vector< const uint8_t > ToOneByteVector() const
Definition string.h:139
base::Vector< const base::uc16 > ToUC16Vector() const
Definition string.h:145
static void WriteToFlat(Tagged< String > source, SinkCharT *sink, uint32_t start, uint32_t length)
Definition string.cc:772
static V8_INLINE HandleType< String > Flatten(Isolate *isolate, HandleType< T > string, AllocationType allocation=AllocationType::kYoung)
static bool IsOneByteRepresentationUnderneath(Tagged< String > string)
Definition string-inl.h:373
#define V8_INFINITY
Definition globals.h:23
int start
int end
LineAndColumn current
#define EXPORT_TEMPLATE_DEFINE(export)
int32_t offset
double remainder
ZoneVector< RpoNumber > & result
int x
FunctionLiteral * literal
Definition liveedit.cc:294
int m
Definition mul-fft.cc:294
int n
Definition mul-fft.cc:296
STL namespace.
constexpr bool IsPowerOfTwo(T value)
Definition bits.h:187
void DoubleToAscii(double v, DtoaMode mode, int requested_digits, Vector< char > buffer, int *sign, int *length, int *point)
Definition dtoa.cc:31
constexpr double uint64_to_double(uint64_t d64)
Definition double.h:20
V8_INLINE Dest bit_cast(Source const &source)
Definition macros.h:95
uint16_t uc16
Definition strings.h:18
const int kBase10MaximalLength
Definition dtoa.h:34
Vector< const uint8_t > OneByteVector(const char *data, size_t length)
Definition vector.h:337
@ DTOA_FIXED
Definition dtoa.h:21
@ DTOA_SHORTEST
Definition dtoa.h:17
@ DTOA_PRECISION
Definition dtoa.h:23
uint32_t ToStringResultLength(Digits X, int radix, bool sign)
Definition tostring.cc:597
void DeleteArray(T *array)
Definition allocation.h:63
double JunkStringValue()
int32_t DoubleToInt32_NoInline(double x)
bool isDigit(int x, int radix)
std::optional< double > TryStringToDouble(LocalIsolate *isolate, DirectHandle< String > object, uint32_t max_length_for_conversion)
double OctalStringToDouble(base::Vector< const uint8_t > str)
double FlatStringToDouble(Tagged< String > string, ConversionFlag flag, double empty_string_val)
double Modulo(double x, double y)
Definition utils.h:105
double HexStringToDouble(base::Vector< const uint8_t > str)
constexpr int kCharSize
Definition globals.h:396
double StringToInt(Isolate *isolate, DirectHandle< String > string, int radix)
bool IsSpecialIndex(Tagged< String > string)
bool IsInt32Double(double value)
static std::string_view CreateExponentialRepresentation(char *decimal_rep, int rep_length, int exponent, bool negative, int significant_digits, base::Vector< char > buffer)
bool AdvanceToNonspace(const Char **current, const Char *end)
bool IsWhiteSpaceOrLineTerminator(base::uc32 c)
std::string_view IntToStringView(int n, base::Vector< char > buffer)
constexpr int N
MaybeHandle< BigInt > BigIntLiteral(IsolateT *isolate, const char *string)
double ImplicitOctalStringToDouble(base::Vector< const uint8_t > str)
double BinaryStringToDouble(base::Vector< const uint8_t > str)
std::string_view DoubleToExponentialStringView(double value, int f, base::Vector< char > buffer)
double SignedZero(bool negative)
constexpr int kDoubleToFixedMaxDigitsBeforePoint
Definition conversions.h:71
int32_t DoubleToInt32(double x)
double InternalStringToDouble(const Char *current, const Char *end, ConversionFlag flag, double empty_string_val)
int FastD2I(double x)
constexpr bool IsDecimalDigit(base::uc32 c)
constexpr uint64_t kQuietNaNMask
Definition globals.h:701
float DoubleToFloat32_NoInline(double x)
float DoubleToFloat32(double x)
@ ALLOW_NON_DECIMAL_PREFIX
double InternalStringToIntDouble(const Char *start, const Char *end, bool negative, bool allow_trailing_junk)
return value
Definition map-inl.h:893
std::string_view DoubleToStringView(double v, base::Vector< char > buffer)
std::optional< double > TryStringToInt(LocalIsolate *isolate, DirectHandle< String > object, int radix)
bool SubStringEquals(const Char **current, const Char *end, const char *substring)
constexpr int kMaxInt
Definition globals.h:374
std::string_view DoubleToRadixStringView(double value, int radix, base::Vector< char > buffer)
void MemCopy(void *dest, const void *src, size_t size)
Definition memcopy.h:124
std::string_view DoubleToFixedStringView(double value, int f, base::Vector< char > buffer)
std::string_view DoubleToPrecisionStringView(double value, int p, base::Vector< char > buffer)
constexpr int kMaxFractionDigits
Definition conversions.h:70
double StringToDouble(const char *str, ConversionFlag flags, double empty_string_val)
bool isBinaryDigit(int x)
MaybeHandle< BigInt > StringToBigInt(Isolate *isolate, DirectHandle< String > string)
std::unique_ptr< char[]> BigIntLiteralToDecimal(LocalIsolate *isolate, base::Vector< const uint8_t > literal)
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define CHECK(condition)
Definition logging.h:124
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define DCHECK_GT(v1, v2)
Definition logging.h:487
#define USE(...)
Definition macros.h:293
#define V8_EXPORT_PRIVATE
Definition macros.h:460
#define arraysize(array)
Definition macros.h:67
#define V8_INLINE
Definition v8config.h:500
#define V8_UNLIKELY(condition)
Definition v8config.h:660