• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ecmascript/base/number_helper.h"
17 #include <cmath>
18 #include <cstddef>
19 #include <cstdint>
20 #include <iomanip>
21 #include <sstream>
22 #include <sys/time.h>
23 
24 #include "ecmascript/base/builtins_base.h"
25 #include "ecmascript/base/string_helper.h"
26 #include "ecmascript/js_tagged_value-inl.h"
27 #include "ecmascript/object_factory.h"
28 
29 namespace panda::ecmascript::base {
30 enum class Sign { NONE, NEG, POS };
31 thread_local uint64_t RandomGenerator::randomState {0};
32 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
33 #define RETURN_IF_CONVERSION_END(p, end, result) \
34     if ((p) == (end)) {                          \
35         return (result);                         \
36     }
37 
38 constexpr char CHARS[] = "0123456789abcdefghijklmnopqrstuvwxyz";  // NOLINT (modernize-avoid-c-arrays)
39 constexpr uint64_t MAX_MANTISSA = 0x1ULL << 52U;
40 
ToDigit(uint8_t c)41 static inline uint8_t ToDigit(uint8_t c)
42 {
43     if (c >= '0' && c <= '9') {
44         return c - '0';
45     }
46     if (c >= 'A' && c <= 'Z') {
47         return c - 'A' + DECIMAL;
48     }
49     if (c >= 'a' && c <= 'z') {
50         return c - 'a' + DECIMAL;
51     }
52     return '$';
53 }
54 
GotoNonspace(uint8_t ** ptr,const uint8_t * end)55 bool NumberHelper::GotoNonspace(uint8_t **ptr, const uint8_t *end)
56 {
57     while (*ptr < end) {
58         uint16_t c = **ptr;
59         size_t size = 1;
60         if (c > INT8_MAX) {
61             size = 0;
62             uint16_t utf8Bit = INT8_MAX + 1;  // equal 0b1000'0000
63             while (utf8Bit > 0 && (c & utf8Bit) == utf8Bit) {
64                 ++size;
65                 utf8Bit >>= 1UL;
66             }
67             if (base::utf_helper::ConvertRegionUtf8ToUtf16(*ptr, &c, end - *ptr, 1, 0) <= 0) {
68                 return true;
69             }
70         }
71         if (!StringHelper::IsNonspace(c)) {
72             return true;
73         }
74         *ptr += size;  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
75     }
76     return false;
77 }
78 
SignedZero(Sign sign)79 static inline double SignedZero(Sign sign)
80 {
81     return sign == Sign::NEG ? -0.0 : 0.0;
82 }
83 
IsEmptyString(const uint8_t * start,const uint8_t * end)84 bool NumberHelper::IsEmptyString(const uint8_t *start, const uint8_t *end)
85 {
86     auto p = const_cast<uint8_t *>(start);
87     return !NumberHelper::GotoNonspace(&p, end);
88 }
89 
DoubleToString(JSThread * thread,double number,int radix)90 JSTaggedValue NumberHelper::DoubleToString(JSThread *thread, double number, int radix)
91 {
92     bool negative = false;
93     if (number < 0.0) {
94         negative = true;
95         number = -number;
96     }
97 
98     double numberInteger = std::floor(number);
99     double numberFraction = number - numberInteger;
100 
101     auto value = bit_cast<uint64_t>(number);
102     value += 1;
103     double delta = HALF * (bit_cast<double>(value) - number);
104 
105     CString result;
106     if (numberFraction != 0 && numberFraction >= delta) {
107         result += ".";
108         result += DecimalsToString(&numberInteger, numberFraction, radix, delta);
109     }
110 
111     result = IntergerToString(numberInteger, radix) + result;
112 
113     if (negative) {
114         result = "-" + result;
115     }
116 
117     return BuiltinsBase::GetTaggedString(thread, result.c_str());
118 }
119 
DoubleToExponential(JSThread * thread,double number,int digit)120 JSTaggedValue NumberHelper::DoubleToExponential(JSThread *thread, double number, int digit)
121 {
122     CStringStream ss;
123     if (digit < 0) {
124         ss << std::setiosflags(std::ios::scientific) << std::setprecision(base::MAX_PRECISION) << number;
125     } else {
126         ss << std::setiosflags(std::ios::scientific) << std::setprecision(digit) << number;
127     }
128     CString result = ss.str();
129     size_t found = result.find_last_of('e');
130     if (found != CString::npos && found < result.size() - 2 && result[found + 2] == '0') {
131         result.erase(found + 2, 1); // 2:offset of e
132     }
133     if (digit < 0) {
134         size_t end = found;
135         while (--found > 0) {
136             if (result[found] != '0') {
137                 break;
138             }
139         }
140         if (result[found] == '.') {
141             found--;
142         }
143         if (found < end - 1) {
144             result.erase(found + 1, end - found - 1);
145         }
146     }
147     return BuiltinsBase::GetTaggedString(thread, result.c_str());
148 }
149 
DoubleToFixed(JSThread * thread,double number,int digit)150 JSTaggedValue NumberHelper::DoubleToFixed(JSThread *thread, double number, int digit)
151 {
152     CStringStream ss;
153     ss << std::setiosflags(std::ios::fixed) << std::setprecision(digit) << number;
154     return BuiltinsBase::GetTaggedString(thread, ss.str().c_str());
155 }
156 
DoubleToPrecision(JSThread * thread,double number,int digit)157 JSTaggedValue NumberHelper::DoubleToPrecision(JSThread *thread, double number, int digit)
158 {
159     if (number == 0.0) {
160         return DoubleToFixed(thread, number, digit - 1);
161     }
162     CStringStream ss;
163     double positiveNumber = number > 0 ? number : -number;
164     int logDigit = std::floor(log10(positiveNumber));
165     int radixDigit = digit - logDigit - 1;
166     const int MAX_EXPONENT_DIGIT = 6;
167     if ((logDigit >= 0 && radixDigit >= 0) || (logDigit < 0 && radixDigit <= MAX_EXPONENT_DIGIT)) {
168         return DoubleToFixed(thread, number, std::abs(radixDigit));
169     }
170     return DoubleToExponential(thread, number, digit - 1);
171 }
172 
StringToDoubleWithRadix(const uint8_t * start,const uint8_t * end,int radix)173 JSTaggedValue NumberHelper::StringToDoubleWithRadix(const uint8_t *start, const uint8_t *end, int radix)
174 {
175     auto p = const_cast<uint8_t *>(start);
176     JSTaggedValue nanResult = BuiltinsBase::GetTaggedDouble(NAN_VALUE);
177     // 1. skip space and line terminal
178     if (!NumberHelper::GotoNonspace(&p, end)) {
179         return nanResult;
180     }
181 
182     // 2. sign bit
183     bool negative = false;
184     if (*p == '-') {
185         negative = true;
186         RETURN_IF_CONVERSION_END(++p, end, nanResult);
187     } else if (*p == '+') {
188         RETURN_IF_CONVERSION_END(++p, end, nanResult);
189     }
190     // 3. 0x or 0X
191     bool stripPrefix = true;
192     // 4. If R  0, then
193     //     a. If R < 2 or R > 36, return NaN.
194     //     b. If R  16, let stripPrefix be false.
195     if (radix != 0) {
196         if (radix < MIN_RADIX || radix > MAX_RADIX) {
197             return nanResult;
198         }
199         if (radix != HEXADECIMAL) {
200             stripPrefix = false;
201         }
202     } else {
203         radix = DECIMAL;
204     }
205     int size = 0;
206     if (stripPrefix) {
207         if (*p == '0') {
208             size++;
209             if (++p != end && (*p == 'x' || *p == 'X')) {
210                 RETURN_IF_CONVERSION_END(++p, end, nanResult);
211                 radix = HEXADECIMAL;
212             }
213         }
214     }
215 
216     double result = 0;
217     bool isDone = false;
218     do {
219         double part = 0;
220         uint32_t multiplier = 1;
221         for (; p != end; ++p) {
222             // The maximum value to ensure that uint32_t will not overflow
223             const uint32_t MAX_MULTIPER = 0xffffffffU / 36;
224             uint32_t m = multiplier * radix;
225             if (m > MAX_MULTIPER) {
226                 break;
227             }
228 
229             int currentBit = ToDigit(*p);
230             if (currentBit >= radix) {
231                 isDone = true;
232                 break;
233             }
234             size++;
235             part = part * radix + currentBit;
236             multiplier = m;
237         }
238         result = result * multiplier + part;
239         if (isDone) {
240             break;
241         }
242     } while (p != end);
243 
244     if (size == 0) {
245         return nanResult;
246     }
247 
248     if (negative) {
249         result = -result;
250     }
251     return BuiltinsBase::GetTaggedDouble(result);
252 }
253 
Carry(char current,int radix)254 char NumberHelper::Carry(char current, int radix)
255 {
256     int digit = (current > '9') ? (current - 'a' + DECIMAL) : (current - '0');
257     digit = (digit == (radix - 1)) ? 0 : digit + 1;
258     return CHARS[digit];
259 }
260 
IntergerToString(double number,int radix)261 CString NumberHelper::IntergerToString(double number, int radix)
262 {
263     ASSERT(radix >= MIN_RADIX && radix <= MAX_RADIX);
264     CString result;
265     while (number / radix > MAX_MANTISSA) {
266         number /= radix;
267         result = CString("0").append(result);
268     }
269     do {
270         double remainder = std::fmod(number, radix);
271         result = CHARS[static_cast<int>(remainder)] + result;
272         number = (number - remainder) / radix;
273     } while (number > 0);
274     return result;
275 }
276 
DecimalsToString(double * numberInteger,double fraction,int radix,double delta)277 CString NumberHelper::DecimalsToString(double *numberInteger, double fraction, int radix, double delta)
278 {
279     CString result;
280     while (fraction >= delta) {
281         fraction *= radix;
282         delta *= radix;
283         int64_t integer = std::floor(fraction);
284         fraction -= integer;
285         result += CHARS[integer];
286         if (fraction > HALF && fraction + delta > 1) {
287             size_t fractionEnd = result.size() - 1;
288             result[fractionEnd] = Carry(*result.rbegin(), radix);
289             for (; fractionEnd > 0; fractionEnd--) {
290                 if (result[fractionEnd] == '0') {
291                     result[fractionEnd - 1] = Carry(result[fractionEnd - 1], radix);
292                 } else {
293                     break;
294                 }
295             }
296             if (fractionEnd == 0) {
297                 (*numberInteger)++;
298             }
299             break;
300         }
301     }
302     // delete 0 in the end
303     size_t found = result.find_last_not_of('0');
304     if (found != CString::npos) {
305         result.erase(found + 1);
306     }
307 
308     return result;
309 }
310 
IntToString(int number)311 CString NumberHelper::IntToString(int number)
312 {
313     return ToCString(number);
314 }
315 
316 // 7.1.12.1 ToString Applied to the Number Type
NumberToString(const JSThread * thread,JSTaggedValue number)317 JSHandle<EcmaString> NumberHelper::NumberToString(const JSThread *thread, JSTaggedValue number)
318 {
319     ASSERT(number.IsNumber());
320     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
321     if (number.IsInt()) {
322         return factory->NewFromCanBeCompressString(IntToString(number.GetInt()));
323     }
324 
325     double d = number.GetDouble();
326     if (std::isnan(d)) {
327         return factory->NewFromCanBeCompressString("NaN");
328     }
329     if (d == 0.0) {
330         return factory->NewFromCanBeCompressString("0");
331     }
332     if (d >= INT32_MIN + 1 && d <= INT32_MAX && d == static_cast<double>(static_cast<int32_t>(d))) {
333         return factory->NewFromCanBeCompressString(IntToString(static_cast<int32_t>(d)));
334     }
335 
336     std::string result;
337     if (d < 0) {
338         result += "-";
339         d = -d;
340     }
341 
342     if (std::isinf(d)) {
343         result += "Infinity";
344         return factory->NewFromStdStringUnCheck(result, true);
345     }
346 
347     ASSERT(d > 0);
348 
349     // 5. Otherwise, let n, k, and s be integers such that k ≥ 1, 10k−1 ≤ s < 10k, the Number value for s × 10n−k is m,
350     // and k is as small as possible. If there are multiple possibilities for s, choose the value of s for which s ×
351     // 10n−k is closest in value to m. If there are two such possible values of s, choose the one that is even. Note
352     // that k is the number of digits in the decimal representation of s and that s is not divisible by 10.
353     CStringStream str;
354     str << std::scientific << std::showpoint << std::setprecision(DOUBLE_MAX_PRECISION) << d;
355     if (strtod(str.str().c_str(), nullptr) != d) {
356         str.clear();
357         str.str("");
358         str << std::scientific << std::showpoint << std::setprecision(DOUBLE_MAX_PRECISION + 1) << d;
359     }
360     std::string scientificStr(str.str());
361 
362     auto indexOfE = scientificStr.find_last_of('e');
363     ASSERT(indexOfE != std::string::npos);
364     std::string base = scientificStr.substr(0, indexOfE);
365     // skip trailing zeros, and base must not be empty.
366     base = base.substr(0, base.find_last_not_of('0') + 1);
367     int k = static_cast<int>(base.size()) - 1;
368     int n = std::stoi(scientificStr.substr(indexOfE + 1)) + 1;
369     if (n > 0 && n <= 21) {  // NOLINT(readability-magic-numbers)
370         base.erase(1, 1);
371         if (k <= n) {
372             // 6. If k ≤ n ≤ 21, return the String consisting of the code units of the k digits of the decimal
373             // representation of s (in order, with no leading zeroes), followed by n−k occurrences of the code unit
374             // 0x0030 (DIGIT ZERO).
375             base += std::string(n - k, '0');
376         } else {
377             // 7. If 0 < n ≤ 21, return the String consisting of the code units of the most significant n digits of the
378             // decimal representation of s, followed by the code unit 0x002E (FULL STOP), followed by the code units of
379             // the remaining k−n digits of the decimal representation of s.
380             base.insert(n, 1, '.');
381         }
382     } else if (-6 < n && n <= 0) {  // NOLINT(readability-magic-numbers)
383         // 8. If −6 < n ≤ 0, return the String consisting of the code unit 0x0030 (DIGIT ZERO), followed by the code
384         // unit 0x002E (FULL STOP), followed by −n occurrences of the code unit 0x0030 (DIGIT ZERO), followed by the
385         // code units of the k digits of the decimal representation of s.
386         base.erase(1, 1);
387         base = std::string("0.") + std::string(-n, '0') + base;
388     } else {
389         if (k == 1) {
390             // 9. Otherwise, if k = 1, return the String consisting of the code unit of the single digit of s
391             base.erase(1, 1);
392         }
393         // followed by code unit 0x0065 (LATIN SMALL LETTER E), followed by the code unit 0x002B (PLUS SIGN) or the code
394         // unit 0x002D (HYPHEN-MINUS) according to whether n−1 is positive or negative, followed by the code units of
395         // the decimal representation of the integer abs(n−1) (with no leading zeroes).
396         base += "e" + (n >= 1 ? std::string("+") : "") + std::to_string(n - 1);
397     }
398     result += base;
399     return factory->NewFromStdStringUnCheck(result, true);
400 }
401 
TruncateDouble(double d)402 double NumberHelper::TruncateDouble(double d)
403 {
404     if (std::isnan(d)) {
405         return 0;
406     }
407     if (!std::isfinite(d)) {
408         return d;
409     }
410     // -0 to +0
411     if (d == 0.0) {
412         return 0;
413     }
414     return (d >= 0) ? std::floor(d) : std::ceil(d);
415 }
416 
StringToDouble(const uint8_t * start,const uint8_t * end,uint8_t radix,uint32_t flags)417 double NumberHelper::StringToDouble(const uint8_t *start, const uint8_t *end, uint8_t radix, uint32_t flags)
418 {
419     auto p = const_cast<uint8_t *>(start);
420     // 1. skip space and line terminal
421     if (!NumberHelper::GotoNonspace(&p, end)) {
422         return 0.0;
423     }
424 
425     // 2. get number sign
426     Sign sign = Sign::NONE;
427     if (*p == '+') {
428         RETURN_IF_CONVERSION_END(++p, end, NAN_VALUE);
429         sign = Sign::POS;
430     } else if (*p == '-') {
431         RETURN_IF_CONVERSION_END(++p, end, NAN_VALUE);
432         sign = Sign::NEG;
433     }
434     bool ignoreTrailing = (flags & IGNORE_TRAILING) != 0;
435 
436     // 3. judge Infinity
437     static const char INF[] = "Infinity";  // NOLINT(modernize-avoid-c-arrays)
438     if (*p == INF[0]) {
439         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
440         for (const char *i = &INF[1]; *i != '\0'; ++i) {
441             if (++p == end || *p != *i) {
442                 return NAN_VALUE;
443             }
444         }
445         ++p;
446         if (!ignoreTrailing && NumberHelper::GotoNonspace(&p, end)) {
447             return NAN_VALUE;
448         }
449         return sign == Sign::NEG ? -POSITIVE_INFINITY : POSITIVE_INFINITY;
450     }
451 
452     // 4. get number radix
453     bool leadingZero = false;
454     bool prefixRadix = false;
455     if (*p == '0' && radix == 0) {
456         RETURN_IF_CONVERSION_END(++p, end, SignedZero(sign));
457         if (*p == 'x' || *p == 'X') {
458             if ((flags & ALLOW_HEX) == 0) {
459                 return ignoreTrailing ? SignedZero(sign) : NAN_VALUE;
460             }
461             RETURN_IF_CONVERSION_END(++p, end, NAN_VALUE);
462             if (sign != Sign::NONE) {
463                 return NAN_VALUE;
464             }
465             prefixRadix = true;
466             radix = HEXADECIMAL;
467         } else if (*p == 'o' || *p == 'O') {
468             if ((flags & ALLOW_OCTAL) == 0) {
469                 return ignoreTrailing ? SignedZero(sign) : NAN_VALUE;
470             }
471             RETURN_IF_CONVERSION_END(++p, end, NAN_VALUE);
472             if (sign != Sign::NONE) {
473                 return NAN_VALUE;
474             }
475             prefixRadix = true;
476             radix = OCTAL;
477         } else if (*p == 'b' || *p == 'B') {
478             if ((flags & ALLOW_BINARY) == 0) {
479                 return ignoreTrailing ? SignedZero(sign) : NAN_VALUE;
480             }
481             RETURN_IF_CONVERSION_END(++p, end, NAN_VALUE);
482             if (sign != Sign::NONE) {
483                 return NAN_VALUE;
484             }
485             prefixRadix = true;
486             radix = BINARY;
487         } else {
488             leadingZero = true;
489         }
490     }
491 
492     if (radix == 0) {
493         radix = DECIMAL;
494     }
495     auto pStart = p;
496     // 5. skip leading '0'
497     while (*p == '0') {
498         RETURN_IF_CONVERSION_END(++p, end, SignedZero(sign));
499         leadingZero = true;
500     }
501     // 6. parse to number
502     uint64_t intNumber = 0;
503     uint64_t numberMax = (UINT64_MAX - (radix - 1)) / radix;
504     int digits = 0;
505     int exponent = 0;
506     do {
507         uint8_t c = ToDigit(*p);
508         if (c >= radix) {
509             if (!prefixRadix || ignoreTrailing || (pStart != p && !NumberHelper::GotoNonspace(&p, end))) {
510                 break;
511             }
512             // "0b" "0x1.2" "0b1e2" ...
513             return NAN_VALUE;
514         }
515         ++digits;
516         if (intNumber < numberMax) {
517             intNumber = intNumber * radix + c;
518         } else {
519             ++exponent;
520         }
521     } while (++p != end);
522 
523     auto number = static_cast<double>(intNumber);
524     if (sign == Sign::NEG) {
525         if (number == 0) {
526             number = -0.0;
527         } else {
528             number = -number;
529         }
530     }
531 
532     // 7. deal with other radix except DECIMAL
533     if (p == end || radix != DECIMAL) {
534         if ((digits == 0 && !leadingZero) || (p != end && !ignoreTrailing && NumberHelper::GotoNonspace(&p, end))) {
535             // no digits there, like "0x", "0xh", or error trailing of "0x3q"
536             return NAN_VALUE;
537         }
538         return number * std::pow(radix, exponent);
539     }
540 
541     // 8. parse '.'
542     if (radix == DECIMAL && *p == '.') {
543         RETURN_IF_CONVERSION_END(++p, end, (digits > 0) ? (number * std::pow(radix, exponent)) : NAN_VALUE);
544         while (ToDigit(*p) < radix) {
545             --exponent;
546             ++digits;
547             if (++p == end) {
548                 break;
549             }
550         }
551     }
552     if (digits == 0 && !leadingZero) {
553         // no digits there, like ".", "sss", or ".e1"
554         return NAN_VALUE;
555     }
556     auto pEnd = p;
557 
558     // 9. parse 'e/E' with '+/-'
559     char exponentSign = '+';
560     int additionalExponent = 0;
561     constexpr int MAX_EXPONENT = INT32_MAX / 2;
562     if (radix == DECIMAL && (p != end && (*p == 'e' || *p == 'E'))) {
563         RETURN_IF_CONVERSION_END(++p, end, NAN_VALUE);
564 
565         // 10. parse exponent number
566         if (*p == '+' || *p == '-') {
567             exponentSign = static_cast<char>(*p);
568             RETURN_IF_CONVERSION_END(++p, end, NAN_VALUE);
569         }
570         uint8_t digit;
571         while ((digit = ToDigit(*p)) < radix) {
572             if (additionalExponent > MAX_EXPONENT / radix) {
573                 additionalExponent = MAX_EXPONENT;
574             } else {
575                 additionalExponent = additionalExponent * radix + digit;
576             }
577             if (++p == end) {
578                 break;
579             }
580         }
581     }
582     exponent += (exponentSign == '-' ? -additionalExponent : additionalExponent);
583     if (!ignoreTrailing && NumberHelper::GotoNonspace(&p, end)) {
584         return NAN_VALUE;
585     }
586 
587     // 10. build StringNumericLiteral string
588     CString buffer;
589     if (sign == Sign::NEG) {
590         buffer += "-";
591     }
592     for (uint8_t *i = pStart; i < pEnd; ++i) {  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
593         if (*i != static_cast<uint8_t>('.')) {
594             buffer += *i;
595         }
596     }
597 
598     // 11. convert none-prefix radix string
599     return Strtod(buffer.c_str(), exponent, radix);
600 }
601 
Strtod(const char * str,int exponent,uint8_t radix)602 double NumberHelper::Strtod(const char *str, int exponent, uint8_t radix)
603 {
604     ASSERT(str != nullptr);
605     ASSERT(radix >= base::MIN_RADIX && radix <= base::MAX_RADIX);
606     auto p = const_cast<char *>(str);
607     Sign sign = Sign::NONE;
608     uint64_t number = 0;
609     uint64_t numberMax = (UINT64_MAX - (radix - 1)) / radix;
610     double result = 0.0;
611     if (*p == '-') {
612         sign = Sign::NEG;
613         ++p;
614     }
615     while (*p == '0') {
616         ++p;
617     }
618     while (*p != '\0') {
619         uint8_t digit = ToDigit(static_cast<uint8_t>(*p));
620         if (digit >= radix) {
621             break;
622         }
623         if (number < numberMax) {
624             number = number * radix + digit;
625         } else {
626             ++exponent;
627         }
628         ++p;
629     }
630     if (exponent < 0) {
631         result = number / std::pow(radix, -exponent);
632     } else {
633         result = number * std::pow(radix, exponent);
634     }
635     return sign == Sign::NEG ? -result : result;
636 }
637 
DoubleToInt(double d,size_t bits)638 int32_t NumberHelper::DoubleToInt(double d, size_t bits)
639 {
640     int32_t ret = 0;
641     auto u64 = bit_cast<uint64_t>(d);
642     int exp = static_cast<int>((u64 & DOUBLE_EXPONENT_MASK) >> DOUBLE_SIGNIFICAND_SIZE) - DOUBLE_EXPONENT_BIAS;
643     if (exp < static_cast<int>(bits - 1)) {
644         // smaller than INT<bits>_MAX, fast conversion
645         ret = static_cast<int32_t>(d);
646     } else if (exp < static_cast<int>(bits + DOUBLE_SIGNIFICAND_SIZE)) {
647         // Still has significand bits after mod 2^<bits>
648         // Get low <bits> bits by shift left <64 - bits> and shift right <64 - bits>
649         uint64_t value = (((u64 & DOUBLE_SIGNIFICAND_MASK) | DOUBLE_HIDDEN_BIT)
650                           << (exp - DOUBLE_SIGNIFICAND_SIZE + INT64_BITS - bits)) >>
651                          (INT64_BITS - bits);
652         ret = static_cast<int32_t>(value);
653         if ((u64 & DOUBLE_SIGN_MASK) == DOUBLE_SIGN_MASK && ret != INT32_MIN) {
654             ret = -ret;
655         }
656     } else {
657         // No significand bits after mod 2^<bits>, contains NaN and INF
658         ret = 0;
659     }
660     return ret;
661 }
662 
DoubleInRangeInt32(double d)663 int32_t NumberHelper::DoubleInRangeInt32(double d)
664 {
665     if (d > INT_MAX) {
666         return INT_MAX;
667     }
668     if (d < INT_MIN) {
669         return INT_MIN;
670     }
671     return base::NumberHelper::DoubleToInt(d, base::INT32_BITS);
672 }
673 
StringToBigInt(JSThread * thread,JSHandle<JSTaggedValue> strVal)674 JSTaggedValue NumberHelper::StringToBigInt(JSThread *thread, JSHandle<JSTaggedValue> strVal)
675 {
676     Span<const uint8_t> str;
677     auto strObj = static_cast<EcmaString *>(strVal->GetTaggedObject());
678     size_t strLen = strObj->GetLength();
679     if (strLen == 0) {
680         return BigInt::Int32ToBigInt(thread, 0).GetTaggedValue();
681     }
682     [[maybe_unused]] CVector<uint8_t> buf;  // Span will use buf.data(), shouldn't define inside 'if'
683     if (UNLIKELY(strObj->IsUtf16())) {
684         size_t len = base::utf_helper::Utf16ToUtf8Size(strObj->GetDataUtf16(), strLen) - 1;
685         buf.reserve(len);
686         len = base::utf_helper::ConvertRegionUtf16ToUtf8(strObj->GetDataUtf16(), buf.data(), strLen, len, 0);
687         str = Span<const uint8_t>(buf.data(), len);
688     } else {
689         str = Span<const uint8_t>(strObj->GetDataUtf8(), strLen);
690     }
691     auto p = const_cast<uint8_t *>(str.begin());
692     auto end = str.end();
693     // 1. skip space and line terminal
694     if (!NumberHelper::GotoNonspace(&p, end)) {
695         return BigInt::Int32ToBigInt(thread, 0).GetTaggedValue();
696     }
697     // 2. get bigint sign
698     Sign sign = Sign::NONE;
699     if (*p == '+') {
700         RETURN_IF_CONVERSION_END(++p, end, JSTaggedValue(NAN_VALUE));
701         sign = Sign::POS;
702     } else if (*p == '-') {
703         RETURN_IF_CONVERSION_END(++p, end, JSTaggedValue(NAN_VALUE));
704         sign = Sign::NEG;
705     }
706     // 3. bigint not allow Infinity, decimal points, or exponents.
707     if (isalpha(*p)) {
708         return JSTaggedValue(NAN_VALUE);
709     }
710     // 4. get bigint radix
711     uint8_t radix = DECIMAL;
712     if (*p == '0') {
713         if (++p == end) {
714             return BigInt::Int32ToBigInt(thread, 0).GetTaggedValue();
715         }
716         if (*p == 'x' || *p == 'X') {
717             RETURN_IF_CONVERSION_END(++p, end, JSTaggedValue(NAN_VALUE));
718             if (sign != Sign::NONE) {
719                 return JSTaggedValue(NAN_VALUE);
720             }
721             radix = HEXADECIMAL;
722         } else if (*p == 'o' || *p == 'O') {
723             RETURN_IF_CONVERSION_END(++p, end, JSTaggedValue(NAN_VALUE));
724             if (sign != Sign::NONE) {
725                 return JSTaggedValue(NAN_VALUE);
726             }
727             radix = OCTAL;
728         } else if (*p == 'b' || *p == 'B') {
729             RETURN_IF_CONVERSION_END(++p, end, JSTaggedValue(NAN_VALUE));
730             if (sign != Sign::NONE) {
731                 return JSTaggedValue(NAN_VALUE);
732             }
733             radix = BINARY;
734         }
735     }
736 
737     auto pStart = p;
738     // 5. skip leading '0'
739     while (*p == '0') {
740         if (++p == end) {
741             return BigInt::Int32ToBigInt(thread, 0).GetTaggedValue();
742         }
743     }
744     // 6. parse to bigint
745     std::string buffer;
746     if (sign == Sign::NEG) {
747         buffer += "-";
748     }
749     do {
750         uint8_t c = ToDigit(*p);
751         if (c >= radix) {
752             if (pStart != p && !NumberHelper::GotoNonspace(&p, end)) {
753                 break;
754             }
755             return JSTaggedValue(NAN_VALUE);
756         }
757         buffer += *p;
758     } while (++p != end);
759     return BigIntHelper::SetBigInt(thread, buffer, radix).GetTaggedValue();
760 }
GetRandomState()761 uint64_t &RandomGenerator::GetRandomState()
762 {
763     return randomState;
764 }
XorShift64(uint64_t * pVal)765 uint64_t RandomGenerator::XorShift64(uint64_t *pVal)
766 {
767     uint64_t x = *pVal;
768     x ^= x >> RIGHT12;
769     x ^= x << LEFT25;
770     x ^= x >> RIGHT27;
771     *pVal = x;
772     return x * GET_MULTIPLY;
773 }
InitRandom()774 void RandomGenerator::InitRandom()
775 {
776     struct timeval tv;
777     gettimeofday(&tv, NULL);
778     randomState = static_cast<uint64_t>((tv.tv_sec * SECONDS_TO_SUBTLE) + tv.tv_usec);
779     // the state must be non zero
780     if (randomState == 0) {
781         randomState = 1;
782     }
783 }
784 }  // namespace panda::ecmascript::base
785