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
This commit is contained in:
Zoltan Herczeg
2020-08-04 14:16:38 +02:00
committed by GitHub
parent be9dbeffdb
commit b5a96c9eca
16 changed files with 481 additions and 215 deletions
+7 -10
View File
@@ -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
+178 -16
View File
@@ -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);
@@ -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);
+19 -10
View File
@@ -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 */
/**
+15 -2
View File
@@ -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);
+2 -2
View File
@@ -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))
{