From bdb39f1f03d52c500adb8b36f490f0bda3d26795 Mon Sep 17 00:00:00 2001 From: Zoltan Herczeg Date: Tue, 4 Aug 2020 16:53:38 +0200 Subject: [PATCH] Implement binary bitwise BigInt operators (#4105) JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com --- jerry-core/ecma/operations/ecma-big-uint.c | 368 +++++++++++++++++++-- jerry-core/ecma/operations/ecma-big-uint.h | 37 +++ jerry-core/ecma/operations/ecma-bigint.c | 194 +++++++++++ jerry-core/ecma/operations/ecma-bigint.h | 4 + jerry-core/vm/opcodes-ecma-bitwise.c | 17 +- tests/jerry/es.next/bigint6.js | 54 +++ tests/test262-esnext-excludelist.xml | 16 - 7 files changed, 647 insertions(+), 43 deletions(-) create mode 100644 tests/jerry/es.next/bigint6.js diff --git a/jerry-core/ecma/operations/ecma-big-uint.c b/jerry-core/ecma/operations/ecma-big-uint.c index a6023a07c..e33fac983 100644 --- a/jerry-core/ecma/operations/ecma-big-uint.c +++ b/jerry-core/ecma/operations/ecma-big-uint.c @@ -26,6 +26,9 @@ JERRY_STATIC_ASSERT (sizeof (ecma_bigint_two_digits_t) == 2 * sizeof (ecma_bigin JERRY_STATIC_ASSERT ((1 << ECMA_BIGINT_DIGIT_SHIFT) == (8 * sizeof (ecma_bigint_digit_t)), ecma_bigint_digit_shift_is_incorrect); +JERRY_STATIC_ASSERT ((ECMA_BIG_UINT_BITWISE_DECREASE_LEFT << 1) == ECMA_BIG_UINT_BITWISE_DECREASE_RIGHT, + ecma_big_uint_bitwise_left_and_right_sub_option_bits_must_follow_each_other); + /** * Create a new BigInt value * @@ -64,12 +67,12 @@ ecma_bigint_create (uint32_t size) /**< size of the new BigInt value */ } /* ecma_bigint_create */ /** - * Extend a BigInt value with a new data prefix value + * Extend a BigUInt value with a new data prefix value * - * @return new BigInt value, NULL on error + * @return new BigUInt value, NULL on error */ ecma_extended_primitive_t * -ecma_big_uint_extend (ecma_extended_primitive_t *value_p, /**< BigInt value */ +ecma_big_uint_extend (ecma_extended_primitive_t *value_p, /**< BigUInt value */ ecma_bigint_digit_t digit) /**< new digit */ { uint32_t old_size = ECMA_BIGINT_GET_SIZE (value_p); @@ -96,6 +99,39 @@ ecma_big_uint_extend (ecma_extended_primitive_t *value_p, /**< BigInt value */ return result_p; } /* ecma_big_uint_extend */ +/** + * Discard the high-order digits of a BigUInt + * + * @return 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 */ +{ + JERRY_ASSERT (value_p != NULL); + JERRY_ASSERT (ECMA_BIGINT_GET_SIZE (value_p) > new_size); + + if (ECMA_BIGINT_SIZE_IS_ODD (new_size) + && ((new_size + sizeof (ecma_bigint_digit_t)) == ECMA_BIGINT_GET_SIZE (value_p))) + { + value_p->u.bigint_sign_and_size -= (uint32_t) sizeof (ecma_bigint_digit_t); + return value_p; + } + + ecma_extended_primitive_t *result_p = ecma_bigint_create (new_size); + + if (JERRY_UNLIKELY (result_p == NULL)) + { + ecma_deref_bigint (value_p); + return NULL; + } + + memcpy (ECMA_BIGINT_GET_DIGITS (result_p, 0), ECMA_BIGINT_GET_DIGITS (value_p, 0), new_size); + ecma_deref_bigint (value_p); + + return result_p; +} /* ecma_big_uint_shrink_value */ + /** * Compare two BigUInt numbers * @@ -530,28 +566,8 @@ ecma_big_uint_sub (ecma_extended_primitive_t *left_value_p, /**< left BigUInt va } while (new_end_p[-1] == 0); - ecma_bigint_digit_t *result_data_p = ECMA_BIGINT_GET_DIGITS (result_p, 0); - uint32_t old_size = ECMA_BIGINT_GET_SIZE (result_p); - uint32_t new_size = (uint32_t) ((uint8_t *) new_end_p - (uint8_t *) result_data_p); - - if (ECMA_BIGINT_SIZE_IS_ODD (new_size) && ((new_size + sizeof (ecma_bigint_digit_t)) == old_size)) - { - result_p->u.bigint_sign_and_size -= (uint32_t) sizeof (ecma_bigint_digit_t); - return result_p; - } - - ecma_extended_primitive_t *new_result_p = ecma_bigint_create (new_size); - - if (JERRY_UNLIKELY (new_result_p == NULL)) - { - ecma_deref_bigint (result_p); - return NULL; - } - - memcpy (ECMA_BIGINT_GET_DIGITS (new_result_p, 0), result_data_p, new_size); - ecma_deref_bigint (result_p); - - return new_result_p; + 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)); } /* ecma_big_uint_sub */ /** @@ -1156,6 +1172,12 @@ ecma_big_uint_shift_left (ecma_extended_primitive_t *left_value_p, /**< left Big } ecma_extended_primitive_t *result_value_p = ecma_bigint_create (result_size); + + if (JERRY_UNLIKELY (result_value_p == NULL)) + { + return NULL; + } + ecma_bigint_digit_t *left_p = ECMA_BIGINT_GET_DIGITS (left_value_p, 0); ecma_bigint_digit_t *result_p = ECMA_BIGINT_GET_DIGITS (result_value_p, 0); @@ -1195,7 +1217,7 @@ ecma_big_uint_shift_left (ecma_extended_primitive_t *left_value_p, /**< left Big /** * Shift right BigInt values by an uint32 value * - * return new BigInt value, NULL on error + * @return new BigInt value, NULL on error */ ecma_extended_primitive_t * ecma_big_uint_shift_right (ecma_extended_primitive_t *left_value_p, /**< left BigUInt value */ @@ -1227,6 +1249,11 @@ ecma_big_uint_shift_right (ecma_extended_primitive_t *left_value_p, /**< left B uint32_t size = left_size - crop_size; ecma_extended_primitive_t *result_value_p = ecma_bigint_create (size); + if (JERRY_UNLIKELY (result_value_p == NULL)) + { + return NULL; + } + if (shift_right == 0) { memcpy (ECMA_BIGINT_GET_DIGITS (result_value_p, 0), ECMA_BIGINT_GET_DIGITS (left_value_p, crop_size), size); @@ -1249,4 +1276,293 @@ ecma_big_uint_shift_right (ecma_extended_primitive_t *left_value_p, /**< left B return 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 */ + +/** + * Helper function for bitwise operations which increases the result by 1 + * + * @return new BigInt 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 */ + +/** + * Perform bitwise operations on two BigUInt numbers + * + * return new BigInt value, NULL on error + */ +ecma_extended_primitive_t * +ecma_big_uint_bitwise_op (uint32_t operation_and_options, /**< bitwise operation type and options */ + ecma_extended_primitive_t *left_value_p, /**< left BigUInt value */ + ecma_extended_primitive_t *right_value_p) /**< right BigUInt value */ +{ + uint32_t left_size = ECMA_BIGINT_GET_SIZE (left_value_p); + uint32_t right_size = ECMA_BIGINT_GET_SIZE (right_value_p); + + JERRY_ASSERT (left_size > 0 && ECMA_BIGINT_GET_LAST_DIGIT (left_value_p, left_size) != 0); + JERRY_ASSERT (right_size > 0 && ECMA_BIGINT_GET_LAST_DIGIT (right_value_p, right_size) != 0); + + uint32_t operation_type = ECMA_BIGINT_BITWISE_GET_OPERATION_TYPE (operation_and_options); + + switch (operation_type) + { + case ECMA_BIG_UINT_BITWISE_AND: + { + if (left_size > right_size) + { + left_size = right_size; + break; + } + /* FALLTHRU */ + } + case ECMA_BIG_UINT_BITWISE_AND_NOT: + { + if (right_size > left_size) + { + right_size = left_size; + } + break; + } + default: + { + JERRY_ASSERT (operation_type == ECMA_BIG_UINT_BITWISE_OR + || operation_type == ECMA_BIG_UINT_BITWISE_XOR); + + if (right_size <= left_size) + { + break; + } + + /* Swap values. */ + ecma_extended_primitive_t *tmp_value_p = left_value_p; + left_value_p = right_value_p; + right_value_p = tmp_value_p; + + uint32_t tmp_size = left_size; + left_size = right_size; + right_size = tmp_size; + + uint32_t decrease_opts = (operation_and_options & ECMA_BIG_UINT_BITWISE_DECREASE_BOTH); + + /* When exactly one bit is set, invert both bits. */ + if (decrease_opts >= ECMA_BIG_UINT_BITWISE_DECREASE_LEFT + && decrease_opts <= ECMA_BIG_UINT_BITWISE_DECREASE_RIGHT) + { + operation_and_options ^= ECMA_BIG_UINT_BITWISE_DECREASE_BOTH; + } + break; + } + } + + ecma_extended_primitive_t *result_value_p = ecma_bigint_create (left_size); + + if (JERRY_UNLIKELY (result_value_p == NULL)) + { + return NULL; + } + + ecma_bigint_digit_t *left_p = ECMA_BIGINT_GET_DIGITS (left_value_p, 0); + ecma_bigint_digit_t *right_p = ECMA_BIGINT_GET_DIGITS (right_value_p, 0); + ecma_bigint_digit_t *result_p = ECMA_BIGINT_GET_DIGITS (result_value_p, 0); + ecma_bigint_digit_t *result_end_p = ECMA_BIGINT_GET_DIGITS (result_value_p, right_size); + + if (!(operation_and_options & ECMA_BIG_UINT_BITWISE_DECREASE_BOTH)) + { + JERRY_ASSERT (!(operation_and_options & ECMA_BIG_UINT_BITWISE_INCREASE_RESULT)); + + if (operation_type == ECMA_BIG_UINT_BITWISE_AND) + { + do + { + *result_p++ = *left_p++ & *right_p++; + } + while (result_p < result_end_p); + + if (result_p[-1] == 0) + { + return ecma_big_uint_normalize_result (result_value_p, result_p); + } + return result_value_p; + } + + if (operation_type == ECMA_BIG_UINT_BITWISE_OR) + { + do + { + *result_p++ = *left_p++ | *right_p++; + } + while (result_p < result_end_p); + + if (left_size > right_size) + { + memcpy (result_p, left_p, left_size - right_size); + } + return result_value_p; + } + + JERRY_ASSERT (operation_type == ECMA_BIG_UINT_BITWISE_XOR); + + do + { + *result_p++ = *left_p++ ^ *right_p++; + } + while (result_p < result_end_p); + + if (left_size > right_size) + { + memcpy (result_p, left_p, left_size - right_size); + return result_value_p; + } + + if (result_p[-1] == 0) + { + return ecma_big_uint_normalize_result (result_value_p, result_p); + } + return result_value_p; + } + + uint32_t left_carry = 0, right_carry = 0; + + if (operation_and_options & ECMA_BIG_UINT_BITWISE_DECREASE_LEFT) + { + left_carry = 1; + } + + if (operation_and_options & ECMA_BIG_UINT_BITWISE_DECREASE_RIGHT) + { + right_carry = 1; + } + + do + { + ecma_bigint_digit_t left = (*left_p++) - left_carry; + + if (left != ~((ecma_bigint_digit_t) 0)) + { + left_carry = 0; + } + + ecma_bigint_digit_t right = (*right_p++) - right_carry; + + if (right != ~((ecma_bigint_digit_t) 0)) + { + right_carry = 0; + } + + switch (operation_type) + { + case ECMA_BIG_UINT_BITWISE_AND: + { + *result_p++ = left & right; + break; + } + case ECMA_BIG_UINT_BITWISE_OR: + { + *result_p++ = left | right; + break; + } + case ECMA_BIG_UINT_BITWISE_XOR: + { + *result_p++ = left ^ right; + break; + } + default: + { + JERRY_ASSERT (operation_type == ECMA_BIG_UINT_BITWISE_AND_NOT); + *result_p++ = left & ~right; + break; + } + } + } + while (result_p < result_end_p); + + if (operation_type != ECMA_BIG_UINT_BITWISE_AND) + { + result_end_p = ECMA_BIGINT_GET_DIGITS (result_value_p, left_size); + + if (left_carry > 0) + { + while (*left_p == 0) + { + *result_p++ = ~((ecma_bigint_digit_t) 0); + left_p++; + + JERRY_ASSERT (result_p < result_end_p); + } + + *result_p++ = *left_p++ - 1; + } + + if (result_p < result_end_p) + { + memcpy (result_p, left_p, (size_t) ((uint8_t *) result_end_p - (uint8_t *) result_p)); + + if (operation_and_options & ECMA_BIG_UINT_BITWISE_INCREASE_RESULT) + { + return ecma_big_uint_increase_result (result_value_p); + } + return result_value_p; + } + } + + if (operation_and_options & ECMA_BIG_UINT_BITWISE_INCREASE_RESULT) + { + return ecma_big_uint_increase_result (result_value_p); + } + + if (result_p[-1] == 0) + { + return ecma_big_uint_normalize_result (result_value_p, result_p); + } + return result_value_p; +} /* ecma_big_uint_bitwise_op */ + #endif /* ENABLED (JERRY_BUILTIN_BIGINT) */ diff --git a/jerry-core/ecma/operations/ecma-big-uint.h b/jerry-core/ecma/operations/ecma-big-uint.h index a8e16af8b..de4434d38 100644 --- a/jerry-core/ecma/operations/ecma-big-uint.h +++ b/jerry-core/ecma/operations/ecma-big-uint.h @@ -59,6 +59,39 @@ 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))) +/** + * Bitwise operation types. + */ +typedef enum +{ + ECMA_BIG_UINT_BITWISE_AND, /**< bitwise 'and' operation */ + ECMA_BIG_UINT_BITWISE_OR, /**< bitwise 'or' operation */ + ECMA_BIG_UINT_BITWISE_XOR, /**< bitwise 'xor' operation */ + ECMA_BIG_UINT_BITWISE_AND_NOT, /**< bitwise 'and not' operation */ +} ecma_big_uint_bitwise_operation_types_t; + +/** + * Returns with the type of the operation. + */ +#define ECMA_BIGINT_BITWISE_GET_OPERATION_TYPE(operation_and_options) \ + ((operation_and_options) & 0xf) + +/** + * Options for bitwise operations. + */ +typedef enum +{ + ECMA_BIG_UINT_BITWISE_DECREASE_LEFT = (1 << 4), /**< subtract 1 from left value */ + ECMA_BIG_UINT_BITWISE_DECREASE_RIGHT = (1 << 5), /**< subtract 1 from right value */ + ECMA_BIG_UINT_BITWISE_INCREASE_RESULT = (1 << 6), /**< add 1 to the result */ +} ecma_big_uint_bitwise_options_t; + +/** + * Subtract 1 from both left and right values. + */ +#define ECMA_BIG_UINT_BITWISE_DECREASE_BOTH \ + (ECMA_BIG_UINT_BITWISE_DECREASE_LEFT | ECMA_BIG_UINT_BITWISE_DECREASE_RIGHT) + 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); @@ -83,6 +116,10 @@ ecma_extended_primitive_t *ecma_big_uint_div_mod (ecma_extended_primitive_t *div 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_bitwise_op (uint32_t operation_and_options, + ecma_extended_primitive_t *left_value_p, + ecma_extended_primitive_t *right_value_p); + #endif /* ENABLED (JERRY_BUILTIN_BIGINT) */ #endif /* ECMA_BIG_UINT_H */ diff --git a/jerry-core/ecma/operations/ecma-bigint.c b/jerry-core/ecma/operations/ecma-bigint.c index f9590b050..8da8be0a6 100644 --- a/jerry-core/ecma/operations/ecma-bigint.c +++ b/jerry-core/ecma/operations/ecma-bigint.c @@ -970,4 +970,198 @@ ecma_bigint_shift (ecma_value_t left_value, /**< left BigInt value */ 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 */ + +/** + * Convert the result to an ecma value + * + * @return ecma BigInt value or ECMA_VALUE_ERROR + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_bigint_bitwise_op (uint32_t operation_and_options, /**< bitwise operation type and options */ + ecma_extended_primitive_t *left_value_p, /**< left BigInt value */ + ecma_extended_primitive_t *right_value_p) /**< right BigInt value */ +{ + ecma_extended_primitive_t *result_p; + result_p = ecma_big_uint_bitwise_op (operation_and_options, left_value_p, right_value_p); + + if (JERRY_UNLIKELY (result_p == NULL)) + { + return ecma_bigint_raise_memory_error (); + } + + if ((operation_and_options & ECMA_BIG_UINT_BITWISE_INCREASE_RESULT) + && ECMA_BIGINT_GET_SIZE (result_p) > 0) + { + result_p->u.bigint_sign_and_size |= ECMA_BIGINT_SIGN; + } + + return ecma_make_extended_primitive_value (result_p, ECMA_TYPE_BIGINT); +} /* ecma_bigint_bitwise_op */ + +/** + * Perform bitwise 'and' operations on two BigUInt numbers + * + * @return ecma BigInt value or ECMA_VALUE_ERROR + * Returned value must be freed with ecma_free_value. + */ +ecma_value_t +ecma_bigint_and (ecma_value_t left_value, /**< left BigInt value */ + ecma_value_t right_value) /**< right BigInt 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_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN)) + { + if (!(right_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN)) + { + return ecma_bigint_bitwise_op (ECMA_BIG_UINT_BITWISE_AND, left_p, right_p); + } + + /* x & (-y) == x & ~(y-1) == x &~ (y-1) */ + uint32_t operation_and_options = ECMA_BIG_UINT_BITWISE_AND_NOT | ECMA_BIG_UINT_BITWISE_DECREASE_RIGHT; + return ecma_bigint_bitwise_op (operation_and_options, left_p, right_p); + } + + if (!(right_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN)) + { + /* (-x) & y == ~(x-1) & y == y &~ (x-1) */ + uint32_t operation_and_options = ECMA_BIG_UINT_BITWISE_AND_NOT | ECMA_BIG_UINT_BITWISE_DECREASE_RIGHT; + return ecma_bigint_bitwise_op (operation_and_options, right_p, left_p); + } + + /* (-x) & (-y) == ~(x-1) & ~(y-1) == ~((x-1) | (y-1)) == -(((x-1) | (y-1)) + 1) */ + uint32_t operation_and_options = (ECMA_BIG_UINT_BITWISE_OR + | ECMA_BIG_UINT_BITWISE_DECREASE_BOTH + | ECMA_BIG_UINT_BITWISE_INCREASE_RESULT); + return ecma_bigint_bitwise_op (operation_and_options, left_p, right_p); +} /* ecma_bigint_and */ + +/** + * Perform bitwise 'or' operations on two BigUInt numbers + * + * @return ecma BigInt value or ECMA_VALUE_ERROR + * Returned value must be freed with ecma_free_value. + */ +ecma_value_t +ecma_bigint_or (ecma_value_t left_value, /**< left BigInt value */ + ecma_value_t right_value) /**< right BigInt 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 (right_p); + return right_value; + } + + if (right_size == 0) + { + ecma_ref_extended_primitive (left_p); + return left_value; + } + + if (!(left_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN)) + { + if (!(right_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN)) + { + return ecma_bigint_bitwise_op (ECMA_BIG_UINT_BITWISE_OR, left_p, right_p); + } + + /* x | (-y) == x | ~(y-1) == ~((y-1) &~ x) == -(((y-1) &~ x) + 1) */ + uint32_t operation_and_options = (ECMA_BIG_UINT_BITWISE_AND_NOT + | ECMA_BIG_UINT_BITWISE_DECREASE_LEFT + | ECMA_BIG_UINT_BITWISE_INCREASE_RESULT); + return ecma_bigint_bitwise_op (operation_and_options, right_p, left_p); + } + + if (!(right_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN)) + { + /* (-x) | y == ~(x-1) | y == ~((x-1) &~ y) == -(((x-1) &~ y) + 1) */ + uint32_t operation_and_options = (ECMA_BIG_UINT_BITWISE_AND_NOT + | ECMA_BIG_UINT_BITWISE_DECREASE_LEFT + | ECMA_BIG_UINT_BITWISE_INCREASE_RESULT); + return ecma_bigint_bitwise_op (operation_and_options, left_p, right_p); + } + + /* (-x) | (-y) == ~(x-1) | ~(y-1) == ~((x-1) & (y-1)) = -(((x-1) & (y-1)) + 1) */ + uint32_t operation_and_options = (ECMA_BIG_UINT_BITWISE_AND + | ECMA_BIG_UINT_BITWISE_DECREASE_BOTH + | ECMA_BIG_UINT_BITWISE_INCREASE_RESULT); + return ecma_bigint_bitwise_op (operation_and_options, left_p, right_p); +} /* ecma_bigint_or */ + +/** + * Perform bitwise 'xor' operations on two BigUInt numbers + * + * @return ecma BigInt value or ECMA_VALUE_ERROR + * Returned value must be freed with ecma_free_value. + */ +ecma_value_t +ecma_bigint_xor (ecma_value_t left_value, /**< left BigInt value */ + ecma_value_t right_value) /**< right BigInt 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 (right_p); + return right_value; + } + + if (right_size == 0) + { + ecma_ref_extended_primitive (left_p); + return left_value; + } + + if (!(left_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN)) + { + if (!(right_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN)) + { + return ecma_bigint_bitwise_op (ECMA_BIG_UINT_BITWISE_XOR, left_p, right_p); + } + + /* x ^ (-y) == x ^ ~(y-1) == ~(x ^ (y-1)) == -((x ^ (y-1)) + 1) */ + uint32_t operation_and_options = (ECMA_BIG_UINT_BITWISE_XOR + | ECMA_BIG_UINT_BITWISE_DECREASE_RIGHT + | ECMA_BIG_UINT_BITWISE_INCREASE_RESULT); + return ecma_bigint_bitwise_op (operation_and_options, left_p, right_p); + } + + if (!(right_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN)) + { + /* (-x) | y == ~(x-1) ^ y == ~((x-1) ^ y) == -(((x-1) ^ y) + 1) */ + uint32_t operation_and_options = (ECMA_BIG_UINT_BITWISE_XOR + | ECMA_BIG_UINT_BITWISE_DECREASE_LEFT + | ECMA_BIG_UINT_BITWISE_INCREASE_RESULT); + return ecma_bigint_bitwise_op (operation_and_options, left_p, right_p); + } + + /* (-x) ^ (-y) == ~(x-1) ^ ~(y-1) == (x-1) ^ (y-1) */ + uint32_t operation_and_options = ECMA_BIG_UINT_BITWISE_XOR | ECMA_BIG_UINT_BITWISE_DECREASE_BOTH; + return ecma_bigint_bitwise_op (operation_and_options, left_p, right_p); +} /* ecma_bigint_xor */ + #endif /* ENABLED (JERRY_BUILTIN_BIGINT) */ diff --git a/jerry-core/ecma/operations/ecma-bigint.h b/jerry-core/ecma/operations/ecma-bigint.h index f75f51380..d617f16a3 100644 --- a/jerry-core/ecma/operations/ecma-bigint.h +++ b/jerry-core/ecma/operations/ecma-bigint.h @@ -56,6 +56,10 @@ 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); +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); +ecma_value_t ecma_bigint_xor (ecma_value_t left_value, ecma_value_t right_value); + #endif /* ENABLED (JERRY_BUILTIN_BIGINT) */ #endif /* ECMA_BIG_INT_H */ diff --git a/jerry-core/vm/opcodes-ecma-bitwise.c b/jerry-core/vm/opcodes-ecma-bitwise.c index 233f306c6..138b2008f 100644 --- a/jerry-core/vm/opcodes-ecma-bitwise.c +++ b/jerry-core/vm/opcodes-ecma-bitwise.c @@ -145,6 +145,21 @@ do_number_bitwise_logic (number_bitwise_logic_op op, /**< number bitwise logic o { switch (op) { + case NUMBER_BITWISE_LOGIC_AND: + { + ret_value = ecma_bigint_and (left_value, right_value); + break; + } + case NUMBER_BITWISE_LOGIC_OR: + { + ret_value = ecma_bigint_or (left_value, right_value); + break; + } + case NUMBER_BITWISE_LOGIC_XOR: + { + ret_value = ecma_bigint_xor (left_value, right_value); + break; + } case NUMBER_BITWISE_SHIFT_LEFT: { ret_value = ecma_bigint_shift (left_value, right_value, true); @@ -157,7 +172,7 @@ do_number_bitwise_logic (number_bitwise_logic_op op, /**< number bitwise logic o } default: { - ret_value = ecma_raise_common_error (ECMA_ERR_MSG ("Not supported BigInt operation")); + ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Not supported BigInt operation")); break; } } diff --git a/tests/jerry/es.next/bigint6.js b/tests/jerry/es.next/bigint6.js new file mode 100644 index 000000000..3270c2abe --- /dev/null +++ b/tests/jerry/es.next/bigint6.js @@ -0,0 +1,54 @@ +/* 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. + */ + +// Test bitwise 'and' operation + +assert((0n & 0n) === 0n) +assert((0x12345678n & 0n) === 0n) +assert((0n & 0x12345678n) === 0n) +assert((0xff00ff00ff00ff00ff00n & 0xff00ff00ff00ff00ffn) === 0n) +assert((0x12345678ffffffff12345678ffffffffn & 0xffff87654321n) === 0x567887654321n) +assert((0xf56cd2479efcdn & 0x56cdf23bc02134e3bdc56f43297be4c27n) === 0x6540004384c05n) +assert((0x45c308bd83cf279n & -0x100000000n) === 0x45c308b00000000n) +assert((-0x10000000000000000n & 0xffffffffffffffffn) === 0n) +assert((-0x11234567890abcdefn & 0xffffffffffffffffffffn) === 0xfffeedcba9876f543211n) +assert((-0x10000000000000n & -0x10000000000000n) === -0x10000000000000n) +assert((-0x100000000000000001n & -0x1n) === -0x100000000000000001n) + +// Test bitwise 'or' operation + +assert((0n | 0n) === 0n) +assert((0x123456789abcdefn | 0n) === 0x123456789abcdefn) +assert((0n | 0x123456789abcdefn) === 0x123456789abcdefn) +assert((0xaa00bb00cc00dd00ee00n | 0xff00ee00dd00cc00bbn) === 0xaaffbbeeccddddcceebbn); +assert((0xfedcba09876543210fedcba09876543210n | 0x7n) === 0xfedcba09876543210fedcba09876543217n) +assert((0x8n | 0xfedcba09876543210fedcba09876543210n) === 0xfedcba09876543210fedcba09876543218n) +assert((-0xc34bd5f946c7a92b69b3a96cd7c2a12n | 0xfcbacfbn) === -0xc34bd5f946c7a92b69b3a96c0340201n) +assert((-0xb314c297ba3n | 0xfeacb00000000n) === -0x1304c297ba3n) +assert((-0x74b186cd308b377cb23n | -0x5cba7935b213cd657d937c42975de63802a7b92cd49an) === -0x74900280200b124c001n) +assert((-0x10000000000000000n | -0x100000000000000000000000000000000n) === -0x10000000000000000n) + +// Test bitwise 'xor' operation + +assert((0n ^ 0n) === 0n) +assert((0x123456789abcdefn ^ 0n) === 0x123456789abcdefn) +assert((0n ^ 0x123456789abcdefn) === 0x123456789abcdefn) +assert((0x74b186cd308b355cb23cd28cd75n ^ 0x74b186cd308b355cb23cd28cd75n) === 0n) +assert((0xff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ffn ^ 0xf0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0fn) === 0xff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff0n) +assert((0x31988644a57e18n ^ 0xb2303b6f2efcb4de7761c01622440f9d985d07dbfe03c9f1n) === 0xb2303b6f2efcb4de7761c01622440f9d986c9f5dbaa6b7e9n) +assert((-0xd858541b8eb3e6ae247b1f84dbd8cc2db66n ^ 0x0811a0e70710fcf965n) === -0xd858541b8eb3e6ae24fa058aaba9c3e2201n) +assert((0x38d00faa3f33n ^ -0x89c40cdc4a064dcd8b3663feb322026dn) === -0x89c40cdc4a064dcd8b365b2ebc883d60n) +assert((-0x66cb3001b88361a25b8715922n ^ -0x66cb3001b88361a25b8715922n) === 0n) +assert((-0x893bff556397300afe6411d8727c0aaffn ^ -0xef69f24dfcd1447397d62217c6ad2n) === 0x893b103c91daccdbba17860e506bcc02fn) diff --git a/tests/test262-esnext-excludelist.xml b/tests/test262-esnext-excludelist.xml index 5f3a4a7b4..414fe6a0a 100644 --- a/tests/test262-esnext-excludelist.xml +++ b/tests/test262-esnext-excludelist.xml @@ -4259,20 +4259,8 @@ - - - - - - - - - - - - @@ -6882,10 +6870,6 @@ - - - -