From 6adf0c1a87e164af7979131b16612b456a50fbe8 Mon Sep 17 00:00:00 2001 From: Zoltan Herczeg Date: Wed, 12 Aug 2020 16:33:31 +0200 Subject: [PATCH] Support BigInt to number conversion using Number constructor (#4121) JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com --- jerry-core/api/jerry.c | 2 +- jerry-core/ecma/base/ecma-helpers-number.c | 4 +- jerry-core/ecma/base/ecma-helpers.h | 1 + .../ecma-builtin-date-prototype.c | 2 +- .../ecma/builtin-objects/ecma-builtin-date.c | 2 +- .../ecma/builtin-objects/ecma-builtin-json.c | 4 +- .../ecma/builtin-objects/ecma-builtin-math.c | 8 +- .../builtin-objects/ecma-builtin-number.c | 37 ++++- .../builtin-objects/ecma-builtin-string.c | 2 +- .../ecma/operations/ecma-array-object.c | 4 +- .../ecma/operations/ecma-arraybuffer-object.c | 2 +- jerry-core/ecma/operations/ecma-big-uint.c | 52 +++---- jerry-core/ecma/operations/ecma-big-uint.h | 2 + jerry-core/ecma/operations/ecma-bigint.c | 134 ++++++++++++++++++ jerry-core/ecma/operations/ecma-bigint.h | 1 + jerry-core/ecma/operations/ecma-comparison.c | 2 +- jerry-core/ecma/operations/ecma-conversion.c | 11 +- jerry-core/ecma/operations/ecma-conversion.h | 4 +- .../ecma/operations/ecma-number-object.c | 2 +- tests/jerry/es.next/bigint9.js | 42 ++++++ tests/test262-esnext-excludelist.xml | 2 - 21 files changed, 266 insertions(+), 54 deletions(-) create mode 100644 tests/jerry/es.next/bigint9.js diff --git a/jerry-core/api/jerry.c b/jerry-core/api/jerry.c index e870a7747..ea14eeff1 100644 --- a/jerry-core/api/jerry.c +++ b/jerry-core/api/jerry.c @@ -1301,7 +1301,7 @@ jerry_value_to_number (const jerry_value_t value) /**< input value */ return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (error_value_msg_p))); } - return jerry_return (ecma_op_to_number (value)); + return jerry_return (ecma_op_to_number (value, ECMA_TO_NUMERIC_NO_OPTS)); } /* jerry_value_to_number */ /** diff --git a/jerry-core/ecma/base/ecma-helpers-number.c b/jerry-core/ecma/base/ecma-helpers-number.c index 9ebcbbe09..010bb8d00 100644 --- a/jerry-core/ecma/base/ecma-helpers-number.c +++ b/jerry-core/ecma/base/ecma-helpers-number.c @@ -48,7 +48,7 @@ JERRY_STATIC_ASSERT (sizeof (ecma_number_t) == sizeof (uint32_t), * * @return ecma-number with specified sign, biased_exponent and fraction */ -static ecma_number_t +ecma_number_t ecma_number_pack (bool sign, /**< sign */ uint32_t biased_exp, /**< biased exponent */ uint64_t fraction) /**< fraction */ @@ -111,7 +111,7 @@ JERRY_STATIC_ASSERT (sizeof (ecma_number_t) == sizeof (uint64_t), * * @return ecma-number with specified sign, biased_exponent and fraction */ -static ecma_number_t +ecma_number_t ecma_number_pack (bool sign, /**< sign */ uint32_t biased_exp, /**< biased exponent */ uint64_t fraction) /**< fraction */ diff --git a/jerry-core/ecma/base/ecma-helpers.h b/jerry-core/ecma/base/ecma-helpers.h index a4d796323..55e08807b 100644 --- a/jerry-core/ecma/base/ecma-helpers.h +++ b/jerry-core/ecma/base/ecma-helpers.h @@ -426,6 +426,7 @@ 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); diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-date-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-date-prototype.c index d13b4cdcc..bcd3fe853 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-date-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-date-prototype.c @@ -396,7 +396,7 @@ ecma_builtin_date_prototype_dispatch_set (uint16_t builtin_routine_id, /**< buil for (uint32_t i = 0; i < conversions; i++) { - ecma_value_t value = ecma_op_to_number (arguments_list[i]); + ecma_value_t value = ecma_op_to_number (arguments_list[i], ECMA_TO_NUMERIC_NO_OPTS); if (ECMA_IS_VALUE_ERROR (value)) { diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-date.c b/jerry-core/ecma/builtin-objects/ecma-builtin-date.c index edd5da054..b4fcbc8d6 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-date.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-date.c @@ -776,7 +776,7 @@ ecma_builtin_date_dispatch_construct (const ecma_value_t *arguments_list_p, /**< } else { - ecma_value_t prim_value = ecma_op_to_number (argument); + ecma_value_t prim_value = ecma_op_to_number (argument, ECMA_TO_NUMERIC_NO_OPTS); if (ECMA_IS_VALUE_ERROR (prim_value)) { diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-json.c b/jerry-core/ecma/builtin-objects/ecma-builtin-json.c index 56f31d067..982bab14a 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-json.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-json.c @@ -1269,7 +1269,7 @@ ecma_builtin_json_serialize_property (ecma_json_stringify_context_t *context_p, /* 5.a */ if (class_name == LIT_MAGIC_STRING_NUMBER_UL) { - value = ecma_op_to_number (value); + value = ecma_op_to_number (value, ECMA_TO_NUMERIC_NO_OPTS); ecma_deref_object (obj_p); if (ECMA_IS_VALUE_ERROR (value)) @@ -1598,7 +1598,7 @@ ecma_builtin_json_stringify (ecma_value_t this_arg, /**< 'this' argument */ /* 5.a */ if (class_name == LIT_MAGIC_STRING_NUMBER_UL) { - ecma_value_t value = ecma_op_to_number (arg3); + ecma_value_t value = ecma_op_to_number (arg3, ECMA_TO_NUMERIC_NO_OPTS); if (ECMA_IS_VALUE_ERROR (value)) { diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-math.c b/jerry-core/ecma/builtin-objects/ecma-builtin-math.c index 24ccfa457..f165551d1 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-math.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-math.c @@ -135,7 +135,7 @@ ecma_builtin_math_object_max_min (bool is_max, /**< 'max' or 'min' operation */ } else { - ecma_value_t value = ecma_op_to_number (*arg); + ecma_value_t value = ecma_op_to_number (*arg, ECMA_TO_NUMERIC_NO_OPTS); if (ECMA_IS_VALUE_ERROR (value)) { @@ -215,7 +215,7 @@ ecma_builtin_math_object_hypot (const ecma_value_t *arg, /**< arguments list */ } else { - ecma_value_t value = ecma_op_to_number (*arg); + ecma_value_t value = ecma_op_to_number (*arg, ECMA_TO_NUMERIC_NO_OPTS); if (ECMA_IS_VALUE_ERROR (value)) { return value; @@ -357,7 +357,7 @@ ecma_builtin_math_dispatch_routine (uint16_t builtin_routine_id, /**< built-in w } else { - ecma_value_t value = ecma_op_to_number (arguments_list[0]); + ecma_value_t value = ecma_op_to_number (arguments_list[0], ECMA_TO_NUMERIC_NO_OPTS); if (ECMA_IS_VALUE_ERROR (value)) { @@ -379,7 +379,7 @@ ecma_builtin_math_dispatch_routine (uint16_t builtin_routine_id, /**< built-in w } else { - ecma_value_t value = ecma_op_to_number (arguments_list[1]); + ecma_value_t value = ecma_op_to_number (arguments_list[1], ECMA_TO_NUMERIC_NO_OPTS); if (ECMA_IS_VALUE_ERROR (value)) { diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-number.c b/jerry-core/ecma/builtin-objects/ecma-builtin-number.c index 6548cf80d..e85e026de 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-number.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-number.c @@ -16,6 +16,7 @@ #include #include "ecma-alloc.h" +#include "ecma-bigint.h" #include "ecma-builtins.h" #include "ecma-conversion.h" #include "ecma-exceptions.h" @@ -84,7 +85,16 @@ ecma_builtin_number_dispatch_call (const ecma_value_t *arguments_list_p, /**< ar } else { - ret_value = ecma_op_to_number (arguments_list_p[0]); + ret_value = ecma_op_to_number (arguments_list_p[0], ECMA_TO_NUMERIC_ALLOW_BIGINT); + +#if ENABLED (JERRY_BUILTIN_BIGINT) + if (ecma_is_value_bigint (ret_value)) + { + ecma_value_t bigint = ret_value; + ret_value = ecma_bigint_to_number (bigint); + ecma_free_value (bigint); + } +#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */ } return ret_value; @@ -103,13 +113,30 @@ ecma_builtin_number_dispatch_construct (const ecma_value_t *arguments_list_p, /* if (arguments_list_len == 0) { - ecma_value_t completion = ecma_op_create_number_object (ecma_make_integer_value (0)); - return completion; + return ecma_op_create_number_object (ecma_make_integer_value (0)); } - else + +#if ENABLED (JERRY_BUILTIN_BIGINT) + ecma_value_t value = ecma_op_to_number (arguments_list_p[0], ECMA_TO_NUMERIC_ALLOW_BIGINT); + + if (ecma_is_value_bigint (value)) { - return ecma_op_create_number_object (arguments_list_p[0]); + ecma_value_t bigint = value; + value = ecma_bigint_to_number (bigint); + ecma_free_value (bigint); } + + if (ECMA_IS_VALUE_ERROR (value)) + { + return value; + } + + ecma_value_t result = ecma_op_create_number_object (value); + ecma_free_value (value); + return result; +#else /* !ENABLED (JERRY_BUILTIN_BIGINT) */ + return ecma_op_create_number_object (arguments_list_p[0]); +#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */ } /* ecma_builtin_number_dispatch_construct */ #if ENABLED (JERRY_ESNEXT) diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-string.c b/jerry-core/ecma/builtin-objects/ecma-builtin-string.c index a03df9911..095b2230b 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-string.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-string.c @@ -291,7 +291,7 @@ ecma_builtin_string_object_from_code_point (ecma_value_t this_arg, /**< 'this' a for (uint32_t index = 0; index < args_number; index++) { - ecma_value_t to_number_value = ecma_op_to_number (args[index]); + ecma_value_t to_number_value = ecma_op_to_number (args[index], ECMA_TO_NUMERIC_NO_OPTS); if (ECMA_IS_VALUE_ERROR (to_number_value)) { diff --git a/jerry-core/ecma/operations/ecma-array-object.c b/jerry-core/ecma/operations/ecma-array-object.c index 29fdbd6bd..d395e1373 100644 --- a/jerry-core/ecma/operations/ecma-array-object.c +++ b/jerry-core/ecma/operations/ecma-array-object.c @@ -925,7 +925,7 @@ ecma_op_array_object_set_length (ecma_object_t *object_p, /**< the array object { bool is_throw = (flags & ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_IS_THROW); - ecma_value_t completion = ecma_op_to_number (new_value); + ecma_value_t completion = ecma_op_to_number (new_value, ECMA_TO_NUMERIC_NO_OPTS); if (ECMA_IS_VALUE_ERROR (completion)) { @@ -941,7 +941,7 @@ ecma_op_array_object_set_length (ecma_object_t *object_p, /**< the array object if (ecma_is_value_object (new_value)) { - ecma_value_t compared_num_val = ecma_op_to_number (new_value); + ecma_value_t compared_num_val = ecma_op_to_number (new_value, ECMA_TO_NUMERIC_NO_OPTS); if (ECMA_IS_VALUE_ERROR (compared_num_val)) { diff --git a/jerry-core/ecma/operations/ecma-arraybuffer-object.c b/jerry-core/ecma/operations/ecma-arraybuffer-object.c index 0199108a1..290e4e92c 100644 --- a/jerry-core/ecma/operations/ecma-arraybuffer-object.c +++ b/jerry-core/ecma/operations/ecma-arraybuffer-object.c @@ -119,7 +119,7 @@ ecma_op_create_arraybuffer_object (const ecma_value_t *arguments_list_p, /**< li } else { - ecma_value_t to_number_value = ecma_op_to_number (arguments_list_p[0]); + ecma_value_t to_number_value = ecma_op_to_number (arguments_list_p[0], ECMA_TO_NUMERIC_NO_OPTS); if (ECMA_IS_VALUE_ERROR (to_number_value)) { diff --git a/jerry-core/ecma/operations/ecma-big-uint.c b/jerry-core/ecma/operations/ecma-big-uint.c index c280c38d9..0aa357163 100644 --- a/jerry-core/ecma/operations/ecma-big-uint.c +++ b/jerry-core/ecma/operations/ecma-big-uint.c @@ -93,6 +93,32 @@ ecma_big_uint_extend (ecma_extended_primitive_t *value_p, /**< BigUInt value */ return result_p; } /* ecma_big_uint_extend */ +/** + * Count the number of leading zero bits of a digit + * + * return number of leading zero bits + */ +ecma_bigint_digit_t +ecma_big_uint_count_leading_zero (ecma_bigint_digit_t digit) /**< digit value */ +{ + ecma_bigint_digit_t shift = 4 * sizeof (ecma_bigint_digit_t); + ecma_bigint_digit_t result = 8 * sizeof (ecma_bigint_digit_t); + + do + { + ecma_bigint_digit_t value = digit >> shift; + if (value > 0) + { + digit = value; + result -= shift; + } + shift >>= 1; + } + while (shift > 0); + + return result - digit; +} /* ecma_big_uint_count_leading_zero */ + /** * Helper function which discards the leading zero digits of a BigUInt value * @@ -876,32 +902,6 @@ ecma_big_uint_mul (ecma_extended_primitive_t *left_value_p, /**< left BigUInt va return ecma_big_uint_extend (result_p, extra_space[0]); } /* ecma_big_uint_mul */ -/** - * Count the number of leading zero bits of a digit - * - * return new BigUInt value, NULL on error - */ -static ecma_bigint_digit_t -ecma_big_uint_count_leading_zero (ecma_bigint_digit_t digit) /**< digit value */ -{ - ecma_bigint_digit_t shift = 4 * sizeof (ecma_bigint_digit_t); - ecma_bigint_digit_t result = 8 * sizeof (ecma_bigint_digit_t); - - do - { - ecma_bigint_digit_t value = digit >> shift; - if (value > 0) - { - digit = value; - result -= shift; - } - shift >>= 1; - } - while (shift > 0); - - return result - digit; -} /* ecma_big_uint_count_leading_zero */ - /** * Divide left BigUInt value with right digit value * diff --git a/jerry-core/ecma/operations/ecma-big-uint.h b/jerry-core/ecma/operations/ecma-big-uint.h index 777c26c31..80cbb1cf9 100644 --- a/jerry-core/ecma/operations/ecma-big-uint.h +++ b/jerry-core/ecma/operations/ecma-big-uint.h @@ -100,6 +100,8 @@ typedef enum ecma_extended_primitive_t *ecma_bigint_create (uint32_t size); ecma_extended_primitive_t *ecma_big_uint_extend (ecma_extended_primitive_t *value_p, ecma_bigint_digit_t digit); +ecma_bigint_digit_t ecma_big_uint_count_leading_zero (ecma_bigint_digit_t digit); + int ecma_big_uint_compare (ecma_extended_primitive_t *left_value_p, ecma_extended_primitive_t *right_value_p); ecma_extended_primitive_t *ecma_big_uint_mul_digit (ecma_extended_primitive_t *value_p, diff --git a/jerry-core/ecma/operations/ecma-bigint.c b/jerry-core/ecma/operations/ecma-bigint.c index e612176ca..001a4d63c 100644 --- a/jerry-core/ecma/operations/ecma-bigint.c +++ b/jerry-core/ecma/operations/ecma-bigint.c @@ -482,6 +482,140 @@ ecma_bigint_to_bigint (ecma_value_t value, /**< any value */ return result; } /* ecma_bigint_to_bigint */ +/** + * Convert a BigInt value to number value + * + * @return ecma number value or ECMA_VALUE_ERROR + * Returned value must be freed with ecma_free_value. + */ +ecma_value_t +ecma_bigint_to_number (ecma_value_t value) /**< BigInt value */ +{ + JERRY_ASSERT (ecma_is_value_bigint (value)); + + if (value == ECMA_BIGINT_ZERO) + { + return ecma_make_integer_value (0); + } + + ecma_extended_primitive_t *value_p = ecma_get_extended_primitive_from_value (value); + uint32_t size = ECMA_BIGINT_GET_SIZE (value_p); + ecma_bigint_digit_t *digits_p = ECMA_BIGINT_GET_DIGITS (value_p, size); + + if (size == sizeof (ecma_bigint_digit_t)) + { + if (!(value_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN)) + { + if (digits_p[-1] <= ECMA_INTEGER_NUMBER_MAX) + { + return ecma_make_integer_value ((ecma_integer_value_t) digits_p[-1]); + } + } + else if (digits_p[-1] <= -ECMA_INTEGER_NUMBER_MIN) + { + return ecma_make_integer_value (-(ecma_integer_value_t) digits_p[-1]); + } + } + + uint64_t fraction = 0; + ecma_bigint_digit_t shift_left; + + if (digits_p[-1] == 1) + { + JERRY_ASSERT (size > sizeof (ecma_bigint_digit_t)); + + fraction = ((uint64_t) digits_p[-2]) << (8 * sizeof (ecma_bigint_digit_t)); + shift_left = (uint32_t) (8 * sizeof (ecma_bigint_digit_t)); + + if (size >= 3 * sizeof (ecma_bigint_digit_t)) + { + fraction |= (uint64_t) digits_p[-3]; + } + } + else + { + shift_left = ecma_big_uint_count_leading_zero (digits_p[-1]) + 1; + + fraction = ((uint64_t) digits_p[-1]) << (8 * sizeof (ecma_bigint_digit_t) + shift_left); + + if (size >= 2 * sizeof (ecma_bigint_digit_t)) + { + fraction |= ((uint64_t) digits_p[-2]) << shift_left; + } + + if (size >= 3 * sizeof (ecma_bigint_digit_t)) + { + fraction |= ((uint64_t) digits_p[-3]) >> (8 * sizeof (ecma_bigint_digit_t) - shift_left); + } + } + + uint32_t biased_exp = (uint32_t) (((1 << (ECMA_NUMBER_BIASED_EXP_WIDTH - 1)) - 1) + (size * 8 - shift_left)); + + /* Rounding result. */ + const uint64_t rounding_bit = (((uint64_t) 1) << (8 * sizeof (uint64_t) - ECMA_NUMBER_FRACTION_WIDTH - 1)); + bool round_up = false; + + if (fraction & rounding_bit) + { + round_up = true; + + /* IEEE_754 roundTiesToEven mode: when rounding_bit is set, and all the remaining bits + * are zero, the number needs to be rounded down the bit before rounding_bit is zero. */ + if ((fraction & ((rounding_bit << 2) - 1)) == rounding_bit) + { + round_up = false; + + if ((size >= (3 * sizeof (ecma_bigint_digit_t))) + && (shift_left == (8 * sizeof (ecma_bigint_digit_t)) + || (digits_p[-3] & ((((ecma_bigint_digit_t) 1) << shift_left) - 1)) == 0)) + { + ecma_bigint_digit_t *digits_start_p = ECMA_BIGINT_GET_DIGITS (value_p, 0); + + digits_p -= 3; + + while (digits_p > digits_start_p) + { + if (digits_p[-1] != 0) + { + round_up = true; + break; + } + digits_p--; + } + } + } + } + + if (round_up) + { + fraction += rounding_bit; + fraction >>= (8 * sizeof (uint64_t) - ECMA_NUMBER_FRACTION_WIDTH); + + if (fraction == 0) + { + biased_exp++; + } + } + else + { + fraction >>= (8 * sizeof (uint64_t) - ECMA_NUMBER_FRACTION_WIDTH); + } + + bool sign = (value_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN); + ecma_number_t result; + + if (biased_exp < (1u << ECMA_NUMBER_BIASED_EXP_WIDTH) - 1) + { + result = ecma_number_pack (sign, biased_exp, fraction); + } + else + { + result = ecma_number_make_infinity (sign); + } + + return ecma_make_number_value (result); +} /* ecma_bigint_to_number */ + /** * Returns with a BigInt if the value is BigInt, * or the value is object, and its default value is BigInt diff --git a/jerry-core/ecma/operations/ecma-bigint.h b/jerry-core/ecma/operations/ecma-bigint.h index 20195275d..aa42ab08b 100644 --- a/jerry-core/ecma/operations/ecma-bigint.h +++ b/jerry-core/ecma/operations/ecma-bigint.h @@ -53,6 +53,7 @@ ecma_value_t ecma_bigint_parse_string (const lit_utf8_byte_t *string_p, lit_utf8 ecma_value_t ecma_bigint_parse_string_value (ecma_value_t string, uint32_t options); ecma_string_t *ecma_bigint_to_string (ecma_value_t value, ecma_bigint_digit_t radix); ecma_value_t ecma_bigint_to_bigint (ecma_value_t value, bool allow_numbers); +ecma_value_t ecma_bigint_to_number (ecma_value_t value); ecma_value_t ecma_bigint_get_bigint (ecma_value_t value, bool *free_result_p); ecma_value_t ecma_bigint_create_from_digits (const uint64_t *digits_p, uint32_t size, bool sign); uint32_t ecma_bigint_get_size_in_digits (ecma_value_t value); diff --git a/jerry-core/ecma/operations/ecma-comparison.c b/jerry-core/ecma/operations/ecma-comparison.c index 92f9ae6f7..fe097c82b 100644 --- a/jerry-core/ecma/operations/ecma-comparison.c +++ b/jerry-core/ecma/operations/ecma-comparison.c @@ -113,7 +113,7 @@ ecma_op_abstract_equality_compare (ecma_value_t x, /**< first operand */ if (ecma_is_value_number (y)) { /* 4. */ - ecma_value_t x_num_value = ecma_op_to_number (x); + ecma_value_t x_num_value = ecma_op_to_number (x, ECMA_TO_NUMERIC_NO_OPTS); if (ECMA_IS_VALUE_ERROR (x_num_value)) { diff --git a/jerry-core/ecma/operations/ecma-conversion.c b/jerry-core/ecma/operations/ecma-conversion.c index ae7a66763..5e84ced84 100644 --- a/jerry-core/ecma/operations/ecma-conversion.c +++ b/jerry-core/ecma/operations/ecma-conversion.c @@ -269,8 +269,11 @@ ecma_op_to_boolean (ecma_value_t value) /**< ecma value */ * Returned value must be freed with ecma_free_value */ ecma_value_t -ecma_op_to_number (ecma_value_t value) /**< ecma value */ +ecma_op_to_number (ecma_value_t value, /**< ecma value */ + ecma_to_numeric_options_t options) /**< option bits */ { + JERRY_UNUSED (options); + ecma_check_value_type_is_spec_defined (value); if (ecma_is_value_integer_number (value)) @@ -314,6 +317,10 @@ ecma_op_to_number (ecma_value_t value) /**< ecma value */ #if ENABLED (JERRY_BUILTIN_BIGINT) if (ecma_is_value_bigint (value)) { + if (options & ECMA_TO_NUMERIC_ALLOW_BIGINT) + { + return ecma_copy_value (value); + } return ecma_raise_type_error (ECMA_ERR_MSG ("Cannot convert a BigInt value to a number")); } #endif /* ENABLED (JERRY_BUILTIN_BIGINT) */ @@ -329,7 +336,7 @@ ecma_op_to_number (ecma_value_t value) /**< ecma value */ return def_value; } - ecma_value_t ret_value = ecma_op_to_number (def_value); + ecma_value_t ret_value = ecma_op_to_number (def_value, options); ecma_fast_free_value (def_value); diff --git a/jerry-core/ecma/operations/ecma-conversion.h b/jerry-core/ecma/operations/ecma-conversion.h index 634efc4e7..af5321f17 100644 --- a/jerry-core/ecma/operations/ecma-conversion.h +++ b/jerry-core/ecma/operations/ecma-conversion.h @@ -43,7 +43,7 @@ typedef enum typedef enum { ECMA_TO_NUMERIC_NO_OPTS = 0, /**< no options (same as toNumber operation) */ - ECMA_TO_NUMERIC_ALLOW_BIGINT = (1 << 0), /**< allow BigInt values */ + ECMA_TO_NUMERIC_ALLOW_BIGINT = (1 << 0), /**< allow BigInt values (ignored if BigInts are disabled) */ } ecma_to_numeric_options_t; ecma_value_t ecma_op_check_object_coercible (ecma_value_t value); @@ -53,7 +53,7 @@ bool ecma_op_same_value_zero (ecma_value_t x, ecma_value_t y); #endif /* ENABLED (JERRY_BUILTIN_MAP) */ ecma_value_t ecma_op_to_primitive (ecma_value_t value, ecma_preferred_type_hint_t preferred_type); bool ecma_op_to_boolean (ecma_value_t value); -ecma_value_t ecma_op_to_number (ecma_value_t value); +ecma_value_t ecma_op_to_number (ecma_value_t value, ecma_to_numeric_options_t options); ecma_value_t ecma_op_to_numeric (ecma_value_t value, ecma_number_t *number_p, ecma_to_numeric_options_t options); ecma_string_t *ecma_op_to_string (ecma_value_t value); ecma_string_t *ecma_op_to_property_key (ecma_value_t value); diff --git a/jerry-core/ecma/operations/ecma-number-object.c b/jerry-core/ecma/operations/ecma-number-object.c index 5b35295f2..d249e95ca 100644 --- a/jerry-core/ecma/operations/ecma-number-object.c +++ b/jerry-core/ecma/operations/ecma-number-object.c @@ -41,7 +41,7 @@ ecma_value_t ecma_op_create_number_object (ecma_value_t arg) /**< argument passed to the Number constructor */ { - ecma_value_t conv_to_num_completion = ecma_op_to_number (arg); + ecma_value_t conv_to_num_completion = ecma_op_to_number (arg, ECMA_TO_NUMERIC_NO_OPTS); if (ECMA_IS_VALUE_ERROR (conv_to_num_completion)) { diff --git a/tests/jerry/es.next/bigint9.js b/tests/jerry/es.next/bigint9.js new file mode 100644 index 000000000..7702eddbe --- /dev/null +++ b/tests/jerry/es.next/bigint9.js @@ -0,0 +1,42 @@ +/* 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. + */ + +assert(Number(0n) === 0) +assert(Number(1n) === 1) +assert(Number(2n) === 2) +assert(Number(0x100n) === 256) +assert(Number(-1n) === -1) +assert(Number(-2n) === -2) +assert(Number(-0x100n) === -256) + +assert(Number(0x1fffffffffffffn) === 0x1fffffffffffff) +assert(Number(-0x3fffffffffffffn) === -0x40000000000000) +assert(Number(1000n ** 1000n) === Number.POSITIVE_INFINITY) +assert(Number((-1000n) ** 1001n) === Number.NEGATIVE_INFINITY) + +// Rounding to even + +assert(Number(0x80000000000004n) === 0x80000000000000) +assert(Number(0x80000000000008n) === 0x80000000000008) +assert(Number(0x8000000000000cn) === 0x80000000000010) +assert(Number(0x80000000000004n) === 0x80000000000000) +assert(Number(0x80000000000006n) === 0x80000000000008) +assert(Number(0x800000000000f400000000000000000000000000000000n) === 0x800000000000f000000000000000000000000000000000) +assert(Number(0x800000000000f400000000000000000000000000000001n) === 0x800000000000f800000000000000000000000000000000) + +// Construct + +assert((new Number(0n)).valueOf() === 0) +assert((new Number(-3256n)).valueOf() == -3256) diff --git a/tests/test262-esnext-excludelist.xml b/tests/test262-esnext-excludelist.xml index adc7509db..453f92e4c 100644 --- a/tests/test262-esnext-excludelist.xml +++ b/tests/test262-esnext-excludelist.xml @@ -658,7 +658,6 @@ - @@ -1062,7 +1061,6 @@ -