Create API for handling BigInts (#4111)
JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
+134
-1
@@ -19,6 +19,7 @@
|
||||
#include "ecma-alloc.h"
|
||||
#include "ecma-array-object.h"
|
||||
#include "ecma-arraybuffer-object.h"
|
||||
#include "ecma-bigint.h"
|
||||
#include "ecma-builtin-helpers.h"
|
||||
#include "ecma-builtins.h"
|
||||
#include "ecma-comparison.h"
|
||||
@@ -108,6 +109,15 @@ static const char * const error_value_msg_p = "argument cannot have an error fla
|
||||
*/
|
||||
static const char * const wrong_args_msg_p = "wrong type of argument";
|
||||
|
||||
#if !ENABLED (JERRY_BUILTIN_BIGINT)
|
||||
|
||||
/**
|
||||
* Error message, if BigInt support is disabled
|
||||
*/
|
||||
static const char * const error_bigint_not_supported_p = "BigInt support is disabled";
|
||||
|
||||
#endif /* !ENABLED (JERRY_BUILTIN_BIGINT) */
|
||||
|
||||
#endif /* ENABLED (JERRY_ERROR_MESSAGES) */
|
||||
|
||||
/** \addtogroup jerry Jerry engine interface
|
||||
@@ -841,6 +851,25 @@ jerry_value_is_symbol (const jerry_value_t value) /**< api value */
|
||||
#endif /* ENABLED (JERRY_ESNEXT) */
|
||||
} /* jerry_value_is_symbol */
|
||||
|
||||
/**
|
||||
* Check if the specified value is BigInt.
|
||||
*
|
||||
* @return true - if the specified value is BigInt,
|
||||
* false - otherwise
|
||||
*/
|
||||
bool
|
||||
jerry_value_is_bigint (const jerry_value_t value) /**< api value */
|
||||
{
|
||||
jerry_assert_api_available ();
|
||||
|
||||
#if ENABLED (JERRY_BUILTIN_BIGINT)
|
||||
return ecma_is_value_bigint (value);
|
||||
#else /* !ENABLED (JERRY_BUILTIN_BIGINT) */
|
||||
JERRY_UNUSED (value);
|
||||
return false;
|
||||
#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
|
||||
} /* jerry_value_is_bigint */
|
||||
|
||||
/**
|
||||
* Check if the specified value is undefined.
|
||||
*
|
||||
@@ -1345,9 +1374,36 @@ jerry_value_to_string (const jerry_value_t value) /**< input value */
|
||||
return ecma_create_error_reference_from_context ();
|
||||
}
|
||||
|
||||
return jerry_return (ecma_make_string_value (str_p));
|
||||
return ecma_make_string_value (str_p);
|
||||
} /* jerry_value_to_string */
|
||||
|
||||
/**
|
||||
* Call the BigInt constructor ecma builtin operation on the api value.
|
||||
*
|
||||
* Note:
|
||||
* returned value must be freed with jerry_release_value, when it is no longer needed.
|
||||
*
|
||||
* @return BigInt value - if success
|
||||
* thrown error - otherwise
|
||||
*/
|
||||
jerry_value_t
|
||||
jerry_value_to_bigint (const jerry_value_t value) /**< input value */
|
||||
{
|
||||
jerry_assert_api_available ();
|
||||
|
||||
#if ENABLED (JERRY_BUILTIN_BIGINT)
|
||||
if (ecma_is_value_error_reference (value))
|
||||
{
|
||||
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (error_value_msg_p)));
|
||||
}
|
||||
|
||||
return jerry_return (ecma_bigint_to_bigint (value, true));
|
||||
#else /* !ENABLED (JERRY_BUILTIN_BIGINT) */
|
||||
JERRY_UNUSED (value);
|
||||
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (error_bigint_not_supported_p)));
|
||||
#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
|
||||
} /* jerry_value_to_bigint */
|
||||
|
||||
/**
|
||||
* Acquire specified Jerry API value.
|
||||
*
|
||||
@@ -1776,6 +1832,29 @@ jerry_create_symbol (const jerry_value_t value) /**< api value */
|
||||
#endif /* ENABLED (JERRY_ESNEXT) */
|
||||
} /* jerry_create_symbol */
|
||||
|
||||
/**
|
||||
* Create BigInt from a sequence of uint64 digits
|
||||
*
|
||||
* @return value of the created bigint, if success
|
||||
* thrown error, otherwise
|
||||
*/
|
||||
jerry_value_t
|
||||
jerry_create_bigint (const uint64_t *digits_p, /**< BigInt digits (lowest digit first) */
|
||||
uint32_t size, /**< number of BigInt digits */
|
||||
bool sign) /**< sign bit, true if the result should be negative */
|
||||
{
|
||||
jerry_assert_api_available ();
|
||||
|
||||
#if ENABLED (JERRY_BUILTIN_BIGINT)
|
||||
return jerry_return (ecma_bigint_create_from_digits (digits_p, size, sign));
|
||||
#else /* !ENABLED (JERRY_BUILTIN_BIGINT) */
|
||||
JERRY_UNUSED (digits_p);
|
||||
JERRY_UNUSED (size);
|
||||
JERRY_UNUSED (sign);
|
||||
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (error_bigint_not_supported_p)));
|
||||
#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
|
||||
} /* jerry_create_bigint */
|
||||
|
||||
/**
|
||||
* Calculates the size of the given pattern and creates a RegExp object.
|
||||
*
|
||||
@@ -3405,6 +3484,60 @@ jerry_get_symbol_descriptive_string (const jerry_value_t symbol) /**< symbol val
|
||||
#endif /* ENABLED (JERRY_ESNEXT) */
|
||||
} /** jerry_get_symbol_descriptive_string */
|
||||
|
||||
/**
|
||||
* Get the number of uint64 digits of a BigInt value
|
||||
*
|
||||
* @return number of uint64 digits
|
||||
*/
|
||||
uint32_t
|
||||
jerry_get_bigint_size_in_digits (jerry_value_t value) /**< BigInt value */
|
||||
{
|
||||
jerry_assert_api_available ();
|
||||
|
||||
#if ENABLED (JERRY_BUILTIN_BIGINT)
|
||||
if (!ecma_is_value_bigint (value))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ecma_bigint_get_size_in_digits (value);
|
||||
#else /* !ENABLED (JERRY_BUILTIN_BIGINT) */
|
||||
JERRY_UNUSED (value);
|
||||
return 0;
|
||||
#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
|
||||
} /* jerry_get_bigint_size_in_digits */
|
||||
|
||||
/**
|
||||
* Get the uint64 digits of a BigInt value (lowest digit first)
|
||||
*/
|
||||
void
|
||||
jerry_get_bigint_digits (jerry_value_t value, /**< BigInt value */
|
||||
uint64_t *digits_p, /**< [out] buffer for digits */
|
||||
uint32_t size, /**< buffer size in digits */
|
||||
bool *sign_p) /**< [out] sign of BigInt */
|
||||
{
|
||||
#if ENABLED (JERRY_BUILTIN_BIGINT)
|
||||
if (!ecma_is_value_bigint (value))
|
||||
{
|
||||
if (sign_p != NULL)
|
||||
{
|
||||
*sign_p = false;
|
||||
}
|
||||
memset (digits_p, 0, size * sizeof (uint64_t));
|
||||
}
|
||||
|
||||
ecma_bigint_get_digits_and_sign (value, digits_p, size, sign_p);
|
||||
#else /* !ENABLED (JERRY_BUILTIN_BIGINT) */
|
||||
JERRY_UNUSED (value);
|
||||
|
||||
if (sign_p != NULL)
|
||||
{
|
||||
*sign_p = false;
|
||||
}
|
||||
memset (digits_p, 0, size * sizeof (uint64_t));
|
||||
#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
|
||||
} /* jerry_get_bigint_digits */
|
||||
|
||||
/**
|
||||
* Validate UTF-8 string
|
||||
*
|
||||
|
||||
@@ -51,37 +51,7 @@ ecma_builtin_bigint_dispatch_call (const ecma_value_t *arguments_list_p, /**< ar
|
||||
JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL);
|
||||
|
||||
ecma_value_t value = (arguments_list_len == 0) ? ECMA_VALUE_UNDEFINED : arguments_list_p[0];
|
||||
bool free_value = false;
|
||||
|
||||
if (ecma_is_value_object (value))
|
||||
{
|
||||
ecma_object_t *obj_p = ecma_get_object_from_value (value);
|
||||
value = ecma_op_object_default_value (obj_p, ECMA_PREFERRED_TYPE_NUMBER);
|
||||
free_value = true;
|
||||
|
||||
if (ECMA_IS_VALUE_ERROR (value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
ecma_value_t ret_value = ECMA_VALUE_EMPTY;
|
||||
|
||||
if (ecma_is_value_number (value))
|
||||
{
|
||||
ret_value = ecma_bigint_number_to_bigint (ecma_get_number_from_value (value));
|
||||
}
|
||||
else
|
||||
{
|
||||
ret_value = ecma_bigint_to_bigint (value);
|
||||
}
|
||||
|
||||
if (free_value)
|
||||
{
|
||||
ecma_free_value (value);
|
||||
}
|
||||
|
||||
return ret_value;
|
||||
return ecma_bigint_to_bigint (value, true);
|
||||
} /* ecma_builtin_bigint_dispatch_call */
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "ecma-big-uint.h"
|
||||
#include "ecma-exceptions.h"
|
||||
#include "ecma-helpers.h"
|
||||
#include "ecma-objects.h"
|
||||
#include "lit-char-helpers.h"
|
||||
|
||||
#if ENABLED (JERRY_BUILTIN_BIGINT)
|
||||
@@ -340,7 +341,7 @@ ecma_bigint_number_to_digits (ecma_number_t number, /**< ecma number */
|
||||
* @return ecma BigInt value or ECMA_VALUE_ERROR
|
||||
* Returned value must be freed with ecma_free_value.
|
||||
*/
|
||||
ecma_value_t
|
||||
static ecma_value_t
|
||||
ecma_bigint_number_to_bigint (ecma_number_t number) /**< ecma number */
|
||||
{
|
||||
if (ecma_number_is_nan (number) || ecma_number_is_infinity (number))
|
||||
@@ -397,34 +398,222 @@ ecma_bigint_number_to_bigint (ecma_number_t number) /**< ecma number */
|
||||
* Returned value must be freed with ecma_free_value.
|
||||
*/
|
||||
ecma_value_t
|
||||
ecma_bigint_to_bigint (ecma_value_t value) /**< any value */
|
||||
ecma_bigint_to_bigint (ecma_value_t value, /**< any value */
|
||||
bool allow_numbers) /**< converting ecma numbers is allowed */
|
||||
{
|
||||
if (ecma_is_value_boolean (value))
|
||||
{
|
||||
if (ecma_is_value_false (value))
|
||||
{
|
||||
return ECMA_BIGINT_ZERO;
|
||||
}
|
||||
bool free_value = false;
|
||||
|
||||
if (ecma_is_value_object (value))
|
||||
{
|
||||
value = ecma_op_object_default_value (ecma_get_object_from_value (value), ECMA_PREFERRED_TYPE_NUMBER);
|
||||
free_value = true;
|
||||
|
||||
if (ECMA_IS_VALUE_ERROR (value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
ecma_value_t result;
|
||||
|
||||
if (ecma_is_value_string (value))
|
||||
{
|
||||
result = ecma_bigint_parse_string_value (value, ECMA_BIGINT_PARSE_NO_OPTIONS);
|
||||
}
|
||||
else if (ecma_is_value_bigint (value))
|
||||
{
|
||||
result = value;
|
||||
|
||||
if (!free_value && value != ECMA_BIGINT_ZERO)
|
||||
{
|
||||
ecma_ref_extended_primitive (ecma_get_extended_primitive_from_value (value));
|
||||
}
|
||||
else
|
||||
{
|
||||
free_value = false;
|
||||
}
|
||||
}
|
||||
else if (allow_numbers && ecma_is_value_number (value))
|
||||
{
|
||||
result = ecma_bigint_number_to_bigint (ecma_get_number_from_value (value));
|
||||
}
|
||||
else if (ecma_is_value_false (value))
|
||||
{
|
||||
result = ECMA_BIGINT_ZERO;
|
||||
}
|
||||
else if (ecma_is_value_true (value))
|
||||
{
|
||||
ecma_extended_primitive_t *result_p = ecma_bigint_create (sizeof (ecma_bigint_digit_t));
|
||||
|
||||
if (JERRY_UNLIKELY (result_p == NULL))
|
||||
if (result_p != NULL)
|
||||
{
|
||||
return ecma_bigint_raise_memory_error ();
|
||||
*ECMA_BIGINT_GET_DIGITS (result_p, 0) = 1;
|
||||
result = ecma_make_extended_primitive_value (result_p, ECMA_TYPE_BIGINT);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = ecma_bigint_raise_memory_error ();
|
||||
}
|
||||
|
||||
*ECMA_BIGINT_GET_DIGITS (result_p, 0) = 1;
|
||||
return ecma_make_extended_primitive_value (result_p, ECMA_TYPE_BIGINT);
|
||||
}
|
||||
|
||||
if (!ecma_is_value_string (value))
|
||||
else
|
||||
{
|
||||
return ecma_raise_type_error (ECMA_ERR_MSG ("Value cannot be converted to BigInt"));
|
||||
result = ecma_raise_type_error (ECMA_ERR_MSG ("Value cannot be converted to BigInt"));
|
||||
}
|
||||
|
||||
return ecma_bigint_parse_string_value (value, ECMA_BIGINT_PARSE_NO_OPTIONS);
|
||||
if (free_value)
|
||||
{
|
||||
ecma_free_value (value);
|
||||
}
|
||||
|
||||
return result;
|
||||
} /* ecma_bigint_to_bigint */
|
||||
|
||||
/**
|
||||
* Create BigInt value from uint64 digits
|
||||
*
|
||||
* @return ecma BigInt value or ECMA_VALUE_ERROR
|
||||
* Returned value must be freed with ecma_free_value.
|
||||
*/
|
||||
ecma_value_t
|
||||
ecma_bigint_create_from_digits (const uint64_t *digits_p, /**< BigInt digits */
|
||||
uint32_t size, /**< number of BigInt digits */
|
||||
bool sign) /**< sign bit, true if the result should be negative */
|
||||
{
|
||||
const uint64_t *digits_end_p = digits_p + size;
|
||||
|
||||
while (digits_end_p > digits_p && digits_end_p[-1] == 0)
|
||||
{
|
||||
digits_end_p--;
|
||||
}
|
||||
|
||||
if (digits_p == digits_end_p)
|
||||
{
|
||||
return ECMA_BIGINT_ZERO;
|
||||
}
|
||||
|
||||
size = (uint32_t) (digits_end_p - digits_p);
|
||||
|
||||
if (size < ECMA_BIGINT_MAX_SIZE)
|
||||
{
|
||||
size *= (uint32_t) sizeof (uint64_t);
|
||||
}
|
||||
|
||||
if ((digits_end_p[-1] >> (8 * sizeof (ecma_bigint_digit_t))) == 0)
|
||||
{
|
||||
size -= (uint32_t) sizeof (ecma_bigint_digit_t);
|
||||
}
|
||||
|
||||
ecma_extended_primitive_t *result_value_p = ecma_bigint_create (size);
|
||||
|
||||
if (JERRY_UNLIKELY (result_value_p == NULL))
|
||||
{
|
||||
return ecma_bigint_raise_memory_error ();
|
||||
}
|
||||
|
||||
if (sign)
|
||||
{
|
||||
result_value_p->u.bigint_sign_and_size |= ECMA_BIGINT_SIGN;
|
||||
}
|
||||
|
||||
ecma_bigint_digit_t *result_p = ECMA_BIGINT_GET_DIGITS (result_value_p, 0);
|
||||
|
||||
while (digits_p < digits_end_p)
|
||||
{
|
||||
uint64_t digit = *digits_p++;
|
||||
|
||||
result_p[0] = (ecma_bigint_digit_t) digit;
|
||||
result_p[1] = (ecma_bigint_digit_t) (digit >> (8 * sizeof (ecma_bigint_digit_t)));
|
||||
result_p+= 2;
|
||||
}
|
||||
|
||||
return ecma_make_extended_primitive_value (result_value_p, ECMA_TYPE_BIGINT);
|
||||
} /* ecma_bigint_create_from_digits */
|
||||
|
||||
/**
|
||||
* Get the number of uint64 digits of a BigInt value
|
||||
*
|
||||
* @return number of uint64 digits
|
||||
*/
|
||||
uint32_t
|
||||
ecma_bigint_get_size_in_digits (ecma_value_t value) /**< BigInt value */
|
||||
{
|
||||
JERRY_ASSERT (ecma_is_value_bigint (value));
|
||||
|
||||
if (value == ECMA_BIGINT_ZERO)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
ecma_extended_primitive_t *value_p = ecma_get_extended_primitive_from_value (value);
|
||||
uint32_t size = ECMA_BIGINT_GET_SIZE (value_p);
|
||||
|
||||
return (size + (uint32_t) sizeof (ecma_bigint_digit_t)) / sizeof (uint64_t);
|
||||
} /* ecma_bigint_get_size_in_digits */
|
||||
|
||||
/**
|
||||
* Get the uint64 digits of a BigInt value
|
||||
*/
|
||||
void
|
||||
ecma_bigint_get_digits_and_sign (ecma_value_t value, /**< BigInt value */
|
||||
uint64_t *digits_p, /**< [out] buffer for digits */
|
||||
uint32_t size, /**< buffer size in digits */
|
||||
bool *sign_p) /**< [out] sign of BigInt */
|
||||
{
|
||||
JERRY_ASSERT (ecma_is_value_bigint (value));
|
||||
|
||||
if (value == ECMA_BIGINT_ZERO)
|
||||
{
|
||||
if (sign_p != NULL)
|
||||
{
|
||||
*sign_p = false;
|
||||
}
|
||||
memset (digits_p, 0, size * sizeof (uint64_t));
|
||||
return;
|
||||
}
|
||||
|
||||
ecma_extended_primitive_t *value_p = ecma_get_extended_primitive_from_value (value);
|
||||
|
||||
if (sign_p != NULL)
|
||||
{
|
||||
*sign_p = (value_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN) != 0;
|
||||
}
|
||||
|
||||
uint32_t bigint_size = ECMA_BIGINT_GET_SIZE (value_p);
|
||||
uint32_t copy_size = bigint_size / sizeof (uint64_t);
|
||||
|
||||
if (copy_size > size)
|
||||
{
|
||||
copy_size = size;
|
||||
}
|
||||
|
||||
const uint64_t *digits_end_p = digits_p + copy_size;
|
||||
ecma_bigint_digit_t *source_p = ECMA_BIGINT_GET_DIGITS (value_p, 0);
|
||||
|
||||
while (digits_p < digits_end_p)
|
||||
{
|
||||
*digits_p++ = source_p[0] | (((uint64_t) source_p[1]) << (8 * sizeof (ecma_bigint_digit_t)));
|
||||
source_p += 2;
|
||||
}
|
||||
|
||||
size -= copy_size;
|
||||
|
||||
if (size == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ECMA_BIGINT_SIZE_IS_ODD (bigint_size))
|
||||
{
|
||||
*digits_p++ = source_p[0];
|
||||
size--;
|
||||
}
|
||||
|
||||
if (size > 0)
|
||||
{
|
||||
memset (digits_p, 0, size * sizeof (uint64_t));
|
||||
}
|
||||
} /* ecma_bigint_get_digits_and_sign */
|
||||
|
||||
/**
|
||||
* Compare two BigInt values
|
||||
*
|
||||
|
||||
@@ -42,8 +42,10 @@ ecma_value_t ecma_bigint_parse_string (const lit_utf8_byte_t *string_p, lit_utf8
|
||||
uint32_t options);
|
||||
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_number_to_bigint (ecma_number_t number);
|
||||
ecma_value_t ecma_bigint_to_bigint (ecma_value_t value);
|
||||
ecma_value_t ecma_bigint_to_bigint (ecma_value_t value, bool allow_numbers);
|
||||
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);
|
||||
void ecma_bigint_get_digits_and_sign (ecma_value_t value, uint64_t *digits_p, uint32_t size, bool *sign_p);
|
||||
|
||||
bool ecma_bigint_is_equal_to_bigint (ecma_value_t left_value, ecma_value_t right_value);
|
||||
bool ecma_bigint_is_equal_to_number (ecma_value_t left_value, ecma_number_t right_value);
|
||||
|
||||
@@ -388,6 +388,7 @@ bool jerry_value_is_promise (const jerry_value_t value);
|
||||
bool jerry_value_is_proxy (const jerry_value_t value);
|
||||
bool jerry_value_is_string (const jerry_value_t value);
|
||||
bool jerry_value_is_symbol (const jerry_value_t value);
|
||||
bool jerry_value_is_bigint (const jerry_value_t value);
|
||||
bool jerry_value_is_undefined (const jerry_value_t value);
|
||||
|
||||
/**
|
||||
@@ -474,6 +475,7 @@ jerry_value_t jerry_value_to_number (const jerry_value_t value);
|
||||
jerry_value_t jerry_value_to_object (const jerry_value_t value);
|
||||
jerry_value_t jerry_value_to_primitive (const jerry_value_t value);
|
||||
jerry_value_t jerry_value_to_string (const jerry_value_t value);
|
||||
jerry_value_t jerry_value_to_bigint (const jerry_value_t value);
|
||||
|
||||
/**
|
||||
* Acquire types with reference counter (increase the references).
|
||||
@@ -512,6 +514,7 @@ jerry_value_t jerry_create_external_string (const jerry_char_t *str_p,
|
||||
jerry_value_t jerry_create_external_string_sz (const jerry_char_t *str_p, jerry_size_t str_size,
|
||||
jerry_object_native_free_callback_t free_cb);
|
||||
jerry_value_t jerry_create_symbol (const jerry_value_t value);
|
||||
jerry_value_t jerry_create_bigint (const uint64_t *digits_p, uint32_t size, bool sign);
|
||||
jerry_value_t jerry_create_undefined (void);
|
||||
|
||||
/**
|
||||
@@ -595,6 +598,12 @@ jerry_promise_state_t jerry_get_promise_state (const jerry_value_t promise);
|
||||
*/
|
||||
jerry_value_t jerry_get_symbol_descriptive_string (const jerry_value_t symbol);
|
||||
|
||||
/**
|
||||
* BigInt functions.
|
||||
*/
|
||||
uint32_t jerry_get_bigint_size_in_digits (jerry_value_t value);
|
||||
void jerry_get_bigint_digits (jerry_value_t value, uint64_t *digits_p, uint32_t size, bool *sign_p);
|
||||
|
||||
/**
|
||||
* Input validator functions.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user