aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDániel Bátyai <dbatyai@inf.u-szeged.hu>2021-12-03 12:58:37 +0100
committerGitHub <noreply@github.com>2021-12-03 12:58:37 +0100
commit81d2319144377f87e716c73a9b8b46f2bf5d09e5 (patch)
tree92dd7f340e08bf8a42f7540b74659a218635b628
parenta1c1d4271061eff9f4bb4a0c9c31bb68c7f1514d (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
-rw-r--r--jerry-core/CMakeLists.txt2
-rw-r--r--jerry-core/ecma/base/ecma-globals.h208
-rw-r--r--jerry-core/ecma/base/ecma-helpers-conversion.c669
-rw-r--r--jerry-core/ecma/base/ecma-helpers-number.c836
-rw-r--r--jerry-core/ecma/base/ecma-helpers-number.h245
-rw-r--r--jerry-core/ecma/base/ecma-helpers-string.c1
-rw-r--r--jerry-core/ecma/base/ecma-helpers-value.c11
-rw-r--r--jerry-core/ecma/base/ecma-helpers.h9
-rw-r--r--jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c1
-rw-r--r--jerry-core/ecma/builtin-objects/ecma-builtin-date.c4
-rw-r--r--jerry-core/ecma/builtin-objects/ecma-builtin-helpers-sort.c1
-rw-r--r--jerry-core/ecma/builtin-objects/ecma-builtin-helpers.c1
-rw-r--r--jerry-core/ecma/builtin-objects/ecma-builtin-math.c36
-rw-r--r--jerry-core/ecma/builtin-objects/ecma-builtin-number-prototype.c295
-rw-r--r--jerry-core/ecma/builtin-objects/ecma-builtin-number.c1
-rw-r--r--jerry-core/ecma/builtin-objects/ecma-builtins.c1
-rw-r--r--jerry-core/ecma/operations/ecma-array-object.c1
-rw-r--r--jerry-core/ecma/operations/ecma-bigint.c32
-rw-r--r--jerry-core/ecma/operations/ecma-conversion.c1
-rw-r--r--jerry-core/ecma/operations/ecma-iterator-object.c1
-rw-r--r--jerry-core/ecma/operations/ecma-number-arithmetic.c56
-rw-r--r--jerry-core/ecma/operations/ecma-number-arithmetic.h35
-rw-r--r--jerry-core/ecma/operations/ecma-typedarray-object.c2
-rw-r--r--jerry-core/lit/lit-char-helpers.c40
-rw-r--r--jerry-core/lit/lit-char-helpers.h1
-rw-r--r--jerry-core/parser/js/js-lexer.c39
-rw-r--r--jerry-core/vm/opcodes-ecma-arithmetics.c17
-rw-r--r--tests/jerry/number-prototype-to-string.js6
-rw-r--r--tests/jerry/test_suite_15.js2
-rw-r--r--tests/unit-core/test-to-length.c1
30 files changed, 987 insertions, 1568 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
diff --git a/tests/jerry/number-prototype-to-string.js b/tests/jerry/number-prototype-to-string.js
index 46510bb5..614eee2c 100644
--- a/tests/jerry/number-prototype-to-string.js
+++ b/tests/jerry/number-prototype-to-string.js
@@ -42,8 +42,8 @@ assert((-0.03125).toString(2) === "-0.00001");
assert((-0.03125).toString(16) === "-0.08");
assert((-0.0001).toString(4) === "-0.000000122031232023223013010030231")
assert((-0).toString(16) === "0");
-assert((1e+73).toString(35) === "2nx1mg1l0w4ujlpt449c5qfrkkmtpgpsfsc2prlaqtnjbli2")
-assert((-1e+73).toString(35) === "-2nx1mg1l0w4ujlpt449c5qfrkkmtpgpsfsc2prlaqtnjbli2")
+assert((1e+73).toString(35) === "2nx1mg1l0w6b000000000000000000000000000000000000")
+assert((-1e+73).toString(35) === "-2nx1mg1l0w6b000000000000000000000000000000000000")
assert((1).toString(undefined) === "1")
assert((123400).toString(2) === "11110001000001000");
@@ -90,7 +90,7 @@ assert ((-0x100000000000061).toString(16) === "-100000000000060");
assert((123400).toString(new Number(16)) === "1e208");
-assert(65535.9.toString(3) === "10022220020.2200220022002200220022102110122000001102212");
+assert(65535.9.toString(3) === "10022220020.220022002200220022002201");
var digit_chars = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
diff --git a/tests/jerry/test_suite_15.js b/tests/jerry/test_suite_15.js
index 65b0767a..2a6a1544 100644
--- a/tests/jerry/test_suite_15.js
+++ b/tests/jerry/test_suite_15.js
@@ -1175,7 +1175,7 @@
(function tc_15_07_04_02__001() {
var a = Number(0.1);
- assert(a.toString(36) === "0.3llllllllllqsn8td1p464unmi");
+ assert(a.toString(36) === "0.3lllllllllm");
})();
(function tc_15_07_04_02__013() {
diff --git a/tests/unit-core/test-to-length.c b/tests/unit-core/test-to-length.c
index b5a43501..657b9260 100644
--- a/tests/unit-core/test-to-length.c
+++ b/tests/unit-core/test-to-length.c
@@ -20,6 +20,7 @@
#include "ecma-conversion.h"
#include "ecma-exceptions.h"
#include "ecma-globals.h"
+#include "ecma-helpers-number.h"
#include "ecma-helpers.h"
#include "ecma-init-finalize.h"