From 9dcfe450d40953694f1536bb58d52390f8fb469c Mon Sep 17 00:00:00 2001 From: zhixinaa <1696730989@qq.com> Date: Tue, 22 Aug 2023 09:23:09 +0800 Subject: [PATCH] Optimise Number.parseFloat issue:I7YFC6 Change-Id: Ib28a98211e0fc1610d0da840afd13fca82089901 Signed-off-by: zhixinaa <1696730989@qq.com> --- ecmascript/base/number_helper.cpp | 191 +++++++++++++++++------- ecmascript/base/number_helper.h | 4 +- ecmascript/builtins/builtins_number.cpp | 3 - 3 files changed, 140 insertions(+), 58 deletions(-) diff --git a/ecmascript/base/number_helper.cpp b/ecmascript/base/number_helper.cpp index b1541be437..0d93665af8 100644 --- a/ecmascript/base/number_helper.cpp +++ b/ecmascript/base/number_helper.cpp @@ -53,26 +53,88 @@ static inline uint8_t ToDigit(uint8_t c) return '$'; } -bool NumberHelper::GotoNonspace(uint8_t **ptr, const uint8_t *end) +constexpr bool IsOneByteWhitespaceOrLineTerminator(uint8_t c) { + return c == '\t' || c == '\v' || c == '\f' || c == ' ' || c == u'\xa0' ||c == '\r' || c == '\n'; +} +static const double exact_powers_of_ten[] = { + 1.0, // 10^0 + 10.0, + 100.0, + 1000.0, + 10000.0, + 100000.0, + 1000000.0, + 10000000.0, + 100000000.0, + 1000000000.0, + 10000000000.0, // 10^10 + 100000000000.0, + 1000000000000.0, + 10000000000000.0, + 100000000000000.0, + 1000000000000000.0, + 10000000000000000.0, + 100000000000000000.0, + 1000000000000000000.0, + 10000000000000000000.0, + 100000000000000000000.0, // 10^20 + 1000000000000000000000.0, // 10^22 = 0x21E19E0C9BAB2400000 = 0x878678326EAC9 * 2^22 + 10000000000000000000000.0 +}; + +static const int kExactPowersOfTenSize = 24; + +#define INT_0_TO_127_LIST(V) \ +V(0) V(1) V(2) V(3) V(4) V(5) V(6) V(7) V(8) V(9) \ +V(10) V(11) V(12) V(13) V(14) V(15) V(16) V(17) V(18) V(19) \ +V(20) V(21) V(22) V(23) V(24) V(25) V(26) V(27) V(28) V(29) \ +V(30) V(31) V(32) V(33) V(34) V(35) V(36) V(37) V(38) V(39) \ +V(40) V(41) V(42) V(43) V(44) V(45) V(46) V(47) V(48) V(49) \ +V(50) V(51) V(52) V(53) V(54) V(55) V(56) V(57) V(58) V(59) \ +V(60) V(61) V(62) V(63) V(64) V(65) V(66) V(67) V(68) V(69) \ +V(70) V(71) V(72) V(73) V(74) V(75) V(76) V(77) V(78) V(79) \ +V(80) V(81) V(82) V(83) V(84) V(85) V(86) V(87) V(88) V(89) \ +V(90) V(91) V(92) V(93) V(94) V(95) V(96) V(97) V(98) V(99) \ +V(100) V(101) V(102) V(103) V(104) V(105) V(106) V(107) V(108) V(109) \ +V(110) V(111) V(112) V(113) V(114) V(115) V(116) V(117) V(118) V(119) \ +V(120) V(121) V(122) V(123) V(124) V(125) V(126) V(127) + +const constexpr bool kOneByteCharFlags[256] = { +#define BUILD_CHAR_FLAGS(N) IsOneByteWhitespaceOrLineTerminator(N), + INT_0_TO_127_LIST(BUILD_CHAR_FLAGS) +#undef BUILD_CHAR_FLAGS +#define BUILD_CHAR_FLAGS(N) IsOneByteWhitespaceOrLineTerminator(N + 128), + INT_0_TO_127_LIST(BUILD_CHAR_FLAGS) +#undef BUILD_CHAR_FLAGS +}; + +bool IsWhiteSpaceOrLineTerminator(uint8_t **ptr, const uint8_t *end) { + uint16_t c = **ptr; + size_t size = 0; + uint16_t utf8Bit = INT8_MAX + 1; // equal 0b1000'0000 + while (utf8Bit > 0 && (c & utf8Bit) == utf8Bit) { + ++size; + utf8Bit >>= 1UL; + } + + if (base::utf_helper::ConvertRegionUtf8ToUtf16(*ptr, &c, end - *ptr, 1, 0) <= 0) { + return true; + } + if (!StringHelper::IsNonspace(c)) return true; + *ptr += size; + return false; +} +inline bool NumberHelper::GotoNonspace(uint8_t **ptr, const uint8_t *end) { while (*ptr < end) { uint16_t c = **ptr; - size_t size = 1; if (c > INT8_MAX) { - size = 0; - uint16_t utf8Bit = INT8_MAX + 1; // equal 0b1000'0000 - while (utf8Bit > 0 && (c & utf8Bit) == utf8Bit) { - ++size; - utf8Bit >>= 1UL; - } - if (base::utf_helper::ConvertRegionUtf8ToUtf16(*ptr, &c, end - *ptr, 1, 0) <= 0) { - return true; - } + if(IsWhiteSpaceOrLineTerminator(ptr,end)) return true; } - if (!StringHelper::IsNonspace(c)) { - return true; + else { + if (!kOneByteCharFlags[c]) return true; + ++*ptr; } - *ptr += size; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) } return false; } @@ -451,8 +513,29 @@ int64_t NumberHelper::DoubleToInt64(double d) return static_cast(d); } +static uint64_t ReadUint64(CString buffer,int radix, int & exp){ + uint64_t intNumber = 0; + uint64_t numberMax = (UINT64_MAX - (radix - 1)) / radix; + if (!buffer.size()) { + return 0; + } + + if (buffer[0] != '-') { + intNumber = ToDigit(buffer[0]); + } + for (size_t i=1;i(start); // 1. skip space and line terminal if (!NumberHelper::GotoNonspace(&p, end)) { @@ -467,6 +550,7 @@ double NumberHelper::StringToDouble(const uint8_t *start, const uint8_t *end, ui } else if (*p == '-') { RETURN_IF_CONVERSION_END(++p, end, NAN_VALUE); sign = Sign::NEG; + buffer += "-"; } bool ignoreTrailing = (flags & IGNORE_TRAILING) != 0; @@ -536,8 +620,6 @@ double NumberHelper::StringToDouble(const uint8_t *start, const uint8_t *end, ui leadingZero = true; } // 6. parse to number - uint64_t intNumber = 0; - uint64_t numberMax = (UINT64_MAX - (radix - 1)) / radix; int digits = 0; int exponent = 0; do { @@ -549,39 +631,51 @@ double NumberHelper::StringToDouble(const uint8_t *start, const uint8_t *end, ui // "0b" "0x1.2" "0b1e2" ... return NAN_VALUE; } + buffer += *p; ++digits; - if (intNumber < numberMax) { - intNumber = intNumber * radix + c; - } else { - ++exponent; - } } while (++p != end); - auto number = static_cast(intNumber); - if (sign == Sign::NEG) { - if (number == 0) { - number = -0.0; - } else { - number = -number; - } - } - // 7. deal with other radix except DECIMAL if (p == end || radix != DECIMAL) { if ((digits == 0 && !leadingZero) || (p != end && !ignoreTrailing && NumberHelper::GotoNonspace(&p, end))) { // no digits there, like "0x", "0xh", or error trailing of "0x3q" return NAN_VALUE; } + uint64_t intNumber = ReadUint64(buffer, radix, exponent); + double number = static_cast(intNumber); + if (sign == Sign::NEG) { + if (number == 0) { + number = -0.0; + } else { + number = -number; + } + } return number * std::pow(radix, exponent); } // 8. parse '.' if (radix == DECIMAL && *p == '.') { - RETURN_IF_CONVERSION_END(++p, end, (digits > 0 || (digits == 0 && leadingZero)) ? - (number * std::pow(radix, exponent)) : NAN_VALUE); + if (++p == end) { + if(digits == 0 && !leadingZero){ + return NAN_VALUE; + } + else{ + uint64_t intNumber = ReadUint64(buffer, radix, exponent); + double number = static_cast(intNumber); + if (sign == Sign::NEG) { + if (number == 0) { + number = -0.0; + } else { + number = -number; + } + } + return number * std::pow(radix, exponent); + } + } while (ToDigit(*p) < radix) { --exponent; ++digits; + buffer += *p; if (++p == end) { break; } @@ -591,7 +685,6 @@ double NumberHelper::StringToDouble(const uint8_t *start, const uint8_t *end, ui // no digits there, like ".", "sss", or ".e1" return NAN_VALUE; } - auto pEnd = p; // 9. parse 'e/E' with '+/-' char exponentSign = '+'; @@ -622,29 +715,17 @@ double NumberHelper::StringToDouble(const uint8_t *start, const uint8_t *end, ui return NAN_VALUE; } - // 10. build StringNumericLiteral string - CString buffer; - if (sign == Sign::NEG) { - buffer += "-"; - } - for (uint8_t *i = pStart; i < pEnd; ++i) { // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) - if (*i != static_cast('.')) { - buffer += *i; - } - } - // 11. convert none-prefix radix string - return Strtod(buffer.c_str(), exponent, radix); + return Strtod(buffer.c_str(), exponent); } -double NumberHelper::Strtod(const char *str, int exponent, uint8_t radix) +double NumberHelper::Strtod(const char *str, int exponent) { ASSERT(str != nullptr); - ASSERT(radix >= base::MIN_RADIX && radix <= base::MAX_RADIX); auto p = const_cast(str); Sign sign = Sign::NONE; uint64_t number = 0; - uint64_t numberMax = (UINT64_MAX - (radix - 1)) / radix; + uint64_t numberMax = (UINT64_MAX - (DECIMAL - 1)) / DECIMAL; double result = 0.0; if (*p == '-') { sign = Sign::NEG; @@ -655,21 +736,25 @@ double NumberHelper::Strtod(const char *str, int exponent, uint8_t radix) } while (*p != '\0') { uint8_t digit = ToDigit(static_cast(*p)); - if (digit >= radix) { + if (digit >= DECIMAL) { break; } if (number < numberMax) { - number = number * radix + digit; + number = number * DECIMAL + digit; } else { ++exponent; } ++p; } + int exponent_abs = exponent < 0?-exponent : exponent; + double pow_val = (exponent_abs str = EcmaStringAccessor(numberString).ToUtf8Span(buf); // 4. If neither trimmedString nor any prefix of trimmedString satisfies the syntax of a StrDecimalLiteral // (see 7.1.3.1), return NaN. - if (NumberHelper::IsEmptyString(str.begin(), str.end())) { - return BuiltinsBase::GetTaggedDouble(base::NAN_VALUE); - } double result = NumberHelper::StringToDouble(str.begin(), str.end(), 0, base::IGNORE_TRAILING); return GetTaggedDouble(result); } -- Gitee