Support BigInt to number conversion using Number constructor (#4121)
JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
@@ -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))
|
||||
{
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user