diff --git a/jerry-core/ecma/base/ecma-helpers.c b/jerry-core/ecma/base/ecma-helpers.c index 059edb414..cce126483 100644 --- a/jerry-core/ecma/base/ecma-helpers.c +++ b/jerry-core/ecma/base/ecma-helpers.c @@ -1271,11 +1271,7 @@ ecma_deref_bigint (ecma_extended_primitive_t *bigint_p) /**< bigint value */ uint32_t size = ECMA_BIGINT_GET_SIZE (bigint_p); - if (size == 0) - { - jmem_pools_free (bigint_p, sizeof (ecma_extended_primitive_t)); - return; - } + JERRY_ASSERT (size > 0); size_t mem_size = ECMA_BIGINT_GET_BYTE_SIZE (size) + sizeof (ecma_extended_primitive_t); jmem_heap_free_block (bigint_p, mem_size); diff --git a/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h index 8cf863622..7fdcd070a 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h @@ -678,6 +678,8 @@ BUILTIN (ECMA_BUILTIN_ID_MAP_ITERATOR_PROTOTYPE, map_iterator_prototype) #endif /* ENABLED (JERRY_BUILTIN_SET) */ +#endif /* ENABLED (JERRY_ESNEXT) */ + #if ENABLED (JERRY_BUILTIN_BIGINT) /* The %BigInt.prototype% object */ BUILTIN (ECMA_BUILTIN_ID_BIGINT_PROTOTYPE, @@ -694,8 +696,6 @@ BUILTIN_ROUTINE (ECMA_BUILTIN_ID_BIGINT, bigint) #endif /* ENABLED (JERRY_BUILTIN_BIGINT) */ -#endif /* ENABLED (JERRY_ESNEXT) */ - #if ENABLED (JERRY_BUILTIN_DATAVIEW) /* The DataView prototype object (ECMA-262 v6, 24.2.3.1) */ BUILTIN (ECMA_BUILTIN_ID_DATAVIEW_PROTOTYPE, diff --git a/jerry-core/ecma/operations/ecma-big-uint.c b/jerry-core/ecma/operations/ecma-big-uint.c index b742c45a2..c280c38d9 100644 --- a/jerry-core/ecma/operations/ecma-big-uint.c +++ b/jerry-core/ecma/operations/ecma-big-uint.c @@ -94,23 +94,38 @@ ecma_big_uint_extend (ecma_extended_primitive_t *value_p, /**< BigUInt value */ } /* ecma_big_uint_extend */ /** - * Discard the high-order digits of a BigUInt + * Helper function which discards the leading zero digits of a BigUInt value * - * @return BigUInt value, NULL on error + * @return new BigUInt value, NULL on error */ static ecma_extended_primitive_t * -ecma_big_uint_shrink_value (ecma_extended_primitive_t *value_p, /**< BigUInt value */ - uint32_t new_size) /**< new size, which is smaller than the original size */ +ecma_big_uint_normalize_result (ecma_extended_primitive_t *value_p, /**< BigUInt value */ + ecma_bigint_digit_t *last_digit_p) /**< points to the end of BigUInt */ { - JERRY_ASSERT (value_p != NULL); - JERRY_ASSERT (ECMA_BIGINT_GET_SIZE (value_p) > new_size); + JERRY_ASSERT (last_digit_p[-1] == 0); - if (new_size == 0) + ecma_bigint_digit_t *first_digit_p = ECMA_BIGINT_GET_DIGITS (value_p, 0); + + /* The following code is tricky. The value stored in first_digit_p[-1] is the size + * of the BigUInt value, and it cannot be zero. Hence the loop below will terminate. */ + JERRY_ASSERT (first_digit_p[-1] != 0); + + do + { + --last_digit_p; + } + while (last_digit_p[-1] == 0); + + JERRY_ASSERT (last_digit_p >= first_digit_p); + + if (first_digit_p == last_digit_p) { ecma_deref_bigint (value_p); return ECMA_BIGINT_POINTER_TO_ZERO; } + uint32_t new_size = (uint32_t) ((uint8_t *) last_digit_p - (uint8_t *) first_digit_p); + if (ECMA_BIGINT_SIZE_IS_ODD (new_size) && ((new_size + sizeof (ecma_bigint_digit_t)) == ECMA_BIGINT_GET_SIZE (value_p))) { @@ -130,7 +145,42 @@ ecma_big_uint_shrink_value (ecma_extended_primitive_t *value_p, /**< BigUInt val ecma_deref_bigint (value_p); return result_p; -} /* ecma_big_uint_shrink_value */ +} /* ecma_big_uint_normalize_result */ + +/** + * Helper function which increases the result by 1 and extends or shrinks the BigUInt when necessary + * + * @return new BigUInt value, NULL on error + */ +static ecma_extended_primitive_t * +ecma_big_uint_increase_result (ecma_extended_primitive_t *value_p) /**< BigUInt value */ +{ + uint32_t size = ECMA_BIGINT_GET_SIZE (value_p); + + JERRY_ASSERT (size > 0); + + ecma_bigint_digit_t *first_digit_p = ECMA_BIGINT_GET_DIGITS (value_p, 0); + ecma_bigint_digit_t *last_digit_p = ECMA_BIGINT_GET_DIGITS (value_p, size); + + while (*first_digit_p == ~((ecma_bigint_digit_t) 0)) + { + *first_digit_p++ = 0; + + if (first_digit_p == last_digit_p) + { + return ecma_big_uint_extend (value_p, 1); + } + } + + (*first_digit_p)++; + + if (last_digit_p[-1] != 0) + { + return value_p; + } + + return ecma_big_uint_normalize_result (value_p, last_digit_p); +} /* ecma_big_uint_increase_result */ /** * Compare two BigUInt numbers @@ -376,7 +426,7 @@ ecma_big_uint_to_string (ecma_extended_primitive_t *value_p, /**< BigUInt value /** * Increase the value of a BigUInt value by 1 * - * return new BigInt value, NULL on error + * return new BigUInt value, NULL on error */ ecma_extended_primitive_t * ecma_big_uint_increase (ecma_extended_primitive_t *value_p) /**< BigUInt value */ @@ -441,7 +491,7 @@ ecma_big_uint_increase (ecma_extended_primitive_t *value_p) /**< BigUInt value * /** * Decrease the value of a BigUInt value by 1 * - * return new BigInt value, NULL on error + * return new BigUInt value, NULL on error */ ecma_extended_primitive_t * ecma_big_uint_decrease (ecma_extended_primitive_t *value_p) /**< BigUInt value */ @@ -508,7 +558,7 @@ ecma_big_uint_decrease (ecma_extended_primitive_t *value_p) /**< BigUInt value * /** * Add right BigUInt value to the left BigUInt value * - * return new BigInt value, NULL on error + * return new BigUInt value, NULL on error */ ecma_extended_primitive_t * ecma_big_uint_add (ecma_extended_primitive_t *left_value_p, /**< left BigUInt value */ @@ -609,7 +659,7 @@ ecma_big_uint_add (ecma_extended_primitive_t *left_value_p, /**< left BigUInt va /** * Substract right BigUInt value from the left BigUInt value * - * return new BigInt value, NULL on error + * return new BigUInt value, NULL on error */ ecma_extended_primitive_t * ecma_big_uint_sub (ecma_extended_primitive_t *left_value_p, /**< left BigUInt value */ @@ -683,29 +733,18 @@ ecma_big_uint_sub (ecma_extended_primitive_t *left_value_p, /**< left BigUInt va return result_p; } - ecma_bigint_digit_t *new_end_p = current_p; - - if (new_end_p[-1] != 0) + if (current_p[-1] != 0) { return result_p; } - do - { - new_end_p--; - - JERRY_ASSERT (new_end_p > ECMA_BIGINT_GET_DIGITS (result_p, 0)); - } - while (new_end_p[-1] == 0); - - ecma_bigint_digit_t *first_digit_p = ECMA_BIGINT_GET_DIGITS (result_p, 0); - return ecma_big_uint_shrink_value (result_p, (uint32_t) ((uint8_t *) new_end_p - (uint8_t *) first_digit_p)); + return ecma_big_uint_normalize_result (result_p, current_p); } /* ecma_big_uint_sub */ /** * Multiply two BigUInt values * - * return new BigInt value, NULL on error + * return new BigUInt value, NULL on error */ ecma_extended_primitive_t * ecma_big_uint_mul (ecma_extended_primitive_t *left_value_p, /**< left BigUInt value */ @@ -840,7 +879,7 @@ ecma_big_uint_mul (ecma_extended_primitive_t *left_value_p, /**< left BigUInt va /** * Count the number of leading zero bits of a digit * - * return new BigInt value, NULL on error + * 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 */ @@ -866,7 +905,7 @@ ecma_big_uint_count_leading_zero (ecma_bigint_digit_t digit) /**< digit value */ /** * Divide left BigUInt value with right digit value * - * return new BigInt value, NULL on error + * return new BigUInt value, NULL on error */ static ecma_extended_primitive_t * ecma_big_uint_div_digit (ecma_extended_primitive_t *left_value_p, /**< left BigUInt value */ @@ -951,7 +990,7 @@ ecma_big_uint_div_digit (ecma_extended_primitive_t *left_value_p, /**< left BigU } /* ecma_big_uint_div_digit */ /** - * Shift left BigInt digits + * Shift left a BigUInt value by a digit value * * return newly allocated buffer, NULL on error */ @@ -1014,7 +1053,7 @@ ecma_big_uint_div_shift_left (ecma_extended_primitive_t *value_p, /**< BigUInt v /** * Divide left BigUInt value with right BigUInt value * - * return new BigInt value, NULL on error + * return new BigUInt value, NULL on error */ ecma_extended_primitive_t * ecma_big_uint_div_mod (ecma_extended_primitive_t *dividend_value_p, /**< divider BigUInt value */ @@ -1279,9 +1318,9 @@ error: } /* ecma_big_uint_div_mod */ /** - * Shift left BigInt values by an uint32 value + * Shift left BigUInt values by an uint32 value * - * return new BigInt value, NULL on error + * return new BigUInt value, NULL on error */ ecma_extended_primitive_t * ecma_big_uint_shift_left (ecma_extended_primitive_t *left_value_p, /**< left BigUInt value */ @@ -1352,13 +1391,14 @@ ecma_big_uint_shift_left (ecma_extended_primitive_t *left_value_p, /**< left Big } /* ecma_big_uint_shift_left */ /** - * Shift right BigInt values by an uint32 value + * Shift right BigUInt values by an uint32 value * - * @return new BigInt value, NULL on error + * @return new BigUInt value, NULL on error */ ecma_extended_primitive_t * ecma_big_uint_shift_right (ecma_extended_primitive_t *left_value_p, /**< left BigUInt value */ - uint32_t right_value) /**< shift value */ + uint32_t right_value, /**< shift value */ + bool increase_result) /**< increase result */ { JERRY_ASSERT (right_value > 0); @@ -1380,7 +1420,39 @@ ecma_big_uint_shift_right (ecma_extended_primitive_t *left_value_p, /**< left B if (left_size <= crop_size) { - return ECMA_BIGINT_POINTER_TO_ZERO; + if (JERRY_LIKELY (!increase_result)) + { + return ECMA_BIGINT_POINTER_TO_ZERO; + } + + ecma_extended_primitive_t *result_value_p = ecma_bigint_create (sizeof (ecma_bigint_digit_t)); + if (result_value_p != NULL) + { + *ECMA_BIGINT_GET_DIGITS (result_value_p, 0) = 1; + } + return result_value_p; + } + + if (JERRY_UNLIKELY (increase_result) + && (shift_right == 0 + || (*ECMA_BIGINT_GET_DIGITS (left_value_p, crop_size) << shift_left) == 0)) + { + ecma_bigint_digit_t *left_p = ECMA_BIGINT_GET_DIGITS (left_value_p, 0); + ecma_bigint_digit_t *left_end_p = ECMA_BIGINT_GET_DIGITS (left_value_p, crop_size); + + while (left_p < left_end_p) + { + if (*left_p != 0) + { + break; + } + left_p++; + } + + if (left_p == left_end_p) + { + increase_result = false; + } } uint32_t size = left_size - crop_size; @@ -1394,7 +1466,12 @@ ecma_big_uint_shift_right (ecma_extended_primitive_t *left_value_p, /**< left B if (shift_right == 0) { memcpy (ECMA_BIGINT_GET_DIGITS (result_value_p, 0), ECMA_BIGINT_GET_DIGITS (left_value_p, crop_size), size); - return result_value_p; + + if (JERRY_LIKELY (!increase_result)) + { + return result_value_p; + } + return ecma_big_uint_increase_result (result_value_p); } ecma_bigint_digit_t *left_p = ECMA_BIGINT_GET_DIGITS (left_value_p, left_size); @@ -1410,71 +1487,91 @@ ecma_big_uint_shift_right (ecma_extended_primitive_t *left_value_p, /**< left B } while (result_p > end_p); - return result_value_p; + if (JERRY_LIKELY (!increase_result)) + { + return result_value_p; + } + return ecma_big_uint_increase_result (result_value_p); } /* ecma_big_uint_shift_right */ -/** - * Helper function for bitwise operations which drops leading zeroes - * - * @return ecma BigInt value or ECMA_VALUE_ERROR - * Returned value must be freed with ecma_free_value. - */ -static ecma_extended_primitive_t * -ecma_big_uint_normalize_result (ecma_extended_primitive_t *value_p, /**< BigUInt value */ - ecma_bigint_digit_t *last_digit_p) /**< points to the end of BigUInt */ -{ - JERRY_ASSERT (last_digit_p[-1] == 0); - - ecma_bigint_digit_t *first_digit_p = ECMA_BIGINT_GET_DIGITS (value_p, 0); - - do - { - --last_digit_p; - } - while (last_digit_p > first_digit_p && last_digit_p[-1] == 0); - - return ecma_big_uint_shrink_value (value_p, (uint32_t) ((uint8_t *) last_digit_p - (uint8_t *) first_digit_p)); -} /* ecma_big_uint_normalize_result */ +#if ENABLED (JERRY_ESNEXT) /** - * Helper function for bitwise operations which increases the result by 1 + * Compute the left value raised to the power of right value * - * @return new BigInt value, NULL on error + * return new BigUInt value, NULL on error */ -static ecma_extended_primitive_t * -ecma_big_uint_increase_result (ecma_extended_primitive_t *value_p) /**< BigUInt value */ +ecma_extended_primitive_t * +ecma_big_uint_pow (ecma_extended_primitive_t *left_value_p, /**< left BigUInt value */ + uint32_t right_value) /**< power value */ { - uint32_t size = ECMA_BIGINT_GET_SIZE (value_p); + ecma_extended_primitive_t *result_p = ECMA_BIGINT_NUMBER_IS_ODD (right_value) ? left_value_p : NULL; + ecma_extended_primitive_t *square_p = left_value_p; - JERRY_ASSERT (size > 0); + JERRY_ASSERT (right_value >= 2); - ecma_bigint_digit_t *first_digit_p = ECMA_BIGINT_GET_DIGITS (value_p, 0); - ecma_bigint_digit_t *last_digit_p = ECMA_BIGINT_GET_DIGITS (value_p, size); - - while (*first_digit_p == ~((ecma_bigint_digit_t) 0)) + while (true) { - *first_digit_p++ = 0; + ecma_extended_primitive_t *new_square_p = ecma_big_uint_mul (square_p, square_p); - if (first_digit_p == last_digit_p) + if (JERRY_UNLIKELY (new_square_p == NULL)) { - return ecma_big_uint_extend (value_p, 1); + if (result_p != NULL && result_p != left_value_p) + { + ecma_deref_bigint (result_p); + } + result_p = NULL; + break; + } + + if (square_p != left_value_p) + { + ecma_deref_bigint (square_p); + } + + square_p = new_square_p; + right_value >>= 1; + + if (ECMA_BIGINT_NUMBER_IS_ODD (right_value)) + { + if (result_p != NULL) + { + ecma_extended_primitive_t *new_result_p = ecma_big_uint_mul (square_p, result_p); + + if (result_p != left_value_p) + { + ecma_deref_bigint (result_p); + } + + result_p = new_result_p; + } + else + { + ecma_ref_extended_primitive (square_p); + result_p = square_p; + } + + if (JERRY_UNLIKELY (result_p == NULL) || right_value == 1) + { + break; + } } } - (*first_digit_p)++; - - if (last_digit_p[-1] != 0) + if (square_p != left_value_p) { - return value_p; + ecma_deref_bigint (square_p); } - return ecma_big_uint_normalize_result (value_p, last_digit_p); -} /* ecma_big_uint_increase_result */ + return result_p; +} /* ecma_big_uint_pow */ + +#endif /* ENABLED (JERRY_ESNEXT) */ /** * Perform bitwise operations on two BigUInt numbers * - * return new BigInt value, NULL on error + * return new BigUInt value, NULL on error */ ecma_extended_primitive_t * ecma_big_uint_bitwise_op (uint32_t operation_and_options, /**< bitwise operation type and options */ diff --git a/jerry-core/ecma/operations/ecma-big-uint.h b/jerry-core/ecma/operations/ecma-big-uint.h index 5d3dd8c69..777c26c31 100644 --- a/jerry-core/ecma/operations/ecma-big-uint.h +++ b/jerry-core/ecma/operations/ecma-big-uint.h @@ -59,6 +59,11 @@ typedef uint64_t ecma_bigint_two_digits_t; #define ECMA_BIGINT_HIGH_DIGIT(digit) \ (((ecma_bigint_two_digits_t) digit) << (8 * sizeof (ecma_bigint_digit_t))) +/** + * Tells whether a number (usually a digit or uint32_t value) is an odd number. + */ +#define ECMA_BIGINT_NUMBER_IS_ODD(number) ((number & 0x1) != 0) + /** * Bitwise operation types. */ @@ -117,7 +122,12 @@ ecma_extended_primitive_t *ecma_big_uint_div_mod (ecma_extended_primitive_t *div 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); +ecma_extended_primitive_t *ecma_big_uint_shift_right (ecma_extended_primitive_t *left_value_p, uint32_t right_value, + bool increase_result); + +#if ENABLED (JERRY_ESNEXT) +ecma_extended_primitive_t *ecma_big_uint_pow (ecma_extended_primitive_t *left_value_p, uint32_t right_value); +#endif /* ENABLED (JERRY_ESNEXT) */ ecma_extended_primitive_t *ecma_big_uint_bitwise_op (uint32_t operation_and_options, ecma_extended_primitive_t *left_value_p, diff --git a/jerry-core/ecma/operations/ecma-bigint.c b/jerry-core/ecma/operations/ecma-bigint.c index 975929654..e612176ca 100644 --- a/jerry-core/ecma/operations/ecma-bigint.c +++ b/jerry-core/ecma/operations/ecma-bigint.c @@ -113,11 +113,7 @@ ecma_bigint_parse_string (const lit_utf8_byte_t *string_p, /**< string represena } else if (size == 0) { - if (options & ECMA_BIGINT_PARSE_DISALLOW_SYNTAX_ERROR) - { - return ECMA_VALUE_FALSE; - } - return ecma_raise_syntax_error (ECMA_ERR_MSG ("BigInt cannot be constructed from empty string")); + return ECMA_BIGINT_ZERO; } const lit_utf8_byte_t *string_end_p = string_p + size; @@ -289,7 +285,7 @@ ecma_bigint_number_to_digits (ecma_number_t number, /**< ecma number */ ecma_number_unpack (number, NULL, &biased_exp, &fraction); - if (biased_exp == 0) + if (biased_exp == 0 && fraction == 0) { /* Number is zero. */ return ECMA_BIGINT_NUMBER_TO_DIGITS_SET_DIGITS (0); @@ -784,6 +780,11 @@ ecma_bigint_is_equal_to_number (ecma_value_t left_value, /**< left BigInt value */ #define ECMA_BIGINT_TO_SIGN(value) (1 - (((int) (value)) << 1)) +/** + * Convert 0 to -1, and 1 to 1. Useful for getting negated sign. + */ +#define ECMA_BIGINT_TO_NEGATED_SIGN(value) (-1 + (((int) (value)) << 1)) + /** * Compare two BigInt values * @@ -795,10 +796,26 @@ ecma_bigint_compare_to_bigint (ecma_value_t left_value, /**< left 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); + if (left_value == ECMA_BIGINT_ZERO) + { + if (right_value == ECMA_BIGINT_ZERO) + { + return 0; + } + ecma_extended_primitive_t *right_p = ecma_get_extended_primitive_from_value (right_value); + return ECMA_BIGINT_TO_NEGATED_SIGN (right_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN); + } + + ecma_extended_primitive_t *left_p = ecma_get_extended_primitive_from_value (left_value); uint32_t left_sign = left_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN; + + if (right_value == ECMA_BIGINT_ZERO) + { + return ECMA_BIGINT_TO_SIGN (left_sign); + } + + ecma_extended_primitive_t *right_p = ecma_get_extended_primitive_from_value (right_value); uint32_t right_sign = right_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN; if ((left_sign ^ right_sign) != 0) @@ -806,7 +823,12 @@ ecma_bigint_compare_to_bigint (ecma_value_t left_value, /**< left BigInt value * return ECMA_BIGINT_TO_SIGN (left_sign); } - return ecma_big_uint_compare (left_p, right_p); + if (left_sign == 0) + { + return ecma_big_uint_compare (left_p, right_p); + } + + return -ecma_big_uint_compare (left_p, right_p); } /* ecma_bigint_compare_to_bigint */ /** @@ -1250,6 +1272,7 @@ ecma_bigint_shift (ecma_value_t left_value, /**< left BigInt value */ ecma_extended_primitive_t *result_p; ecma_bigint_digit_t shift = ECMA_BIGINT_GET_LAST_DIGIT (right_p, sizeof (ecma_bigint_digit_t)); + uint32_t left_sign = left_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN; if (is_left) { @@ -1257,7 +1280,10 @@ ecma_bigint_shift (ecma_value_t left_value, /**< left BigInt value */ } else { - result_p = ecma_big_uint_shift_right (left_p, shift); + /* -x >> y == ~(x - 1) >> y == ~((x - 1) >> y) == -(((x - 1) >> y) + 1) + * When a non-zero bit is shifted out: (x - 1) >> y == x >> y, so the formula is -((x >> y) + 1) + * When only zero bits are shifted out: (((x - 1) >> y) + 1) == x >> y so the formula is: -(x >> y) */ + result_p = ecma_big_uint_shift_right (left_p, shift, left_sign != 0); if (result_p == ECMA_BIGINT_POINTER_TO_ZERO) { @@ -1270,10 +1296,102 @@ ecma_bigint_shift (ecma_value_t left_value, /**< left BigInt value */ return ecma_bigint_raise_memory_error (); } - result_p->u.bigint_sign_and_size |= left_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN; + result_p->u.bigint_sign_and_size |= left_sign; return ecma_make_extended_primitive_value (result_p, ECMA_TYPE_BIGINT); } /* ecma_bigint_shift */ +#if ENABLED (JERRY_ESNEXT) + +/** + * Compute the left value raised to the power of right value + * + * @return ecma BigInt value or ECMA_VALUE_ERROR + * Returned value must be freed with ecma_free_value. + */ +ecma_value_t +ecma_bigint_pow (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)); + + if (right_value == ECMA_BIGINT_ZERO) + { + return ecma_bigint_create_from_digit (1, false); + } + + ecma_extended_primitive_t *right_p = ecma_get_extended_primitive_from_value (right_value); + + if (right_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN) + { + return ecma_raise_range_error (ECMA_ERR_MSG ("Negative exponent is not allowed for BigInts")); + } + + if (left_value == ECMA_BIGINT_ZERO) + { + return ECMA_BIGINT_ZERO; + } + + ecma_extended_primitive_t *left_p = ecma_get_extended_primitive_from_value (left_value); + ecma_bigint_digit_t base = 0; + + if (ECMA_BIGINT_GET_SIZE (left_p) == sizeof (ecma_bigint_digit_t)) + { + base = *ECMA_BIGINT_GET_DIGITS (left_p, 0); + + JERRY_ASSERT (base != 0); + + if (base == 1) + { + if (!(left_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN) + || ECMA_BIGINT_NUMBER_IS_ODD (*ECMA_BIGINT_GET_DIGITS (right_p, 0))) + { + ecma_ref_extended_primitive (left_p); + return left_value; + } + + return ecma_bigint_create_from_digit (1, false); + } + } + + if (JERRY_UNLIKELY (ECMA_BIGINT_GET_SIZE (right_p) > sizeof (ecma_bigint_digit_t))) + { + return ecma_bigint_raise_memory_error (); + } + + ecma_bigint_digit_t power = *ECMA_BIGINT_GET_DIGITS (right_p, 0); + + if (power == 1) + { + ecma_ref_extended_primitive (left_p); + return left_value; + } + + ecma_extended_primitive_t *result_p; + + if (base == 2) + { + result_p = ecma_big_uint_shift_left (left_p, power - 1); + } + else + { + result_p = ecma_big_uint_pow (left_p, power); + } + + if (JERRY_UNLIKELY (result_p == NULL)) + { + return ecma_bigint_raise_memory_error (); + } + + if ((left_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN) && ECMA_BIGINT_NUMBER_IS_ODD (power)) + { + result_p->u.bigint_sign_and_size |= ECMA_BIGINT_SIGN; + } + + return ecma_make_extended_primitive_value (result_p, ECMA_TYPE_BIGINT); +} /* ecma_bigint_pow */ + +#endif /* ENABLED (JERRY_ESNEXT) */ + /** * Convert the result to an ecma value * diff --git a/jerry-core/ecma/operations/ecma-bigint.h b/jerry-core/ecma/operations/ecma-bigint.h index 70711786f..20195275d 100644 --- a/jerry-core/ecma/operations/ecma-bigint.h +++ b/jerry-core/ecma/operations/ecma-bigint.h @@ -69,6 +69,9 @@ ecma_value_t ecma_bigint_add_sub (ecma_value_t left_value, ecma_value_t right_va 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); +#if ENABLED (JERRY_ESNEXT) +ecma_value_t ecma_bigint_pow (ecma_value_t left_value, ecma_value_t right_value); +#endif /* ENABLED (JERRY_ESNEXT) */ ecma_value_t ecma_bigint_and (ecma_value_t left_value, ecma_value_t right_value); ecma_value_t ecma_bigint_or (ecma_value_t left_value, ecma_value_t right_value); diff --git a/jerry-core/ecma/operations/ecma-comparison.c b/jerry-core/ecma/operations/ecma-comparison.c index def2a8d31..92f9ae6f7 100644 --- a/jerry-core/ecma/operations/ecma-comparison.c +++ b/jerry-core/ecma/operations/ecma-comparison.c @@ -92,9 +92,9 @@ ecma_op_abstract_equality_compare (ecma_value_t x, /**< first operand */ } /* Swap values. */ - ecma_value_t tmp = x; - x = y; - y = tmp; + x ^= y; + y ^= x; + x ^= y; } if (ecma_is_value_string (x)) @@ -127,9 +127,9 @@ ecma_op_abstract_equality_compare (ecma_value_t x, /**< first operand */ } /* Swap values. */ - ecma_value_t tmp = x; - x = y; - y = tmp; + x ^= y; + y ^= x; + x ^= y; } if (ecma_is_value_boolean (y)) @@ -192,7 +192,10 @@ ecma_op_abstract_equality_compare (ecma_value_t x, /**< first operand */ return ecma_make_boolean_value (ecma_bigint_is_equal_to_number (x, ecma_get_number_from_value (y))); } - return ECMA_VALUE_FALSE; + /* Swap values. */ + x ^= y; + y ^= x; + x ^= y; } #endif /* ENABLED (JERRY_BUILTIN_BIGINT) */ diff --git a/jerry-core/parser/js/js-lexer.c b/jerry-core/parser/js/js-lexer.c index c5257bdaa..123f46115 100644 --- a/jerry-core/parser/js/js-lexer.c +++ b/jerry-core/parser/js/js-lexer.c @@ -1474,7 +1474,7 @@ lexer_parse_number (parser_context_t *context_p) /**< context */ #endif /* ENABLED (JERRY_BUILTIN_BIGINT) */ length = (size_t) (source_p - context_p->source_p); - if (length > PARSER_MAXIMUM_IDENT_LENGTH) + if (length > PARSER_MAXIMUM_STRING_LENGTH) { parser_raise_error (context_p, PARSER_ERR_NUMBER_TOO_LONG); } diff --git a/jerry-core/parser/js/js-parser-expr.c b/jerry-core/parser/js/js-parser-expr.c index 9e62c3028..aa1105517 100644 --- a/jerry-core/parser/js/js-parser-expr.c +++ b/jerry-core/parser/js/js-parser-expr.c @@ -1883,6 +1883,12 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */ { is_negative_number = !is_negative_number; } +#if ENABLED (JERRY_BUILTIN_BIGINT) + else if (JERRY_LIKELY (context_p->token.extra_value == LEXER_NUMBER_BIGINT)) + { + break; + } +#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */ parser_stack_pop_uint8 (context_p); } while (context_p->stack_top_uint8 == LEXER_PLUS diff --git a/jerry-core/vm/opcodes-ecma-arithmetics.c b/jerry-core/vm/opcodes-ecma-arithmetics.c index e0e7f76b6..1bed3d827 100644 --- a/jerry-core/vm/opcodes-ecma-arithmetics.c +++ b/jerry-core/vm/opcodes-ecma-arithmetics.c @@ -134,11 +134,13 @@ do_number_arithmetic (number_arithmetic_op op, /**< number arithmetic operation ret_value = ecma_bigint_div_mod (left_value, right_value, true); break; } - default: +#if ENABLED (JERRY_ESNEXT) + case NUMBER_ARITHMETIC_EXPONENTIATION: { - ret_value = ecma_raise_common_error (ECMA_ERR_MSG ("Not supported BigInt operation")); + ret_value = ecma_bigint_pow (left_value, right_value); break; } +#endif /* ENABLED (JERRY_ESNEXT) */ } ecma_free_value (left_value); diff --git a/tests/jerry/es.next/bigint1.js b/tests/jerry/es.next/bigint1.js index 47f24cad1..c68a69436 100644 --- a/tests/jerry/es.next/bigint1.js +++ b/tests/jerry/es.next/bigint1.js @@ -227,6 +227,16 @@ check_result16(BigInt("0x8fef5fcfffef5fcfffef5fcfffef5fcff") >> BigInt("51"), "1 check_result16(BigInt("0x8fef5fcfffef5fcfffef5fcfffef5fcff") >> BigInt("63"), "11fdebf9fffdebf9ff") check_result16(BigInt("0x8fef5fcfffef5fcfffef5fcfffef5fcff") >> BigInt("64"), "8fef5fcfffef5fcff") +check_result16(-BigInt("0xff") >> BigInt("8"), "-1") +check_result16(-BigInt("0xff") >> BigInt("1000"), "-1") +check_result16(-BigInt("0xff") >> BigInt("7"), "-2") +check_result16(-BigInt("0xff00000000") >> BigInt("32"), "-ff") +check_result16(-BigInt("0xff80000000") >> BigInt("32"), "-100") +check_result16(-BigInt("0xff00000000000000000000000000000000") >> BigInt("128"), "-ff") +check_result16(-BigInt("0xff80000000000000000000000000000000") >> BigInt("128"), "-100") +check_result16(-BigInt("0xfe00000000000000000000000000000000") >> BigInt("129"), "-7f") +check_result16(-BigInt("0xff00000000000000000000000000000000") >> BigInt("129"), "-80") + check_result16(BigInt("0x8fef5fcfffef5fcfffef5fcfffef5fcff") >> BigInt("10000000000000000000000000"), "0") try { diff --git a/tests/jerry/es.next/bigint8.js b/tests/jerry/es.next/bigint8.js new file mode 100644 index 000000000..bfe8e8245 --- /dev/null +++ b/tests/jerry/es.next/bigint8.js @@ -0,0 +1,55 @@ +/* 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. + */ + +// Exponentiation + +try { + 12n ** -7n + assert(false) +} catch (e) { + assert(e instanceof RangeError) +} + +assert((0n ** 0n) === 1n) +assert((1n ** 0n) === 1n) +assert(((-2n) ** 0n) === 1n) +assert((1000000000000000000000000000000000n ** 0n) === 1n) +assert(((-1000000000000000000000000000000000n) ** 0n) === 1n) + +assert((1n ** 1n) === 1n) +assert((1n ** 10000000000000000000000000000000n) === 1n) +assert(((-1n) ** 1n) === -1n) +assert(((-1n) ** 10000000000000000000000000000000n) === 1n) +assert(((-1n) ** 10000000000000000000000000000001n) === -1n) + +assert((2n ** 10n) === 1024n) +assert((2n ** 11n) === 2048n) +assert(((-2n) ** 10n) === 1024n) +assert(((-2n) ** 11n) === -2048n) +assert((2n ** 64n) === 0x10000000000000000n) +assert((2n ** 65n) === 0x20000000000000000n) +assert(((-2n) ** 64n) === 0x10000000000000000n) +assert(((-2n) ** 65n) === -0x20000000000000000n) + +assert((2n ** 190n) === 0x400000000000000000000000000000000000000000000000n) +assert((2n ** 191n) === 0x800000000000000000000000000000000000000000000000n) +assert(((-2n) ** 190n) === 0x400000000000000000000000000000000000000000000000n) +assert(((-2n) ** 191n) === -0x800000000000000000000000000000000000000000000000n) + +assert((103n ** 32n) === 25750827556851106532658069028441289322166445432839581773436522241n) +assert((103n ** 31n) === 250008034532535014880175427460595041962781023619801764790645847n) +assert(((-79n) ** 32n) === 5297450670659957549009604563595170759963655420038456036451841n) +assert(((-79n) ** 31n) === -67056337603290601886197526121457857721058929367575392866479n) + diff --git a/tests/test262-esnext-excludelist.xml b/tests/test262-esnext-excludelist.xml index 9c0fa66a9..907c809ba 100644 --- a/tests/test262-esnext-excludelist.xml +++ b/tests/test262-esnext-excludelist.xml @@ -658,7 +658,6 @@ - @@ -6134,9 +6133,6 @@ - - - @@ -6547,15 +6543,7 @@ - - - - - - - - @@ -6591,24 +6579,11 @@ - - - - - - - - - - - - - @@ -6777,9 +6752,6 @@ - - - @@ -6800,7 +6772,6 @@ -