Implement BigInt primitve type and some of its operations (#4062)
Supported operations: - parse BigInt (decimal, hexadecimal, binary) - toString with any radix between 2 and 36 - arithmetic operations: negate, add, subtract, multiply, divide, modulo - left and right shift JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,88 @@
|
||||
/* 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_BIG_UINT_H
|
||||
#define ECMA_BIG_UINT_H
|
||||
|
||||
#include "ecma-globals.h"
|
||||
|
||||
#if ENABLED (JERRY_BUILTIN_BIGINT)
|
||||
|
||||
/**
|
||||
* Limit of BigUInt memory allocation in JerryScript.
|
||||
*/
|
||||
#define ECMA_BIGINT_MAX_SIZE 0x10000
|
||||
|
||||
/**
|
||||
* Unsigned type which can hold two digits.
|
||||
*/
|
||||
typedef uint64_t ecma_bigint_two_digits_t;
|
||||
|
||||
/**
|
||||
* Shift used by left/right shifting of a value.
|
||||
*/
|
||||
#define ECMA_BIGINT_DIGIT_SHIFT 5
|
||||
|
||||
/**
|
||||
* Return with the digits of a BigInt value.
|
||||
*/
|
||||
#define ECMA_BIGINT_GET_DIGITS(value_p, offset) \
|
||||
((ecma_bigint_digit_t *) (((uint8_t *) (value_p)) + sizeof (ecma_extended_primitive_t) + (offset)))
|
||||
|
||||
/**
|
||||
* Return with the digits of a BigInt value.
|
||||
*/
|
||||
#define ECMA_BIGINT_GET_LAST_DIGIT(value_p, size) \
|
||||
*ECMA_BIGINT_GET_DIGITS (value_p, size - sizeof (ecma_bigint_digit_t))
|
||||
|
||||
/**
|
||||
* Returns true if size is an odd number.
|
||||
*/
|
||||
#define ECMA_BIGINT_SIZE_IS_ODD(size) \
|
||||
(((size) & sizeof (ecma_bigint_digit_t)) != 0)
|
||||
|
||||
/**
|
||||
* Returns a two digit value where the high digit is set to the passed digit.
|
||||
*/
|
||||
#define ECMA_BIGINT_HIGH_DIGIT(digit) \
|
||||
(((ecma_bigint_two_digits_t) digit) << (8 * sizeof (ecma_bigint_digit_t)))
|
||||
|
||||
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);
|
||||
|
||||
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,
|
||||
ecma_bigint_digit_t mul, ecma_bigint_digit_t add);
|
||||
|
||||
uint8_t *ecma_big_uint_to_string (ecma_extended_primitive_t *value_p, uint32_t radix,
|
||||
uint32_t *char_start_p, uint32_t *char_size_p);
|
||||
|
||||
ecma_extended_primitive_t *ecma_big_uint_add (ecma_extended_primitive_t *left_value_p,
|
||||
ecma_extended_primitive_t *right_value_p);
|
||||
ecma_extended_primitive_t *ecma_big_uint_sub (ecma_extended_primitive_t *left_value_p,
|
||||
ecma_extended_primitive_t *right_value_p);
|
||||
ecma_extended_primitive_t *ecma_big_uint_mul (ecma_extended_primitive_t *left_value_p,
|
||||
ecma_extended_primitive_t *right_value_p);
|
||||
ecma_extended_primitive_t *ecma_big_uint_div_mod (ecma_extended_primitive_t *dividend_value_p,
|
||||
ecma_extended_primitive_t *divisor_value_p,
|
||||
bool is_mod);
|
||||
|
||||
ecma_extended_primitive_t *ecma_big_uint_shift_left (ecma_extended_primitive_t *left_value_p, uint32_t right_value);
|
||||
ecma_extended_primitive_t *ecma_big_uint_shift_right (ecma_extended_primitive_t *left_value_p, uint32_t right_value);
|
||||
|
||||
#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
|
||||
|
||||
#endif /* ECMA_BIG_UINT_H */
|
||||
@@ -0,0 +1,66 @@
|
||||
/* 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-alloc.h"
|
||||
#include "ecma-bigint-object.h"
|
||||
#include "ecma-builtins.h"
|
||||
#include "ecma-exceptions.h"
|
||||
#include "ecma-gc.h"
|
||||
#include "ecma-globals.h"
|
||||
#include "ecma-helpers.h"
|
||||
#include "ecma-objects.h"
|
||||
#include "ecma-objects-general.h"
|
||||
|
||||
#if ENABLED (JERRY_BUILTIN_BIGINT)
|
||||
|
||||
/** \addtogroup ecma ECMA
|
||||
* @{
|
||||
*
|
||||
* \addtogroup ecmabigintobject ECMA BigInt object related routines
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* BigInt object creation operation.
|
||||
*
|
||||
* See also: ECMA-262 v11, 7.1.18
|
||||
*
|
||||
* @return ecma value
|
||||
* Returned value must be freed with ecma_free_value
|
||||
*/
|
||||
ecma_value_t
|
||||
ecma_op_create_bigint_object (ecma_value_t arg) /**< argument passed to the toObject operation */
|
||||
{
|
||||
JERRY_ASSERT (ecma_is_value_bigint (arg));
|
||||
|
||||
ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_BIGINT_PROTOTYPE);
|
||||
|
||||
ecma_object_t *object_p = ecma_create_object (prototype_obj_p,
|
||||
sizeof (ecma_extended_object_t),
|
||||
ECMA_OBJECT_TYPE_CLASS);
|
||||
|
||||
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
|
||||
ext_object_p->u.class_prop.class_id = LIT_MAGIC_STRING_BIGINT_UL;
|
||||
ext_object_p->u.class_prop.u.value = ecma_copy_value (arg);
|
||||
|
||||
return ecma_make_object_value (object_p);
|
||||
} /* ecma_op_create_bigint_object */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
|
||||
@@ -0,0 +1,39 @@
|
||||
/* 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_BIGINT_OBJECT_H
|
||||
#define ECMA_BIGINT_OBJECT_H
|
||||
|
||||
#include "ecma-globals.h"
|
||||
|
||||
#if ENABLED (JERRY_BUILTIN_BIGINT)
|
||||
|
||||
/** \addtogroup ecma ECMA
|
||||
* @{
|
||||
*
|
||||
* \addtogroup ecmabigintobject ECMA BigInt object related routines
|
||||
* @{
|
||||
*/
|
||||
|
||||
ecma_value_t ecma_op_create_bigint_object (ecma_value_t arg);
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
|
||||
|
||||
#endif /* !ECMA_BIGINT_OBJECT_H */
|
||||
@@ -0,0 +1,508 @@
|
||||
/* 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-bigint.h"
|
||||
#include "ecma-big-uint.h"
|
||||
#include "ecma-exceptions.h"
|
||||
#include "ecma-helpers.h"
|
||||
#include "lit-char-helpers.h"
|
||||
|
||||
#if ENABLED (JERRY_BUILTIN_BIGINT)
|
||||
|
||||
/**
|
||||
* Raise a not enough memory error
|
||||
*
|
||||
* @return ECMA_VALUE_ERROR
|
||||
* Returned value must be freed with ecma_free_value.
|
||||
*/
|
||||
static ecma_value_t
|
||||
ecma_bigint_raise_memory_error (void)
|
||||
{
|
||||
return ecma_raise_range_error (ECMA_ERR_MSG ("Cannot allocate memory for a BigInt value"));
|
||||
} /* ecma_bigint_raise_memory_error */
|
||||
|
||||
/**
|
||||
* Parse a string and create a BigInt value
|
||||
*
|
||||
* @return ecma BigInt value or ECMA_VALUE_ERROR
|
||||
* Returned value must be freed with ecma_free_value.
|
||||
*/
|
||||
ecma_value_t
|
||||
ecma_bigint_parse_string (const lit_utf8_byte_t *string_p, /**< string represenation of the BigInt */
|
||||
lit_utf8_size_t size) /**< string size */
|
||||
{
|
||||
ecma_bigint_digit_t radix = 10;
|
||||
uint32_t sign = 0;
|
||||
|
||||
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_B || string_p[1] == LIT_CHAR_UPPERCASE_B)
|
||||
{
|
||||
radix = 2;
|
||||
string_p += 2;
|
||||
size -= 2;
|
||||
}
|
||||
}
|
||||
else if (size >= 2)
|
||||
{
|
||||
if (string_p[0] == LIT_CHAR_PLUS)
|
||||
{
|
||||
size--;
|
||||
string_p++;
|
||||
}
|
||||
else if (string_p[0] == LIT_CHAR_MINUS)
|
||||
{
|
||||
sign = ECMA_BIGINT_SIGN;
|
||||
size--;
|
||||
string_p++;
|
||||
}
|
||||
}
|
||||
else if (size == 0)
|
||||
{
|
||||
return ecma_raise_syntax_error (ECMA_ERR_MSG ("BigInt cannot be constructed from empty string"));
|
||||
}
|
||||
|
||||
const lit_utf8_byte_t *string_end_p = string_p + size;
|
||||
|
||||
while (string_p < string_end_p && *string_p == LIT_CHAR_0)
|
||||
{
|
||||
string_p++;
|
||||
}
|
||||
|
||||
ecma_extended_primitive_t *result_p = NULL;
|
||||
|
||||
if (string_p == string_end_p)
|
||||
{
|
||||
result_p = ecma_bigint_create (0);
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
ecma_bigint_digit_t digit = radix;
|
||||
|
||||
if (*string_p >= LIT_CHAR_0 && *string_p <= LIT_CHAR_9)
|
||||
{
|
||||
digit = (ecma_bigint_digit_t) (*string_p - LIT_CHAR_0);
|
||||
}
|
||||
else
|
||||
{
|
||||
lit_utf8_byte_t character = (lit_utf8_byte_t) LEXER_TO_ASCII_LOWERCASE (*string_p);
|
||||
|
||||
if (character >= LIT_CHAR_LOWERCASE_A && character <= LIT_CHAR_LOWERCASE_F)
|
||||
{
|
||||
digit = (ecma_bigint_digit_t) (character - (LIT_CHAR_LOWERCASE_A - 10));
|
||||
}
|
||||
}
|
||||
|
||||
if (digit >= radix)
|
||||
{
|
||||
if (result_p != NULL)
|
||||
{
|
||||
ecma_deref_bigint (result_p);
|
||||
}
|
||||
return ecma_raise_syntax_error (ECMA_ERR_MSG ("String cannot be converted to BigInt value"));
|
||||
}
|
||||
|
||||
result_p = ecma_big_uint_mul_digit (result_p, radix, digit);
|
||||
|
||||
if (JERRY_UNLIKELY (result_p == NULL))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (++string_p < string_end_p);
|
||||
}
|
||||
|
||||
if (JERRY_UNLIKELY (result_p == NULL))
|
||||
{
|
||||
return ecma_bigint_raise_memory_error ();
|
||||
}
|
||||
|
||||
result_p->u.bigint_sign_and_size |= sign;
|
||||
return ecma_make_extended_primitive_value (result_p, ECMA_TYPE_BIGINT);
|
||||
} /* ecma_bigint_parse_string */
|
||||
|
||||
/**
|
||||
* Create a string representation for a BigInt value
|
||||
*
|
||||
* @return ecma string or ECMA_VALUE_ERROR
|
||||
* Returned value must be freed with ecma_free_value.
|
||||
*/
|
||||
ecma_string_t *
|
||||
ecma_bigint_to_string (ecma_value_t value, /**< BigInt value */
|
||||
ecma_bigint_digit_t radix) /**< conversion radix */
|
||||
{
|
||||
JERRY_ASSERT (ecma_is_value_bigint (value));
|
||||
|
||||
ecma_extended_primitive_t *bigint_p = ecma_get_extended_primitive_from_value (value);
|
||||
|
||||
if (ECMA_BIGINT_GET_SIZE (bigint_p) == 0)
|
||||
{
|
||||
return ecma_new_ecma_string_from_code_unit (LIT_CHAR_0);
|
||||
}
|
||||
|
||||
uint32_t char_start_p, char_size_p;
|
||||
lit_utf8_byte_t *string_buffer_p = ecma_big_uint_to_string (bigint_p, radix, &char_start_p, &char_size_p);
|
||||
|
||||
if (JERRY_UNLIKELY (string_buffer_p == NULL))
|
||||
{
|
||||
ecma_raise_range_error (ECMA_ERR_MSG ("Cannot allocate memory for a string representation of a BigInt value"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
JERRY_ASSERT (char_start_p > 0);
|
||||
|
||||
if (bigint_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN)
|
||||
{
|
||||
string_buffer_p[--char_start_p] = LIT_CHAR_MINUS;
|
||||
}
|
||||
|
||||
ecma_string_t *string_p;
|
||||
string_p = ecma_new_ecma_string_from_utf8 (string_buffer_p + char_start_p, char_size_p - char_start_p);
|
||||
|
||||
jmem_heap_free_block (string_buffer_p, char_size_p);
|
||||
return string_p;
|
||||
} /* ecma_bigint_to_string */
|
||||
|
||||
/**
|
||||
* Negate a non-zero BigInt value
|
||||
*
|
||||
* @return ecma BigInt value or ECMA_VALUE_ERROR
|
||||
* Returned value must be freed with ecma_free_value.
|
||||
*/
|
||||
ecma_value_t
|
||||
ecma_bigint_negate (ecma_extended_primitive_t *value_p) /**< BigInt value */
|
||||
{
|
||||
uint32_t size = ECMA_BIGINT_GET_SIZE (value_p);
|
||||
|
||||
JERRY_ASSERT (size > 0 && ECMA_BIGINT_GET_LAST_DIGIT (value_p, size) != 0);
|
||||
|
||||
ecma_extended_primitive_t *result_p = ecma_bigint_create (size);
|
||||
|
||||
if (JERRY_UNLIKELY (result_p == NULL))
|
||||
{
|
||||
return ecma_bigint_raise_memory_error ();
|
||||
}
|
||||
|
||||
memcpy (result_p + 1, value_p + 1, size);
|
||||
result_p->refs_and_type = ECMA_EXTENDED_PRIMITIVE_REF_ONE | ECMA_TYPE_BIGINT;
|
||||
result_p->u.bigint_sign_and_size = value_p->u.bigint_sign_and_size ^ ECMA_BIGINT_SIGN;
|
||||
|
||||
return ecma_make_extended_primitive_value (result_p, ECMA_TYPE_BIGINT);
|
||||
} /* ecma_bigint_negate */
|
||||
|
||||
/**
|
||||
* Add/subtract right BigInt value to/from left BigInt value
|
||||
*
|
||||
* @return ecma BigInt value or ECMA_VALUE_ERROR
|
||||
* Returned value must be freed with ecma_free_value.
|
||||
*/
|
||||
ecma_value_t
|
||||
ecma_bigint_add_sub (ecma_value_t left_value, /**< left BigInt value */
|
||||
ecma_value_t right_value, /**< right BigInt value */
|
||||
bool is_add) /**< true if add operation should be performed */
|
||||
{
|
||||
JERRY_ASSERT (ecma_is_value_bigint (left_value) && ecma_is_value_bigint (right_value));
|
||||
|
||||
ecma_extended_primitive_t *left_p = ecma_get_extended_primitive_from_value (left_value);
|
||||
ecma_extended_primitive_t *right_p = ecma_get_extended_primitive_from_value (right_value);
|
||||
uint32_t left_size = ECMA_BIGINT_GET_SIZE (left_p);
|
||||
uint32_t right_size = ECMA_BIGINT_GET_SIZE (right_p);
|
||||
|
||||
if (right_size == 0)
|
||||
{
|
||||
ecma_ref_extended_primitive (left_p);
|
||||
return left_value;
|
||||
}
|
||||
|
||||
if (left_size == 0)
|
||||
{
|
||||
if (!is_add)
|
||||
{
|
||||
return ecma_bigint_negate (right_p);
|
||||
}
|
||||
|
||||
ecma_ref_extended_primitive (right_p);
|
||||
return right_value;
|
||||
}
|
||||
|
||||
uint32_t sign = is_add ? 0 : ECMA_BIGINT_SIGN;
|
||||
|
||||
if (((left_p->u.bigint_sign_and_size ^ right_p->u.bigint_sign_and_size) & ECMA_BIGINT_SIGN) == sign)
|
||||
{
|
||||
ecma_extended_primitive_t *result_p = ecma_big_uint_add (left_p, right_p);
|
||||
|
||||
if (JERRY_UNLIKELY (result_p == NULL))
|
||||
{
|
||||
return ecma_bigint_raise_memory_error ();
|
||||
}
|
||||
|
||||
result_p->u.bigint_sign_and_size |= left_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN;
|
||||
return ecma_make_extended_primitive_value (result_p, ECMA_TYPE_BIGINT);
|
||||
}
|
||||
|
||||
int compare_result = ecma_big_uint_compare (left_p, right_p);
|
||||
ecma_extended_primitive_t *result_p;
|
||||
|
||||
if (compare_result == 0)
|
||||
{
|
||||
sign = 0;
|
||||
result_p = ecma_bigint_create (0);
|
||||
}
|
||||
else if (compare_result > 0)
|
||||
{
|
||||
sign = left_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN;
|
||||
result_p = ecma_big_uint_sub (left_p, right_p);
|
||||
}
|
||||
else
|
||||
{
|
||||
sign = right_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN;
|
||||
|
||||
if (!is_add)
|
||||
{
|
||||
sign ^= ECMA_BIGINT_SIGN;
|
||||
}
|
||||
|
||||
result_p = ecma_big_uint_sub (right_p, left_p);
|
||||
}
|
||||
|
||||
if (JERRY_UNLIKELY (result_p == NULL))
|
||||
{
|
||||
return ecma_bigint_raise_memory_error ();
|
||||
}
|
||||
|
||||
result_p->u.bigint_sign_and_size |= sign;
|
||||
return ecma_make_extended_primitive_value (result_p, ECMA_TYPE_BIGINT);
|
||||
} /* ecma_bigint_add_sub */
|
||||
|
||||
/**
|
||||
* Multiply two BigInt values
|
||||
*
|
||||
* @return ecma BigInt value or ECMA_VALUE_ERROR
|
||||
* Returned value must be freed with ecma_free_value.
|
||||
*/
|
||||
ecma_value_t
|
||||
ecma_bigint_mul (ecma_value_t left_value, /**< left BigInt value */
|
||||
ecma_value_t right_value) /**< right BigInt value */
|
||||
{
|
||||
JERRY_ASSERT (ecma_is_value_bigint (left_value) && ecma_is_value_bigint (right_value));
|
||||
|
||||
ecma_extended_primitive_t *left_p = ecma_get_extended_primitive_from_value (left_value);
|
||||
ecma_extended_primitive_t *right_p = ecma_get_extended_primitive_from_value (right_value);
|
||||
uint32_t left_size = ECMA_BIGINT_GET_SIZE (left_p);
|
||||
uint32_t right_size = ECMA_BIGINT_GET_SIZE (right_p);
|
||||
|
||||
if (left_size == 0)
|
||||
{
|
||||
ecma_ref_extended_primitive (left_p);
|
||||
return left_value;
|
||||
}
|
||||
|
||||
if (right_size == 0)
|
||||
{
|
||||
ecma_ref_extended_primitive (right_p);
|
||||
return right_value;
|
||||
}
|
||||
|
||||
if (left_size == sizeof (ecma_bigint_digit_t)
|
||||
&& ECMA_BIGINT_GET_LAST_DIGIT (left_p, sizeof (ecma_bigint_digit_t)) == 1)
|
||||
{
|
||||
if (left_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN)
|
||||
{
|
||||
return ecma_bigint_negate (right_p);
|
||||
}
|
||||
|
||||
ecma_ref_extended_primitive (right_p);
|
||||
return right_value;
|
||||
}
|
||||
|
||||
if (right_size == sizeof (ecma_bigint_digit_t)
|
||||
&& ECMA_BIGINT_GET_LAST_DIGIT (right_p, sizeof (ecma_bigint_digit_t)) == 1)
|
||||
{
|
||||
if (right_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN)
|
||||
{
|
||||
return ecma_bigint_negate (left_p);
|
||||
}
|
||||
|
||||
ecma_ref_extended_primitive (left_p);
|
||||
return left_value;
|
||||
}
|
||||
|
||||
ecma_extended_primitive_t *result_p = ecma_big_uint_mul (left_p, right_p);
|
||||
|
||||
if (JERRY_UNLIKELY (result_p == NULL))
|
||||
{
|
||||
return ecma_bigint_raise_memory_error ();
|
||||
}
|
||||
|
||||
uint32_t sign = (left_p->u.bigint_sign_and_size ^ right_p->u.bigint_sign_and_size) & ECMA_BIGINT_SIGN;
|
||||
result_p->u.bigint_sign_and_size |= sign;
|
||||
return ecma_make_extended_primitive_value (result_p, ECMA_TYPE_BIGINT);
|
||||
} /* ecma_bigint_mul */
|
||||
|
||||
/**
|
||||
* Divide two BigInt values
|
||||
*
|
||||
* @return ecma BigInt value or ECMA_VALUE_ERROR
|
||||
* Returned value must be freed with ecma_free_value.
|
||||
*/
|
||||
ecma_value_t
|
||||
ecma_bigint_div_mod (ecma_value_t left_value, /**< left BigInt value */
|
||||
ecma_value_t right_value, /**< right BigInt value */
|
||||
bool is_mod) /**< true if return with remainder */
|
||||
{
|
||||
JERRY_ASSERT (ecma_is_value_bigint (left_value) && ecma_is_value_bigint (right_value));
|
||||
|
||||
ecma_extended_primitive_t *left_p = ecma_get_extended_primitive_from_value (left_value);
|
||||
ecma_extended_primitive_t *right_p = ecma_get_extended_primitive_from_value (right_value);
|
||||
uint32_t left_size = ECMA_BIGINT_GET_SIZE (left_p);
|
||||
uint32_t right_size = ECMA_BIGINT_GET_SIZE (right_p);
|
||||
|
||||
if (right_size == 0)
|
||||
{
|
||||
return ecma_raise_range_error (ECMA_ERR_MSG ("BigInt division by zero"));
|
||||
}
|
||||
|
||||
if (left_size == 0)
|
||||
{
|
||||
ecma_ref_extended_primitive (left_p);
|
||||
return left_value;
|
||||
}
|
||||
|
||||
int compare_result = ecma_big_uint_compare (left_p, right_p);
|
||||
ecma_extended_primitive_t *result_p;
|
||||
|
||||
if (compare_result < 0)
|
||||
{
|
||||
if (is_mod)
|
||||
{
|
||||
ecma_ref_extended_primitive (left_p);
|
||||
return left_value;
|
||||
}
|
||||
else
|
||||
{
|
||||
result_p = ecma_bigint_create (0);
|
||||
}
|
||||
}
|
||||
else if (compare_result == 0)
|
||||
{
|
||||
if (is_mod)
|
||||
{
|
||||
result_p = ecma_bigint_create (0);
|
||||
}
|
||||
else
|
||||
{
|
||||
result_p = ecma_bigint_create (sizeof (ecma_bigint_digit_t));
|
||||
|
||||
if (result_p != NULL)
|
||||
{
|
||||
*ECMA_BIGINT_GET_DIGITS (result_p, 0) = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result_p = ecma_big_uint_div_mod (left_p, right_p, is_mod);
|
||||
}
|
||||
|
||||
if (JERRY_UNLIKELY (result_p == NULL))
|
||||
{
|
||||
return ecma_bigint_raise_memory_error ();
|
||||
}
|
||||
|
||||
if (ECMA_BIGINT_GET_SIZE (result_p) == 0)
|
||||
{
|
||||
return ecma_make_extended_primitive_value (result_p, ECMA_TYPE_BIGINT);
|
||||
}
|
||||
|
||||
if (is_mod)
|
||||
{
|
||||
result_p->u.bigint_sign_and_size |= left_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t sign = (left_p->u.bigint_sign_and_size ^ right_p->u.bigint_sign_and_size) & ECMA_BIGINT_SIGN;
|
||||
result_p->u.bigint_sign_and_size |= sign;
|
||||
}
|
||||
|
||||
return ecma_make_extended_primitive_value (result_p, ECMA_TYPE_BIGINT);
|
||||
} /* ecma_bigint_div_mod */
|
||||
|
||||
/**
|
||||
* Shift left BigInt value to left or right
|
||||
*
|
||||
* @return ecma BigInt value or ECMA_VALUE_ERROR
|
||||
* Returned value must be freed with ecma_free_value.
|
||||
*/
|
||||
ecma_value_t
|
||||
ecma_bigint_shift (ecma_value_t left_value, /**< left BigInt value */
|
||||
ecma_value_t right_value, /**< right BigInt value */
|
||||
bool is_left) /**< true if left shift operation should be performed */
|
||||
{
|
||||
JERRY_ASSERT (ecma_is_value_bigint (left_value) && ecma_is_value_bigint (right_value));
|
||||
|
||||
ecma_extended_primitive_t *left_p = ecma_get_extended_primitive_from_value (left_value);
|
||||
ecma_extended_primitive_t *right_p = ecma_get_extended_primitive_from_value (right_value);
|
||||
uint32_t right_size = ECMA_BIGINT_GET_SIZE (right_p);
|
||||
|
||||
if (right_size == 0 || ECMA_BIGINT_GET_SIZE (left_p) == 0)
|
||||
{
|
||||
ecma_ref_extended_primitive (left_p);
|
||||
return left_value;
|
||||
}
|
||||
|
||||
if (right_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN)
|
||||
{
|
||||
is_left = !is_left;
|
||||
}
|
||||
|
||||
if (right_size > sizeof (ecma_bigint_digit_t))
|
||||
{
|
||||
if (is_left)
|
||||
{
|
||||
return ecma_bigint_raise_memory_error ();
|
||||
}
|
||||
|
||||
return ecma_make_extended_primitive_value (ecma_bigint_create (0), ECMA_TYPE_BIGINT);
|
||||
}
|
||||
|
||||
ecma_extended_primitive_t *result_p;
|
||||
ecma_bigint_digit_t shift = ECMA_BIGINT_GET_LAST_DIGIT (right_p, sizeof (ecma_bigint_digit_t));
|
||||
|
||||
if (is_left)
|
||||
{
|
||||
result_p = ecma_big_uint_shift_left (left_p, shift);
|
||||
}
|
||||
else
|
||||
{
|
||||
result_p = ecma_big_uint_shift_right (left_p, shift);
|
||||
}
|
||||
|
||||
if (JERRY_UNLIKELY (result_p == NULL))
|
||||
{
|
||||
return ecma_bigint_raise_memory_error ();
|
||||
}
|
||||
|
||||
result_p->u.bigint_sign_and_size |= left_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN;
|
||||
return ecma_make_extended_primitive_value (result_p, ECMA_TYPE_BIGINT);
|
||||
} /* ecma_bigint_shift */
|
||||
#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
|
||||
@@ -0,0 +1,39 @@
|
||||
/* 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_BIG_INT_H
|
||||
#define ECMA_BIG_INT_H
|
||||
|
||||
#include "ecma-globals.h"
|
||||
|
||||
#if ENABLED (JERRY_BUILTIN_BIGINT)
|
||||
|
||||
/**
|
||||
* Sign bit of a BigInt value. The number is negative, if this bit is set.
|
||||
*/
|
||||
#define ECMA_BIGINT_SIGN 0x1
|
||||
|
||||
ecma_value_t ecma_bigint_parse_string (const lit_utf8_byte_t *string_p, lit_utf8_size_t size);
|
||||
ecma_string_t *ecma_bigint_to_string (ecma_value_t value, ecma_bigint_digit_t radix);
|
||||
|
||||
ecma_value_t ecma_bigint_negate (ecma_extended_primitive_t *value_p);
|
||||
ecma_value_t ecma_bigint_add_sub (ecma_value_t left_value, ecma_value_t right_value, bool is_add);
|
||||
ecma_value_t ecma_bigint_mul (ecma_value_t left_value, ecma_value_t right_value);
|
||||
ecma_value_t ecma_bigint_div_mod (ecma_value_t left_value, ecma_value_t right_value, bool is_mod);
|
||||
ecma_value_t ecma_bigint_shift (ecma_value_t left_value, ecma_value_t right_value, bool is_left);
|
||||
|
||||
#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
|
||||
|
||||
#endif /* ECMA_BIG_INT_H */
|
||||
@@ -20,6 +20,8 @@
|
||||
#include <math.h>
|
||||
|
||||
#include "ecma-alloc.h"
|
||||
#include "ecma-bigint.h"
|
||||
#include "ecma-bigint-object.h"
|
||||
#include "ecma-boolean-object.h"
|
||||
#include "ecma-conversion.h"
|
||||
#include "ecma-exceptions.h"
|
||||
@@ -279,12 +281,6 @@ ecma_op_to_number (ecma_value_t value) /**< ecma value */
|
||||
ecma_string_t *str_p = ecma_get_string_from_value (value);
|
||||
return ecma_make_number_value (ecma_string_to_number (str_p));
|
||||
}
|
||||
#if ENABLED (JERRY_ESNEXT)
|
||||
if (ecma_is_value_symbol (value))
|
||||
{
|
||||
return ecma_raise_type_error (ECMA_ERR_MSG ("Cannot convert a Symbol value to a number."));
|
||||
}
|
||||
#endif /* ENABLED (JERRY_ESNEXT) */
|
||||
|
||||
if (ecma_is_value_undefined (value))
|
||||
{
|
||||
@@ -301,6 +297,20 @@ ecma_op_to_number (ecma_value_t value) /**< ecma value */
|
||||
return ecma_make_integer_value (ecma_is_value_true (value) ? 1 : 0);
|
||||
}
|
||||
|
||||
#if ENABLED (JERRY_ESNEXT)
|
||||
if (ecma_is_value_symbol (value))
|
||||
{
|
||||
return ecma_raise_type_error (ECMA_ERR_MSG ("Cannot convert a Symbol value to a number"));
|
||||
}
|
||||
#endif /* ENABLED (JERRY_ESNEXT) */
|
||||
|
||||
#if ENABLED (JERRY_BUILTIN_BIGINT)
|
||||
if (ecma_is_value_bigint (value))
|
||||
{
|
||||
return ecma_raise_type_error (ECMA_ERR_MSG ("Cannot convert a BigInt value to a number"));
|
||||
}
|
||||
#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
|
||||
|
||||
JERRY_ASSERT (ecma_is_value_object (value));
|
||||
|
||||
ecma_object_t *obj_p = ecma_get_object_from_value (value);
|
||||
@@ -364,13 +374,6 @@ ecma_get_number (ecma_value_t value, /**< ecma value*/
|
||||
return ECMA_VALUE_EMPTY;
|
||||
}
|
||||
|
||||
#if ENABLED (JERRY_ESNEXT)
|
||||
if (ecma_is_value_symbol (value))
|
||||
{
|
||||
return ecma_raise_type_error (ECMA_ERR_MSG ("Cannot convert a Symbol value to a number."));
|
||||
}
|
||||
#endif /* ENABLED (JERRY_ESNEXT) */
|
||||
|
||||
if (ecma_is_value_true (value))
|
||||
{
|
||||
*number_p = 1;
|
||||
@@ -383,6 +386,20 @@ ecma_get_number (ecma_value_t value, /**< ecma value*/
|
||||
return ECMA_VALUE_EMPTY;
|
||||
}
|
||||
|
||||
#if ENABLED (JERRY_ESNEXT)
|
||||
if (ecma_is_value_symbol (value))
|
||||
{
|
||||
return ecma_raise_type_error (ECMA_ERR_MSG ("Cannot convert a Symbol value to a number."));
|
||||
}
|
||||
#endif /* ENABLED (JERRY_ESNEXT) */
|
||||
|
||||
#if ENABLED (JERRY_BUILTIN_BIGINT)
|
||||
if (ecma_is_value_bigint (value))
|
||||
{
|
||||
return ecma_raise_type_error (ECMA_ERR_MSG ("Cannot convert a BigInt value to a number"));
|
||||
}
|
||||
#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
|
||||
|
||||
JERRY_ASSERT (ecma_is_value_object (value));
|
||||
|
||||
ecma_object_t *obj_p = ecma_get_object_from_value (value);
|
||||
@@ -452,14 +469,6 @@ ecma_op_to_string (ecma_value_t value) /**< ecma value */
|
||||
return ecma_get_magic_string (LIT_MAGIC_STRING_NULL);
|
||||
}
|
||||
|
||||
#if ENABLED (JERRY_ESNEXT)
|
||||
if (ecma_is_value_symbol (value))
|
||||
{
|
||||
ecma_raise_type_error (ECMA_ERR_MSG ("Cannot convert a Symbol value to a string."));
|
||||
return NULL;
|
||||
}
|
||||
#endif /* ENABLED (JERRY_ESNEXT) */
|
||||
|
||||
if (ecma_is_value_true (value))
|
||||
{
|
||||
return ecma_get_magic_string (LIT_MAGIC_STRING_TRUE);
|
||||
@@ -470,6 +479,21 @@ ecma_op_to_string (ecma_value_t value) /**< ecma value */
|
||||
return ecma_get_magic_string (LIT_MAGIC_STRING_FALSE);
|
||||
}
|
||||
|
||||
#if ENABLED (JERRY_ESNEXT)
|
||||
if (ecma_is_value_symbol (value))
|
||||
{
|
||||
ecma_raise_type_error (ECMA_ERR_MSG ("Cannot convert a Symbol value to a string."));
|
||||
return NULL;
|
||||
}
|
||||
#endif /* ENABLED (JERRY_ESNEXT) */
|
||||
|
||||
#if ENABLED (JERRY_BUILTIN_BIGINT)
|
||||
if (ecma_is_value_bigint (value))
|
||||
{
|
||||
return ecma_bigint_to_string (value, 10);
|
||||
}
|
||||
#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
|
||||
|
||||
JERRY_ASSERT (ecma_is_value_object (value));
|
||||
|
||||
ecma_object_t *obj_p = ecma_get_object_from_value (value);
|
||||
@@ -567,6 +591,12 @@ ecma_op_to_object (ecma_value_t value) /**< ecma value */
|
||||
return ecma_op_create_symbol_object (value);
|
||||
}
|
||||
#endif /* ENABLED (JERRY_ESNEXT) */
|
||||
#if ENABLED (JERRY_BUILTIN_BIGINT)
|
||||
else if (ecma_is_value_bigint (value))
|
||||
{
|
||||
return ecma_op_create_bigint_object (value);
|
||||
}
|
||||
#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
|
||||
else
|
||||
{
|
||||
if (ecma_is_value_undefined (value)
|
||||
|
||||
@@ -174,6 +174,12 @@ ecma_op_get_value_object_base (ecma_value_t base_value, /**< base value */
|
||||
id = ECMA_BUILTIN_ID_SYMBOL_PROTOTYPE;
|
||||
}
|
||||
#endif /* ENABLED (JERRY_ESNEXT) */
|
||||
#if ENABLED (JERRY_BUILTIN_BIGINT)
|
||||
else if (ecma_is_value_bigint (base_value))
|
||||
{
|
||||
id = ECMA_BUILTIN_ID_BIGINT_PROTOTYPE;
|
||||
}
|
||||
#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
|
||||
else
|
||||
{
|
||||
JERRY_ASSERT (ecma_is_value_boolean (base_value));
|
||||
|
||||
@@ -2648,6 +2648,12 @@ ecma_object_get_class_name (ecma_object_t *obj_p) /**< object */
|
||||
return LIT_MAGIC_STRING_FUNCTION_UL;
|
||||
}
|
||||
#endif /* ENABLED (JERRY_BUILTIN_PROXY) */
|
||||
#if ENABLED (JERRY_BUILTIN_BIGINT)
|
||||
case ECMA_BUILTIN_ID_BIGINT:
|
||||
{
|
||||
return LIT_MAGIC_STRING_FUNCTION_UL;
|
||||
}
|
||||
#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
|
||||
default:
|
||||
{
|
||||
JERRY_ASSERT (ecma_object_check_class_name_is_object (obj_p));
|
||||
|
||||
Reference in New Issue
Block a user