diff options
author | Dániel Bátyai <dbatyai@inf.u-szeged.hu> | 2021-12-03 12:58:37 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-12-03 12:58:37 +0100 |
commit | 81d2319144377f87e716c73a9b8b46f2bf5d09e5 (patch) | |
tree | 92dd7f340e08bf8a42f7540b74659a218635b628 /jerry-core | |
parent | a1c1d4271061eff9f4bb4a0c9c31bb68c7f1514d (diff) |
Improve float number handling and conversion (#4820)
Fixes #4739.
JerryScript-DCO-1.0-Signed-off-by: Dániel Bátyai dbatyai@inf.u-szeged.hu
Diffstat (limited to 'jerry-core')
27 files changed, 982 insertions, 1564 deletions
diff --git a/jerry-core/CMakeLists.txt b/jerry-core/CMakeLists.txt index cdcb0f49..04815fce 100644 --- a/jerry-core/CMakeLists.txt +++ b/jerry-core/CMakeLists.txt @@ -283,7 +283,6 @@ set(SOURCE_CORE_FILES ecma/operations/ecma-iterator-object.c ecma/operations/ecma-jobqueue.c ecma/operations/ecma-lex-env.c - ecma/operations/ecma-number-arithmetic.c ecma/operations/ecma-number-object.c ecma/operations/ecma-objects-general.c ecma/operations/ecma-objects.c @@ -462,7 +461,6 @@ if(ENABLE_AMALGAM) ecma/operations/ecma-iterator-object.h ecma/operations/ecma-jobqueue.h ecma/operations/ecma-lex-env.h - ecma/operations/ecma-number-arithmetic.h ecma/operations/ecma-number-object.h ecma/operations/ecma-objects-general.h ecma/operations/ecma-objects.h diff --git a/jerry-core/ecma/base/ecma-globals.h b/jerry-core/ecma/base/ecma-globals.h index 1273ffc3..40f8db5a 100644 --- a/jerry-core/ecma/base/ecma-globals.h +++ b/jerry-core/ecma/base/ecma-globals.h @@ -1386,112 +1386,34 @@ typedef struct #define ECMA_PROPERTY_FLAGS_MASK \ ((uint16_t) (JERRY_PROP_IS_CONFIGURABLE | JERRY_PROP_IS_ENUMERABLE | JERRY_PROP_IS_WRITABLE)) -#if !JERRY_NUMBER_TYPE_FLOAT64 -/** - * Description of an ecma-number - */ -typedef float ecma_number_t; - -/** - * It makes possible to read/write an ecma_number_t as uint32_t without strict aliasing rule violation. - */ -typedef union -{ - ecma_number_t as_ecma_number_t; - uint32_t as_uint32_t; -} ecma_number_accessor_t; - -#define DOUBLE_TO_ECMA_NUMBER_T(value) (ecma_number_t) (value) - -/** - * Maximum number of significant digits that ecma-number can store - */ -#define ECMA_NUMBER_MAX_DIGITS (9) - -/** - * Width of sign field - * - * See also: - * IEEE-754 2008, 3.6, Table 3.5 - */ -#define ECMA_NUMBER_SIGN_WIDTH (1) - -/** - * Width of biased exponent field - * - * See also: - * IEEE-754 2008, 3.6, Table 3.5 - */ -#define ECMA_NUMBER_BIASED_EXP_WIDTH (8) - -/** - * Width of fraction field - * - * See also: - * IEEE-754 2008, 3.6, Table 3.5 - */ -#define ECMA_NUMBER_FRACTION_WIDTH (23) -#elif JERRY_NUMBER_TYPE_FLOAT64 /** * Description of an ecma-number */ +#if JERRY_NUMBER_TYPE_FLOAT64 typedef double ecma_number_t; +#else /* !JERRY_NUMBER_TYPE_FLOAT64 */ +typedef float ecma_number_t; +#endif /* !JERRY_NUMBER_TYPE_FLOAT64 */ /** - * It makes possible to read/write an ecma_number_t as uint64_t without strict aliasing rule violation. - */ -typedef union -{ - ecma_number_t as_ecma_number_t; - uint64_t as_uint64_t; -} ecma_number_accessor_t; - -#define DOUBLE_TO_ECMA_NUMBER_T(value) value - -/** - * Maximum number of significant digits that ecma-number can store - */ -#define ECMA_NUMBER_MAX_DIGITS (19) - -/** - * Width of sign field - * - * See also: - * IEEE-754 2008, 3.6, Table 3.5 - */ -#define ECMA_NUMBER_SIGN_WIDTH (1) - -/** - * Width of biased exponent field - * - * See also: - * IEEE-754 2008, 3.6, Table 3.5 - */ -#define ECMA_NUMBER_BIASED_EXP_WIDTH (11) - -/** - * Width of fraction field - * - * See also: - * IEEE-754 2008, 3.6, Table 3.5 + * Convert double to an ecma-number. */ -#define ECMA_NUMBER_FRACTION_WIDTH (52) -#endif /* !JERRY_NUMBER_TYPE_FLOAT64 */ +#define DOUBLE_TO_ECMA_NUMBER_T(value) ((ecma_number_t) (value)) /** * Value '0' of ecma_number_t */ -#define ECMA_NUMBER_ZERO ((ecma_number_t) 0) +#define ECMA_NUMBER_ZERO ((ecma_number_t) 0.0f) /** * Value '1' of ecma_number_t */ -#define ECMA_NUMBER_ONE ((ecma_number_t) 1) +#define ECMA_NUMBER_ONE ((ecma_number_t) 1.0f) /** * Value '2' of ecma_number_t */ -#define ECMA_NUMBER_TWO ((ecma_number_t) 2) +#define ECMA_NUMBER_TWO ((ecma_number_t) 2.0f) /** * Value '0.5' of ecma_number_t @@ -1501,117 +1423,7 @@ typedef union /** * Value '-1' of ecma_number_t */ -#define ECMA_NUMBER_MINUS_ONE ((ecma_number_t) -1) - -#if !JERRY_NUMBER_TYPE_FLOAT64 -/** - * Number.MIN_VALUE (i.e., the smallest positive value of ecma-number) - * - * See also: ECMA_262 v5, 15.7.3.3 - */ -#define ECMA_NUMBER_MIN_VALUE (FLT_MIN) -/** - * Number.MAX_VALUE (i.e., the maximum value of ecma-number) - * - * See also: ECMA_262 v5, 15.7.3.2 - */ -#define ECMA_NUMBER_MAX_VALUE (FLT_MAX) -/** - * Number.EPSILON - * - * See also: ECMA_262 v6, 20.1.2.1 - */ -#define ECMA_NUMBER_EPSILON ((ecma_number_t) 1.1920928955078125e-7) - -/** - * Number.MAX_SAFE_INTEGER - * - * See also: ECMA_262 v6, 20.1.2.6 - */ -#define ECMA_NUMBER_MAX_SAFE_INTEGER ((ecma_number_t) 0xFFFFFF) - -/** - * Number.MIN_SAFE_INTEGER - * - * See also: ECMA_262 v6, 20.1.2.8 - */ -#define ECMA_NUMBER_MIN_SAFE_INTEGER ((ecma_number_t) -0xFFFFFF) -#elif JERRY_NUMBER_TYPE_FLOAT64 -/** - * Number.MAX_VALUE (i.e., the maximum value of ecma-number) - * - * See also: ECMA_262 v5, 15.7.3.2 - */ -#define ECMA_NUMBER_MAX_VALUE ((ecma_number_t) 1.7976931348623157e+308) - -/** - * Number.MIN_VALUE (i.e., the smallest positive value of ecma-number) - * - * See also: ECMA_262 v5, 15.7.3.3 - */ -#define ECMA_NUMBER_MIN_VALUE ((ecma_number_t) 5e-324) - -/** - * Number.EPSILON - * - * See also: ECMA_262 v6, 20.1.2.1 - */ -#define ECMA_NUMBER_EPSILON ((ecma_number_t) 2.2204460492503130808472633361816e-16) - -/** - * Number.MAX_SAFE_INTEGER - * - * See also: ECMA_262 v6, 20.1.2.6 - */ -#define ECMA_NUMBER_MAX_SAFE_INTEGER ((ecma_number_t) 0x1FFFFFFFFFFFFF) - -/** - * Number.MIN_SAFE_INTEGER - * - * See also: ECMA_262 v6, 20.1.2.8 - */ -#define ECMA_NUMBER_MIN_SAFE_INTEGER ((ecma_number_t) -0x1FFFFFFFFFFFFF) -#endif /* !JERRY_NUMBER_TYPE_FLOAT64 */ - -/** - * Euler number - */ -#define ECMA_NUMBER_E ((ecma_number_t) 2.7182818284590452354) - -/** - * Natural logarithm of 10 - */ -#define ECMA_NUMBER_LN10 ((ecma_number_t) 2.302585092994046) - -/** - * Natural logarithm of 2 - */ -#define ECMA_NUMBER_LN2 ((ecma_number_t) 0.6931471805599453) - -/** - * Logarithm base 2 of the Euler number - */ -#define ECMA_NUMBER_LOG2E ((ecma_number_t) 1.4426950408889634) - -/** - * Logarithm base 10 of the Euler number - */ -#define ECMA_NUMBER_LOG10E ((ecma_number_t) 0.4342944819032518) - -/** - * Pi number - */ -#define ECMA_NUMBER_PI ((ecma_number_t) 3.1415926535897932) - -/** - * Square root of 0.5 - */ -#define ECMA_NUMBER_SQRT_1_2 ((ecma_number_t) 0.7071067811865476) - -/** - * Square root of 2 - */ -#define ECMA_NUMBER_SQRT2 ((ecma_number_t) 1.4142135623730951) +#define ECMA_NUMBER_MINUS_ONE ((ecma_number_t) -1.0f) /** * Maximum number of characters in string representation of ecma-number diff --git a/jerry-core/ecma/base/ecma-helpers-conversion.c b/jerry-core/ecma/base/ecma-helpers-conversion.c index 8a7a9d10..8409caa3 100644 --- a/jerry-core/ecma/base/ecma-helpers-conversion.c +++ b/jerry-core/ecma/base/ecma-helpers-conversion.c @@ -16,6 +16,7 @@ #include <math.h> #include "ecma-globals.h" +#include "ecma-helpers-number.h" #include "ecma-helpers.h" #include "jrt-libc-includes.h" @@ -41,8 +42,8 @@ */ typedef struct { - uint64_t lo; /**< low 64 bits */ uint64_t hi; /**< high 64 bits */ + uint64_t lo; /**< low 64 bits */ } ecma_uint128_t; /** @@ -60,58 +61,58 @@ ecma_round_high_to_uint64 (ecma_uint128_t *num_p) { return (num_p->hi + 1); } + return num_p->hi; } /* ecma_round_high_to_uint64 */ /** - * Check if 128-bit integer is zero + * Left shift 128-bit integer by max 63 bits. */ -#define ECMA_UINT128_IS_ZERO(name) (name.hi == 0 && name.lo == 0) +static void JERRY_ATTR_ALWAYS_INLINE +ecma_uint128_shift_left (ecma_uint128_t *num_p, int32_t shift) +{ + num_p->hi = (num_p->hi << shift) | (num_p->lo >> (64 - shift)); + num_p->lo <<= shift; +} /* ecma_uint128_shift_left */ /** - * Left shift 128-bit integer by max 63 bits + * Right shift 128-bit integer by max 63 bits. */ -#define ECMA_UINT128_LEFT_SHIFT_MAX63(name, shift) \ - { \ - name.hi = (name.hi << (shift)) | (name.lo >> (64 - (shift))); \ - name.lo <<= (shift); \ - } +static void JERRY_ATTR_ALWAYS_INLINE +ecma_uint128_shift_right (ecma_uint128_t *num_p, int32_t shift) +{ + num_p->lo = (num_p->lo >> shift) | (num_p->hi << (64 - shift)); + num_p->hi >>= shift; +} /* ecma_uint128_shift_right */ /** - * Right shift 128-bit integer by max 63 bits + * Add two 128-bit integer values and assign the result to the left one. */ -#define ECMA_UINT128_RIGHT_SHIFT_MAX63(name, shift) \ - { \ - name.lo = (name.lo >> (shift)) | (name.hi << (64 - (shift))); \ - name.hi >>= (shift); \ - } +static void +ecma_uint128_add (ecma_uint128_t *left_p, ecma_uint128_t *right_p) +{ + left_p->hi += right_p->hi; + left_p->lo += right_p->lo; -/** - * Add 128-bit integer - */ -#define ECMA_UINT128_ADD(name_add_to, name_to_add) \ - { \ - name_add_to.hi += name_to_add.hi; \ - name_add_to.lo += name_to_add.lo; \ - if (name_add_to.lo < name_to_add.lo) \ - { \ - name_add_to.hi++; \ - } \ + if (left_p->lo < right_p->lo) + { + left_p->hi++; } +} /* ecma_uint128_add */ /** * Multiply 128-bit integer by 10 */ -#define ECMA_UINT128_MUL10(name) \ - { \ - ECMA_UINT128_LEFT_SHIFT_MAX63 (name, 1u); \ - \ - ecma_uint128_t name##_tmp = name; \ - \ - ECMA_UINT128_LEFT_SHIFT_MAX63 (name##_tmp, 2u); \ - \ - ECMA_UINT128_ADD (name, name##_tmp); \ - } +static void +ecma_uint128_mul10 (ecma_uint128_t *num_p) +{ + ecma_uint128_shift_left (num_p, 1u); + + ecma_uint128_t tmp = { .hi = num_p->hi, .lo = num_p->lo }; + ecma_uint128_shift_left (&tmp, 2u); + + ecma_uint128_add (num_p, &tmp); +} /* ecma_uint128_mul10 */ /** * Divide 128-bit integer by 10 @@ -128,121 +129,122 @@ ecma_round_high_to_uint64 (ecma_uint128_t *num_p) * * Q = Q3 *2^96 + Q2 *2^64 + Q1 *2^32 + Q0 *2^0 // 128-bit quotient */ -#define ECMA_UINT128_DIV10(name) \ - { \ - /* estimation of reciprocal of 10, 128 bits right of the binary point (T1 == T2) */ \ - const uint64_t tenth_l = 0x9999999aul; \ - const uint64_t tenth_m = 0x99999999ul; \ - const uint64_t tenth_h = 0x19999999ul; \ - \ - uint64_t l0 = ((uint32_t) name.lo) * tenth_l; \ - uint64_t l1 = (name.lo >> 32u) * tenth_l; \ - uint64_t l2 = ((uint32_t) name.hi) * tenth_l; \ - uint64_t l3 = (name.hi >> 32u) * tenth_l; \ - uint64_t m0 = ((uint32_t) name.lo) * tenth_m; \ - uint64_t m1 = (name.lo >> 32u) * tenth_m; \ - uint64_t m2 = ((uint32_t) name.hi) * tenth_m; \ - uint64_t m3 = (name.hi >> 32u) * tenth_m; \ - uint64_t h0 = ((uint32_t) name.lo) * tenth_h; \ - uint64_t h1 = (name.lo >> 32u) * tenth_h; \ - uint64_t h2 = ((uint32_t) name.hi) * tenth_h; \ - uint64_t h3 = (name.hi >> 32u) * tenth_h; \ - \ - uint64_t q0 = l0 >> 32u; \ - q0 += (uint32_t) l1; \ - q0 += (uint32_t) m0; \ - \ - q0 >>= 32u; \ - q0 += l1 >> 32u; \ - q0 += m0 >> 32u; \ - q0 += (uint32_t) l2; \ - q0 += (uint32_t) m1; \ - q0 += (uint32_t) m0; \ - \ - q0 >>= 32u; \ - q0 += l2 >> 32u; \ - q0 += m1 >> 32u; \ - q0 += m0 >> 32u; \ - q0 += (uint32_t) l3; \ - q0 += (uint32_t) m2; \ - q0 += (uint32_t) m1; \ - q0 += (uint32_t) h0; \ - \ - q0 >>= 32u; \ - q0 += l3 >> 32u; \ - q0 += m2 >> 32u; \ - q0 += m1 >> 32u; \ - q0 += h0 >> 32u; \ - q0 += (uint32_t) m3; \ - q0 += (uint32_t) m2; \ - q0 += (uint32_t) h1; \ - \ - uint64_t q1 = q0 >> 32u; \ - q1 += m3 >> 32u; \ - q1 += m2 >> 32u; \ - q1 += h1 >> 32u; \ - q1 += (uint32_t) m3; \ - q1 += (uint32_t) h2; \ - \ - uint64_t q32 = q1 >> 32u; \ - q32 += m3 >> 32u; \ - q32 += h2 >> 32u; \ - q32 += h3; \ - \ - name.lo = (q1 << 32u) | ((uint32_t) q0); \ - name.hi = q32; \ - } - -#if defined(__GNUC__) || defined(__clang__) - -/** - * Count leading zeros in the topmost 64 bits of a 128-bit integer. - */ -#define ECMA_UINT128_CLZ_MAX63(name) __builtin_clzll (name.hi) - -/** - * Count leading zeros in the topmost 4 bits of a 128-bit integer. - */ -#define ECMA_UINT128_CLZ_MAX4(name) __builtin_clzll (name.hi) - -#else /* !__GNUC__ && !__clang__ */ +static void +ecma_uint128_div10 (ecma_uint128_t *num_p) +{ + /* estimation of reciprocal of 10, 128 bits right of the binary point (T1 == T2) */ + const uint64_t tenth_l = 0x9999999aul; + const uint64_t tenth_m = 0x99999999ul; + const uint64_t tenth_h = 0x19999999ul; + + const uint64_t l0 = ((uint32_t) num_p->lo) * tenth_l; + const uint64_t l1 = (num_p->lo >> 32u) * tenth_l; + const uint64_t l2 = ((uint32_t) num_p->hi) * tenth_l; + const uint64_t l3 = (num_p->hi >> 32u) * tenth_l; + const uint64_t m0 = ((uint32_t) num_p->lo) * tenth_m; + const uint64_t m1 = (num_p->lo >> 32u) * tenth_m; + const uint64_t m2 = ((uint32_t) num_p->hi) * tenth_m; + const uint64_t m3 = (num_p->hi >> 32u) * tenth_m; + const uint64_t h0 = ((uint32_t) num_p->lo) * tenth_h; + const uint64_t h1 = (num_p->lo >> 32u) * tenth_h; + const uint64_t h2 = ((uint32_t) num_p->hi) * tenth_h; + const uint64_t h3 = (num_p->hi >> 32u) * tenth_h; + + uint64_t q0 = l0 >> 32u; + q0 += (uint32_t) l1; + q0 += (uint32_t) m0; + + q0 >>= 32u; + q0 += l1 >> 32u; + q0 += m0 >> 32u; + q0 += (uint32_t) l2; + q0 += (uint32_t) m1; + q0 += (uint32_t) m0; + + q0 >>= 32u; + q0 += l2 >> 32u; + q0 += m1 >> 32u; + q0 += m0 >> 32u; + q0 += (uint32_t) l3; + q0 += (uint32_t) m2; + q0 += (uint32_t) m1; + q0 += (uint32_t) h0; + + q0 >>= 32u; + q0 += l3 >> 32u; + q0 += m2 >> 32u; + q0 += m1 >> 32u; + q0 += h0 >> 32u; + q0 += (uint32_t) m3; + q0 += (uint32_t) m2; + q0 += (uint32_t) h1; + + uint64_t q1 = q0 >> 32u; + q1 += m3 >> 32u; + q1 += m2 >> 32u; + q1 += h1 >> 32u; + q1 += (uint32_t) m3; + q1 += (uint32_t) h2; + + uint64_t q32 = q1 >> 32u; + q32 += m3 >> 32u; + q32 += h2 >> 32u; + q32 += h3; + + num_p->lo = (q1 << 32u) | ((uint32_t) q0); + num_p->hi = q32; +} /* ecma_uint128_div10 */ /** * Count leading zeros in a 64-bit integer. The behaviour is undefined for 0. * * @return number of leading zeros. */ -static inline int JERRY_ATTR_ALWAYS_INLINE +inline static int JERRY_ATTR_CONST ecma_uint64_clz (uint64_t n) /**< integer to count leading zeros in */ { +#if defined(__GNUC__) || defined(__clang__) + return __builtin_clzll (n); +#else /* !defined (__GNUC__) && !defined (__clang__) */ JERRY_ASSERT (n != 0); int cnt = 0; uint64_t one = 0x8000000000000000ull; + while ((n & one) == 0) { cnt++; one >>= 1; } + return cnt; +#endif /* !defined (__GNUC__) && !defined (__clang__) */ } /* ecma_uint64_clz */ /** - * Number of leading zeros in 4-bit integers. - */ -static const uint8_t ecma_uint4_clz[] = { 4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }; - -/** - * Count leading zeros in the topmost 64 bits of a 128-bit integer. + * Count leading zeros in the top 4 bits of a 64-bit integer. + * + * @return number of leading zeros in top 4 bits. */ -#define ECMA_UINT128_CLZ_MAX63(name) ecma_uint64_clz (name.hi) +inline static int JERRY_ATTR_ALWAYS_INLINE JERRY_ATTR_CONST +ecma_uint64_clz_top4 (uint64_t n) /**< integer to count leading zeros in */ +{ + static const uint8_t ecma_uint4_clz[] = { 4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }; + return ecma_uint4_clz[n >> 60]; +} /* ecma_uint64_clz */ /** - * Count leading zeros in the topmost 4 bits of a 128-bit integer. + * Shift required to clear 4 bits of a 64-bit integer. + * + * @return 0-4 */ -#define ECMA_UINT128_CLZ_MAX4(name) ecma_uint4_clz[name.hi >> 60] +inline static int JERRY_ATTR_ALWAYS_INLINE JERRY_ATTR_CONST +ecma_uint64_normalize_shift (uint64_t n) /**< integer to count leading zeros in */ +{ + static const uint8_t ecma_uint4_shift[] = { 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4 }; -#endif /* __GNUC__ || __clang__ */ + return ecma_uint4_shift[n >> 60]; +} /* ecma_uint64_normalize_shift */ /** * @} @@ -285,72 +287,58 @@ static const uint8_t ecma_uint4_clz[] = { 4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, * @return NaN - if the conversion fails * converted number - otherwise */ -static ecma_number_t +ecma_number_t ecma_utf8_string_to_number_by_radix (const lit_utf8_byte_t *str_p, /**< utf-8 string */ - const lit_utf8_byte_t *end_p, /**< end of utf-8 string */ - uint32_t radix) /**< radix */ + const lit_utf8_size_t string_size, /**< end of utf-8 string */ + uint32_t radix, /**< radix */ + uint32_t options) /**< option flags */ { #if JERRY_ESNEXT - bool allow_underscore = (radix & ECMA_CONVERSION_ALLOW_UNDERSCORE); - radix &= (uint32_t) ~ECMA_CONVERSION_ALLOW_UNDERSCORE; -#endif /* JERRY_ESNEXT */ - JERRY_ASSERT (radix == 2 || radix == 8 || radix == 16); - - ecma_number_t num = ECMA_NUMBER_ZERO; - -#if JERRY_ESNEXT - if (radix <= 8) - { - lit_code_point_t upper_limit = LIT_CHAR_0 + radix; + bool allow_underscore = (options & ECMA_CONVERSION_ALLOW_UNDERSCORE); +#else /* !JERRY_ESNEXT */ + JERRY_UNUSED (options); +#endif /* !JERRY_ESNEXT */ - for (const lit_utf8_byte_t *iter_p = str_p; iter_p <= end_p; iter_p++) - { - int32_t digit_value; + JERRY_ASSERT (radix == 2 || radix == 8 || radix == 16); + JERRY_ASSERT (*str_p == LIT_CHAR_0); - if (*iter_p >= LIT_CHAR_0 && *iter_p < upper_limit) - { - digit_value = (*iter_p - LIT_CHAR_0); - } - else - { - return ecma_number_make_nan (); - } + const lit_utf8_byte_t *end_p = str_p + string_size; - num = num * radix + (ecma_number_t) digit_value; - } + /* Skip leading zero */ + str_p++; - return num; + if (radix != 8 || LEXER_TO_ASCII_LOWERCASE (*str_p) == LIT_CHAR_LOWERCASE_O) + { + /* Skip radix specifier */ + str_p++; } -#endif /* JERRY_ESNEXT */ - for (const lit_utf8_byte_t *iter_p = str_p; iter_p <= end_p; iter_p++) + ecma_number_t num = ECMA_NUMBER_ZERO; + + while (str_p < end_p) { - int32_t digit_value; + lit_utf8_byte_t digit = *str_p++; - if (*iter_p >= LIT_CHAR_0 && *iter_p <= LIT_CHAR_9) - { - digit_value = (*iter_p - LIT_CHAR_0); - } - else if (*iter_p >= LIT_CHAR_LOWERCASE_A && *iter_p <= LIT_CHAR_LOWERCASE_F) - { - digit_value = 10 + (*iter_p - LIT_CHAR_LOWERCASE_A); - } - else if (*iter_p >= LIT_CHAR_UPPERCASE_A && *iter_p <= LIT_CHAR_UPPERCASE_F) - { - digit_value = 10 + (*iter_p - LIT_CHAR_UPPERCASE_A); - } #if JERRY_ESNEXT - else if (*iter_p == LIT_CHAR_UNDERSCORE && allow_underscore) + if (digit == LIT_CHAR_UNDERSCORE && allow_underscore) { continue; } #endif /* JERRY_ESNEXT */ - else + + if (!lit_char_is_hex_digit (digit)) { return ecma_number_make_nan (); } - num = num * (ecma_number_t) radix + (ecma_number_t) digit_value; + uint32_t value = lit_char_hex_to_int (digit); + + if (value >= radix) + { + return ecma_number_make_nan (); + } + + num = num * radix + value; } return num; @@ -370,45 +358,15 @@ ecma_utf8_string_to_number (const lit_utf8_byte_t *str_p, /**< utf-8 string */ lit_utf8_size_t str_size, /**< string size */ uint32_t options) /**< allowing underscore option bit */ { - /* TODO: Check license issues */ - - if (str_size == 0) - { - return ECMA_NUMBER_ZERO; - } - ecma_string_trim_helper (&str_p, &str_size); - const lit_utf8_byte_t *end_p = str_p + (str_size - 1); + const lit_utf8_byte_t *end_p = str_p + str_size; - if (str_size < 1) + if (str_size == 0) { return ECMA_NUMBER_ZERO; } - if (end_p >= str_p + 2 && str_p[0] == LIT_CHAR_0) - { - switch (LEXER_TO_ASCII_LOWERCASE (str_p[1])) - { - case LIT_CHAR_LOWERCASE_X: - { - return ecma_utf8_string_to_number_by_radix (str_p + 2, end_p, 16 | options); - } - case LIT_CHAR_LOWERCASE_O: - { - return ecma_utf8_string_to_number_by_radix (str_p + 2, end_p, 8 | options); - } - case LIT_CHAR_LOWERCASE_B: - { - return ecma_utf8_string_to_number_by_radix (str_p + 2, end_p, 2 | options); - } - default: - { - break; - } - } - } - - bool sign = false; /* positive */ + bool sign = false; if (*str_p == LIT_CHAR_PLUS) { @@ -416,122 +374,117 @@ ecma_utf8_string_to_number (const lit_utf8_byte_t *str_p, /**< utf-8 string */ } else if (*str_p == LIT_CHAR_MINUS) { - sign = true; /* negative */ - + sign = true; str_p++; } - if (str_p > end_p) + if (str_p + 2 < end_p && str_p[0] == LIT_CHAR_0) { - return ecma_number_make_nan (); - } + uint8_t radix = lit_char_to_radix (str_p[1]); - /* Checking if significant part of parse string is equal to "Infinity" */ - const lit_utf8_byte_t *infinity_zt_str_p = lit_get_magic_string_utf8 (LIT_MAGIC_STRING_INFINITY_UL); + if (radix != 10) + { + return ecma_utf8_string_to_number_by_radix (str_p, str_size, radix, options); + } + } - JERRY_ASSERT (strlen ((const char *) infinity_zt_str_p) == 8); + /* Check if string is equal to "Infinity". */ + const lit_utf8_byte_t *infinity_str_p = lit_get_magic_string_utf8 (LIT_MAGIC_STRING_INFINITY_UL); + const lit_utf8_size_t infinity_length = lit_get_magic_string_size (LIT_MAGIC_STRING_INFINITY_UL); - if ((end_p - str_p) == (8 - 1) && memcmp (infinity_zt_str_p, str_p, 8) == 0) + if ((lit_utf8_size_t) (end_p - str_p) == infinity_length && memcmp (infinity_str_p, str_p, infinity_length) == 0) { return ecma_number_make_infinity (sign); } - uint64_t fraction_uint64 = 0; - uint32_t digits = 0; - int32_t e = 0; - bool digit_seen = false; + uint64_t significand = 0; + uint32_t digit_count = 0; + int32_t decimal_exponent = 0; + bool has_significand = false; - /* Parsing digits before dot (or before end of digits part if there is no dot in number) */ - while (str_p <= end_p) + /* Parsing integer part */ + while (str_p < end_p) { - int32_t digit_value; - - if (*str_p >= LIT_CHAR_0 && *str_p <= LIT_CHAR_9) - { - digit_seen = true; - digit_value = (*str_p - LIT_CHAR_0); - } #if JERRY_ESNEXT - else if (*str_p == LIT_CHAR_UNDERSCORE && (options & ECMA_CONVERSION_ALLOW_UNDERSCORE)) + if (*str_p == LIT_CHAR_UNDERSCORE && (options & ECMA_CONVERSION_ALLOW_UNDERSCORE)) { str_p++; continue; } #endif /* JERRY_ESNEXT */ - else + + if (!lit_char_is_decimal_digit (*str_p)) { break; } - if (digits != 0 || digit_value != 0) + has_significand = true; + uint32_t digit_value = (uint32_t) (*str_p++ - LIT_CHAR_0); + + if (digit_count == 0 && digit_value == 0) { - if (digits < ECMA_NUMBER_MAX_DIGITS) - { - fraction_uint64 = fraction_uint64 * 10 + (uint32_t) digit_value; - digits++; - } - else - { - e++; - } + /* Leading zeros are omitted. */ + continue; } - str_p++; + if (digit_count >= ECMA_NUMBER_MAX_DIGITS) + { + decimal_exponent++; + continue; + } + + significand = significand * 10 + digit_value; + digit_count++; } - if (str_p <= end_p && *str_p == LIT_CHAR_DOT) + /* Parse fraction part */ + if (str_p < end_p && *str_p == LIT_CHAR_DOT) { str_p++; - if (!digit_seen && str_p > end_p) + while (str_p < end_p) { - return ecma_number_make_nan (); - } - - /* Parsing number's part that is placed after dot */ - while (str_p <= end_p) - { - int32_t digit_value; - - if (*str_p >= LIT_CHAR_0 && *str_p <= LIT_CHAR_9) - { - digit_seen = true; - digit_value = (*str_p - LIT_CHAR_0); - } - else if (*str_p == LIT_CHAR_UNDERSCORE && (options & ECMA_CONVERSION_ALLOW_UNDERSCORE)) +#if JERRY_ESNEXT + if (*str_p == LIT_CHAR_UNDERSCORE && (options & ECMA_CONVERSION_ALLOW_UNDERSCORE)) { str_p++; continue; } - else +#endif /* JERRY_ESNEXT */ + + if (!lit_char_is_decimal_digit (*str_p)) { break; } - if (digits < ECMA_NUMBER_MAX_DIGITS) - { - if (digits != 0 || digit_value != 0) - { - fraction_uint64 = fraction_uint64 * 10 + (uint32_t) digit_value; - digits++; - } + has_significand = true; + uint32_t digit_value = (uint32_t) (*str_p++ - LIT_CHAR_0); - e--; + if (digit_count == 0 && digit_value == 0) + { + /* Leading zeros are omitted. */ + decimal_exponent--; + continue; } - str_p++; + if (digit_count < ECMA_NUMBER_MAX_DIGITS) + { + significand = significand * 10 + digit_value; + digit_count++; + decimal_exponent--; + } } } - /* Parsing exponent literal */ - int32_t e_in_lit = 0; - bool e_in_lit_sign = false; - - if (str_p <= end_p && (*str_p == LIT_CHAR_LOWERCASE_E || *str_p == LIT_CHAR_UPPERCASE_E)) + /* Parsing exponent */ + if (str_p < end_p && LEXER_TO_ASCII_LOWERCASE (*str_p) == LIT_CHAR_LOWERCASE_E) { str_p++; - if (!digit_seen || str_p > end_p) + int32_t exponent = 0; + int32_t exponent_sign = 1; + + if (str_p >= end_p) { return ecma_number_make_nan (); } @@ -542,81 +495,53 @@ ecma_utf8_string_to_number (const lit_utf8_byte_t *str_p, /**< utf-8 string */ } else if (*str_p == LIT_CHAR_MINUS) { - e_in_lit_sign = true; + exponent_sign = -1; str_p++; } - if (str_p > end_p) + if (str_p >= end_p || !lit_char_is_decimal_digit (*str_p)) { return ecma_number_make_nan (); } - while (str_p <= end_p) + while (str_p < end_p) { - int32_t digit_value; - - if (*str_p >= LIT_CHAR_0 && *str_p <= LIT_CHAR_9) - { - digit_value = (*str_p - LIT_CHAR_0); - } #if JERRY_ESNEXT - else if (*str_p == LIT_CHAR_UNDERSCORE && (options & ECMA_CONVERSION_ALLOW_UNDERSCORE)) + if (*str_p == LIT_CHAR_UNDERSCORE && (options & ECMA_CONVERSION_ALLOW_UNDERSCORE)) { str_p++; continue; } #endif /* JERRY_ESNEXT */ - else + + if (!lit_char_is_decimal_digit (*str_p)) { - return ecma_number_make_nan (); + break; } - e_in_lit = e_in_lit * 10 + digit_value; - int32_t e_check = e + (int32_t) digits - 1 + (e_in_lit_sign ? -e_in_lit : e_in_lit); + int32_t digit_value = (*str_p++ - LIT_CHAR_0); + exponent = exponent * 10 + digit_value; - if (e_check > NUMBER_MAX_DECIMAL_EXPONENT) + if (exponent_sign * exponent > NUMBER_MAX_DECIMAL_EXPONENT) { return ecma_number_make_infinity (sign); } - else if (e_check < NUMBER_MIN_DECIMAL_EXPONENT) + + if (exponent_sign * exponent < NUMBER_MIN_DECIMAL_EXPONENT) { return sign ? -ECMA_NUMBER_ZERO : ECMA_NUMBER_ZERO; } - - str_p++; } - } - /* Adding value of exponent literal to exponent value */ - if (e_in_lit_sign) - { - e -= e_in_lit; - } - else - { - e += e_in_lit; + decimal_exponent += exponent_sign * exponent; } - bool e_sign; - - if (e < 0) - { - e_sign = true; - e = -e; - } - else - { - e_sign = false; - } - - if (str_p <= end_p) + if (!has_significand || str_p < end_p) { return ecma_number_make_nan (); } - JERRY_ASSERT (str_p == end_p + 1); - - if (fraction_uint64 == 0) + if (significand == 0) { return sign ? -ECMA_NUMBER_ZERO : ECMA_NUMBER_ZERO; } @@ -627,85 +552,93 @@ ecma_utf8_string_to_number (const lit_utf8_byte_t *str_p, /**< utf-8 string */ * * Normalized: |4 bits zero|124-bit mantissa with highest bit set to 1| */ - ecma_uint128_t fraction_uint128 = { 0, fraction_uint64 }; + ecma_uint128_t significand_uint128 = { .hi = significand, .lo = 0 }; /* Normalizing mantissa */ - int shift = 4 - ECMA_UINT128_CLZ_MAX63 (fraction_uint128); + int shift = 4 - ecma_uint64_clz (significand_uint128.hi); + if (shift < 0) { - ECMA_UINT128_LEFT_SHIFT_MAX63 (fraction_uint128, -shift); + ecma_uint128_shift_left (&significand_uint128, -shift); } else { - ECMA_UINT128_RIGHT_SHIFT_MAX63 (fraction_uint128, shift); + ecma_uint128_shift_right (&significand_uint128, shift); } - int32_t binary_exponent = 1 + shift; - if (!e_sign) - { - /* positive or zero decimal exponent */ - JERRY_ASSERT (e >= 0); + int32_t binary_exponent = ECMA_NUMBER_FRACTION_WIDTH + shift; - while (e > 0) - { - JERRY_ASSERT (ECMA_UINT128_CLZ_MAX63 (fraction_uint128) == 4); - - ECMA_UINT128_MUL10 (fraction_uint128); - - e--; - - /* Normalizing mantissa */ - shift = 4 - ECMA_UINT128_CLZ_MAX4 (fraction_uint128); - JERRY_ASSERT (shift >= 0); - ECMA_UINT128_RIGHT_SHIFT_MAX63 (fraction_uint128, shift); - binary_exponent += shift; - } - } - else + while (decimal_exponent > 0) { - /* negative decimal exponent */ - JERRY_ASSERT (e != 0); + JERRY_ASSERT (ecma_uint64_clz (significand_uint128.hi) == 4); - while (e > 0) - { - /* Denormalizing mantissa, moving highest 1 to bit 127 */ - shift = ECMA_UINT128_CLZ_MAX4 (fraction_uint128); - JERRY_ASSERT (shift <= 4); - ECMA_UINT128_LEFT_SHIFT_MAX63 (fraction_uint128, shift); - binary_exponent -= shift; + ecma_uint128_mul10 (&significand_uint128); + decimal_exponent--; - JERRY_ASSERT (!ECMA_UINT128_IS_ZERO (fraction_uint128)); + /* Re-normalizing mantissa */ + shift = ecma_uint64_normalize_shift (significand_uint128.hi); + JERRY_ASSERT (shift >= 0 && shift <= 4); - ECMA_UINT128_DIV10 (fraction_uint128); + ecma_uint128_shift_right (&significand_uint128, shift); + binary_exponent += shift; + } - e--; - } + while (decimal_exponent < 0) + { + /* Denormalizing mantissa, moving highest 1 to bit 127 */ + JERRY_ASSERT (ecma_uint64_clz (significand_uint128.hi) <= 4); + shift = ecma_uint64_clz_top4 (significand_uint128.hi); + JERRY_ASSERT (shift >= 0 && shift <= 4); - /* Normalizing mantissa */ - shift = 4 - ECMA_UINT128_CLZ_MAX4 (fraction_uint128); - JERRY_ASSERT (shift >= 0); - ECMA_UINT128_RIGHT_SHIFT_MAX63 (fraction_uint128, shift); - binary_exponent += shift; + ecma_uint128_shift_left (&significand_uint128, shift); + binary_exponent -= shift; - JERRY_ASSERT (ECMA_UINT128_CLZ_MAX63 (fraction_uint128) == 4); + ecma_uint128_div10 (&significand_uint128); + decimal_exponent++; } - JERRY_ASSERT (!ECMA_UINT128_IS_ZERO (fraction_uint128)); - JERRY_ASSERT (ECMA_UINT128_CLZ_MAX63 (fraction_uint128) == 4); - /* * Preparing mantissa for conversion to 52-bit representation, converting it to: * * |11 zero bits|1|116 mantissa bits| */ - ECMA_UINT128_RIGHT_SHIFT_MAX63 (fraction_uint128, 7u); - binary_exponent += 7; + JERRY_ASSERT (ecma_uint64_clz (significand_uint128.hi) <= 4); + shift = 11 - ecma_uint64_clz_top4 (significand_uint128.hi); + ecma_uint128_shift_right (&significand_uint128, shift); + binary_exponent += shift; + + JERRY_ASSERT (ecma_uint64_clz (significand_uint128.hi) == 11); + + binary_exponent += ECMA_NUMBER_EXPONENT_BIAS; + + /* Handle denormal numbers */ + if (binary_exponent < 1) + { + ecma_uint128_shift_right (&significand_uint128, -binary_exponent + 1); + binary_exponent = 0; + } - JERRY_ASSERT (ECMA_UINT128_CLZ_MAX63 (fraction_uint128) == 11); + significand = ecma_round_high_to_uint64 (&significand_uint128); - fraction_uint64 = ecma_round_high_to_uint64 (&fraction_uint128); + if (significand >= 1ull << (ECMA_NUMBER_FRACTION_WIDTH + 1)) + { + /* Rounding carried over to the most significant bit, re-normalize. + * No need to shift mantissa right, as the low 52 bits will be 0 regardless. */ + binary_exponent++; + } - return ecma_number_make_from_sign_mantissa_and_exponent (sign, fraction_uint64, binary_exponent); + if (binary_exponent >= ((1 << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1)) + { + return ecma_number_make_infinity (sign); + } + + /* Mask low 52 bits. */ + significand &= ((1ull << ECMA_NUMBER_FRACTION_WIDTH) - 1); + + JERRY_ASSERT (binary_exponent < (1 << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1); + JERRY_ASSERT (significand < (1ull << ECMA_NUMBER_FRACTION_WIDTH)); + + return ecma_number_create (sign, (uint32_t) binary_exponent, significand); #elif !JERRY_NUMBER_TYPE_FLOAT64 /* Less precise conversion */ ecma_number_t num = (ecma_number_t) (uint32_t) fraction_uint64; @@ -791,7 +724,7 @@ ecma_number_to_uint32 (ecma_number_t num) /**< ecma-number */ if (abs_num >= num_2_pow_32) { - num_in_uint32_range = ecma_number_calc_remainder (abs_num, num_2_pow_32); + num_in_uint32_range = ecma_number_remainder (abs_num, num_2_pow_32); } else { @@ -940,8 +873,6 @@ ecma_number_to_utf8_string (ecma_number_t num, /**< ecma-number */ return (lit_utf8_size_t) (dst_p - buffer_p); } - JERRY_ASSERT (ecma_number_get_next (ecma_number_get_prev (num)) == num); - /* 5. */ uint32_t num_uint32 = ecma_number_to_uint32 (num); diff --git a/jerry-core/ecma/base/ecma-helpers-number.c b/jerry-core/ecma/base/ecma-helpers-number.c index a7921436..8e3241b2 100644 --- a/jerry-core/ecma/base/ecma-helpers-number.c +++ b/jerry-core/ecma/base/ecma-helpers-number.c @@ -13,6 +13,8 @@ * limitations under the License. */ +#include "ecma-helpers-number.h" + #include <math.h> #include "ecma-conversion.h" @@ -33,179 +35,97 @@ JERRY_STATIC_ASSERT (ECMA_DIRECT_SHIFT == ECMA_VALUE_SHIFT + 1, currently_direct JERRY_STATIC_ASSERT (((1 << (ECMA_DIRECT_SHIFT - 1)) | ECMA_TYPE_DIRECT) == ECMA_DIRECT_TYPE_SIMPLE_VALUE, currently_directly_encoded_values_start_after_direct_type_simple_value); -/** - * Position of the sign bit in ecma-numbers - */ -#define ECMA_NUMBER_SIGN_POS (ECMA_NUMBER_FRACTION_WIDTH + ECMA_NUMBER_BIASED_EXP_WIDTH) -#if !JERRY_NUMBER_TYPE_FLOAT64 -JERRY_STATIC_ASSERT (sizeof (ecma_number_t) == sizeof (uint32_t), size_of_ecma_number_t_must_be_equal_to_4_bytes); +JERRY_STATIC_ASSERT (sizeof (ecma_number_t) == sizeof (ecma_binary_num_t), + size_of_ecma_number_t_must_be_equal_to_binary_representation); /** - * Packing sign, fraction and biased exponent to ecma-number + * Convert an ecma-number to it's binary representation. * - * @return ecma-number with specified sign, biased_exponent and fraction - */ -ecma_number_t -ecma_number_pack (bool sign, /**< sign */ - uint32_t biased_exp, /**< biased exponent */ - uint64_t fraction) /**< fraction */ -{ - JERRY_ASSERT ((biased_exp & ~((1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1)) == 0); - JERRY_ASSERT ((fraction & ~((1ull << ECMA_NUMBER_FRACTION_WIDTH) - 1)) == 0); - - uint32_t packed_value = - (((sign ? 1u : 0u) << ECMA_NUMBER_SIGN_POS) | (biased_exp << ECMA_NUMBER_FRACTION_WIDTH) | ((uint32_t) fraction)); - - ecma_number_accessor_t u; - u.as_uint32_t = packed_value; - return u.as_ecma_number_t; -} /* ecma_number_pack */ - -/** - * Unpacking sign, fraction and biased exponent from ecma-number + * @return binary representation */ -void -ecma_number_unpack (ecma_number_t num, /**< ecma-number */ - bool *sign_p, /**< [out] sign (optional) */ - uint32_t *biased_exp_p, /**< [out] biased exponent (optional) */ - uint64_t *fraction_p) /**< [out] fraction (optional) */ +extern inline ecma_binary_num_t JERRY_ATTR_ALWAYS_INLINE JERRY_ATTR_CONST +ecma_number_to_binary (ecma_number_t number) /**< ecma number */ { - ecma_number_accessor_t u; - u.as_ecma_number_t = num; - uint32_t packed_value = u.as_uint32_t; - - if (sign_p != NULL) - { - *sign_p = ((packed_value >> ECMA_NUMBER_SIGN_POS) != 0); - } - - if (biased_exp_p != NULL) - { - *biased_exp_p = (((packed_value) & ~(1u << ECMA_NUMBER_SIGN_POS)) >> ECMA_NUMBER_FRACTION_WIDTH); - } - - if (fraction_p != NULL) - { - *fraction_p = (packed_value & ((1u << ECMA_NUMBER_FRACTION_WIDTH) - 1)); - } -} /* ecma_number_unpack */ - -/** - * Value used to calculate exponent from biased exponent - * - * See also: - * IEEE-754 2008, 3.6, Table 3.5 - */ -const int32_t ecma_number_exponent_bias = 127; + ecma_number_accessor_t f; + f.as_number = number; -#elif JERRY_NUMBER_TYPE_FLOAT64 -JERRY_STATIC_ASSERT (sizeof (ecma_number_t) == sizeof (uint64_t), size_of_ecma_number_t_must_be_equal_to_8_bytes); + return f.as_binary; +} /* ecma_number_to_binary */ /** - * Packing sign, fraction and biased exponent to ecma-number + * Convert a binary representation to the corresponding ecma-number. * - * @return ecma-number with specified sign, biased_exponent and fraction + * @return ecma-number */ -ecma_number_t -ecma_number_pack (bool sign, /**< sign */ - uint32_t biased_exp, /**< biased exponent */ - uint64_t fraction) /**< fraction */ +extern inline ecma_number_t JERRY_ATTR_ALWAYS_INLINE JERRY_ATTR_CONST +ecma_number_from_binary (ecma_binary_num_t binary) /**< binary representation */ { - uint64_t packed_value = (((sign ? 1ull : 0ull) << ECMA_NUMBER_SIGN_POS) - | (((uint64_t) biased_exp) << ECMA_NUMBER_FRACTION_WIDTH) | fraction); - - JERRY_ASSERT ((biased_exp & ~((1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1)) == 0); - JERRY_ASSERT ((fraction & ~((1ull << ECMA_NUMBER_FRACTION_WIDTH) - 1)) == 0); + ecma_number_accessor_t f; + f.as_binary = binary; - ecma_number_accessor_t u; - u.as_uint64_t = packed_value; - return u.as_ecma_number_t; -} /* ecma_number_pack */ + return f.as_number; +} /* ecma_number_from_binary */ /** - * Unpacking sign, fraction and biased exponent from ecma-number + * Check signedness of the binary number. + * + * @return true - if sign bit is set + * false - otherwise */ -void -ecma_number_unpack (ecma_number_t num, /**< ecma-number */ - bool *sign_p, /**< [out] sign (optional) */ - uint32_t *biased_exp_p, /**< [out] biased exponent (optional) */ - uint64_t *fraction_p) /**< [out] fraction (optional) */ +extern inline bool JERRY_ATTR_ALWAYS_INLINE JERRY_ATTR_CONST +ecma_number_sign (ecma_binary_num_t binary) /**< binary representation */ { - ecma_number_accessor_t u; - u.as_ecma_number_t = num; - uint64_t packed_value = u.as_uint64_t; - - if (sign_p != NULL) - { - *sign_p = ((packed_value >> ECMA_NUMBER_SIGN_POS) != 0); - } - - if (biased_exp_p != NULL) - { - *biased_exp_p = (uint32_t) (((packed_value) & ~(1ull << ECMA_NUMBER_SIGN_POS)) >> ECMA_NUMBER_FRACTION_WIDTH); - } - - if (fraction_p != NULL) - { - *fraction_p = (packed_value & ((1ull << ECMA_NUMBER_FRACTION_WIDTH) - 1)); - } -} /* ecma_number_unpack */ + return (binary & ECMA_NUMBER_SIGN_BIT) != 0; +} /* ecma_number_sign */ /** - * Value used to calculate exponent from biased exponent + * Get biased exponent field of the binary number. * - * See also: - * IEEE-754 2008, 3.6, Table 3.5 + * @return unsigned integer value of the biased exponent field */ -const int32_t ecma_number_exponent_bias = 1023; - -#endif /* JERRY_NUMBER_TYPE_FLOAT64 */ +extern inline uint32_t JERRY_ATTR_ALWAYS_INLINE JERRY_ATTR_CONST +ecma_number_biased_exp (ecma_binary_num_t binary) /**< binary representation */ +{ + return (uint32_t) ((binary & ~ECMA_NUMBER_SIGN_BIT) >> ECMA_NUMBER_FRACTION_WIDTH); +} /* ecma_number_biased_exp */ /** - * Get fraction of number + * Get fraction field of the binary number. * - * @return normalized fraction field of number + * @return unsigned integer value of the fraction field */ -static uint64_t -ecma_number_get_fraction_field (ecma_number_t num) /**< ecma-number */ +extern inline uint64_t JERRY_ATTR_ALWAYS_INLINE JERRY_ATTR_CONST +ecma_number_fraction (ecma_binary_num_t binary) /**< binary representation */ { - uint64_t fraction; - - ecma_number_unpack (num, NULL, NULL, &fraction); - - return fraction; -} /* ecma_number_get_fraction_field */ + return binary & ((1ull << ECMA_NUMBER_FRACTION_WIDTH) - 1); +} /* ecma_number_fraction */ /** - * Get exponent of number + * Packing sign, fraction and biased exponent to ecma-number * - * @return exponent corresponding to normalized fraction of number + * @return ecma-number with specified sign, biased_exponent and fraction */ -static uint32_t -ecma_number_get_biased_exponent_field (ecma_number_t num) /**< ecma-number */ +ecma_number_t +ecma_number_create (bool sign, /**< sign */ + uint32_t biased_exp, /**< biased exponent */ + uint64_t fraction) /**< fraction */ { - uint32_t biased_exp; - - ecma_number_unpack (num, NULL, &biased_exp, NULL); + JERRY_ASSERT ((biased_exp & ~((1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1)) == 0); + JERRY_ASSERT ((fraction & ~((1ull << ECMA_NUMBER_FRACTION_WIDTH) - 1)) == 0); - return biased_exp; -} /* ecma_number_get_biased_exponent_field */ + ecma_binary_num_t binary = biased_exp; + binary <<= ECMA_NUMBER_FRACTION_WIDTH; -/** - * Get sign bit of number - * - * @return 0 or 1 - value of sign bit - */ -static uint32_t -ecma_number_get_sign_field (ecma_number_t num) /**< ecma-number */ -{ - bool sign; + binary |= fraction; - ecma_number_unpack (num, &sign, NULL, NULL); + if (sign) + { + binary |= ECMA_NUMBER_SIGN_BIT; + } - return sign; -} /* ecma_number_get_sign_field */ + return ecma_number_from_binary (binary); +} /* ecma_number_create */ /** * Check if ecma-number is NaN @@ -220,12 +140,12 @@ ecma_number_is_nan (ecma_number_t num) /**< ecma-number */ bool is_nan = (num != num); #ifndef JERRY_NDEBUG - uint32_t biased_exp = ecma_number_get_biased_exponent_field (num); - uint64_t fraction = ecma_number_get_fraction_field (num); - /* IEEE-754 2008, 3.4, a */ - bool is_nan_ieee754 = ((biased_exp == (1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1) && (fraction != 0)); + ecma_binary_num_t binary = ecma_number_to_binary (num); + bool is_nan_exponent = (ecma_number_biased_exp (binary) == (1 << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1); + bool is_nan_fraction = (ecma_number_fraction (binary) > 0); + bool is_nan_ieee754 = is_nan_exponent && is_nan_fraction; JERRY_ASSERT (is_nan == is_nan_ieee754); #endif /* !JERRY_NDEBUG */ @@ -237,17 +157,13 @@ ecma_number_is_nan (ecma_number_t num) /**< ecma-number */ * * @return NaN value */ -ecma_number_t +extern inline ecma_number_t JERRY_ATTR_ALWAYS_INLINE JERRY_ATTR_CONST ecma_number_make_nan (void) { - /* IEEE754 QNaN = sign bit: 0, exponent: all 1 bits, fraction: 1....0 */ ecma_number_accessor_t f; -#if JERRY_NUMBER_TYPE_FLOAT64 - f.as_uint64_t = 0x7ff8000000000000ull; /* double QNaN, same as the C99 nan("") returns. */ -#else /* !JERRY_NUMBER_TYPE_FLOAT64 */ - f.as_uint32_t = 0x7fc00000u; /* float QNaN, same as the C99 nanf("") returns. */ -#endif /* JERRY_NUMBER_TYPE_FLOAT64 */ - return f.as_ecma_number_t; + f.as_binary = ECMA_NUMBER_BINARY_QNAN; + + return f.as_number; } /* ecma_number_make_nan */ /** @@ -256,18 +172,18 @@ ecma_number_make_nan (void) * @return if !sign - +Infinity value, * else - -Infinity value. */ -ecma_number_t -ecma_number_make_infinity (bool sign) /**< true - for negative Infinity, - false - for positive Infinity */ +extern inline ecma_number_t JERRY_ATTR_ALWAYS_INLINE JERRY_ATTR_CONST +ecma_number_make_infinity (bool sign) /**< sign of the value */ { - /* IEEE754 INF = sign bit: sign, exponent: all 1 bits, fraction: 0....0 */ ecma_number_accessor_t f; -#if JERRY_NUMBER_TYPE_FLOAT64 - f.as_uint64_t = sign ? 0xfff0000000000000ull : 0x7ff0000000000000ull; -#else /* !JERRY_NUMBER_TYPE_FLOAT64 */ - f.as_uint32_t = sign ? 0xff800000u : 0x7f800000u; -#endif /* JERRY_NUMBER_TYPE_FLOAT64 */ - return f.as_ecma_number_t; + f.as_binary = ECMA_NUMBER_BINARY_INF; + + if (sign) + { + f.as_binary |= ECMA_NUMBER_SIGN_BIT; + } + + return f.as_number; } /* ecma_number_make_infinity */ /** @@ -276,13 +192,12 @@ ecma_number_make_infinity (bool sign) /**< true - for negative Infinity, * @return true - if sign bit of ecma-number is set * false - otherwise */ -extern inline bool JERRY_ATTR_ALWAYS_INLINE +extern inline bool JERRY_ATTR_ALWAYS_INLINE JERRY_ATTR_CONST ecma_number_is_negative (ecma_number_t num) /**< ecma-number */ { JERRY_ASSERT (!ecma_number_is_nan (num)); - /* IEEE-754 2008, 3.4 */ - return (ecma_number_get_sign_field (num) != 0); + return (ecma_number_to_binary (num) & ECMA_NUMBER_SIGN_BIT) != 0; } /* ecma_number_is_negative */ /** @@ -291,16 +206,13 @@ ecma_number_is_negative (ecma_number_t num) /**< ecma-number */ * @return true - if fraction is zero and biased exponent is zero, * false - otherwise */ -bool +extern inline bool JERRY_ATTR_ALWAYS_INLINE JERRY_ATTR_CONST ecma_number_is_zero (ecma_number_t num) /**< ecma-number */ { bool is_zero = (num == ECMA_NUMBER_ZERO); #ifndef JERRY_NDEBUG - /* IEEE-754 2008, 3.4, e */ - bool is_zero_ieee754 = - (ecma_number_get_fraction_field (num) == 0 && ecma_number_get_biased_exponent_field (num) == 0); - + bool is_zero_ieee754 = ((ecma_number_to_binary (num) & ~ECMA_NUMBER_SIGN_BIT) == 0); JERRY_ASSERT (is_zero == is_zero_ieee754); #endif /* !JERRY_NDEBUG */ @@ -314,14 +226,10 @@ ecma_number_is_zero (ecma_number_t num) /**< ecma-number */ * fraction is filled with zero bits, * false - otherwise */ -bool +extern inline bool JERRY_ATTR_ALWAYS_INLINE JERRY_ATTR_CONST ecma_number_is_infinity (ecma_number_t num) /**< ecma-number */ { - uint32_t biased_exp = ecma_number_get_biased_exponent_field (num); - uint64_t fraction = ecma_number_get_fraction_field (num); - - /* IEEE-754 2008, 3.4, b */ - return ((biased_exp == (1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1) && (fraction == 0)); + return (ecma_number_to_binary (num) & ~ECMA_NUMBER_SIGN_BIT) == ECMA_NUMBER_BINARY_INF; } /* ecma_number_is_infinity */ /** @@ -330,7 +238,7 @@ ecma_number_is_infinity (ecma_number_t num) /**< ecma-number */ * @return true - if number is finite * false - if number is NaN or infinity */ -extern inline bool JERRY_ATTR_ALWAYS_INLINE +extern inline bool JERRY_ATTR_ALWAYS_INLINE JERRY_ATTR_CONST ecma_number_is_finite (ecma_number_t num) /**< ecma-number */ { #if defined(__GNUC__) || defined(__clang__) @@ -343,194 +251,38 @@ ecma_number_is_finite (ecma_number_t num) /**< ecma-number */ } /* ecma_number_is_finite */ /** - * Get fraction and exponent of the number - * - * @return shift of dot in the fraction - */ -static int32_t -ecma_number_get_fraction_and_exponent (ecma_number_t num, /**< ecma-number */ - uint64_t *out_fraction_p, /**< [out] fraction of the number */ - int32_t *out_exponent_p) /**< [out] exponent of the number */ -{ - JERRY_ASSERT (!ecma_number_is_nan (num)); - - uint32_t biased_exp = ecma_number_get_biased_exponent_field (num); - uint64_t fraction = ecma_number_get_fraction_field (num); - int32_t exponent; - - if (JERRY_UNLIKELY (biased_exp == 0)) - { - /* IEEE-754 2008, 3.4, d */ - if (ecma_number_is_zero (num)) - { - exponent = -ecma_number_exponent_bias; - } - else - { - exponent = 1 - ecma_number_exponent_bias; - - while (!(fraction & (1ull << ECMA_NUMBER_FRACTION_WIDTH))) - { - JERRY_ASSERT (fraction != 0); - - fraction <<= 1; - exponent--; - } - } - } - else if (ecma_number_is_infinity (num)) - { - /* The fraction and exponent should round to infinity */ - exponent = (int32_t) biased_exp - ecma_number_exponent_bias; - - JERRY_ASSERT ((fraction & (1ull << ECMA_NUMBER_FRACTION_WIDTH)) == 0); - fraction |= 1ull << ECMA_NUMBER_FRACTION_WIDTH; - } - else - { - /* IEEE-754 2008, 3.4, c */ - exponent = (int32_t) biased_exp - ecma_number_exponent_bias; - - JERRY_ASSERT (biased_exp > 0 && biased_exp < (1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1); - JERRY_ASSERT ((fraction & (1ull << ECMA_NUMBER_FRACTION_WIDTH)) == 0); - fraction |= 1ull << ECMA_NUMBER_FRACTION_WIDTH; - } - - *out_fraction_p = fraction; - *out_exponent_p = exponent; - return ECMA_NUMBER_FRACTION_WIDTH; -} /* ecma_number_get_fraction_and_exponent */ - -/** - * Make normalised positive Number from given fraction and exponent - * - * @return ecma-number - */ -static ecma_number_t -ecma_number_make_normal_positive_from_fraction_and_exponent (uint64_t fraction, /**< fraction */ - int32_t exponent) /**< exponent */ -{ - uint32_t biased_exp = (uint32_t) (exponent + ecma_number_exponent_bias); - JERRY_ASSERT (biased_exp > 0 && biased_exp < (1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1); - JERRY_ASSERT ((fraction & ~((1ull << (ECMA_NUMBER_FRACTION_WIDTH + 1)) - 1)) == 0); - JERRY_ASSERT ((fraction & (1ull << ECMA_NUMBER_FRACTION_WIDTH)) != 0); - - return ecma_number_pack (false, biased_exp, fraction & ~(1ull << ECMA_NUMBER_FRACTION_WIDTH)); -} /* ecma_number_make_normal_positive_from_fraction_and_exponent */ - -/** - * Make Number of given sign from given mantissa value and binary exponent - * - * @return ecma-number (possibly Infinity of specified sign) - */ -ecma_number_t -ecma_number_make_from_sign_mantissa_and_exponent (bool sign, /**< true - for negative sign, - false - for positive sign */ - uint64_t mantissa, /**< mantissa */ - int32_t exponent) /**< binary exponent */ -{ - /* Rounding mantissa to fit into fraction field width */ - if (mantissa & ~((1ull << (ECMA_NUMBER_FRACTION_WIDTH + 1)) - 1)) - { - /* Rounded mantissa looks like the following: |00...0|1|fraction_width mantissa bits| */ - while ((mantissa & ~((1ull << (ECMA_NUMBER_FRACTION_WIDTH + 1)) - 1)) != 0) - { - uint64_t rightmost_bit = (mantissa & 1); - - exponent++; - mantissa >>= 1; - - if ((mantissa & ~((1ull << (ECMA_NUMBER_FRACTION_WIDTH + 1)) - 1)) == 0) - { - /* Rounding to nearest value */ - mantissa += rightmost_bit; - - /* In the first case loop is finished, - and in the second - just one shift follows and then loop finishes */ - JERRY_ASSERT (((mantissa & ~((1ull << (ECMA_NUMBER_FRACTION_WIDTH + 1)) - 1)) == 0) - || (mantissa == (1ull << (ECMA_NUMBER_FRACTION_WIDTH + 1)))); - } - } - } - - /* Normalizing mantissa */ - while (mantissa != 0 && ((mantissa & (1ull << ECMA_NUMBER_FRACTION_WIDTH)) == 0)) - { - exponent--; - mantissa <<= 1; - } - - /* Moving floating point */ - exponent += ECMA_NUMBER_FRACTION_WIDTH - 1; - - int32_t biased_exp_signed = exponent + ecma_number_exponent_bias; - - if (biased_exp_signed < 1) - { - /* Denormalizing mantissa if biased_exponent is less than zero */ - while (biased_exp_signed < 0) - { - biased_exp_signed++; - mantissa >>= 1; - } - - /* Rounding to nearest value */ - mantissa += 1; - mantissa >>= 1; - - /* Encoding denormalized exponent */ - biased_exp_signed = 0; - } - else - { - /* Clearing highest mantissa bit that should have been non-zero if mantissa is non-zero */ - mantissa &= ~(1ull << ECMA_NUMBER_FRACTION_WIDTH); - } - - uint32_t biased_exp = (uint32_t) biased_exp_signed; - - if (biased_exp >= ((1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1)) - { - return ecma_number_make_infinity (sign); - } - - JERRY_ASSERT (biased_exp < (1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1); - JERRY_ASSERT ((mantissa & ~((1ull << ECMA_NUMBER_FRACTION_WIDTH) - 1)) == 0); - - return ecma_number_pack (sign, biased_exp, mantissa); -} /* ecma_number_make_from_sign_mantissa_and_exponent */ - -/** * Get previous representable ecma-number * * @return maximum ecma-number that is less compared to passed argument */ -ecma_number_t +ecma_number_t JERRY_ATTR_CONST ecma_number_get_prev (ecma_number_t num) /**< ecma-number */ { +#if defined(__GNUC__) || defined(__clang__) + return __builtin_nextafter (num, -INFINITY); +#else /* !defined (__GNUC__) && !defined (__clang__) */ JERRY_ASSERT (!ecma_number_is_nan (num)); - JERRY_ASSERT (!ecma_number_is_zero (num)); + ecma_binary_num_t binary = ecma_number_to_binary (num); - if (ecma_number_is_negative (num)) + /* If -Infinity, return self */ + if (binary == (ECMA_NUMBER_SIGN_BIT | ECMA_NUMBER_BINARY_INF)) { - return -ecma_number_get_next (num); + return num; } - uint32_t biased_exp = ecma_number_get_biased_exponent_field (num); - uint64_t fraction = ecma_number_get_fraction_field (num); - - if (fraction == 0 && biased_exp != 0) + /* If +0.0, return -0.0 */ + if (binary == ECMA_NUMBER_BINARY_ZERO) { - fraction = (1ull << ECMA_NUMBER_FRACTION_WIDTH) - 1; - - biased_exp--; + return -num; } - else + + if (ecma_number_sign (binary)) { - fraction--; + return ecma_number_from_binary (binary + 1); } - return ecma_number_pack (false, biased_exp, fraction); + return ecma_number_from_binary (binary - 1); +#endif /* !defined (__GNUC__) && !defined (__clang__) */ } /* ecma_number_get_prev */ /** @@ -538,36 +290,34 @@ ecma_number_get_prev (ecma_number_t num) /**< ecma-number */ * * @return minimum ecma-number that is greater compared to passed argument */ -ecma_number_t +ecma_number_t JERRY_ATTR_CONST ecma_number_get_next (ecma_number_t num) /**< ecma-number */ { +#if defined(__GNUC__) || defined(__clang__) + return __builtin_nextafter (num, INFINITY); +#else /* !defined (__GNUC__) && !defined (__clang__) */ JERRY_ASSERT (!ecma_number_is_nan (num)); - JERRY_ASSERT (!ecma_number_is_infinity (num)); + ecma_binary_num_t binary = ecma_number_to_binary (num); - if (ecma_number_is_negative (num)) + /* If +Infinity, return self */ + if (binary == ECMA_NUMBER_BINARY_INF) { - return -ecma_number_get_prev (num); + return num; } - uint32_t biased_exp = ecma_number_get_biased_exponent_field (num); - uint64_t fraction = ecma_number_get_fraction_field (num); - - fraction |= (1ull << ECMA_NUMBER_FRACTION_WIDTH); - - fraction++; - - if ((fraction & (1ull << ECMA_NUMBER_FRACTION_WIDTH)) == 0) + /* If -0.0, return +0.0 */ + if (binary == (ECMA_NUMBER_SIGN_BIT | ECMA_NUMBER_BINARY_ZERO)) { - fraction >>= 1; - - biased_exp++; + return -num; } - JERRY_ASSERT (fraction & (1ull << ECMA_NUMBER_FRACTION_WIDTH)); - - fraction &= ~(1ull << ECMA_NUMBER_FRACTION_WIDTH); + if (ecma_number_sign (binary)) + { + return ecma_number_from_binary (binary - 1); + } - return ecma_number_pack (false, biased_exp, fraction); + return ecma_number_from_binary (binary + 1); +#endif /* !defined (__GNUC__) && !defined (__clang__) */ } /* ecma_number_get_next */ /** @@ -575,38 +325,28 @@ ecma_number_get_next (ecma_number_t num) /**< ecma-number */ * * @return integer part of the number */ -ecma_number_t +ecma_number_t JERRY_ATTR_CONST ecma_number_trunc (ecma_number_t num) /**< ecma-number */ { JERRY_ASSERT (!ecma_number_is_nan (num)); - uint64_t fraction; - int32_t exponent; - const int32_t dot_shift = ecma_number_get_fraction_and_exponent (num, &fraction, &exponent); - const bool sign = ecma_number_is_negative (num); + ecma_binary_num_t binary = ecma_number_to_binary (num); + uint32_t exponent = ecma_number_biased_exp (binary); - if (exponent < 0) + if (exponent < ECMA_NUMBER_EXPONENT_BIAS) { return ECMA_NUMBER_ZERO; } - else if (exponent < dot_shift) - { - fraction &= ~((1ull << (dot_shift - exponent)) - 1); - ecma_number_t tmp = ecma_number_make_normal_positive_from_fraction_and_exponent (fraction, exponent); - if (sign) - { - return -tmp; - } - else - { - return tmp; - } - } - else + uint32_t unbiased_exp = exponent - ECMA_NUMBER_EXPONENT_BIAS; + + if (unbiased_exp >= ECMA_NUMBER_FRACTION_WIDTH) { return num; } + + binary &= ~((1ull << (ECMA_NUMBER_FRACTION_WIDTH - unbiased_exp)) - 1); + return ecma_number_from_binary (binary); } /* ecma_number_trunc */ /** @@ -618,14 +358,12 @@ ecma_number_trunc (ecma_number_t num) /**< ecma-number */ * * @return number - calculated remainder. */ -ecma_number_t -ecma_number_calc_remainder (ecma_number_t left_num, /**< left operand */ - ecma_number_t right_num) /**< right operand */ +ecma_number_t JERRY_ATTR_CONST +ecma_number_remainder (ecma_number_t left_num, /**< left operand */ + ecma_number_t right_num) /**< right operand */ { - JERRY_ASSERT (!ecma_number_is_nan (left_num) && !ecma_number_is_zero (left_num) - && !ecma_number_is_infinity (left_num)); - JERRY_ASSERT (!ecma_number_is_nan (right_num) && !ecma_number_is_zero (right_num) - && !ecma_number_is_infinity (right_num)); + JERRY_ASSERT (ecma_number_is_finite (left_num) && !ecma_number_is_zero (left_num)); + JERRY_ASSERT (ecma_number_is_finite (right_num) && !ecma_number_is_zero (right_num)); const ecma_number_t q = ecma_number_trunc (left_num / right_num); ecma_number_t r = left_num - right_num * q; @@ -636,18 +374,18 @@ ecma_number_calc_remainder (ecma_number_t left_num, /**< left operand */ } return r; -} /* ecma_number_calc_remainder */ +} /* ecma_number_remainder */ /** * Compute power operation according to the ES standard. * * @return x ** y */ -ecma_number_t +ecma_number_t JERRY_ATTR_CONST ecma_number_pow (ecma_number_t x, /**< left operand */ ecma_number_t y) /**< right operand */ { - if (ecma_number_is_nan (y) || (ecma_number_is_infinity (y) && (x == 1.0 || x == -1.0))) + if (ecma_number_is_nan (y) || (ecma_number_is_infinity (y) && (x == ECMA_NUMBER_ONE || x == ECMA_NUMBER_MINUS_ONE))) { /* Handle differences between ES5.1 and ISO C standards for pow. */ return ecma_number_make_nan (); @@ -656,7 +394,7 @@ ecma_number_pow (ecma_number_t x, /**< left operand */ if (ecma_number_is_zero (y)) { /* Handle differences between ES5.1 and ISO C standards for pow. */ - return (ecma_number_t) 1.0; + return ECMA_NUMBER_ONE; } return DOUBLE_TO_ECMA_NUMBER_T (pow (x, y)); @@ -667,23 +405,25 @@ ecma_number_pow (ecma_number_t x, /**< left operand */ * * @return number - result of multiplication. */ -extern inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE +extern inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE JERRY_ATTR_CONST ecma_integer_multiply (ecma_integer_value_t left_integer, /**< left operand */ ecma_integer_value_t right_integer) /**< right operand */ { #if defined(__GNUC__) || defined(__clang__) - /* Check if left_integer is power of 2 */ + /* Check if either integer is power of 2 */ if (JERRY_UNLIKELY ((left_integer & (left_integer - 1)) == 0)) { /* Right shift right_integer with log2 (left_integer) */ return ecma_make_integer_value (right_integer << (__builtin_ctz ((unsigned int) left_integer))); } - else if (JERRY_UNLIKELY ((right_integer & (right_integer - 1)) == 0)) + + if (JERRY_UNLIKELY ((right_integer & (right_integer - 1)) == 0)) { /* Right shift left_integer with log2 (right_integer) */ return ecma_make_integer_value (left_integer << (__builtin_ctz ((unsigned int) right_integer))); } #endif /* defined (__GNUC__) || defined (__clang__) */ + return ecma_make_integer_value (left_integer * right_integer); } /* ecma_integer_multiply */ @@ -697,73 +437,61 @@ ecma_integer_multiply (ecma_integer_value_t left_integer, /**< left operand */ * Returned value must be freed with ecma_free_value. */ ecma_value_t -ecma_number_parse_int (const lit_utf8_byte_t *string_buff, /**< routine's first argument's - * string buffer */ - lit_utf8_size_t string_buff_size, /**< routine's first argument's - * string buffer's size */ - ecma_value_t radix) /**< routine's second argument */ +ecma_number_parse_int (const lit_utf8_byte_t *str_p, /**< routine's first argument's + * string buffer */ + lit_utf8_size_t str_size, /**< routine's first argument's + * string buffer's size */ + ecma_value_t radix_value) /**< routine's second argument */ { - if (string_buff_size == 0) - { - return ecma_make_nan_value (); - } - /* 2. Remove leading whitespace. */ + ecma_string_trim_helper (&str_p, &str_size); - const lit_utf8_byte_t *string_end_p = string_buff + string_buff_size; - const lit_utf8_byte_t *start_p = ecma_string_trim_front (string_buff, string_end_p); - const lit_utf8_byte_t *string_curr_p = start_p; - const lit_utf8_byte_t *end_p = string_end_p; - - if (string_curr_p >= string_end_p) + if (str_size == 0) { return ecma_make_nan_value (); } + const lit_utf8_byte_t *str_end_p = str_p + str_size; + /* 3. */ - int sign = 1; + bool sign = false; /* 4. */ - ecma_char_t current = lit_cesu8_read_next (&string_curr_p); - if (current == LIT_CHAR_MINUS) + if (*str_p == LIT_CHAR_MINUS) { - sign = -1; + sign = true; + str_p++; } - /* 5. */ - if (current == LIT_CHAR_MINUS || current == LIT_CHAR_PLUS) + else if (*str_p == LIT_CHAR_PLUS) { - start_p = string_curr_p; - if (string_curr_p < string_end_p) - { - current = lit_cesu8_read_next (&string_curr_p); - } + str_p++; } /* 6. */ ecma_number_t radix_num; - radix = ecma_op_to_number (radix, &radix_num); + radix_value = ecma_op_to_number (radix_value, &radix_num); - if (ECMA_IS_VALUE_ERROR (radix)) + if (ECMA_IS_VALUE_ERROR (radix_value)) { return ECMA_VALUE_ERROR; } - int32_t rad = ecma_number_to_int32 (radix_num); + int32_t radix = ecma_number_to_int32 (radix_num); /* 7.*/ bool strip_prefix = true; /* 8. */ - if (rad != 0) + if (radix != 0) { /* 8.a */ - if (rad < 2 || rad > 36) + if (radix < 2 || radix > 36) { return ecma_make_nan_value (); } /* 8.b */ - else if (rad != 16) + else if (radix != 16) { strip_prefix = false; } @@ -771,93 +499,65 @@ ecma_number_parse_int (const lit_utf8_byte_t *string_buff, /**< routine's first /* 9. */ else { - rad = 10; + radix = 10; } /* 10. */ - if (strip_prefix && ((end_p - start_p) >= 2) && (current == LIT_CHAR_0)) + if (strip_prefix && ((str_end_p - str_p) >= 2) && (str_p[0] == LIT_CHAR_0) + && (LEXER_TO_ASCII_LOWERCASE (str_p[1]) == LIT_CHAR_LOWERCASE_X)) { - ecma_char_t next = *string_curr_p; - if (next == LIT_CHAR_LOWERCASE_X || next == LIT_CHAR_UPPERCASE_X) - { - /* Skip the 'x' or 'X' characters. */ - start_p = ++string_curr_p; - rad = 16; - } + str_p += 2; + radix = 16; } + ecma_number_t value = ECMA_NUMBER_ZERO; + const lit_utf8_byte_t *digit_start_p = str_p; + /* 11. Check if characters are in [0, Radix - 1]. We also convert them to number values in the process. */ - string_curr_p = start_p; - while (string_curr_p < string_end_p) + while (str_p < str_end_p) { - ecma_char_t current_char = *string_curr_p++; - int32_t current_number; + ecma_char_t ch = *str_p; - if ((current_char >= LIT_CHAR_LOWERCASE_A && current_char <= LIT_CHAR_LOWERCASE_Z)) - { - current_number = current_char - LIT_CHAR_LOWERCASE_A + 10; - } - else if ((current_char >= LIT_CHAR_UPPERCASE_A && current_char <= LIT_CHAR_UPPERCASE_Z)) + int32_t digit = 0; + + if (lit_char_is_decimal_digit (ch)) { - current_number = current_char - LIT_CHAR_UPPERCASE_A + 10; + digit = ch - LIT_CHAR_0; } - else if (lit_char_is_decimal_digit (current_char)) + else if (LEXER_TO_ASCII_LOWERCASE (ch) >= LIT_CHAR_LOWERCASE_A + && LEXER_TO_ASCII_LOWERCASE (ch) <= LIT_CHAR_LOWERCASE_Z) { - current_number = current_char - LIT_CHAR_0; + digit = LEXER_TO_ASCII_LOWERCASE (ch) - LIT_CHAR_LOWERCASE_A + 10; } else { - /* Not a valid number char, set value to radix so it fails to pass as a valid character. */ - current_number = rad; + /* Not a valid digit char, set to invalid value */ + digit = radix; } - if (!(current_number < rad)) + if (digit >= radix) { - end_p = --string_curr_p; break; } + + value *= radix; + value += digit; + + str_p++; } /* 12. */ - if (end_p == start_p) + if (str_p == digit_start_p) { return ecma_make_nan_value (); } - ecma_number_t value = ECMA_NUMBER_ZERO; - ecma_number_t multiplier = 1.0f; - - /* 13. and 14. */ - string_curr_p = end_p; - - while (string_curr_p > start_p) - { - ecma_char_t current_char = *(--string_curr_p); - ecma_number_t current_number = ECMA_NUMBER_MINUS_ONE; - - if ((current_char >= LIT_CHAR_LOWERCASE_A && current_char <= LIT_CHAR_LOWERCASE_Z)) - { - current_number = (ecma_number_t) current_char - LIT_CHAR_LOWERCASE_A + 10; - } - else if ((current_char >= LIT_CHAR_UPPERCASE_A && current_char <= LIT_CHAR_UPPERCASE_Z)) - { - current_number = (ecma_number_t) current_char - LIT_CHAR_UPPERCASE_A + 10; - } - else - { - JERRY_ASSERT (lit_char_is_decimal_digit (current_char)); - current_number = (ecma_number_t) current_char - LIT_CHAR_0; - } - - value += current_number * multiplier; - multiplier *= (ecma_number_t) rad; - } - /* 15. */ - if (sign < 0) + if (sign) { - value *= (ecma_number_t) sign; + value *= ECMA_NUMBER_MINUS_ONE; } + return ecma_make_number_value (value); } /* ecma_number_parse_int */ @@ -871,40 +571,30 @@ ecma_number_parse_int (const lit_utf8_byte_t *string_buff, /**< routine's first * Returned value must be freed with ecma_free_value. */ ecma_value_t -ecma_number_parse_float (const lit_utf8_byte_t *string_buff, /**< routine's first argument's - * string buffer */ - lit_utf8_size_t string_buff_size) /**< routine's first argument's - * string buffer's size */ +ecma_number_parse_float (const lit_utf8_byte_t *str_p, /**< routine's first argument's + * string buffer */ + lit_utf8_size_t str_size) /**< routine's first argument's + * string buffer's size */ { - if (string_buff_size == 0) - { - return ecma_make_nan_value (); - } - /* 2. Remove leading whitespace. */ + ecma_string_trim_helper (&str_p, &str_size); - const lit_utf8_byte_t *str_end_p = string_buff + string_buff_size; - const lit_utf8_byte_t *start_p = ecma_string_trim_front (string_buff, str_end_p); - const lit_utf8_byte_t *str_curr_p = start_p; - const lit_utf8_byte_t *end_p = str_end_p; - + const lit_utf8_byte_t *str_end_p = str_p + str_size; bool sign = false; - ecma_char_t current; - if (str_curr_p < str_end_p) + if (str_size == 0) { - /* Check if sign is present. */ - current = *str_curr_p; - if (current == LIT_CHAR_MINUS) - { - sign = true; - } + return ecma_make_nan_value (); + } - if (current == LIT_CHAR_MINUS || current == LIT_CHAR_PLUS) - { - /* Set starting position to be after the sign character. */ - start_p = ++str_curr_p; - } + if (*str_p == LIT_CHAR_PLUS) + { + str_p++; + } + else if (*str_p == LIT_CHAR_MINUS) + { + sign = true; + str_p++; } /* Check if string is equal to "Infinity". */ @@ -914,126 +604,62 @@ ecma_number_parse_float (const lit_utf8_byte_t *string_buff, /**< routine's firs /* The input string should be at least the length of "Infinity" to be correctly processed as * the infinity value. */ - if ((str_end_p - str_curr_p) >= (int) infinity_length && memcmp (infinity_str_p, str_curr_p, infinity_length) == 0) + if ((lit_utf8_size_t) (str_end_p - str_p) >= infinity_length && memcmp (infinity_str_p, str_p, infinity_length) == 0) { - /* String matched Infinity. */ return ecma_make_number_value (ecma_number_make_infinity (sign)); } - /* Reset to starting position. */ - str_curr_p = start_p; + const lit_utf8_byte_t *num_start_p = str_p; + const lit_utf8_byte_t *num_end_p = str_p; - /* String ended after sign character, or was empty after removing leading whitespace. */ - if (str_curr_p >= str_end_p) + while (str_p < str_end_p && lit_char_is_decimal_digit (*str_p)) { - return ecma_make_nan_value (); + str_p++; } - /* Reset to starting position. */ - str_curr_p = start_p; - - current = *str_curr_p; - - bool has_whole_part = false; - bool has_fraction_part = false; - - /* Check digits of whole part. */ - if (lit_char_is_decimal_digit (current)) + if (str_p < str_end_p && *str_p == LIT_CHAR_DOT) { - has_whole_part = true; - str_curr_p++; + str_p++; - while (str_curr_p < str_end_p) + while (str_p < str_end_p && lit_char_is_decimal_digit (*str_p)) { - current = *str_curr_p++; - if (!lit_char_is_decimal_digit (current)) - { - str_curr_p--; - break; - } + str_p++; } } - /* Set end position to the end of whole part. */ - end_p = str_curr_p; - if (str_curr_p < str_end_p) - { - current = *str_curr_p; - - /* Check decimal point. */ - if (current == LIT_CHAR_DOT) - { - str_curr_p++; + num_end_p = str_p; - if (str_curr_p < str_end_p) - { - current = *str_curr_p; - - if (lit_char_is_decimal_digit (current)) - { - has_fraction_part = true; - - /* Check digits of fractional part. */ - while (str_curr_p < str_end_p) - { - current = *str_curr_p++; - if (!lit_char_is_decimal_digit (current)) - { - str_curr_p--; - break; - } - } - - /* Set end position to end of fraction part. */ - end_p = str_curr_p; - } - } - } - } - - if (str_curr_p < str_end_p) + if (str_p < str_end_p && LEXER_TO_ASCII_LOWERCASE (*str_p) == LIT_CHAR_LOWERCASE_E) { - current = *str_curr_p++; - } + str_p++; - /* Check exponent. */ - if ((current == LIT_CHAR_LOWERCASE_E || current == LIT_CHAR_UPPERCASE_E) && (has_whole_part || has_fraction_part) - && str_curr_p < str_end_p) - { - current = *str_curr_p++; - - /* Check sign of exponent. */ - if ((current == LIT_CHAR_PLUS || current == LIT_CHAR_MINUS) && str_curr_p < str_end_p) + if (str_p < str_end_p && (*str_p == LIT_CHAR_PLUS || *str_p == LIT_CHAR_MINUS)) { - current = *str_curr_p++; + str_p++; } - if (lit_char_is_decimal_digit (current)) + if (str_p < str_end_p && lit_char_is_decimal_digit (*str_p)) { - /* Check digits of exponent part. */ - while (str_curr_p < str_end_p) + str_p++; + + while (str_p < str_end_p && lit_char_is_decimal_digit (*str_p)) { - current = *str_curr_p++; - if (!lit_char_is_decimal_digit (current)) - { - str_curr_p--; - break; - } + str_p++; } - /* Set end position to end of exponent part. */ - end_p = str_curr_p; + num_end_p = str_p; } } - /* String did not contain a valid number. */ - if (start_p == end_p) + lit_utf8_size_t num_size = (lit_utf8_size_t) (num_end_p - num_start_p); + + if (num_size == 0) { return ecma_make_nan_value (); } /* 5. */ - ecma_number_t ret_num = ecma_utf8_string_to_number (start_p, (lit_utf8_size_t) (end_p - start_p), 0); + ecma_number_t ret_num = ecma_utf8_string_to_number (num_start_p, (lit_utf8_size_t) (num_end_p - num_start_p), 0); if (sign) { diff --git a/jerry-core/ecma/base/ecma-helpers-number.h b/jerry-core/ecma/base/ecma-helpers-number.h new file mode 100644 index 00000000..85969d15 --- /dev/null +++ b/jerry-core/ecma/base/ecma-helpers-number.h @@ -0,0 +1,245 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ECMA_HELPERS_NUMBER_H +#define ECMA_HELPERS_NUMBER_H + +#include "ecma-globals.h" + +#include "config.h" + +/** + * Binary representation of an ecma-number + */ +#if JERRY_NUMBER_TYPE_FLOAT64 +typedef uint64_t ecma_binary_num_t; +#else /* !JERRY_NUMBER_TYPE_FLOAT64 */ +typedef uint32_t ecma_binary_num_t; +#endif /* !JERRY_NUMBER_TYPE_FLOAT64 */ + +/** + * Makes it possible to read/write the binary representation of an ecma_number_t + * without strict aliasing rule violation. + */ +typedef union +{ + ecma_number_t as_number; /**< ecma-number */ + ecma_binary_num_t as_binary; /**< binary representation */ +} ecma_number_accessor_t; + +ecma_binary_num_t ecma_number_to_binary (ecma_number_t number); +ecma_number_t ecma_number_from_binary (ecma_binary_num_t binary); + +bool ecma_number_sign (ecma_binary_num_t binary); +uint32_t ecma_number_biased_exp (ecma_binary_num_t binary); +uint64_t ecma_number_fraction (ecma_binary_num_t binary); +ecma_number_t ecma_number_create (bool sign, uint32_t biased_exp, uint64_t fraction); + +/** + * Maximum number of significant decimal digits that an ecma-number can store + */ +#if JERRY_NUMBER_TYPE_FLOAT64 +#define ECMA_NUMBER_MAX_DIGITS (19) +#else /* !JERRY_NUMBER_TYPE_FLOAT64 */ +#define ECMA_NUMBER_MAX_DIGITS (9) +#endif /* !JERRY_NUMBER_TYPE_FLOAT64 */ + +/** + * Width of sign field + * + * See also: + * IEEE-754 2008, 3.6, Table 3.5 + */ +#define ECMA_NUMBER_SIGN_WIDTH (1) + +/** + * Width of biased exponent field + * + * See also: + * IEEE-754 2008, 3.6, Table 3.5 + */ +#if JERRY_NUMBER_TYPE_FLOAT64 +#define ECMA_NUMBER_BIASED_EXP_WIDTH (11) +#else /* !JERRY_NUMBER_TYPE_FLOAT64 */ +#define ECMA_NUMBER_BIASED_EXP_WIDTH (8) +#endif /* !JERRY_NUMBER_TYPE_FLOAT64 */ + +/** + * Exponent bias + */ +#if JERRY_NUMBER_TYPE_FLOAT64 +#define ECMA_NUMBER_EXPONENT_BIAS (1023) +#else /* !JERRY_NUMBER_TYPE_FLOAT64 */ +#define ECMA_NUMBER_EXPONENT_BIAS (127) +#endif /* !JERRY_NUMBER_TYPE_FLOAT64 */ + +/** + * Width of fraction field + * + * See also: + * IEEE-754 2008, 3.6, Table 3.5 + */ +#if JERRY_NUMBER_TYPE_FLOAT64 +#define ECMA_NUMBER_FRACTION_WIDTH (52) +#else /* !JERRY_NUMBER_TYPE_FLOAT64 */ +#define ECMA_NUMBER_FRACTION_WIDTH (23) +#endif /* !JERRY_NUMBER_TYPE_FLOAT64 */ + +/** + * Sign bit in ecma-numbers + */ +#if JERRY_NUMBER_TYPE_FLOAT64 +#define ECMA_NUMBER_SIGN_BIT 0x8000000000000000ull +#else /* !JERRY_NUMBER_TYPE_FLOAT64 */ +#define ECMA_NUMBER_SIGN_BIT 0x7f800000u; +#endif /* !JERRY_NUMBER_TYPE_FLOAT64 */ + +/** + * Binary representation of an IEEE-754 QNaN value. + */ +#if JERRY_NUMBER_TYPE_FLOAT64 +#define ECMA_NUMBER_BINARY_QNAN 0x7ff8000000000000ull +#else /* !JERRY_NUMBER_TYPE_FLOAT64 */ +#define ECMA_NUMBER_BINARY_QNAN 0x7fc00000u +#endif /* JERRY_NUMBER_TYPE_FLOAT64 */ + +/** + * Binary representation of an IEEE-754 Infinity value. + */ +#if JERRY_NUMBER_TYPE_FLOAT64 +#define ECMA_NUMBER_BINARY_INF 0x7ff0000000000000ull +#else /* !JERRY_NUMBER_TYPE_FLOAT64 */ +#define ECMA_NUMBER_BINARY_INF 0x7f800000u +#endif /* JERRY_NUMBER_TYPE_FLOAT64 */ + +/** + * Binary representation of an IEEE-754 zero value. + */ +#define ECMA_NUMBER_BINARY_ZERO 0x0ull + +/** + * Number.MIN_VALUE (i.e., the smallest positive value of ecma-number) + * + * See also: ECMA_262 v5, 15.7.3.3 + */ +#if JERRY_NUMBER_TYPE_FLOAT64 +#define ECMA_NUMBER_MIN_VALUE ((ecma_number_t) 5e-324) +#else /* !JERRY_NUMBER_TYPE_FLOAT64 */ +#define ECMA_NUMBER_MIN_VALUE (FLT_MIN) +#endif /* JERRY_NUMBER_TYPE_FLOAT64 */ + +/** + * Number.MAX_VALUE (i.e., the maximum value of ecma-number) + * + * See also: ECMA_262 v5, 15.7.3.2 + */ +#if JERRY_NUMBER_TYPE_FLOAT64 +#define ECMA_NUMBER_MAX_VALUE ((ecma_number_t) 1.7976931348623157e+308) +#else /* !JERRY_NUMBER_TYPE_FLOAT64 */ +#define ECMA_NUMBER_MAX_VALUE (FLT_MAX) +#endif /* JERRY_NUMBER_TYPE_FLOAT64 */ + +/** + * Number.EPSILON + * + * See also: ECMA_262 v6, 20.1.2.1 + */ +#if JERRY_NUMBER_TYPE_FLOAT64 +#define ECMA_NUMBER_EPSILON ((ecma_number_t) 2.2204460492503130808472633361816e-16) +#else /* !JERRY_NUMBER_TYPE_FLOAT64 */ +#define ECMA_NUMBER_EPSILON ((ecma_number_t) 1.1920928955078125e-7) +#endif /* JERRY_NUMBER_TYPE_FLOAT64 */ + +/** + * Number.MAX_SAFE_INTEGER + * + * See also: ECMA_262 v6, 20.1.2.6 + */ +#if JERRY_NUMBER_TYPE_FLOAT64 +#define ECMA_NUMBER_MAX_SAFE_INTEGER ((ecma_number_t) 0x1FFFFFFFFFFFFF) +#else /* !JERRY_NUMBER_TYPE_FLOAT64 */ +#define ECMA_NUMBER_MAX_SAFE_INTEGER ((ecma_number_t) 0xFFFFFF) +#endif /* JERRY_NUMBER_TYPE_FLOAT64 */ + +/** + * Number.MIN_SAFE_INTEGER + * + * See also: ECMA_262 v6, 20.1.2.8 + */ +#if JERRY_NUMBER_TYPE_FLOAT64 +#define ECMA_NUMBER_MIN_SAFE_INTEGER ((ecma_number_t) -0x1FFFFFFFFFFFFF) +#else /* !JERRY_NUMBER_TYPE_FLOAT64 */ +#define ECMA_NUMBER_MIN_SAFE_INTEGER ((ecma_number_t) -0xFFFFFF) +#endif /* JERRY_NUMBER_TYPE_FLOAT64 */ + +/** + * Number.MAX_VALUE exponent part + */ +#if JERRY_NUMBER_TYPE_FLOAT64 +#define NUMBER_MAX_DECIMAL_EXPONENT 308 +#else /* !JERRY_NUMBER_TYPE_FLOAT64 */ +#define NUMBER_MAX_DECIMAL_EXPONENT 38 +#endif /* JERRY_NUMBER_TYPE_FLOAT64 */ + +/** + * Number.MIN_VALUE exponent part + */ +#if JERRY_NUMBER_TYPE_FLOAT64 +#define NUMBER_MIN_DECIMAL_EXPONENT -324 +#else /* !JERRY_NUMBER_TYPE_FLOAT64 */ +#define NUMBER_MIN_DECIMAL_EXPONENT -45 +#endif /* JERRY_NUMBER_TYPE_FLOAT64 */ + +/** + * Euler number + */ +#define ECMA_NUMBER_E ((ecma_number_t) 2.7182818284590452354) + +/** + * Natural logarithm of 10 + */ +#define ECMA_NUMBER_LN10 ((ecma_number_t) 2.302585092994046) + +/** + * Natural logarithm of 2 + */ +#define ECMA_NUMBER_LN2 ((ecma_number_t) 0.6931471805599453) + +/** + * Logarithm base 2 of the Euler number + */ +#define ECMA_NUMBER_LOG2E ((ecma_number_t) 1.4426950408889634) + +/** + * Logarithm base 10 of the Euler number + */ +#define ECMA_NUMBER_LOG10E ((ecma_number_t) 0.4342944819032518) + +/** + * Pi number + */ +#define ECMA_NUMBER_PI ((ecma_number_t) 3.1415926535897932) + +/** + * Square root of 0.5 + */ +#define ECMA_NUMBER_SQRT_1_2 ((ecma_number_t) 0.7071067811865476) + +/** + * Square root of 2 + */ +#define ECMA_NUMBER_SQRT2 ((ecma_number_t) 1.4142135623730951) + +#endif /* !ECMA_HELPERS_NUMBER_H */ diff --git a/jerry-core/ecma/base/ecma-helpers-string.c b/jerry-core/ecma/base/ecma-helpers-string.c index 12770f36..15f7d79c 100644 --- a/jerry-core/ecma/base/ecma-helpers-string.c +++ b/jerry-core/ecma/base/ecma-helpers-string.c @@ -18,6 +18,7 @@ #include "ecma-exceptions.h" #include "ecma-gc.h" #include "ecma-globals.h" +#include "ecma-helpers-number.h" #include "ecma-helpers.h" #include "jcontext.h" diff --git a/jerry-core/ecma/base/ecma-helpers-value.c b/jerry-core/ecma/base/ecma-helpers-value.c index 4bd673d4..521cfdc8 100644 --- a/jerry-core/ecma/base/ecma-helpers-value.c +++ b/jerry-core/ecma/base/ecma-helpers-value.c @@ -18,6 +18,7 @@ #include "ecma-function-object.h" #include "ecma-gc.h" #include "ecma-globals.h" +#include "ecma-helpers-number.h" #include "ecma-helpers.h" #include "jrt-bit-fields.h" @@ -536,7 +537,7 @@ ecma_make_float_value (ecma_number_t *ecma_num_p) /**< pointer to the float numb * * @return ecma-value */ -extern inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE +extern inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE JERRY_ATTR_CONST ecma_make_nan_value (void) { return ecma_create_float_number (ecma_number_make_nan ()); @@ -550,13 +551,7 @@ ecma_make_nan_value (void) static inline bool JERRY_ATTR_CONST JERRY_ATTR_ALWAYS_INLINE ecma_is_number_equal_to_positive_zero (ecma_number_t ecma_number) /**< number */ { - ecma_number_accessor_t u; - u.as_ecma_number_t = ecma_number; -#if !JERRY_NUMBER_TYPE_FLOAT64 - return u.as_uint32_t == 0; -#else /* JERRY_NUMBER_TYPE_FLOAT64 */ - return u.as_uint64_t == 0; -#endif /* !JERRY_NUMBER_TYPE_FLOAT64 */ + return ecma_number_to_binary (ecma_number) == ECMA_NUMBER_BINARY_ZERO; } /* ecma_is_number_equal_to_positive_zero */ /** diff --git a/jerry-core/ecma/base/ecma-helpers.h b/jerry-core/ecma/base/ecma-helpers.h index 375fd7b8..b8aa0176 100644 --- a/jerry-core/ecma/base/ecma-helpers.h +++ b/jerry-core/ecma/base/ecma-helpers.h @@ -394,8 +394,6 @@ ecma_string_t *ecma_stringbuilder_finalize (ecma_stringbuilder_t *builder_p); void ecma_stringbuilder_destroy (ecma_stringbuilder_t *builder_p); /* ecma-helpers-number.c */ -ecma_number_t ecma_number_pack (bool sign, uint32_t biased_exp, uint64_t fraction); -void ecma_number_unpack (ecma_number_t num, bool *sign_p, uint32_t *biased_exp_p, uint64_t *fraction_p); ecma_number_t ecma_number_make_nan (void); ecma_number_t ecma_number_make_infinity (bool sign); bool ecma_number_is_nan (ecma_number_t num); @@ -403,11 +401,10 @@ bool ecma_number_is_negative (ecma_number_t num); bool ecma_number_is_zero (ecma_number_t num); bool ecma_number_is_infinity (ecma_number_t num); bool ecma_number_is_finite (ecma_number_t num); -ecma_number_t ecma_number_make_from_sign_mantissa_and_exponent (bool sign, uint64_t mantissa, int32_t exponent); ecma_number_t ecma_number_get_prev (ecma_number_t num); ecma_number_t ecma_number_get_next (ecma_number_t num); ecma_number_t ecma_number_trunc (ecma_number_t num); -ecma_number_t ecma_number_calc_remainder (ecma_number_t left_num, ecma_number_t right_num); +ecma_number_t ecma_number_remainder (ecma_number_t left_num, ecma_number_t right_num); ecma_number_t ecma_number_pow (ecma_number_t x, ecma_number_t y); ecma_value_t ecma_number_parse_int (const lit_utf8_byte_t *string_buff, lit_utf8_size_t string_buff_size, ecma_value_t radix); @@ -538,6 +535,10 @@ bool ecma_delete_native_pointer_property (ecma_object_t *obj_p, const jerry_obje /* ecma-helpers-conversion.c */ ecma_number_t ecma_utf8_string_to_number (const lit_utf8_byte_t *str_p, lit_utf8_size_t str_size, uint32_t option); +ecma_number_t ecma_utf8_string_to_number_by_radix (const lit_utf8_byte_t *str_p, + lit_utf8_size_t str_size, + uint32_t radix, + uint32_t option); lit_utf8_size_t ecma_uint32_to_utf8_string (uint32_t value, lit_utf8_byte_t *out_buffer_p, lit_utf8_size_t buffer_size); uint32_t ecma_number_to_uint32 (ecma_number_t num); int32_t ecma_number_to_int32 (ecma_number_t num); diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c index db99022f..0289e246 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c @@ -23,6 +23,7 @@ #include "ecma-function-object.h" #include "ecma-gc.h" #include "ecma-globals.h" +#include "ecma-helpers-number.h" #include "ecma-helpers.h" #include "ecma-objects.h" #include "ecma-string-object.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-date.c b/jerry-core/ecma/builtin-objects/ecma-builtin-date.c index cad9534c..d1dd4183 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-date.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-date.c @@ -677,7 +677,7 @@ ecma_builtin_date_utc (const ecma_value_t args[], /**< arguments list */ if (args_number < required_args_number) { - return ecma_make_number_value (ecma_number_make_nan ()); + return ecma_make_nan_value (); } ecma_number_t tv; @@ -868,7 +868,7 @@ ecma_builtin_date_dispatch_routine (uint8_t builtin_routine_id, /**< built-in wi { if (arguments_number < 1) { - return ecma_make_number_value (ecma_number_make_nan ()); + return ecma_make_nan_value (); } ecma_string_t *str_p = ecma_op_to_string (arguments_list_p[0]); diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-sort.c b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-sort.c index 2cf3621d..dc62069f 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-sort.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-sort.c @@ -15,6 +15,7 @@ #include "ecma-builtin-helpers.h" #include "ecma-globals.h" +#include "ecma-helpers-number.h" /** * Function used to merge two arrays for merge sort. diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.c b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.c index d065b7e8..4add5936 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.c @@ -22,6 +22,7 @@ #include "ecma-exceptions.h" #include "ecma-function-object.h" #include "ecma-gc.h" +#include "ecma-helpers-number.h" #include "ecma-helpers.h" #include "ecma-objects.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-math.c b/jerry-core/ecma/builtin-objects/ecma-builtin-math.c index a9e737ec..a0791ea0 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-math.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-math.c @@ -22,7 +22,6 @@ #include "ecma-gc.h" #include "ecma-globals.h" #include "ecma-helpers.h" -#include "ecma-number-arithmetic.h" #include "ecma-objects-general.h" #include "ecma-objects.h" @@ -438,30 +437,37 @@ ecma_builtin_math_dispatch_routine (uint8_t builtin_routine_id, /**< built-in wi #endif /* JERRY_ESNEXT */ case ECMA_MATH_OBJECT_ROUND: { - if (ecma_number_is_nan (x) || ecma_number_is_zero (x) || ecma_number_is_infinity (x) || fmod (x, 1.0) == 0) + if (ecma_number_is_nan (x) || ecma_number_is_zero (x) || ecma_number_is_infinity (x)) { - /* Do nothing. */ + break; } - else if (ecma_number_is_negative (x) && x >= -ECMA_NUMBER_HALF) + + ecma_number_t fraction = fmod (x, ECMA_NUMBER_ONE); + + if (ecma_number_is_zero (fraction)) { - x = -ECMA_NUMBER_ZERO; + break; } - else - { - const ecma_number_t up_half = x + ECMA_NUMBER_HALF; - const ecma_number_t down_half = x - ECMA_NUMBER_HALF; - const ecma_number_t up_rounded = up_half - ecma_op_number_remainder (up_half, ECMA_NUMBER_ONE); - const ecma_number_t down_rounded = down_half - ecma_op_number_remainder (down_half, ECMA_NUMBER_ONE); - if (up_rounded - x <= x - down_rounded) + if (ecma_number_is_negative (x)) + { + if (x >= -ECMA_NUMBER_HALF) { - x = up_rounded; + x = -ECMA_NUMBER_ZERO; + break; } - else + + if (fraction < -ECMA_NUMBER_HALF) { - x = down_rounded; + x -= ECMA_NUMBER_HALF; } } + else if (fraction >= ECMA_NUMBER_HALF) + { + x += ECMA_NUMBER_HALF; + } + + x = ecma_number_trunc (x); break; } case ECMA_MATH_OBJECT_SIN: diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-number-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-number-prototype.c index 2e94f3a1..1d212f5f 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-number-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-number-prototype.c @@ -21,6 +21,7 @@ #include "ecma-exceptions.h" #include "ecma-gc.h" #include "ecma-globals.h" +#include "ecma-helpers-number.h" #include "ecma-helpers.h" #include "ecma-objects.h" #include "ecma-string-object.h" @@ -133,6 +134,11 @@ ecma_builtin_number_prototype_helper_round (lit_utf8_byte_t *digits_p, /**< [in, } /* ecma_builtin_number_prototype_helper_round */ /** + * Size of Number toString digit buffers. + */ +#define NUMBER_TO_STRING_MAX_DIGIT_COUNT 64u + +/** * The Number.prototype object's 'toString' and 'toLocaleString' routines * * See also: @@ -176,249 +182,130 @@ ecma_builtin_number_prototype_object_to_string (ecma_number_t this_arg_number, / return ecma_make_string_value (ret_str_p); } - int buff_size = 0; - + uint8_t integer_digits[NUMBER_TO_STRING_MAX_DIGIT_COUNT]; + uint8_t fraction_digits[NUMBER_TO_STRING_MAX_DIGIT_COUNT]; + uint32_t integer_zeros = 0; + uint32_t fraction_zeros = 0; bool is_number_negative = false; + if (ecma_number_is_negative (this_arg_number)) { - /* ecma_number_to_decimal can't handle negative numbers, so we get rid of the sign. */ this_arg_number = -this_arg_number; is_number_negative = true; - - /* Add space for the sign in the result. */ - buff_size += 1; } - /* Decompose the number. */ - lit_utf8_byte_t digits[ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER]; - int32_t exponent; - lit_utf8_size_t digit_count = ecma_number_to_decimal (this_arg_number, digits, &exponent); - - /* - * The 'exponent' given by 'ecma_number_to_decimal' specifies where the decimal point is located - * compared to the first digit in 'digits'. - * For example: 120 -> '12', exp: 3 and 0.012 -> '12', exp: -1 - * We convert it to be location of the decimal point compared to the last digit of 'digits': - * 120 -> 12 * 10^1 and 0.012 -> 12 * 10^-3 - */ - exponent = exponent - (int32_t) digit_count; - - /* 'magnitude' will be the magnitude of the number in the specific radix. */ - int magnitude; - int required_digits; - if (exponent >= 0) - { - /* - * If the exponent is non-negative that means we won't have a fractional part, and can calculate - * exactly how many digits we will have. This could be done via a mathematic formula, but in rare - * cases that can cause incorrect results due to precision issues, so we use a loop instead. - */ - magnitude = 0; - ecma_number_t counter = this_arg_number; - while (counter >= radix) - { - counter /= radix; - magnitude++; - } + ecma_number_t integer_part = floor (this_arg_number); + ecma_number_t fraction_part = this_arg_number - integer_part; - /* - * The magnitude will only tell us how many digits we have after the first one, so we add one extra. - * In this case we won't be needing a radix point, so we don't need to worry about space for it. - */ - required_digits = magnitude + 1; - } - else - { - /* - * We can't know exactly how many digits we will need, since the number may be non-terminating in the - * new radix, so we will have to estimate it. We do this by first calculating how many zeros we will - * need in the specific radix before we hit a significant digit. This is calculated from the decimal - * exponent, which we negate so that we get a positive number in the end. - */ - magnitude = (int) floor ((log (10) / log (radix)) * -exponent); - - /* - * We also need to add space for significant digits. The worst case is radix == 2, since this will - * require the most digits. In this case, the upper limit to the number of significant digits we can have is - * ECMA_NUMBER_FRACTION_WIDTH + 1. This should be sufficient for any number. - */ - required_digits = magnitude + ECMA_NUMBER_FRACTION_WIDTH + 1; - - /* - * We add an exta slot for the radix point. It is also likely that we will need extra space for a - * leading zero before the radix point. It's better to add space for that here as well, even if we may not - * need it, since later we won't be able to do so. - */ - buff_size += 2; - } - - /* - * Here we normalize the number so that it is as close to 0 as possible, which will prevent us from losing - * precision in case of extreme numbers when we later split the number into integer and fractional parts. - * This has to be done in the specific radix, otherwise it messes up the result, so we use magnitude instead. - */ - if (exponent > 0) - { - for (int i = 0; i < magnitude; i++) - { - this_arg_number /= radix; - } - } - else if (exponent < 0) + uint8_t *integer_cursor_p = integer_digits + NUMBER_TO_STRING_MAX_DIGIT_COUNT; + uint8_t *fraction_cursor_p = fraction_digits; + + if (fraction_part > 0.0) { - for (int i = 0; i < magnitude; i++) + uint8_t digit; + ecma_number_t precision = (ecma_number_get_next (this_arg_number) - this_arg_number) * 0.5f; + precision = JERRY_MAX (precision, ECMA_NUMBER_MIN_VALUE); + + do { - this_arg_number *= radix; - } - } + fraction_part *= radix; + precision *= radix; - /* Split the number into an integer and a fractional part, since we have to handle them separately. */ - uint64_t whole = (uint64_t) this_arg_number; - ecma_number_t fraction = this_arg_number - (ecma_number_t) whole; + digit = (uint8_t) floor (fraction_part); - bool should_round = false; - if (!ecma_number_is_zero (fraction) && exponent >= 0) - { - /* - * If the exponent is non-negative, and we get a non-zero fractional part, that means - * the normalization might have introduced a small error, in which case we have to correct it by rounding. - * We'll add one extra significant digit which we will later use to round. - */ - required_digits += 1; - should_round = true; - } + if (digit == 0 && fraction_cursor_p == fraction_digits) + { + fraction_zeros++; + continue; + } - /* Get the total required buffer size and allocate the buffer. */ - buff_size += required_digits; - ecma_value_t ret_value; - JMEM_DEFINE_LOCAL_ARRAY (buff, buff_size, lit_utf8_byte_t); - int buff_index = 0; + JERRY_ASSERT (fraction_cursor_p < fraction_digits + NUMBER_TO_STRING_MAX_DIGIT_COUNT); + *fraction_cursor_p++ = digit; + fraction_part -= (ecma_number_t) digit; + } while (fraction_part >= precision); - /* Calculate digits for whole part. */ - while (whole > 0) - { - JERRY_ASSERT (buff_index < buff_size && buff_index < required_digits); - buff[buff_index++] = (lit_utf8_byte_t) (whole % radix); - whole /= radix; - } + /* Round to even */ + if (fraction_part > 0.5 || (fraction_part == 0.5 && (digit & 1) != 0)) + { + /* Add carry and remove overflowing trailing digits */ + while (true) + { + (*(--fraction_cursor_p))++; + + if (*fraction_cursor_p < radix) + { + /* Re-adjust cursor to point after the last significant digit */ + fraction_cursor_p++; + break; + } + + if (fraction_cursor_p == fraction_digits) + { + /* Carry overflowed to integer part */ + integer_part += 1; + break; + } + } + } - /* The digits are backwards, we need to reverse them. */ - for (int i = 0; i < buff_index / 2; i++) - { - lit_utf8_byte_t swap = buff[i]; - buff[i] = buff[buff_index - i - 1]; - buff[buff_index - i - 1] = swap; + /* Convert fraction digits to characters. */ + for (uint8_t *digit_p = fraction_digits; digit_p < fraction_cursor_p; digit_p++) + { + *digit_p = digit_chars[*digit_p]; + } } - /* - * Calculate where we have to put the radix point relative to the beginning of - * the new digits. If the exponent is non-negative this will be right after the number. - */ - int point = exponent >= 0 ? magnitude + 1 : buff_index - magnitude; - - if (point < 0) + while (ecma_number_biased_exp (ecma_number_to_binary (integer_part / radix)) + > ECMA_NUMBER_EXPONENT_BIAS + ECMA_NUMBER_FRACTION_WIDTH) { - /* - * In this case the radix point will be before the first digit, - * so we need to leave space for leading zeros. - */ - JERRY_ASSERT (exponent < 0); - required_digits += point; + integer_zeros++; + integer_part /= radix; } - JERRY_ASSERT (required_digits <= buff_size); + uint64_t integer_u64 = (uint64_t) integer_part; - /* Calculate digits for fractional part. */ - while (buff_index < required_digits) + do { - fraction *= radix; - lit_utf8_byte_t digit = (lit_utf8_byte_t) floor (fraction); + uint64_t remainder = integer_u64 % radix; + *(--integer_cursor_p) = (uint8_t) digit_chars[remainder]; - buff[buff_index++] = digit; - fraction -= (ecma_number_t) floor (fraction); - } + integer_u64 /= radix; + } while (integer_u64 > 0); - if (should_round) - { - /* Consume last digit for rounding. */ - buff_index--; - if (buff[buff_index] > radix / 2) - { - /* We should be rounding up. */ - buff[buff_index - 1]++; + const uint32_t integer_digit_count = + (uint32_t) (integer_digits + NUMBER_TO_STRING_MAX_DIGIT_COUNT - integer_cursor_p); + JERRY_ASSERT (integer_digit_count > 0); - /* Propagate carry forward in the digits. */ - for (int i = buff_index - 1; i > 0 && buff[i] >= radix; i--) - { - buff[i] = (lit_utf8_byte_t) (buff[i] - radix); - buff[i - 1]++; - } + ecma_stringbuilder_t builder = ecma_stringbuilder_create (); - if (buff[0] >= radix) - { - /* - * Carry propagated over the whole number, we need to add a new leading digit. - * We can use the place of the original rounded digit, we just need to shift everything - * right by one. - */ - memmove (buff + 1, buff, (size_t) buff_index); - buff_index++; - buff[0] = 1; - } - } + if (is_number_negative) + { + ecma_stringbuilder_append_byte (&builder, LIT_CHAR_MINUS); } - /* Remove trailing zeros. */ - while (buff_index - 1 > point && buff[buff_index - 1] == 0) + ecma_stringbuilder_append_raw (&builder, integer_cursor_p, integer_digit_count); + + while (integer_zeros--) { - buff_index--; + ecma_stringbuilder_append_byte (&builder, LIT_CHAR_0); } - /* Add leading zeros in case place of radix point is negative. */ - if (point <= 0) + if (fraction_cursor_p != fraction_digits) { - /* We will have 'point' amount of zeros after the radix point, and +1 before. */ - int zero_count = -point + 1; - memmove (buff + zero_count, buff, (size_t) buff_index); - buff_index += zero_count; + ecma_stringbuilder_append_byte (&builder, LIT_CHAR_DOT); - for (int i = 0; i < zero_count; i++) + while (fraction_zeros--) { - buff[i] = 0; + ecma_stringbuilder_append_byte (&builder, LIT_CHAR_0); } - /* We now need to place the radix point after the first zero. */ - point = 1; - } - - /* Convert digits to characters. */ - for (int i = 0; i < buff_index; i++) - { - buff[i] = digit_chars[buff[i]]; - } - - /* Place radix point to the required position. */ - if (point < buff_index) - { - memmove (buff + point + 1, buff + point, (size_t) (buff_index - point)); - buff[point] = '.'; - buff_index++; - } + const uint32_t fraction_digit_count = (uint32_t) (fraction_cursor_p - fraction_digits); + JERRY_ASSERT (fraction_digit_count > 0); - /* Add negative sign if necessary. */ - if (is_number_negative) - { - memmove (buff + 1, buff, (size_t) buff_index); - buff[0] = '-'; - buff_index++; + ecma_stringbuilder_append_raw (&builder, fraction_digits, fraction_digit_count); } - JERRY_ASSERT (buff_index <= buff_size); - ecma_string_t *str_p = ecma_new_ecma_string_from_utf8 (buff, (lit_utf8_size_t) buff_index); - ret_value = ecma_make_string_value (str_p); - JMEM_FINALIZE_LOCAL_ARRAY (buff); - - return ret_value; + return ecma_make_string_value (ecma_stringbuilder_finalize (&builder)); } /* ecma_builtin_number_prototype_object_to_string */ /** diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-number.c b/jerry-core/ecma/builtin-objects/ecma-builtin-number.c index 6626368c..6d4dfbd7 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-number.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-number.c @@ -22,6 +22,7 @@ #include "ecma-exceptions.h" #include "ecma-gc.h" #include "ecma-globals.h" +#include "ecma-helpers-number.h" #include "ecma-helpers.h" #include "ecma-number-object.h" #include "ecma-objects.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtins.c b/jerry-core/ecma/builtin-objects/ecma-builtins.c index a570a0ba..61692cb0 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtins.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtins.c @@ -20,6 +20,7 @@ #include "ecma-function-object.h" #include "ecma-gc.h" #include "ecma-globals.h" +#include "ecma-helpers-number.h" #include "ecma-helpers.h" #include "ecma-objects.h" diff --git a/jerry-core/ecma/operations/ecma-array-object.c b/jerry-core/ecma/operations/ecma-array-object.c index 0e793516..0ce958c3 100644 --- a/jerry-core/ecma/operations/ecma-array-object.c +++ b/jerry-core/ecma/operations/ecma-array-object.c @@ -24,7 +24,6 @@ #include "ecma-globals.h" #include "ecma-helpers.h" #include "ecma-iterator-object.h" -#include "ecma-number-arithmetic.h" #include "ecma-objects-general.h" #include "ecma-objects.h" #include "ecma-property-hashmap.h" diff --git a/jerry-core/ecma/operations/ecma-bigint.c b/jerry-core/ecma/operations/ecma-bigint.c index 2415a1f3..8ce37788 100644 --- a/jerry-core/ecma/operations/ecma-bigint.c +++ b/jerry-core/ecma/operations/ecma-bigint.c @@ -17,6 +17,7 @@ #include "ecma-big-uint.h" #include "ecma-exceptions.h" +#include "ecma-helpers-number.h" #include "ecma-helpers.h" #include "ecma-objects.h" @@ -85,21 +86,10 @@ ecma_bigint_parse_string (const lit_utf8_byte_t *string_p, /**< string represena if (size >= 3 && string_p[0] == LIT_CHAR_0) { - if (string_p[1] == LIT_CHAR_LOWERCASE_X || string_p[1] == LIT_CHAR_UPPERCASE_X) - { - radix = 16; - string_p += 2; - size -= 2; - } - else if (string_p[1] == LIT_CHAR_LOWERCASE_O || string_p[1] == LIT_CHAR_UPPERCASE_O) - { - radix = 8; - string_p += 2; - size -= 2; - } - else if (string_p[1] == LIT_CHAR_LOWERCASE_B || string_p[1] == LIT_CHAR_UPPERCASE_B) + radix = lit_char_to_radix (string_p[1]); + + if (radix != 10) { - radix = 2; string_p += 2; size -= 2; } @@ -292,17 +282,15 @@ static uint32_t ecma_bigint_number_to_digits (ecma_number_t number, /**< ecma number */ ecma_bigint_digit_t *digits_p) /**< [out] BigInt digits */ { - uint32_t biased_exp; - uint64_t fraction; - - ecma_number_unpack (number, NULL, &biased_exp, &fraction); - - if (biased_exp == 0 && fraction == 0) + if (ecma_number_is_zero (number)) { - /* Number is zero. */ return ECMA_BIGINT_NUMBER_TO_DIGITS_SET_DIGITS (0); } + ecma_binary_num_t binary = ecma_number_to_binary (number); + uint32_t biased_exp = ecma_number_biased_exp (binary); + uint64_t fraction = ecma_number_fraction (binary); + if (biased_exp < ((1 << (ECMA_NUMBER_BIASED_EXP_WIDTH - 1)) - 1)) { /* Number is less than 1. */ @@ -618,7 +606,7 @@ ecma_bigint_to_number (ecma_value_t value) /**< BigInt value */ if (biased_exp < (1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1) { - result = ecma_number_pack (sign, biased_exp, fraction); + result = ecma_number_create (sign, biased_exp, fraction); } else { diff --git a/jerry-core/ecma/operations/ecma-conversion.c b/jerry-core/ecma/operations/ecma-conversion.c index 661c5514..9a71b2ff 100644 --- a/jerry-core/ecma/operations/ecma-conversion.c +++ b/jerry-core/ecma/operations/ecma-conversion.c @@ -29,6 +29,7 @@ #include "ecma-function-object.h" #include "ecma-gc.h" #include "ecma-globals.h" +#include "ecma-helpers-number.h" #include "ecma-helpers.h" #include "ecma-number-object.h" #include "ecma-objects-general.h" diff --git a/jerry-core/ecma/operations/ecma-iterator-object.c b/jerry-core/ecma/operations/ecma-iterator-object.c index 943df3e6..21d88724 100644 --- a/jerry-core/ecma/operations/ecma-iterator-object.c +++ b/jerry-core/ecma/operations/ecma-iterator-object.c @@ -24,7 +24,6 @@ #include "ecma-gc.h" #include "ecma-globals.h" #include "ecma-helpers.h" -#include "ecma-number-arithmetic.h" #include "ecma-objects-general.h" #include "ecma-objects.h" diff --git a/jerry-core/ecma/operations/ecma-number-arithmetic.c b/jerry-core/ecma/operations/ecma-number-arithmetic.c deleted file mode 100644 index 2d17900a..00000000 --- a/jerry-core/ecma/operations/ecma-number-arithmetic.c +++ /dev/null @@ -1,56 +0,0 @@ -/* Copyright JS Foundation and other contributors, http://js.foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "ecma-number-arithmetic.h" - -#include "ecma-globals.h" -#include "ecma-helpers.h" - -/** \addtogroup ecma ECMA - * @{ - * - * \addtogroup numberarithmetic ECMA number arithmetic operations - * @{ - */ - -/** - * ECMA-defined number remainder calculation. - * - * See also: - * ECMA-262 v5, 11.5.3 - * - * @return number - calculated remainder. - */ -ecma_number_t -ecma_op_number_remainder (ecma_number_t left_num, /**< left operand */ - ecma_number_t right_num) /**< right operand */ -{ - if (ecma_number_is_nan (left_num) || ecma_number_is_nan (right_num) || ecma_number_is_infinity (left_num) - || ecma_number_is_zero (right_num)) - { - return ecma_number_make_nan (); - } - else if (ecma_number_is_infinity (right_num) || (ecma_number_is_zero (left_num) && !ecma_number_is_zero (right_num))) - { - return left_num; - } - - return ecma_number_calc_remainder (left_num, right_num); -} /* ecma_op_number_remainder */ - -/** - * @} - * @} - */ diff --git a/jerry-core/ecma/operations/ecma-number-arithmetic.h b/jerry-core/ecma/operations/ecma-number-arithmetic.h deleted file mode 100644 index 2d9d00ac..00000000 --- a/jerry-core/ecma/operations/ecma-number-arithmetic.h +++ /dev/null @@ -1,35 +0,0 @@ -/* Copyright JS Foundation and other contributors, http://js.foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ECMA_NUMBER_ARITHMETIC_H -#define ECMA_NUMBER_ARITHMETIC_H - -#include "ecma-globals.h" - -/** \addtogroup ecma ECMA - * @{ - * - * \addtogroup numberarithmetic ECMA number arithmetic operations - * @{ - */ - -ecma_number_t ecma_op_number_remainder (ecma_number_t left_num, ecma_number_t right_num); - -/** - * @} - * @} - */ - -#endif /* !ECMA_NUMBER_ARITHMETIC_H */ diff --git a/jerry-core/ecma/operations/ecma-typedarray-object.c b/jerry-core/ecma/operations/ecma-typedarray-object.c index 7a2d171a..cd8c4f6e 100644 --- a/jerry-core/ecma/operations/ecma-typedarray-object.c +++ b/jerry-core/ecma/operations/ecma-typedarray-object.c @@ -22,10 +22,12 @@ #include "ecma-bigint.h" #include "ecma-builtin-helpers.h" #include "ecma-builtins.h" +#include "ecma-conversion.h" #include "ecma-exceptions.h" #include "ecma-function-object.h" #include "ecma-gc.h" #include "ecma-globals.h" +#include "ecma-helpers-number.h" #include "ecma-helpers.h" #include "ecma-iterator-object.h" #include "ecma-objects-general.h" diff --git a/jerry-core/lit/lit-char-helpers.c b/jerry-core/lit/lit-char-helpers.c index 6eb6c5d9..b99136db 100644 --- a/jerry-core/lit/lit-char-helpers.c +++ b/jerry-core/lit/lit-char-helpers.c @@ -336,6 +336,35 @@ lit_char_is_binary_digit (ecma_char_t c) /** code unit */ #endif /* JERRY_ESNEXT */ /** + * @return radix value + */ +uint8_t +lit_char_to_radix (lit_utf8_byte_t c) /** code unit */ +{ + switch (LEXER_TO_ASCII_LOWERCASE (c)) + { + case LIT_CHAR_LOWERCASE_X: + { + return 16; + } +#if JERRY_ESNEXT + case LIT_CHAR_LOWERCASE_O: + { + return 8; + } + case LIT_CHAR_LOWERCASE_B: + { + return 2; + } +#endif /* JERRY_ESNEXT */ + default: + { + return 10; + } + } +} /* lit_char_to_radix */ + +/** * UnicodeEscape abstract method * * See also: ECMA-262 v10, 24.5.2.3 @@ -370,14 +399,9 @@ lit_char_hex_to_int (ecma_char_t c) /**< code unit, corresponding to { return (uint32_t) (c - LIT_CHAR_ASCII_DIGITS_BEGIN); } - else if (c >= LIT_CHAR_ASCII_LOWERCASE_LETTERS_HEX_BEGIN && c <= LIT_CHAR_ASCII_LOWERCASE_LETTERS_HEX_END) - { - return (uint32_t) (c - LIT_CHAR_ASCII_LOWERCASE_LETTERS_HEX_BEGIN + 10); - } - else - { - return (uint32_t) (c - LIT_CHAR_ASCII_UPPERCASE_LETTERS_HEX_BEGIN + 10); - } + + const uint32_t hex_offset = 10 - (LIT_CHAR_LOWERCASE_A % 32); + return (c % 32) + hex_offset; } /* lit_char_hex_to_int */ /** diff --git a/jerry-core/lit/lit-char-helpers.h b/jerry-core/lit/lit-char-helpers.h index 2f66b917..1be89da4 100644 --- a/jerry-core/lit/lit-char-helpers.h +++ b/jerry-core/lit/lit-char-helpers.h @@ -229,6 +229,7 @@ bool lit_char_is_hex_digit (ecma_char_t c); #if JERRY_ESNEXT bool lit_char_is_binary_digit (ecma_char_t c); #endif /* JERRY_ESNEXT */ +uint8_t lit_char_to_radix (lit_utf8_byte_t c); void lit_char_unicode_escape (ecma_stringbuilder_t *builder_p, ecma_char_t c); uint32_t lit_char_hex_to_int (ecma_char_t c); size_t lit_code_point_to_cesu8_bytes (uint8_t *dst_p, lit_code_point_t code_point); diff --git a/jerry-core/parser/js/js-lexer.c b/jerry-core/parser/js/js-lexer.c index d42a4146..585bde84 100644 --- a/jerry-core/parser/js/js-lexer.c +++ b/jerry-core/parser/js/js-lexer.c @@ -2619,44 +2619,19 @@ lexer_construct_number_object (parser_context_t *context_p, /**< context */ { #endif /* JERRY_BUILTIN_BIGINT */ ecma_number_t num; + uint32_t options = 0; - if (context_p->token.extra_value < LEXER_NUMBER_OCTAL) - { #if JERRY_ESNEXT - num = ecma_utf8_string_to_number (context_p->token.lit_location.char_p, length, ECMA_CONVERSION_ALLOW_UNDERSCORE); -#else /* !JERRY_ESNEXT */ - num = ecma_utf8_string_to_number (context_p->token.lit_location.char_p, length, 0); + options |= ECMA_CONVERSION_ALLOW_UNDERSCORE; #endif /* JERRY_ESNEXT */ + + if (context_p->token.extra_value == LEXER_NUMBER_OCTAL) + { + num = ecma_utf8_string_to_number_by_radix (context_p->token.lit_location.char_p, length, 8, options); } else { - const uint8_t *src_p = context_p->token.lit_location.char_p; - const uint8_t *src_end_p = src_p + length - 1; - ecma_number_t multiplier = 8.0; - - JERRY_ASSERT (src_p[0] == LIT_CHAR_0); - -#if JERRY_ESNEXT - if (context_p->token.extra_value == LEXER_NUMBER_BINARY) - { - src_p++; - multiplier = 2.0; - } - else if (LEXER_TO_ASCII_LOWERCASE (src_p[1]) == LIT_CHAR_LOWERCASE_O) - { - src_p++; - } -#endif /* JERRY_ESNEXT */ - - num = 0; - do - { - if (src_p[1] == LIT_CHAR_UNDERSCORE) - { - src_p++; - } - num = num * multiplier + (ecma_number_t) (*(++src_p) - LIT_CHAR_0); - } while (src_p < src_end_p); + num = ecma_utf8_string_to_number (context_p->token.lit_location.char_p, length, options); } if (is_expr) diff --git a/jerry-core/vm/opcodes-ecma-arithmetics.c b/jerry-core/vm/opcodes-ecma-arithmetics.c index a0b15c81..ec19aa75 100644 --- a/jerry-core/vm/opcodes-ecma-arithmetics.c +++ b/jerry-core/vm/opcodes-ecma-arithmetics.c @@ -18,7 +18,6 @@ #include "ecma-conversion.h" #include "ecma-exceptions.h" #include "ecma-helpers.h" -#include "ecma-number-arithmetic.h" #include "ecma-objects.h" #include "jrt-libc-includes.h" @@ -89,7 +88,21 @@ do_number_arithmetic (number_arithmetic_op op, /**< number arithmetic operation } case NUMBER_ARITHMETIC_REMAINDER: { - result = ecma_op_number_remainder (left_number, right_number); + if (ecma_number_is_nan (left_number) || ecma_number_is_nan (right_number) + || ecma_number_is_infinity (left_number) || ecma_number_is_zero (right_number)) + { + result = ecma_number_make_nan (); + break; + } + + if (ecma_number_is_infinity (right_number) + || (ecma_number_is_zero (left_number) && !ecma_number_is_zero (right_number))) + { + result = left_number; + break; + } + + result = ecma_number_remainder (left_number, right_number); break; } #if JERRY_ESNEXT |