From b5a96c9ecaff2038b19ce904c3b61977aab509c4 Mon Sep 17 00:00:00 2001 From: Zoltan Herczeg Date: Tue, 4 Aug 2020 14:16:38 +0200 Subject: [PATCH] Implement BigInt literal parsing in the parser. (#4089) Support octal literals for BigInts. JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com --- jerry-core/api/jerry-snapshot.c | 3 + jerry-core/ecma/base/ecma-globals.h | 17 +- jerry-core/ecma/base/ecma-literal-storage.c | 194 +++++++++++++++++-- jerry-core/ecma/base/ecma-literal-storage.h | 3 + jerry-core/ecma/operations/ecma-bigint.c | 29 ++- jerry-core/ecma/operations/ecma-bigint.h | 17 +- jerry-core/ecma/operations/ecma-comparison.c | 4 +- jerry-core/include/jerryscript-snapshot.h | 2 +- jerry-core/jcontext/jcontext.h | 3 + jerry-core/parser/js/common.c | 111 ++++++++--- jerry-core/parser/js/js-lexer.c | 136 +++++++++---- jerry-core/parser/js/js-lexer.h | 3 + jerry-core/parser/js/js-parser-util.c | 6 + jerry-core/parser/js/js-parser.h | 3 + tests/jerry/es.next/bigint5.js | 57 ++++++ tests/test262-esnext-excludelist.xml | 108 ----------- 16 files changed, 481 insertions(+), 215 deletions(-) create mode 100644 tests/jerry/es.next/bigint5.js diff --git a/jerry-core/api/jerry-snapshot.c b/jerry-core/api/jerry-snapshot.c index 65e279a0a..036a3e509 100644 --- a/jerry-core/api/jerry-snapshot.c +++ b/jerry-core/api/jerry-snapshot.c @@ -477,6 +477,9 @@ jerry_snapshot_set_offsets (uint32_t *buffer_p, /**< buffer */ for (uint32_t i = 0; i < const_literal_end; i++) { if (ecma_is_value_string (literal_start_p[i]) +#if ENABLED (JERRY_BUILTIN_BIGINT) + || ecma_is_value_bigint (literal_start_p[i]) +#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */ || ecma_is_value_float_number (literal_start_p[i])) { lit_mem_to_snapshot_id_map_entry_t *current_p = lit_map_p; diff --git a/jerry-core/ecma/base/ecma-globals.h b/jerry-core/ecma/base/ecma-globals.h index 06af59c74..a800c4ad0 100644 --- a/jerry-core/ecma/base/ecma-globals.h +++ b/jerry-core/ecma/base/ecma-globals.h @@ -1578,11 +1578,17 @@ typedef enum ((ecma_string_container_t) ((string_desc_p)->refs_and_container & ECMA_STRING_CONTAINER_MASK)) /** - * Checks whether the reference counter is 1. + * Checks whether the reference counter is 1 of a string. */ #define ECMA_STRING_IS_REF_EQUALS_TO_ONE(string_desc_p) \ (((string_desc_p)->refs_and_container >> 4) == 1) +/** + * Checks whether the reference counter is 1 of an extended primitive. + */ +#define ECMA_EXTENDED_PRIMITIVE_IS_REF_EQUALS_TO_ONE(extended_primitive_p) \ + (((extended_primitive_p)->refs_and_type >> 3) == 1) + /** * ECMA string-value descriptor */ @@ -1780,15 +1786,6 @@ typedef struct jmem_cpointer_t values[ECMA_LIT_STORAGE_VALUE_COUNT]; /**< list of values */ } ecma_lit_storage_item_t; -/** - * Number storage item - */ -typedef struct -{ - jmem_cpointer_t next_cp; /**< cpointer ot next item */ - jmem_cpointer_t values[ECMA_LIT_STORAGE_VALUE_COUNT]; /**< list of values */ -} ecma_number_storage_item_t; - #if ENABLED (JERRY_LCACHE) /** * Container of an LCache entry identifier diff --git a/jerry-core/ecma/base/ecma-literal-storage.c b/jerry-core/ecma/base/ecma-literal-storage.c index 99d6833f3..1b0caa2c1 100644 --- a/jerry-core/ecma/base/ecma-literal-storage.c +++ b/jerry-core/ecma/base/ecma-literal-storage.c @@ -14,6 +14,8 @@ */ #include "ecma-alloc.h" +#include "ecma-bigint.h" +#include "ecma-big-uint.h" #include "ecma-literal-storage.h" #include "ecma-helpers.h" #include "jcontext.h" @@ -87,28 +89,59 @@ ecma_free_string_list (jmem_cpointer_t string_list_cp) /**< string list */ * Free number list */ static void -ecma_free_number_list (jmem_cpointer_t number_list_cp) /**< string list */ +ecma_free_number_list (jmem_cpointer_t number_list_cp) /**< number list */ { while (number_list_cp != JMEM_CP_NULL) { - ecma_number_storage_item_t *number_list_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_number_storage_item_t, - number_list_cp); + ecma_lit_storage_item_t *number_list_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_lit_storage_item_t, + number_list_cp); for (int i = 0; i < ECMA_LIT_STORAGE_VALUE_COUNT; i++) { if (number_list_p->values[i] != JMEM_CP_NULL) { - ecma_number_t *num_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_number_t, number_list_p->values[i]); - ecma_dealloc_number (num_p); + ecma_dealloc_number (JMEM_CP_GET_NON_NULL_POINTER (ecma_number_t, number_list_p->values[i])); } } jmem_cpointer_t next_item_cp = number_list_p->next_cp; - jmem_pools_free (number_list_p, sizeof (ecma_number_storage_item_t)); + jmem_pools_free (number_list_p, sizeof (ecma_lit_storage_item_t)); number_list_cp = next_item_cp; } } /* ecma_free_number_list */ +#if ENABLED (JERRY_BUILTIN_BIGINT) + +/** + * Free bigint list + */ +static void +ecma_free_bigint_list (jmem_cpointer_t bigint_list_cp) /**< bigint list */ +{ + while (bigint_list_cp != JMEM_CP_NULL) + { + ecma_lit_storage_item_t *bigint_list_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_lit_storage_item_t, + bigint_list_cp); + + for (int i = 0; i < ECMA_LIT_STORAGE_VALUE_COUNT; i++) + { + if (bigint_list_p->values[i] != JMEM_CP_NULL) + { + ecma_extended_primitive_t *bigint_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_extended_primitive_t, + bigint_list_p->values[i]); + JERRY_ASSERT (ECMA_EXTENDED_PRIMITIVE_IS_REF_EQUALS_TO_ONE (bigint_p)); + ecma_deref_bigint (bigint_p); + } + } + + jmem_cpointer_t next_item_cp = bigint_list_p->next_cp; + jmem_pools_free (bigint_list_p, sizeof (ecma_lit_storage_item_t)); + bigint_list_cp = next_item_cp; + } +} /* ecma_free_bigint_list */ + +#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */ + /** * Finalize literal storage */ @@ -120,6 +153,9 @@ ecma_finalize_lit_storage (void) #endif /* ENABLED (JERRY_ESNEXT) */ ecma_free_string_list (JERRY_CONTEXT (string_list_first_cp)); ecma_free_number_list (JERRY_CONTEXT (number_list_first_cp)); +#if ENABLED (JERRY_BUILTIN_BIGINT) + ecma_free_bigint_list (JERRY_CONTEXT (bigint_list_first_cp)); +#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */ } /* ecma_finalize_lit_storage */ /** @@ -199,7 +235,7 @@ ecma_find_or_create_literal_string (const lit_utf8_byte_t *chars_p, /**< string /** * Find or create a literal number. * - * @return ecma_string_t compressed pointer + * @return ecma value */ ecma_value_t ecma_find_or_create_literal_number (ecma_number_t number_arg) /**< number to be searched */ @@ -218,8 +254,8 @@ ecma_find_or_create_literal_number (ecma_number_t number_arg) /**< number to be while (number_list_cp != JMEM_CP_NULL) { - ecma_number_storage_item_t *number_list_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_number_storage_item_t, - number_list_cp); + ecma_lit_storage_item_t *number_list_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_lit_storage_item_t, + number_list_cp); for (int i = 0; i < ECMA_LIT_STORAGE_VALUE_COUNT; i++) { @@ -246,10 +282,8 @@ ecma_find_or_create_literal_number (ecma_number_t number_arg) /**< number to be number_list_cp = number_list_p->next_cp; } - ecma_number_t *num_p = ecma_get_pointer_from_float_value (num); - jmem_cpointer_t result; - JMEM_CP_SET_NON_NULL_POINTER (result, num_p); + JMEM_CP_SET_NON_NULL_POINTER (result, ecma_get_pointer_from_float_value (num)); if (empty_cpointer_p != NULL) { @@ -257,8 +291,8 @@ ecma_find_or_create_literal_number (ecma_number_t number_arg) /**< number to be return num; } - ecma_number_storage_item_t *new_item_p; - new_item_p = (ecma_number_storage_item_t *) jmem_pools_alloc (sizeof (ecma_number_storage_item_t)); + ecma_lit_storage_item_t *new_item_p; + new_item_p = (ecma_lit_storage_item_t *) jmem_pools_alloc (sizeof (ecma_lit_storage_item_t)); new_item_p->values[0] = result; for (int i = 1; i < ECMA_LIT_STORAGE_VALUE_COUNT; i++) @@ -272,6 +306,78 @@ ecma_find_or_create_literal_number (ecma_number_t number_arg) /**< number to be return num; } /* ecma_find_or_create_literal_number */ +#if ENABLED (JERRY_BUILTIN_BIGINT) + +/** + * Find or create a literal BigInt. + * + * @return BigInt value + */ +ecma_value_t +ecma_find_or_create_literal_bigint (ecma_value_t bigint) /**< bigint to be searched */ +{ + JERRY_ASSERT (ecma_is_value_bigint (bigint)); + + jmem_cpointer_t bigint_list_cp = JERRY_CONTEXT (bigint_list_first_cp); + jmem_cpointer_t *empty_cpointer_p = NULL; + + while (bigint_list_cp != JMEM_CP_NULL) + { + ecma_lit_storage_item_t *bigint_list_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_lit_storage_item_t, + bigint_list_cp); + + for (int i = 0; i < ECMA_LIT_STORAGE_VALUE_COUNT; i++) + { + if (bigint_list_p->values[i] == JMEM_CP_NULL) + { + if (empty_cpointer_p == NULL) + { + empty_cpointer_p = bigint_list_p->values + i; + } + } + else + { + ecma_extended_primitive_t *other_bigint_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_extended_primitive_t, + bigint_list_p->values[i]); + ecma_value_t other_bigint = ecma_make_extended_primitive_value (other_bigint_p, ECMA_TYPE_BIGINT); + + if (ecma_bigint_is_equal_to_bigint (bigint, other_bigint)) + { + ecma_free_value (bigint); + return other_bigint; + } + } + } + + bigint_list_cp = bigint_list_p->next_cp; + } + + jmem_cpointer_t result; + JMEM_CP_SET_NON_NULL_POINTER (result, ecma_get_extended_primitive_from_value (bigint)); + + if (empty_cpointer_p != NULL) + { + *empty_cpointer_p = result; + return bigint; + } + + ecma_lit_storage_item_t *new_item_p; + new_item_p = (ecma_lit_storage_item_t *) jmem_pools_alloc (sizeof (ecma_lit_storage_item_t)); + + new_item_p->values[0] = result; + for (int i = 1; i < ECMA_LIT_STORAGE_VALUE_COUNT; i++) + { + new_item_p->values[i] = JMEM_CP_NULL; + } + + new_item_p->next_cp = JERRY_CONTEXT (bigint_list_first_cp); + JMEM_CP_SET_NON_NULL_POINTER (JERRY_CONTEXT (bigint_list_first_cp), new_item_p); + + return bigint; +} /* ecma_find_or_create_literal_bigint */ + +#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */ + /** * Log2 of snapshot literal alignment. */ @@ -285,13 +391,20 @@ ecma_find_or_create_literal_number (ecma_number_t number_arg) /**< number to be /** * Literal offset shift. */ -#define JERRY_SNAPSHOT_LITERAL_SHIFT (ECMA_VALUE_SHIFT + 1) +#define JERRY_SNAPSHOT_LITERAL_SHIFT (ECMA_VALUE_SHIFT + 2) /** * Literal value is number. */ #define JERRY_SNAPSHOT_LITERAL_IS_NUMBER (1u << ECMA_VALUE_SHIFT) +#if ENABLED (JERRY_BUILTIN_BIGINT) +/** + * Literal value is BigInt. + */ +#define JERRY_SNAPSHOT_LITERAL_IS_BIGINT (2u << ECMA_VALUE_SHIFT) +#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */ + #if ENABLED (JERRY_SNAPSHOT_SAVE) /** @@ -301,7 +414,11 @@ void ecma_save_literals_append_value (ecma_value_t value, /**< value to be appen ecma_collection_t *lit_pool_p) /**< list of known values */ { /* Unlike direct numbers, direct strings are converted to character literals. */ - if (!ecma_is_value_string (value) && !ecma_is_value_float_number (value)) + if (!ecma_is_value_string (value) +#if ENABLED (JERRY_BUILTIN_BIGINT) + && !ecma_is_value_bigint (value) +#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */ + && !ecma_is_value_float_number (value)) { return; } @@ -436,6 +553,15 @@ ecma_save_literals_for_snapshot (ecma_collection_t *lit_pool_p, /**< list of kno { lit_table_size += (uint32_t) sizeof (ecma_number_t); } +#if ENABLED (JERRY_BUILTIN_BIGINT) + else if (ecma_is_value_bigint (lit_buffer_p[i])) + { + ecma_extended_primitive_t *bigint_p = ecma_get_extended_primitive_from_value (lit_buffer_p[i]); + + lit_table_size += (uint32_t) JERRY_ALIGNUP (sizeof (uint32_t) + ECMA_BIGINT_GET_SIZE (bigint_p), + JERRY_SNAPSHOT_LITERAL_ALIGNMENT); + } +#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */ else { ecma_string_t *string_p = ecma_get_string_from_value (lit_buffer_p[i]); @@ -486,6 +612,20 @@ ecma_save_literals_for_snapshot (ecma_collection_t *lit_pool_p, /**< list of kno length = JERRY_ALIGNUP (sizeof (ecma_number_t), JERRY_SNAPSHOT_LITERAL_ALIGNMENT); } +#if ENABLED (JERRY_BUILTIN_BIGINT) + else if (ecma_is_value_bigint (lit_buffer_p[i])) + { + map_p->literal_offset |= JERRY_SNAPSHOT_LITERAL_IS_BIGINT; + + ecma_extended_primitive_t *bigint_p = ecma_get_extended_primitive_from_value (lit_buffer_p[i]); + uint32_t size = ECMA_BIGINT_GET_SIZE (bigint_p); + + memcpy (destination_p, &bigint_p->u.bigint_sign_and_size, sizeof (uint32_t)); + memcpy (destination_p + sizeof (uint32_t), ECMA_BIGINT_GET_DIGITS (bigint_p, 0), size); + + length = JERRY_ALIGNUP (sizeof (uint32_t) + size, JERRY_SNAPSHOT_LITERAL_ALIGNMENT); + } +#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */ else { ecma_string_t *string_p = ecma_get_string_from_value (lit_buffer_p[i]); @@ -533,6 +673,28 @@ ecma_snapshot_get_literal (const uint8_t *literal_base_p, /**< literal start */ return ecma_find_or_create_literal_number (num); } +#if ENABLED (JERRY_BUILTIN_BIGINT) + if (literal_value & JERRY_SNAPSHOT_LITERAL_IS_BIGINT) + { + uint32_t bigint_sign_and_size = *(uint32_t *) literal_p; + uint32_t size = bigint_sign_and_size & ~(uint32_t) (sizeof (ecma_bigint_digit_t) - 1); + + ecma_extended_primitive_t *bigint_p = ecma_bigint_create (size); + + if (bigint_p == NULL) + { + jerry_fatal (ERR_OUT_OF_MEMORY); + } + + /* Only the sign bit can differ. */ + JERRY_ASSERT (bigint_p->u.bigint_sign_and_size == (bigint_sign_and_size & ~(uint32_t) ECMA_BIGINT_SIGN)); + + bigint_p->u.bigint_sign_and_size = bigint_sign_and_size; + memcpy (ECMA_BIGINT_GET_DIGITS (bigint_p, 0), literal_p + sizeof (uint32_t), size); + return ecma_find_or_create_literal_bigint (ecma_make_extended_primitive_value (bigint_p, ECMA_TYPE_BIGINT)); + } +#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */ + uint16_t length = *(const uint16_t *) literal_p; return ecma_find_or_create_literal_string (literal_p + sizeof (uint16_t), length); diff --git a/jerry-core/ecma/base/ecma-literal-storage.h b/jerry-core/ecma/base/ecma-literal-storage.h index bac05b7b1..2ecdcd57d 100644 --- a/jerry-core/ecma/base/ecma-literal-storage.h +++ b/jerry-core/ecma/base/ecma-literal-storage.h @@ -42,6 +42,9 @@ void ecma_finalize_lit_storage (void); ecma_value_t ecma_find_or_create_literal_string (const lit_utf8_byte_t *chars_p, lit_utf8_size_t size); ecma_value_t ecma_find_or_create_literal_number (ecma_number_t number_arg); +#if ENABLED (JERRY_BUILTIN_BIGINT) +ecma_value_t ecma_find_or_create_literal_bigint (ecma_value_t bigint); +#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */ #if ENABLED (JERRY_SNAPSHOT_SAVE) void ecma_save_literals_append_value (ecma_value_t value, ecma_collection_t *lit_pool_p); diff --git a/jerry-core/ecma/operations/ecma-bigint.c b/jerry-core/ecma/operations/ecma-bigint.c index 6d446b94a..f9590b050 100644 --- a/jerry-core/ecma/operations/ecma-bigint.c +++ b/jerry-core/ecma/operations/ecma-bigint.c @@ -36,17 +36,16 @@ ecma_bigint_raise_memory_error (void) /** * Parse a string and create a BigInt value * - * @return ecma BigInt value or ECMA_VALUE_ERROR + * @return ecma BigInt value or a special value allowed by the option flags * 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 */ - bool throw_syntax_error) /**< true, if syntax errors should be thrown - * otherwise ECMA_VALUE_FALSE is returned on syntax error */ + uint32_t options) /**< ecma_bigint_parse_string_options_t option bits */ { ecma_bigint_digit_t radix = 10; - uint32_t sign = 0; + uint32_t sign = (options & ECMA_BIGINT_PARSE_SET_NEGATIVE) ? ECMA_BIGINT_SIGN : 0; if (size >= 3 && string_p[0] == LIT_CHAR_0) { @@ -56,6 +55,12 @@ ecma_bigint_parse_string (const lit_utf8_byte_t *string_p, /**< string represena string_p += 2; size -= 2; } + else if (string_p[1] == LIT_CHAR_LOWERCASE_O || string_p[1] == LIT_CHAR_UPPERCASE_O) + { + radix = 8; + string_p += 2; + size -= 2; + } else if (string_p[1] == LIT_CHAR_LOWERCASE_B || string_p[1] == LIT_CHAR_UPPERCASE_B) { radix = 2; @@ -79,7 +84,7 @@ ecma_bigint_parse_string (const lit_utf8_byte_t *string_p, /**< string represena } else if (size == 0) { - if (!throw_syntax_error) + if (options & ECMA_BIGINT_PARSE_DISALLOW_SYNTAX_ERROR) { return ECMA_VALUE_FALSE; } @@ -97,6 +102,7 @@ ecma_bigint_parse_string (const lit_utf8_byte_t *string_p, /**< string represena if (string_p == string_end_p) { + sign = 0; result_p = ecma_bigint_create (0); } else @@ -126,7 +132,7 @@ ecma_bigint_parse_string (const lit_utf8_byte_t *string_p, /**< string represena ecma_deref_bigint (result_p); } - if (!throw_syntax_error) + if (options & ECMA_BIGINT_PARSE_DISALLOW_SYNTAX_ERROR) { return ECMA_VALUE_FALSE; } @@ -145,6 +151,10 @@ ecma_bigint_parse_string (const lit_utf8_byte_t *string_p, /**< string represena if (JERRY_UNLIKELY (result_p == NULL)) { + if (options & ECMA_BIGINT_PARSE_DISALLOW_MEMORY_ERROR) + { + return ECMA_VALUE_NULL; + } return ecma_bigint_raise_memory_error (); } @@ -160,13 +170,12 @@ ecma_bigint_parse_string (const lit_utf8_byte_t *string_p, /**< string represena */ ecma_value_t ecma_bigint_parse_string_value (ecma_value_t string, /**< ecma string */ - bool throw_syntax_error) /**< true, if syntax errors should be thrown - * otherwise ECMA_VALUE_FALSE is returned on syntax error */ + uint32_t options) /**< ecma_bigint_parse_string_options_t option bits */ { JERRY_ASSERT (ecma_is_value_string (string)); ECMA_STRING_TO_UTF8_STRING (ecma_get_string_from_value (string), string_buffer_p, string_buffer_size); - ecma_value_t result = ecma_bigint_parse_string (string_buffer_p, string_buffer_size, throw_syntax_error); + ecma_value_t result = ecma_bigint_parse_string (string_buffer_p, string_buffer_size, options); ECMA_FINALIZE_UTF8_STRING (string_buffer_p, string_buffer_size); return result; @@ -415,7 +424,7 @@ ecma_bigint_to_bigint (ecma_value_t value) /**< any value */ return ecma_raise_type_error (ECMA_ERR_MSG ("Value cannot be converted to BigInt")); } - return ecma_bigint_parse_string_value (value, true); + return ecma_bigint_parse_string_value (value, ECMA_BIGINT_PARSE_NO_OPTIONS); } /* ecma_bigint_to_bigint */ /** diff --git a/jerry-core/ecma/operations/ecma-bigint.h b/jerry-core/ecma/operations/ecma-bigint.h index e48cffe6c..f75f51380 100644 --- a/jerry-core/ecma/operations/ecma-bigint.h +++ b/jerry-core/ecma/operations/ecma-bigint.h @@ -25,9 +25,22 @@ */ #define ECMA_BIGINT_SIGN 0x1 +/** + * Flags for ecma_bigint_parse_string. + */ +typedef enum +{ + ECMA_BIGINT_PARSE_NO_OPTIONS = 0, /**< no options */ + ECMA_BIGINT_PARSE_SET_NEGATIVE = (1 << 0), /**< return with a negative BigInt value */ + ECMA_BIGINT_PARSE_DISALLOW_SYNTAX_ERROR = (1 << 1), /**< don't throw SyntaxError, + * return with ECMA_VALUE_FALSE */ + ECMA_BIGINT_PARSE_DISALLOW_MEMORY_ERROR = (1 << 2), /**< don't throw out-of-memory error, + * return with ECMA_VALUE_NULL instead */ +} ecma_bigint_parse_string_options_t; + ecma_value_t ecma_bigint_parse_string (const lit_utf8_byte_t *string_p, lit_utf8_size_t size, - bool throw_syntax_error); -ecma_value_t ecma_bigint_parse_string_value (ecma_value_t string, bool throw_syntax_error); + 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); diff --git a/jerry-core/ecma/operations/ecma-comparison.c b/jerry-core/ecma/operations/ecma-comparison.c index 89e7e73b5..def2a8d31 100644 --- a/jerry-core/ecma/operations/ecma-comparison.c +++ b/jerry-core/ecma/operations/ecma-comparison.c @@ -171,7 +171,7 @@ ecma_op_abstract_equality_compare (ecma_value_t x, /**< first operand */ if (ecma_is_value_string (y)) { - ecma_value_t bigint = ecma_bigint_parse_string_value (y, false); + ecma_value_t bigint = ecma_bigint_parse_string_value (y, ECMA_BIGINT_PARSE_DISALLOW_SYNTAX_ERROR); if (ECMA_IS_VALUE_ERROR (bigint) || bigint == ECMA_VALUE_FALSE) @@ -483,7 +483,7 @@ ecma_op_abstract_relational_compare (ecma_value_t x, /**< first operand */ } else if (ecma_is_value_string (py)) { - ret_value = ecma_bigint_parse_string_value (py, false); + ret_value = ecma_bigint_parse_string_value (py, ECMA_BIGINT_PARSE_DISALLOW_SYNTAX_ERROR); if (!ECMA_IS_VALUE_ERROR (ret_value)) { diff --git a/jerry-core/include/jerryscript-snapshot.h b/jerry-core/include/jerryscript-snapshot.h index d5e30b42b..922e76b05 100644 --- a/jerry-core/include/jerryscript-snapshot.h +++ b/jerry-core/include/jerryscript-snapshot.h @@ -30,7 +30,7 @@ extern "C" /** * Jerry snapshot format version. */ -#define JERRY_SNAPSHOT_VERSION (54u) +#define JERRY_SNAPSHOT_VERSION (55u) /** * Flags for jerry_generate_snapshot and jerry_generate_function_snapshot. diff --git a/jerry-core/jcontext/jcontext.h b/jerry-core/jcontext/jcontext.h index 69c9dd579..9d50248d9 100644 --- a/jerry-core/jcontext/jcontext.h +++ b/jerry-core/jcontext/jcontext.h @@ -142,6 +142,9 @@ struct jerry_context_t jmem_cpointer_t symbol_list_first_cp; /**< first item of the global symbol list */ #endif /* ENABLED (JERRY_ESNEXT) */ jmem_cpointer_t number_list_first_cp; /**< first item of the literal number list */ +#if ENABLED (JERRY_BUILTIN_BIGINT) + jmem_cpointer_t bigint_list_first_cp; /**< first item of the literal bigint list */ +#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */ jmem_cpointer_t ecma_global_env_cp; /**< global lexical environment */ #if ENABLED (JERRY_ESNEXT) jmem_cpointer_t ecma_global_scope_cp; /**< global lexical scope */ diff --git a/jerry-core/parser/js/common.c b/jerry-core/parser/js/common.c index 5aeca88dd..fcdff21cc 100644 --- a/jerry-core/parser/js/common.c +++ b/jerry-core/parser/js/common.c @@ -15,6 +15,9 @@ #include "common.h" #include "ecma-helpers.h" +#include "ecma-big-uint.h" +#include "ecma-bigint.h" +#include "lit-char-helpers.h" #if ENABLED (JERRY_PARSER) @@ -77,41 +80,93 @@ util_print_number (ecma_number_t num_p) /**< number to print */ JERRY_DEBUG_MSG ("%s", str_buf); } /* util_print_number */ +#if ENABLED (JERRY_BUILTIN_BIGINT) + +/** + * Debug utility to print a bigint. + */ +static void +util_print_bigint (ecma_value_t bigint) /**< bigint to print */ +{ + ecma_extended_primitive_t *bigint_p = ecma_get_extended_primitive_from_value (bigint); + + if (ECMA_BIGINT_GET_SIZE (bigint_p) == 0) + { + JERRY_DEBUG_MSG ("0"); + return; + } + + uint32_t char_start_p, char_size_p; + lit_utf8_byte_t *string_buffer_p = ecma_big_uint_to_string (bigint_p, 10, &char_start_p, &char_size_p); + + if (JERRY_UNLIKELY (string_buffer_p == NULL)) + { + JERRY_DEBUG_MSG (""); + return; + } + + 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; + } + + util_print_chars (string_buffer_p + char_start_p, char_size_p - char_start_p); + jmem_heap_free_block (string_buffer_p, char_size_p); +} /* util_print_bigint */ + +#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */ + /** * Print literal. */ void util_print_literal (lexer_literal_t *literal_p) /**< literal */ { - if (literal_p->type == LEXER_IDENT_LITERAL) + switch (literal_p->type) { - JERRY_DEBUG_MSG ("ident("); - util_print_chars (literal_p->u.char_p, literal_p->prop.length); - } - else if (literal_p->type == LEXER_FUNCTION_LITERAL) - { - JERRY_DEBUG_MSG ("function"); - return; - } - else if (literal_p->type == LEXER_STRING_LITERAL) - { - JERRY_DEBUG_MSG ("string("); - util_print_chars (literal_p->u.char_p, literal_p->prop.length); - } - else if (literal_p->type == LEXER_NUMBER_LITERAL) - { - JERRY_DEBUG_MSG ("number("); - util_print_number (ecma_get_number_from_value (literal_p->u.value)); - } - else if (literal_p->type == LEXER_REGEXP_LITERAL) - { - JERRY_DEBUG_MSG ("regexp"); - return; - } - else - { - JERRY_DEBUG_MSG ("unknown"); - return; + case LEXER_IDENT_LITERAL: + { + JERRY_DEBUG_MSG ("ident("); + util_print_chars (literal_p->u.char_p, literal_p->prop.length); + break; + } + case LEXER_FUNCTION_LITERAL: + { + JERRY_DEBUG_MSG ("function"); + return; + } + case LEXER_STRING_LITERAL: + { + JERRY_DEBUG_MSG ("string("); + util_print_chars (literal_p->u.char_p, literal_p->prop.length); + break; + } + case LEXER_NUMBER_LITERAL: + { +#if ENABLED (JERRY_BUILTIN_BIGINT) + if (ecma_is_value_bigint (literal_p->u.value)) + { + JERRY_DEBUG_MSG ("bigint("); + util_print_bigint (literal_p->u.value); + break; + } +#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */ + JERRY_DEBUG_MSG ("number("); + util_print_number (ecma_get_number_from_value (literal_p->u.value)); + break; + } + case LEXER_REGEXP_LITERAL: + { + JERRY_DEBUG_MSG ("regexp"); + return; + } + default: + { + JERRY_DEBUG_MSG ("unknown"); + return; + } } JERRY_DEBUG_MSG (")"); diff --git a/jerry-core/parser/js/js-lexer.c b/jerry-core/parser/js/js-lexer.c index 406bc73d0..d7895e2a9 100644 --- a/jerry-core/parser/js/js-lexer.c +++ b/jerry-core/parser/js/js-lexer.c @@ -14,6 +14,7 @@ */ #include "ecma-alloc.h" +#include "ecma-bigint.h" #include "ecma-helpers.h" #include "ecma-function-object.h" #include "ecma-literal-storage.h" @@ -1303,6 +1304,9 @@ lexer_parse_number (parser_context_t *context_p) /**< context */ const uint8_t *source_p = context_p->source_p; const uint8_t *source_end_p = context_p->source_end_p; bool can_be_float = false; +#if ENABLED (JERRY_BUILTIN_BIGINT) + bool can_be_bigint = true; +#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */ size_t length; context_p->token.type = LEXER_LITERAL; @@ -1337,8 +1341,6 @@ lexer_parse_number (parser_context_t *context_p) /**< context */ else if (LEXER_TO_ASCII_LOWERCASE (source_p[1]) == LIT_CHAR_LOWERCASE_O) { context_p->token.extra_value = LEXER_NUMBER_OCTAL; - context_p->token.lit_location.char_p++; - context_p->source_p++; source_p += 2; if (source_p >= source_end_p @@ -1354,6 +1356,9 @@ lexer_parse_number (parser_context_t *context_p) /**< context */ && source_p[1] <= LIT_CHAR_7) { context_p->token.extra_value = LEXER_NUMBER_OCTAL; +#if ENABLED (JERRY_BUILTIN_BIGINT) + can_be_bigint = false; +#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */ if (context_p->status_flags & PARSER_IS_STRICT) { @@ -1371,8 +1376,6 @@ lexer_parse_number (parser_context_t *context_p) /**< context */ else if (LEXER_TO_ASCII_LOWERCASE (source_p[1]) == LIT_CHAR_LOWERCASE_B) { context_p->token.extra_value = LEXER_NUMBER_BINARY; - context_p->token.lit_location.char_p++; - context_p->source_p++; source_p += 2; if (source_p >= source_end_p @@ -1413,6 +1416,10 @@ lexer_parse_number (parser_context_t *context_p) /**< context */ && source_p[0] == LIT_CHAR_DOT) { source_p++; +#if ENABLED (JERRY_BUILTIN_BIGINT) + can_be_bigint = false; +#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */ + while (source_p < source_end_p && source_p[0] >= LIT_CHAR_0 && source_p[0] <= LIT_CHAR_9) @@ -1425,6 +1432,9 @@ lexer_parse_number (parser_context_t *context_p) /**< context */ && LEXER_TO_ASCII_LOWERCASE (source_p[0]) == LIT_CHAR_LOWERCASE_E) { source_p++; +#if ENABLED (JERRY_BUILTIN_BIGINT) + can_be_bigint = false; +#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */ if (source_p < source_end_p && (source_p[0] == LIT_CHAR_PLUS || source_p[0] == LIT_CHAR_MINUS)) @@ -1449,6 +1459,18 @@ lexer_parse_number (parser_context_t *context_p) /**< context */ } } +#if ENABLED (JERRY_BUILTIN_BIGINT) + if (source_p < source_end_p && source_p[0] == LIT_CHAR_LOWERCASE_N) + { + if (!can_be_bigint) + { + parser_raise_error (context_p, PARSER_ERR_INVALID_BIGINT); + } + context_p->token.extra_value = LEXER_NUMBER_BIGINT; + source_p++; + } +#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */ + length = (size_t) (source_p - context_p->source_p); if (length > PARSER_MAXIMUM_IDENT_LENGTH) { @@ -2515,56 +2537,94 @@ lexer_construct_number_object (parser_context_t *context_p, /**< context */ { parser_list_iterator_t literal_iterator; lexer_literal_t *literal_p; + ecma_value_t lit_value; ecma_number_t num; uint32_t literal_index = 0; prop_length_t length = context_p->token.lit_location.length; - if (context_p->token.extra_value < LEXER_NUMBER_OCTAL) +#if ENABLED (JERRY_BUILTIN_BIGINT) + if (JERRY_LIKELY (context_p->token.extra_value != LEXER_NUMBER_BIGINT)) { - num = ecma_utf8_string_to_number (context_p->token.lit_location.char_p, - length); +#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */ + if (context_p->token.extra_value < LEXER_NUMBER_OCTAL) + { + num = ecma_utf8_string_to_number (context_p->token.lit_location.char_p, + length); + } + else + { + const uint8_t *src_p = context_p->token.lit_location.char_p; + const uint8_t *src_end_p = src_p + length - 1; + ecma_number_t multiplier = 8.0; + + JERRY_ASSERT (src_p[0] == LIT_CHAR_0); + +#if ENABLED (JERRY_ESNEXT) + if (context_p->token.extra_value == LEXER_NUMBER_BINARY) + { + src_p++; + multiplier = 2.0; + } + else if (LEXER_TO_ASCII_LOWERCASE (src_p[1]) == LIT_CHAR_LOWERCASE_O) + { + src_p++; + } +#endif /* ENABLED (JERRY_ESNEXT) */ + + num = 0; + do + { + num = num * multiplier + (ecma_number_t) (*(++src_p) - LIT_CHAR_0); + } + while (src_p < src_end_p); + } + + if (is_expr) + { + int32_t int_num = (int32_t) num; + + if (int_num == num + && int_num <= CBC_PUSH_NUMBER_BYTE_RANGE_END + && (int_num != 0 || !is_negative_number)) + { + context_p->lit_object.index = (uint16_t) int_num; + return true; + } + } + + if (is_negative_number) + { + num = -num; + } + + lit_value = ecma_find_or_create_literal_number (num); +#if ENABLED (JERRY_BUILTIN_BIGINT) } else { - const uint8_t *src_p = context_p->token.lit_location.char_p; - const uint8_t *src_end_p = src_p + length - 1; - ecma_number_t multiplier = 8.0; + uint32_t options = ECMA_BIGINT_PARSE_DISALLOW_SYNTAX_ERROR | ECMA_BIGINT_PARSE_DISALLOW_MEMORY_ERROR; -#if ENABLED (JERRY_ESNEXT) - if (context_p->token.extra_value == LEXER_NUMBER_BINARY) + if (is_negative_number) { - multiplier = 2.0; + options |= ECMA_BIGINT_PARSE_SET_NEGATIVE; } -#endif /* ENABLED (JERRY_ESNEXT) */ - num = 0; - do + JERRY_ASSERT (length >= 2); + lit_value = ecma_bigint_parse_string (context_p->token.lit_location.char_p, + (lit_utf8_size_t) (length - 1), + options); + + JERRY_ASSERT (lit_value != ECMA_VALUE_FALSE && !ECMA_IS_VALUE_ERROR (lit_value)); + + if (lit_value == ECMA_VALUE_NULL) { - src_p++; - num = num * multiplier + (ecma_number_t) (*src_p - LIT_CHAR_0); + parser_raise_error (context_p, PARSER_ERR_OUT_OF_MEMORY); } - while (src_p < src_end_p); + + lit_value = ecma_find_or_create_literal_bigint (lit_value); } +#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */ - if (is_expr) - { - int32_t int_num = (int32_t) num; - - if (int_num == num - && int_num <= CBC_PUSH_NUMBER_BYTE_RANGE_END - && (int_num != 0 || !is_negative_number)) - { - context_p->lit_object.index = (uint16_t) int_num; - return true; - } - } - - if (is_negative_number) - { - num = -num; - } - - ecma_value_t lit_value = ecma_find_or_create_literal_number (num); parser_list_iterator_init (&context_p->literal_pool, &literal_iterator); while ((literal_p = (lexer_literal_t *) parser_list_iterator_next (&literal_iterator)) != NULL) diff --git a/jerry-core/parser/js/js-lexer.h b/jerry-core/parser/js/js-lexer.h index f646f84db..aef5079fc 100644 --- a/jerry-core/parser/js/js-lexer.h +++ b/jerry-core/parser/js/js-lexer.h @@ -279,6 +279,9 @@ typedef enum LEXER_NUMBER_HEXADECIMAL, /**< hexadecimal number */ LEXER_NUMBER_OCTAL, /**< octal number */ LEXER_NUMBER_BINARY, /**< binary number */ +#if ENABLED (JERRY_BUILTIN_BIGINT) + LEXER_NUMBER_BIGINT, /**< bigint number */ +#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */ } lexer_number_type_t; /** diff --git a/jerry-core/parser/js/js-parser-util.c b/jerry-core/parser/js/js-parser-util.c index e9e2711a7..c4ee90b00 100644 --- a/jerry-core/parser/js/js-parser-util.c +++ b/jerry-core/parser/js/js-parser-util.c @@ -869,6 +869,12 @@ parser_error_to_string (parser_error_t error) /**< error code */ { return "Identifier cannot start after a number."; } +#if ENABLED (JERRY_BUILTIN_BIGINT) + case PARSER_ERR_INVALID_BIGINT: + { + return "Number is not a valid BigInt."; + } +#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */ case PARSER_ERR_INVALID_REGEXP: { return "Invalid regular expression."; diff --git a/jerry-core/parser/js/js-parser.h b/jerry-core/parser/js/js-parser.h index 46bc5fcde..0f569e833 100644 --- a/jerry-core/parser/js/js-parser.h +++ b/jerry-core/parser/js/js-parser.h @@ -56,6 +56,9 @@ typedef enum PARSER_ERR_INVALID_NUMBER, /**< invalid number literal */ PARSER_ERR_MISSING_EXPONENT, /**< missing exponent */ PARSER_ERR_IDENTIFIER_AFTER_NUMBER, /**< identifier start after number */ +#if ENABLED (JERRY_BUILTIN_BIGINT) + PARSER_ERR_INVALID_BIGINT, /**< number is not a valid BigInt */ +#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */ PARSER_ERR_INVALID_REGEXP, /**< invalid regular expression */ PARSER_ERR_UNKNOWN_REGEXP_FLAG, /**< unknown regexp flag */ diff --git a/tests/jerry/es.next/bigint5.js b/tests/jerry/es.next/bigint5.js new file mode 100644 index 000000000..a4d2fa138 --- /dev/null +++ b/tests/jerry/es.next/bigint5.js @@ -0,0 +1,57 @@ +/* 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. + */ + +function check_syntax_error(code) +{ + try { + eval(code) + assert(false) + } catch (e) { + assert(e instanceof SyntaxError) + } +} + +check_syntax_error("1N") +check_syntax_error("3.5n") +check_syntax_error("3e10n") +check_syntax_error("3e+10n") +check_syntax_error("0xn") +check_syntax_error("0on") +check_syntax_error("0bn") +check_syntax_error("0777n") +check_syntax_error("00777n") +check_syntax_error("0x1 n") + +assert(0n == 0n) +assert(0n == -0n) +assert(12n == 12n) +assert(123456789012345678901234567890123456789012345678901234567890n == 123456789012345678901234567890123456789012345678901234567890n) +assert(12n != -12n) +assert(123456789012345678901234567890123456789012345678901234567890n != -123456789012345678901234567890123456789012345678901234567890n) + +assert(0xffn == 255n) +assert(0o77777n == 0x7fffn) +assert(255n.toString(16) == "ff") + +var o = { 12n : "data" } +assert(o[12] === "data") + +var c = class C { static 19n () { return "BigInt" } } +assert(c[19]() === "BigInt") + +function f(p, q) { + assert(p + q === 5000n) +} +f(-1000n, 6000n) diff --git a/tests/test262-esnext-excludelist.xml b/tests/test262-esnext-excludelist.xml index e97347ebc..b2d639b57 100644 --- a/tests/test262-esnext-excludelist.xml +++ b/tests/test262-esnext-excludelist.xml @@ -699,24 +699,13 @@ - - - - - - - - - - - @@ -826,7 +815,6 @@ - @@ -1087,7 +1075,6 @@ - @@ -1128,8 +1115,6 @@ - - @@ -1162,7 +1147,6 @@ - @@ -2027,8 +2011,6 @@ - - @@ -3164,7 +3146,6 @@ - @@ -4136,12 +4117,6 @@ - - - - - - @@ -4318,22 +4293,16 @@ - - - - - - @@ -6270,16 +6239,6 @@ - - - - - - - - - - @@ -6694,18 +6653,12 @@ - - - - - - @@ -6746,44 +6699,23 @@ - - - - - - - - - - - - - - - - - - - - - @@ -6832,17 +6764,6 @@ - - - - - - - - - - - @@ -6887,7 +6808,6 @@ - @@ -6971,33 +6891,9 @@ - - - - - - - - - - - - - - - - - - - - - - - - @@ -7019,11 +6915,7 @@ - - - -