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