From b9560b7c70f3191f1a06318108afe680c3805ec0 Mon Sep 17 00:00:00 2001 From: Zoltan Herczeg Date: Wed, 10 Jan 2018 15:55:56 +0100 Subject: [PATCH] Rework ecma collection. (#2153) Greatly simplify the iterator part and make it compatible with 32 bit cpointers. JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com --- jerry-core/api/jerry.c | 13 +- jerry-core/ecma/base/ecma-alloc.c | 2 - jerry-core/ecma/base/ecma-alloc.h | 24 -- jerry-core/ecma/base/ecma-gc.c | 22 +- jerry-core/ecma/base/ecma-globals.h | 45 ++- jerry-core/ecma/base/ecma-helpers-value.c | 60 ++- .../base/ecma-helpers-values-collection.c | 352 ++++++------------ jerry-core/ecma/base/ecma-helpers.h | 64 ++-- .../ecma-builtin-array-prototype.c | 25 +- .../ecma-builtin-helpers-json.c | 46 +-- .../builtin-objects/ecma-builtin-helpers.c | 9 +- .../builtin-objects/ecma-builtin-helpers.h | 13 +- .../ecma/builtin-objects/ecma-builtin-json.c | 62 +-- .../builtin-objects/ecma-builtin-object.c | 57 ++- .../ecma-builtin-regexp-prototype.c | 6 +- jerry-core/ecma/operations/ecma-objects.c | 60 +-- .../ecma/operations/ecma-promise-object.c | 34 +- .../ecma/operations/ecma-regexp-object.c | 4 +- jerry-core/parser/js/byte-code.h | 2 +- jerry-core/vm/opcodes.c | 21 +- jerry-core/vm/opcodes.h | 2 +- jerry-core/vm/vm-stack.c | 27 +- jerry-core/vm/vm.c | 82 ++-- 23 files changed, 511 insertions(+), 521 deletions(-) diff --git a/jerry-core/api/jerry.c b/jerry-core/api/jerry.c index 58351d16f..515edc519 100644 --- a/jerry-core/api/jerry.c +++ b/jerry-core/api/jerry.c @@ -2419,19 +2419,18 @@ jerry_foreach_object_property (const jerry_value_t obj_val, /**< object value */ return false; } - ecma_collection_iterator_t names_iter; ecma_object_t *object_p = ecma_get_object_from_value (obj_value); ecma_collection_header_t *names_p = ecma_op_object_get_property_names (object_p, false, true, true); - ecma_collection_iterator_init (&names_iter, names_p); + ecma_value_t *ecma_value_p = ecma_collection_iterator_init (names_p); ecma_value_t property_value = ECMA_VALUE_EMPTY; bool continuous = true; - while (continuous - && ecma_collection_iterator_next (&names_iter)) + while (continuous && ecma_value_p != NULL) { - ecma_string_t *property_name_p = ecma_get_string_from_value (*names_iter.current_value_p); + ecma_string_t *property_name_p = ecma_get_string_from_value (*ecma_value_p); + property_value = ecma_op_object_get (object_p, property_name_p); if (ECMA_IS_VALUE_ERROR (property_value)) @@ -2439,8 +2438,10 @@ jerry_foreach_object_property (const jerry_value_t obj_val, /**< object value */ break; } - continuous = foreach_p (*names_iter.current_value_p, property_value, user_data_p); + continuous = foreach_p (*ecma_value_p, property_value, user_data_p); ecma_free_value (property_value); + + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); } ecma_free_values_collection (names_p, true); diff --git a/jerry-core/ecma/base/ecma-alloc.c b/jerry-core/ecma/base/ecma-alloc.c index 004c6d880..4b7b5d56b 100644 --- a/jerry-core/ecma/base/ecma-alloc.c +++ b/jerry-core/ecma/base/ecma-alloc.c @@ -81,8 +81,6 @@ JERRY_STATIC_ASSERT (sizeof (ecma_extended_object_t) - sizeof (ecma_object_t) <= DEALLOC (ecma_type) DECLARE_ROUTINES_FOR (number) -DECLARE_ROUTINES_FOR (collection_header) -DECLARE_ROUTINES_FOR (collection_chunk) /** * Allocate memory for ecma-object diff --git a/jerry-core/ecma/base/ecma-alloc.h b/jerry-core/ecma/base/ecma-alloc.h index 22d0d066d..512aee84a 100644 --- a/jerry-core/ecma/base/ecma-alloc.h +++ b/jerry-core/ecma/base/ecma-alloc.h @@ -61,30 +61,6 @@ ecma_number_t *ecma_alloc_number (void); */ void ecma_dealloc_number (ecma_number_t *number_p); -/** - * Allocate memory for header of a collection - * - * @return pointer to allocated memory - */ -ecma_collection_header_t *ecma_alloc_collection_header (void); - -/** - * Dealloc memory from the collection's header - */ -void ecma_dealloc_collection_header (ecma_collection_header_t *collection_header_p); - -/** - * Allocate memory for non-first chunk of a collection - * - * @return pointer to allocated memory - */ -ecma_collection_chunk_t *ecma_alloc_collection_chunk (void); - -/** - * Dealloc memory from non-first chunk of a collection - */ -void ecma_dealloc_collection_chunk (ecma_collection_chunk_t *collection_chunk_p); - /** * Allocate memory for ecma-string descriptor * diff --git a/jerry-core/ecma/base/ecma-gc.c b/jerry-core/ecma/base/ecma-gc.c index 1f5bf2a4d..979769405 100644 --- a/jerry-core/ecma/base/ecma-gc.c +++ b/jerry-core/ecma/base/ecma-gc.c @@ -257,19 +257,21 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ } /* Mark all reactions. */ - ecma_collection_iterator_t iter; - ecma_collection_iterator_init (&iter, ((ecma_promise_object_t *) ext_object_p)->fulfill_reactions); + ecma_value_t *ecma_value_p; + ecma_value_p = ecma_collection_iterator_init (((ecma_promise_object_t *) ext_object_p)->fulfill_reactions); - while (ecma_collection_iterator_next (&iter)) + while (ecma_value_p != NULL) { - ecma_gc_set_object_visited (ecma_get_object_from_value (*iter.current_value_p)); + ecma_gc_set_object_visited (ecma_get_object_from_value (*ecma_value_p)); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); } - ecma_collection_iterator_init (&iter, ((ecma_promise_object_t *) ext_object_p)->reject_reactions); + ecma_value_p = ecma_collection_iterator_init (((ecma_promise_object_t *) ext_object_p)->reject_reactions); - while (ecma_collection_iterator_next (&iter)) + while (ecma_value_p != NULL) { - ecma_gc_set_object_visited (ecma_get_object_from_value (*iter.current_value_p)); + ecma_gc_set_object_visited (ecma_get_object_from_value (*ecma_value_p)); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); } } @@ -554,8 +556,10 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ case LIT_MAGIC_STRING_REGEXP_UL: { - ecma_compiled_code_t *bytecode_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t, - ext_object_p->u.class_prop.u.value); + ecma_compiled_code_t *bytecode_p; + bytecode_p = ECMA_GET_INTERNAL_VALUE_ANY_POINTER (ecma_compiled_code_t, + ext_object_p->u.class_prop.u.value); + if (bytecode_p != NULL) { ecma_bytecode_deref (bytecode_p); diff --git a/jerry-core/ecma/base/ecma-globals.h b/jerry-core/ecma/base/ecma-globals.h index 9620a995e..22659271c 100644 --- a/jerry-core/ecma/base/ecma-globals.h +++ b/jerry-core/ecma/base/ecma-globals.h @@ -74,6 +74,7 @@ typedef enum ECMA_TYPE_STRING = 2, /**< pointer to description of a string */ ECMA_TYPE_OBJECT = 3, /**< pointer to description of an object */ ECMA_TYPE_ERROR = 7, /**< pointer to description of an error reference */ + ECMA_TYPE_COLLECTION_CHUNK = ECMA_TYPE_ERROR, /**< pointer to description of a collection chunk */ ECMA_TYPE___MAX = ECMA_TYPE_ERROR /** highest value for ecma types */ } ecma_type_t; @@ -1018,31 +1019,47 @@ typedef double ecma_number_t; */ #define ECMA_STRING_NOT_ARRAY_INDEX UINT32_MAX +/* + * Ecma-collection: a growable list of ecma-values. Currently the list is + * a chain list, where appending new items at the end is cheap operation. + * + * Enumerating elements is also cheap, since each page is terminated by a + * special ecma-value: collection-type. This type has a pointer to the next + * chunk. The last chunk is terminated by a NULL pointer. There when the + * next value is requested from the iterator it simply checks the next + * memory location. If it is not a collection-type value, it returns with + * the value. Otherwise it gets the start address of the next chunk, and + * return the value there. + * + * The collection-type value is always the last item of a collection chunk, + * even if the chunk is not completely filled with values (this is only true + * for the last chunk). Each chunk must have at least one non collection-type + * value as well. + */ + /** * Description of a collection's header. */ typedef struct { - /** Number of elements in the collection */ - ecma_length_t unit_number; - - /** Compressed pointer to first chunk with collection's data */ - jmem_cpointer_t first_chunk_cp; - - /** Compressed pointer to last chunk with collection's data */ - jmem_cpointer_t last_chunk_cp; + jmem_cpointer_t first_chunk_cp; /**< compressed pointer to first chunk with collection's data */ + jmem_cpointer_t last_chunk_cp; /**< compressed pointer to last chunk with collection's data */ + ecma_length_t item_count; /**< number of items in the collection */ } ecma_collection_header_t; /** - * Description of non-first chunk in a collection's chain of chunks + * Maximum number of items stored by a collection chunk (excluding the last collection-type value). + */ +#define ECMA_COLLECTION_CHUNK_ITEMS 5 + +/** + * Collection chunk item. */ typedef struct { - /** Characters */ - lit_utf8_byte_t data[ sizeof (uint64_t) - sizeof (jmem_cpointer_t) ]; - - /** Compressed pointer to next chunk */ - jmem_cpointer_t next_chunk_cp; + ecma_value_t items[ECMA_COLLECTION_CHUNK_ITEMS + 1]; /**< ecma-value list, where the last value is a special + * collection-type value which points to the next chunk, + * so the chunk area is enlarged by one for this value */ } ecma_collection_chunk_t; /** diff --git a/jerry-core/ecma/base/ecma-helpers-value.c b/jerry-core/ecma/base/ecma-helpers-value.c index eff51c736..1452a2553 100644 --- a/jerry-core/ecma/base/ecma-helpers-value.c +++ b/jerry-core/ecma/base/ecma-helpers-value.c @@ -77,6 +77,7 @@ ecma_pointer_to_ecma_value (const void *ptr) /**< pointer */ { #ifdef ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY + JERRY_ASSERT (ptr != NULL); uintptr_t uint_ptr = (uintptr_t) ptr; JERRY_ASSERT ((uint_ptr & ECMA_VALUE_TYPE_MASK) == 0); return (ecma_value_t) uint_ptr; @@ -99,10 +100,11 @@ static inline void * __attr_pure___ __attr_always_inline___ ecma_get_pointer_from_ecma_value (ecma_value_t value) /**< value */ { #ifdef ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY - return (void *) (uintptr_t) ((value) & ~ECMA_VALUE_TYPE_MASK); + void *ptr = (void *) (uintptr_t) ((value) & ~ECMA_VALUE_TYPE_MASK); + JERRY_ASSERT (ptr != NULL); + return ptr; #else /* !ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */ - return ECMA_GET_NON_NULL_POINTER (ecma_number_t, - value >> ECMA_VALUE_SHIFT); + return ECMA_GET_NON_NULL_POINTER (void, value >> ECMA_VALUE_SHIFT); #endif /* ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */ } /* ecma_get_pointer_from_ecma_value */ @@ -319,7 +321,7 @@ ecma_is_value_object (ecma_value_t value) /**< ecma value */ /** * Check if the value is error reference. * - * @return true - if the value contains object value, + * @return true - if the value contains an error reference, * false - otherwise */ inline bool __attr_const___ __attr_always_inline___ @@ -328,6 +330,18 @@ ecma_is_value_error_reference (ecma_value_t value) /**< ecma value */ return (ecma_get_value_type_field (value) == ECMA_TYPE_ERROR); } /* ecma_is_value_error_reference */ +/** + * Check if the value is collection chunk. + * + * @return true - if the value contains a collection chunk, + * false - otherwise + */ +inline bool __attr_const___ __attr_always_inline___ +ecma_is_value_collection_chunk (ecma_value_t value) /**< ecma value */ +{ + return (ecma_get_value_type_field (value) == ECMA_TYPE_COLLECTION_CHUNK); +} /* ecma_is_value_collection_chunk */ + /** * Debug assertion that specified value's type is one of ECMA-defined * script-visible types, i.e.: undefined, null, boolean, number, string, object. @@ -512,6 +526,27 @@ ecma_make_error_reference_value (const ecma_error_reference_t *error_ref_p) /**< return ecma_pointer_to_ecma_value (error_ref_p) | ECMA_TYPE_ERROR; } /* ecma_make_error_reference_value */ +/** + * Collection chunk constructor + */ +inline ecma_value_t __attr_pure___ __attr_always_inline___ +ecma_make_collection_chunk_value (const ecma_collection_chunk_t *collection_chunk_p) /**< collection chunk */ +{ +#ifdef ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY + + uintptr_t uint_ptr = (uintptr_t) collection_chunk_p; + JERRY_ASSERT ((uint_ptr & ECMA_VALUE_TYPE_MASK) == 0); + return ((ecma_value_t) uint_ptr) | ECMA_TYPE_COLLECTION_CHUNK; + +#else /* !ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */ + + jmem_cpointer_t ptr_cp; + ECMA_SET_POINTER (ptr_cp, collection_chunk_p); + return (((ecma_value_t) ptr_cp) << ECMA_VALUE_SHIFT) | ECMA_TYPE_COLLECTION_CHUNK; + +#endif /* ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */ +} /* ecma_make_collection_chunk_value */ + /** * Get integer value from an integer ecma value * @@ -588,6 +623,23 @@ ecma_get_error_reference_from_value (ecma_value_t value) /**< ecma value */ return (ecma_error_reference_t *) ecma_get_pointer_from_ecma_value (value); } /* ecma_get_error_reference_from_value */ +/** + * Get pointer to collection chunk from ecma value + * + * @return the pointer + */ +inline ecma_collection_chunk_t *__attr_pure___ __attr_always_inline___ +ecma_get_collection_chunk_from_value (ecma_value_t value) /**< ecma value */ +{ + JERRY_ASSERT (ecma_get_value_type_field (value) == ECMA_TYPE_COLLECTION_CHUNK); + +#ifdef ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY + return (ecma_collection_chunk_t *) (uintptr_t) ((value) & ~ECMA_VALUE_TYPE_MASK); +#else /* !ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */ + return ECMA_GET_POINTER (ecma_collection_chunk_t, value >> ECMA_VALUE_SHIFT); +#endif /* ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */ +} /* ecma_get_collection_chunk_from_value */ + /** * Invert a boolean value * diff --git a/jerry-core/ecma/base/ecma-helpers-values-collection.c b/jerry-core/ecma/base/ecma-helpers-values-collection.c index f02ee843d..f24f0fcef 100644 --- a/jerry-core/ecma/base/ecma-helpers-values-collection.c +++ b/jerry-core/ecma/base/ecma-helpers-values-collection.c @@ -25,6 +25,12 @@ * @{ */ +/** + * The type of ecma error and ecma collection chunk must be the same. + */ +JERRY_STATIC_ASSERT (ECMA_TYPE_ERROR == ECMA_TYPE_COLLECTION_CHUNK, + ecma_type_error_must_be_the_same_as_ecma_type_collection_chunk); + /** * Allocate a collection of ecma values. * @@ -38,48 +44,56 @@ ecma_new_values_collection (const ecma_value_t values_buffer[], /**< ecma values { JERRY_ASSERT (values_buffer != NULL || values_number == 0); - const size_t values_in_chunk = JERRY_SIZE_OF_STRUCT_MEMBER (ecma_collection_chunk_t, data) / sizeof (ecma_value_t); + ecma_collection_header_t *header_p; + header_p = (ecma_collection_header_t *) jmem_pools_alloc (sizeof (ecma_collection_header_t)); - ecma_collection_header_t *header_p = ecma_alloc_collection_header (); + header_p->item_count = values_number; + header_p->first_chunk_cp = ECMA_NULL_POINTER; + header_p->last_chunk_cp = ECMA_NULL_POINTER; - header_p->unit_number = values_number; + if (values_number == 0) + { + return header_p; + } - jmem_cpointer_t *next_chunk_cp_p = &header_p->first_chunk_cp; - ecma_collection_chunk_t *last_chunk_p = NULL; - ecma_value_t *cur_value_buf_iter_p = NULL; - ecma_value_t *cur_value_buf_end_p = NULL; + ecma_collection_chunk_t *current_chunk_p = NULL; + int current_chunk_index = ECMA_COLLECTION_CHUNK_ITEMS; for (ecma_length_t value_index = 0; value_index < values_number; value_index++) { - if (cur_value_buf_iter_p == cur_value_buf_end_p) + if (unlikely (current_chunk_index >= ECMA_COLLECTION_CHUNK_ITEMS)) { - ecma_collection_chunk_t *chunk_p = ecma_alloc_collection_chunk (); - ECMA_SET_POINTER (*next_chunk_cp_p, chunk_p); - next_chunk_cp_p = &chunk_p->next_chunk_cp; + ecma_collection_chunk_t *next_chunk_p; + next_chunk_p = (ecma_collection_chunk_t *) jmem_pools_alloc (sizeof (ecma_collection_chunk_t)); - cur_value_buf_iter_p = (ecma_value_t *) chunk_p->data; - cur_value_buf_end_p = cur_value_buf_iter_p + values_in_chunk; + if (header_p->last_chunk_cp == ECMA_NULL_POINTER) + { + ECMA_SET_POINTER (header_p->first_chunk_cp, next_chunk_p); + header_p->last_chunk_cp = header_p->first_chunk_cp; + } + else + { + current_chunk_p->items[ECMA_COLLECTION_CHUNK_ITEMS] = ecma_make_collection_chunk_value (next_chunk_p); + ECMA_SET_POINTER (header_p->last_chunk_cp, next_chunk_p); + } - last_chunk_p = chunk_p; + current_chunk_p = next_chunk_p; + current_chunk_index = 0; } - JERRY_ASSERT (cur_value_buf_iter_p + 1 <= cur_value_buf_end_p); + ecma_value_t value = values_buffer[value_index]; - if (do_ref_if_object) + if (do_ref_if_object || !ecma_is_value_object (value)) { - *cur_value_buf_iter_p++ = ecma_copy_value (values_buffer[value_index]); - } - else - { - *cur_value_buf_iter_p++ = ecma_copy_value_if_not_object (values_buffer[value_index]); + value = ecma_copy_value (value); } + + current_chunk_p->items[current_chunk_index++] = value; } - *next_chunk_cp_p = ECMA_NULL_POINTER; - ECMA_SET_POINTER (header_p->last_chunk_cp, last_chunk_p); - + current_chunk_p->items[current_chunk_index] = ecma_make_collection_chunk_value (NULL); return header_p; } /* ecma_new_values_collection */ @@ -91,46 +105,44 @@ ecma_free_values_collection (ecma_collection_header_t *header_p, /**< collection bool do_deref_if_object) /**< if the value is object value, decrement reference counter of the object */ { - JERRY_ASSERT (header_p != NULL); - - const size_t values_in_chunk = JERRY_SIZE_OF_STRUCT_MEMBER (ecma_collection_chunk_t, data) / sizeof (ecma_value_t); - ecma_collection_chunk_t *chunk_p = ECMA_GET_POINTER (ecma_collection_chunk_t, header_p->first_chunk_cp); - ecma_length_t value_index = 0; - while (chunk_p != NULL) + jmem_heap_free_block (header_p, sizeof (ecma_collection_header_t)); + + if (chunk_p == NULL) { - JERRY_ASSERT (value_index < header_p->unit_number); + return; + } - ecma_value_t *cur_value_buf_iter_p = (ecma_value_t *) chunk_p->data; - ecma_value_t *cur_value_buf_end_p = cur_value_buf_iter_p + values_in_chunk; + do + { + ecma_value_t *item_p = chunk_p->items; - while (cur_value_buf_iter_p != cur_value_buf_end_p - && value_index < header_p->unit_number) + JERRY_ASSERT (!ecma_is_value_collection_chunk (*item_p)); + + do { - JERRY_ASSERT (cur_value_buf_iter_p < cur_value_buf_end_p); - if (do_deref_if_object) { - ecma_free_value (*cur_value_buf_iter_p); + ecma_free_value (*item_p); } else { - ecma_free_value_if_not_object (*cur_value_buf_iter_p); + ecma_free_value_if_not_object (*item_p); } - cur_value_buf_iter_p++; - value_index++; + item_p++; } + while (!ecma_is_value_collection_chunk (*item_p)); + + ecma_collection_chunk_t *next_chunk_p = ecma_get_collection_chunk_from_value (*item_p); + + jmem_heap_free_block (chunk_p, sizeof (ecma_collection_chunk_t)); - ecma_collection_chunk_t *next_chunk_p = ECMA_GET_POINTER (ecma_collection_chunk_t, - chunk_p->next_chunk_cp); - ecma_dealloc_collection_chunk (chunk_p); chunk_p = next_chunk_p; } - - ecma_dealloc_collection_header (header_p); + while (chunk_p != NULL); } /* ecma_free_values_collection */ /** @@ -138,234 +150,98 @@ ecma_free_values_collection (ecma_collection_header_t *header_p, /**< collection */ void ecma_append_to_values_collection (ecma_collection_header_t *header_p, /**< collection's header */ - ecma_value_t v, /**< ecma value to append */ + ecma_value_t value, /**< ecma value to append */ bool do_ref_if_object) /**< if the value is object value, increase reference counter of the object */ { - const size_t values_in_chunk = JERRY_SIZE_OF_STRUCT_MEMBER (ecma_collection_chunk_t, data) / sizeof (ecma_value_t); + ecma_length_t item_index; + ecma_collection_chunk_t *chunk_p; - size_t values_number = header_p->unit_number; - size_t pos_of_new_value_in_chunk = values_number % values_in_chunk; - - values_number++; - - if ((ecma_length_t) values_number == values_number) + if (unlikely (header_p->item_count == 0)) { - header_p->unit_number = (ecma_length_t) values_number; + item_index = 0; + chunk_p = (ecma_collection_chunk_t *) jmem_heap_alloc_block (sizeof (ecma_collection_chunk_t)); + + ECMA_SET_POINTER (header_p->first_chunk_cp, chunk_p); + header_p->last_chunk_cp = header_p->first_chunk_cp; } else { - jerry_fatal (ERR_OUT_OF_MEMORY); - } + item_index = header_p->item_count % ECMA_COLLECTION_CHUNK_ITEMS; - ecma_collection_chunk_t *chunk_p = ECMA_GET_POINTER (ecma_collection_chunk_t, - header_p->last_chunk_cp); + chunk_p = ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t, + header_p->last_chunk_cp); - if (pos_of_new_value_in_chunk == 0) - { - /* all chunks are currently filled with values */ - - chunk_p = ecma_alloc_collection_chunk (); - chunk_p->next_chunk_cp = ECMA_NULL_POINTER; - - if (header_p->last_chunk_cp == ECMA_NULL_POINTER) + if (unlikely (item_index == 0)) { - JERRY_ASSERT (header_p->first_chunk_cp == ECMA_NULL_POINTER); + JERRY_ASSERT (ecma_is_value_collection_chunk (chunk_p->items[ECMA_COLLECTION_CHUNK_ITEMS]) + && ecma_get_collection_chunk_from_value (chunk_p->items[ECMA_COLLECTION_CHUNK_ITEMS]) == NULL); - ECMA_SET_NON_NULL_POINTER (header_p->first_chunk_cp, chunk_p); + ecma_collection_chunk_t *next_chunk_p; + next_chunk_p = (ecma_collection_chunk_t *) jmem_heap_alloc_block (sizeof (ecma_collection_chunk_t)); + + chunk_p->items[ECMA_COLLECTION_CHUNK_ITEMS] = ecma_make_collection_chunk_value (next_chunk_p); + ECMA_SET_POINTER (header_p->last_chunk_cp, next_chunk_p); + + chunk_p = next_chunk_p; } else { - ecma_collection_chunk_t *last_chunk_p = ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t, - header_p->last_chunk_cp); - - JERRY_ASSERT (last_chunk_p->next_chunk_cp == ECMA_NULL_POINTER); - - ECMA_SET_NON_NULL_POINTER (last_chunk_p->next_chunk_cp, chunk_p); + JERRY_ASSERT (ecma_is_value_collection_chunk (chunk_p->items[item_index]) + && ecma_get_collection_chunk_from_value (chunk_p->items[item_index]) == NULL); } - - ECMA_SET_NON_NULL_POINTER (header_p->last_chunk_cp, chunk_p); } - else + + if (do_ref_if_object || !ecma_is_value_object (value)) { - /* last chunk can be appended with the new value */ - JERRY_ASSERT (chunk_p != NULL); + value = ecma_copy_value (value); } - ecma_value_t *values_p = (ecma_value_t *) chunk_p->data; - - JERRY_ASSERT ((uint8_t *) (values_p + pos_of_new_value_in_chunk + 1) <= (uint8_t *) (chunk_p + 1)); - - if (do_ref_if_object) - { - values_p[pos_of_new_value_in_chunk] = ecma_copy_value (v); - } - else - { - values_p[pos_of_new_value_in_chunk] = ecma_copy_value_if_not_object (v); - } + chunk_p->items[item_index] = value; + chunk_p->items[item_index + 1] = ecma_make_collection_chunk_value (NULL); + header_p->item_count++; } /* ecma_append_to_values_collection */ -/** - * Remove last element of the collection - * - * Warning: - * the function invalidates all iterators that are configured to access the passed collection - */ -void -ecma_remove_last_value_from_values_collection (ecma_collection_header_t *header_p) /**< collection's header */ -{ - JERRY_ASSERT (header_p != NULL && header_p->unit_number > 0); - - const size_t values_in_chunk = JERRY_SIZE_OF_STRUCT_MEMBER (ecma_collection_chunk_t, data) / sizeof (ecma_value_t); - size_t values_number = header_p->unit_number; - size_t pos_of_value_to_remove_in_chunk = (values_number - 1u) % values_in_chunk; - - ecma_collection_chunk_t *last_chunk_p = ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t, - header_p->last_chunk_cp); - - ecma_value_t *values_p = (ecma_value_t *) last_chunk_p->data; - JERRY_ASSERT ((uint8_t *) (values_p + pos_of_value_to_remove_in_chunk + 1) <= (uint8_t *) (last_chunk_p + 1)); - - ecma_value_t value_to_remove = values_p[pos_of_value_to_remove_in_chunk]; - - ecma_free_value (value_to_remove); - - header_p->unit_number--; - - if (pos_of_value_to_remove_in_chunk == 0) - { - ecma_collection_chunk_t *chunk_to_remove_p = last_chunk_p; - - /* free last chunk */ - if (header_p->first_chunk_cp == header_p->last_chunk_cp) - { - header_p->first_chunk_cp = ECMA_NULL_POINTER; - header_p->last_chunk_cp = ECMA_NULL_POINTER; - } - else - { - ecma_collection_chunk_t *chunk_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t, - header_p->first_chunk_cp); - - while (chunk_iter_p->next_chunk_cp != header_p->last_chunk_cp) - { - chunk_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t, - chunk_iter_p->next_chunk_cp); - } - - ecma_collection_chunk_t *new_last_chunk_p = chunk_iter_p; - - JERRY_ASSERT (ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t, - new_last_chunk_p->next_chunk_cp) == chunk_to_remove_p); - - ECMA_SET_NON_NULL_POINTER (header_p->last_chunk_cp, new_last_chunk_p); - new_last_chunk_p->next_chunk_cp = ECMA_NULL_POINTER; - } - - ecma_dealloc_collection_chunk (chunk_to_remove_p); - } -} /* ecma_remove_last_value_from_values_collection */ - -/** - * Allocate a collection of ecma-strings. - * - * @return pointer to the collection's header - */ -ecma_collection_header_t * -ecma_new_strings_collection (ecma_string_t *string_ptrs_buffer[], /**< pointers to ecma-strings */ - ecma_length_t strings_number) /**< number of ecma-strings */ -{ - JERRY_ASSERT (string_ptrs_buffer != NULL || strings_number == 0); - - ecma_collection_header_t *new_collection_p; - - new_collection_p = ecma_new_values_collection (NULL, 0, false); - - for (ecma_length_t string_index = 0; - string_index < strings_number; - string_index++) - { - ecma_append_to_values_collection (new_collection_p, - ecma_make_string_value (string_ptrs_buffer[string_index]), - false); - } - - return new_collection_p; -} /* ecma_new_strings_collection */ - /** * Initialize new collection iterator for the collection + * + * @return pointer to the first item */ -void -ecma_collection_iterator_init (ecma_collection_iterator_t *iterator_p, /**< context of iterator */ - ecma_collection_header_t *collection_p) /**< header of collection */ +ecma_value_t * +ecma_collection_iterator_init (ecma_collection_header_t *header_p) /**< header of collection */ { - iterator_p->header_p = collection_p; - iterator_p->next_chunk_cp = (collection_p != NULL ? collection_p->first_chunk_cp : JMEM_CP_NULL); - iterator_p->current_index = 0; - iterator_p->current_value_p = NULL; - iterator_p->current_chunk_end_p = NULL; + if (unlikely (!header_p || header_p->item_count == 0)) + { + return NULL; + } + + ecma_collection_chunk_t *chunk_p = ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t, + header_p->first_chunk_cp); + + return chunk_p->items; } /* ecma_collection_iterator_init */ /** * Move collection iterator to next element if there is any. * - * @return true - if iterator moved, - * false - otherwise (current element is last element in the collection) + * @return pointer to the next item */ -bool -ecma_collection_iterator_next (ecma_collection_iterator_t *iterator_p) /**< context of iterator */ +ecma_value_t * +ecma_collection_iterator_next (ecma_value_t *ecma_value_p) /**< current value */ { - if (iterator_p->header_p == NULL - || unlikely (iterator_p->header_p->unit_number == 0) - || unlikely (iterator_p->header_p->first_chunk_cp == JMEM_CP_NULL)) + JERRY_ASSERT (ecma_value_p != NULL); + + ecma_value_p++; + + if (unlikely (ecma_is_value_collection_chunk (*ecma_value_p))) { - return false; + ecma_value_p = ecma_get_collection_chunk_from_value (*ecma_value_p)->items; + + JERRY_ASSERT (ecma_value_p == NULL || !ecma_is_value_collection_chunk (*ecma_value_p)); + return ecma_value_p; } - const size_t values_in_chunk = JERRY_SIZE_OF_STRUCT_MEMBER (ecma_collection_chunk_t, data) / sizeof (ecma_value_t); - - if (iterator_p->current_value_p == NULL) - { - JERRY_ASSERT (iterator_p->current_index == 0); - - ecma_collection_chunk_t *first_chunk_p = ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t, - iterator_p->header_p->first_chunk_cp); - - iterator_p->next_chunk_cp = first_chunk_p->next_chunk_cp; - iterator_p->current_value_p = (ecma_value_t *) &first_chunk_p->data; - iterator_p->current_chunk_end_p = (iterator_p->current_value_p + values_in_chunk); - } - else - { - if (iterator_p->current_index + 1 == iterator_p->header_p->unit_number) - { - return false; - } - - JERRY_ASSERT (iterator_p->current_index + 1 < iterator_p->header_p->unit_number); - - iterator_p->current_index++; - iterator_p->current_value_p++; - } - - if (iterator_p->current_value_p == iterator_p->current_chunk_end_p) - { - ecma_collection_chunk_t *next_chunk_p = ECMA_GET_POINTER (ecma_collection_chunk_t, - iterator_p->next_chunk_cp); - JERRY_ASSERT (next_chunk_p != NULL); - - iterator_p->next_chunk_cp = next_chunk_p->next_chunk_cp; - iterator_p->current_value_p = (ecma_value_t *) &next_chunk_p->data; - iterator_p->current_chunk_end_p = iterator_p->current_value_p + values_in_chunk; - } - else - { - JERRY_ASSERT (iterator_p->current_value_p < iterator_p->current_chunk_end_p); - } - - return true; + return ecma_value_p; } /* ecma_collection_iterator_next */ /** diff --git a/jerry-core/ecma/base/ecma-helpers.h b/jerry-core/ecma/base/ecma-helpers.h index f15595503..f5fbe5ec6 100644 --- a/jerry-core/ecma/base/ecma-helpers.h +++ b/jerry-core/ecma/base/ecma-helpers.h @@ -71,30 +71,53 @@ #ifdef ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY /** - * Set an internal property value of pointer + * Set an internal property value from pointer. */ #define ECMA_SET_INTERNAL_VALUE_POINTER(field, pointer) \ (field) = ((ecma_value_t) pointer) /** - * Get an internal property value of pointer + * Set an internal property value from pointer. Pointer can be NULL. + */ +#define ECMA_SET_INTERNAL_VALUE_ANY_POINTER(field, pointer) \ + (field) = ((ecma_value_t) pointer) + +/** + * Convert an internal property value to pointer. */ #define ECMA_GET_INTERNAL_VALUE_POINTER(type, field) \ ((type *) field) +/** + * Convert an internal property value to pointer. Result can be NULL. + */ +#define ECMA_GET_INTERNAL_VALUE_ANY_POINTER(type, field) \ + ((type *) field) + #else /* !ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */ /** - * Set an internal property value of non-null pointer so that it will correspond - * to specified non_compressed_pointer. + * Set an internal property value from pointer. */ -#define ECMA_SET_INTERNAL_VALUE_POINTER(field, non_compressed_pointer) \ - ECMA_SET_NON_NULL_POINTER (field, non_compressed_pointer) +#define ECMA_SET_INTERNAL_VALUE_POINTER(field, pointer) \ + ECMA_SET_NON_NULL_POINTER (field, pointer) /** - * Get an internal property value of pointer from specified compressed pointer. + * Set an internal property value from pointer. Pointer can be NULL. + */ +#define ECMA_SET_INTERNAL_VALUE_ANY_POINTER(field, pointer) \ + ECMA_SET_POINTER (field, pointer) + +/** + * Convert an internal property value to pointer. */ #define ECMA_GET_INTERNAL_VALUE_POINTER(type, field) \ + ECMA_GET_NON_NULL_POINTER (type, field) + +/** + * Convert an internal property value to pointer. Result can be NULL. + */ +#define ECMA_GET_INTERNAL_VALUE_ANY_POINTER(type, field) \ ECMA_GET_POINTER (type, field) #endif /* ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */ @@ -134,6 +157,7 @@ bool ecma_is_value_number (ecma_value_t value) __attr_const___; bool ecma_is_value_string (ecma_value_t value) __attr_const___; bool ecma_is_value_object (ecma_value_t value) __attr_const___; bool ecma_is_value_error_reference (ecma_value_t value) __attr_const___; +bool ecma_is_value_collection_chunk (ecma_value_t value) __attr_const___; void ecma_check_value_type_is_spec_defined (ecma_value_t value); @@ -146,12 +170,14 @@ ecma_value_t ecma_make_uint32_value (uint32_t uint32_number); ecma_value_t ecma_make_string_value (const ecma_string_t *ecma_string_p) __attr_pure___; ecma_value_t ecma_make_object_value (const ecma_object_t *object_p) __attr_pure___; ecma_value_t ecma_make_error_reference_value (const ecma_error_reference_t *error_ref_p) __attr_pure___; +ecma_value_t ecma_make_collection_chunk_value (const ecma_collection_chunk_t *collection_chunk_p) __attr_pure___; ecma_integer_value_t ecma_get_integer_from_value (ecma_value_t value) __attr_const___; ecma_number_t ecma_get_float_from_value (ecma_value_t value) __attr_pure___; ecma_number_t ecma_get_number_from_value (ecma_value_t value) __attr_pure___; ecma_string_t *ecma_get_string_from_value (ecma_value_t value) __attr_pure___; ecma_object_t *ecma_get_object_from_value (ecma_value_t value) __attr_pure___; ecma_error_reference_t *ecma_get_error_reference_from_value (ecma_value_t value) __attr_pure___; +ecma_collection_chunk_t *ecma_get_collection_chunk_from_value (ecma_value_t value) __attr_pure___; ecma_value_t ecma_invert_boolean_value (ecma_value_t value) __attr_const___; ecma_value_t ecma_copy_value (ecma_value_t value); ecma_value_t ecma_fast_copy_value (ecma_value_t value); @@ -264,27 +290,11 @@ ecma_collection_header_t *ecma_new_values_collection (const ecma_value_t values_ bool do_ref_if_object); void ecma_free_values_collection (ecma_collection_header_t *header_p, bool do_deref_if_object); void ecma_append_to_values_collection (ecma_collection_header_t *header_p, ecma_value_t v, bool do_ref_if_object); -void ecma_remove_last_value_from_values_collection (ecma_collection_header_t *header_p); -ecma_collection_header_t *ecma_new_strings_collection (ecma_string_t *string_ptrs_buffer[], - ecma_length_t strings_number); -/** - * Context of ecma values' collection iterator - */ -typedef struct -{ - ecma_collection_header_t *header_p; /**< collection header */ - jmem_cpointer_t next_chunk_cp; /**< compressed pointer to next chunk */ - ecma_length_t current_index; /**< index of current element */ - const ecma_value_t *current_value_p; /**< pointer to current element */ - const ecma_value_t *current_chunk_beg_p; /**< pointer to beginning of current chunk's data */ - const ecma_value_t *current_chunk_end_p; /**< pointer to place right after the end of current chunk's data */ -} ecma_collection_iterator_t; - -void -ecma_collection_iterator_init (ecma_collection_iterator_t *iterator_p, ecma_collection_header_t *collection_p); -bool -ecma_collection_iterator_next (ecma_collection_iterator_t *iterator_p); +ecma_value_t * +ecma_collection_iterator_init (ecma_collection_header_t *header_p); +ecma_value_t * +ecma_collection_iterator_next (ecma_value_t *iterator_p); /* ecma-helpers.c */ ecma_object_t *ecma_create_object (ecma_object_t *prototype_object_p, size_t ext_object_size, ecma_object_type_t type); diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c index 6f7d79428..0c3283664 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c @@ -1180,14 +1180,13 @@ ecma_builtin_array_prototype_object_sort (ecma_value_t this_arg, /**< this argum uint32_t defined_prop_count = 0; uint32_t copied_num = 0; - ecma_collection_iterator_t iter; - ecma_collection_iterator_init (&iter, array_index_props_p); + ecma_value_t *ecma_value_p = ecma_collection_iterator_init (array_index_props_p); /* Count properties with name that is array index less than len */ - while (ecma_collection_iterator_next (&iter) - && ecma_is_value_empty (ret_value)) + while (ecma_value_p != NULL && ecma_is_value_empty (ret_value)) { - ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p); + ecma_string_t *property_name_p = ecma_get_string_from_value (*ecma_value_p); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); uint32_t index = ecma_string_get_array_index (property_name_p); JERRY_ASSERT (index != ECMA_STRING_NOT_ARRAY_INDEX); @@ -1200,13 +1199,13 @@ ecma_builtin_array_prototype_object_sort (ecma_value_t this_arg, /**< this argum JMEM_DEFINE_LOCAL_ARRAY (values_buffer, defined_prop_count, ecma_value_t); - ecma_collection_iterator_init (&iter, array_index_props_p); + ecma_value_p = ecma_collection_iterator_init (array_index_props_p); /* Copy unsorted array into a native c array. */ - while (ecma_collection_iterator_next (&iter) - && ecma_is_value_empty (ret_value)) + while (ecma_value_p != NULL && ecma_is_value_empty (ret_value)) { - ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p); + ecma_string_t *property_name_p = ecma_get_string_from_value (*ecma_value_p); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); uint32_t index = ecma_string_get_array_index (property_name_p); JERRY_ASSERT (index != ECMA_STRING_NOT_ARRAY_INDEX); @@ -1260,12 +1259,12 @@ ecma_builtin_array_prototype_object_sort (ecma_value_t this_arg, /**< this argum /* Undefined properties should be in the back of the array. */ - ecma_collection_iterator_init (&iter, array_index_props_p); + ecma_value_p = ecma_collection_iterator_init (array_index_props_p); - while (ecma_collection_iterator_next (&iter) - && ecma_is_value_empty (ret_value)) + while (ecma_value_p != NULL && ecma_is_value_empty (ret_value)) { - ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p); + ecma_string_t *property_name_p = ecma_get_string_from_value (*ecma_value_p); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); uint32_t index = ecma_string_get_array_index (property_name_p); JERRY_ASSERT (index != ECMA_STRING_NOT_ARRAY_INDEX); diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-json.c b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-json.c index f95444678..29a444ec8 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-json.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-json.c @@ -26,38 +26,31 @@ */ /** - * Check the object value existance in the collection. + * Check whether the object is pushed onto the occurence stack * * Used by: * - ecma_builtin_json_object step 1 * - ecma_builtin_json_array step 1 * - * @return true, if the object is already in the collection. + * @return true - if the object is pushed onto the occurence stack + * false - otherwise */ bool -ecma_has_object_value_in_collection (ecma_collection_header_t *collection_p, /**< collection */ - ecma_value_t object_value) /**< object value */ +ecma_json_has_object_in_stack (ecma_json_occurence_stack_item_t *stack_p, /**< stack */ + ecma_object_t *object_p) /**< object */ { - JERRY_ASSERT (ecma_is_value_object (object_value)); - - ecma_object_t *obj_p = ecma_get_object_from_value (object_value); - - ecma_collection_iterator_t iterator; - ecma_collection_iterator_init (&iterator, collection_p); - - while (ecma_collection_iterator_next (&iterator)) + while (stack_p != NULL) { - ecma_value_t value = *iterator.current_value_p; - ecma_object_t *current_p = ecma_get_object_from_value (value); - - if (current_p == obj_p) + if (stack_p->object_p == object_p) { return true; } + + stack_p = stack_p->next_p; } return false; -} /* ecma_has_object_value_in_collection */ +} /* ecma_json_has_object_in_stack */ /** * Check the string value existance in the collection. @@ -75,18 +68,18 @@ ecma_has_string_value_in_collection (ecma_collection_header_t *collection_p, /** ecma_string_t *string_p = ecma_get_string_from_value (string_value); - ecma_collection_iterator_t iterator; - ecma_collection_iterator_init (&iterator, collection_p); + ecma_value_t *ecma_value_p = ecma_collection_iterator_init (collection_p); - while (ecma_collection_iterator_next (&iterator)) + while (ecma_value_p != NULL) { - ecma_value_t value = *iterator.current_value_p; - ecma_string_t *current_p = ecma_get_string_from_value (value); + ecma_string_t *current_p = ecma_get_string_from_value (*ecma_value_p); if (ecma_compare_ecma_strings (current_p, string_p)) { return true; } + + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); } return false; @@ -111,15 +104,14 @@ ecma_builtin_helper_json_create_separated_properties (ecma_collection_header_t * { ecma_string_t *properties_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); - ecma_collection_iterator_t iterator; - ecma_collection_iterator_init (&iterator, partial_p); + ecma_value_t *ecma_value_p = ecma_collection_iterator_init (partial_p); bool first = true; - while (ecma_collection_iterator_next (&iterator)) + while (ecma_value_p != NULL) { - ecma_value_t name_value = *iterator.current_value_p; - ecma_string_t *current_p = ecma_get_string_from_value (name_value); + ecma_string_t *current_p = ecma_get_string_from_value (*ecma_value_p); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); if (likely (!first)) { diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.c b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.c index a1bcca1e2..6159ba476 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.c @@ -203,16 +203,15 @@ ecma_builtin_helper_object_get_properties (ecma_object_t *obj_p, /**< object */ only_enumerable_properties, false); - ecma_collection_iterator_t iter; - ecma_collection_iterator_init (&iter, props_p); + ecma_value_t *ecma_value_p = ecma_collection_iterator_init (props_p); - while (ecma_collection_iterator_next (&iter)) + while (ecma_value_p != NULL) { ecma_string_t *index_string_p = ecma_new_ecma_string_from_uint32 (index); ecma_value_t completion = ecma_builtin_helper_def_prop (new_array_p, index_string_p, - *iter.current_value_p, + *ecma_value_p, true, /* Writable */ true, /* Enumerable */ true, /* Configurable */ @@ -222,6 +221,8 @@ ecma_builtin_helper_object_get_properties (ecma_object_t *obj_p, /**< object */ ecma_deref_ecma_string (index_string_p); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); + index++; } diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.h b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.h index a86d4762b..42f074e84 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.h @@ -122,6 +122,15 @@ ecma_value_t ecma_date_value_to_time_string (ecma_number_t datetime_number); /* ecma-builtin-helper-json.c */ +/** + * Occurence stack item of JSON.stringify() + */ +typedef struct struct_ecma_json_occurence_stack_item_t +{ + struct struct_ecma_json_occurence_stack_item_t *next_p; /**< next stack item */ + ecma_object_t *object_p; /**< current object */ +} ecma_json_occurence_stack_item_t; + /** * Context for JSON.stringify() */ @@ -131,7 +140,7 @@ typedef struct ecma_collection_header_t *property_list_p; /** Collection for traversing objects. */ - ecma_collection_header_t *occurence_stack_p; + ecma_json_occurence_stack_item_t *occurence_stack_last_p; /** The actual indentation text. */ ecma_string_t *indent_str_p; @@ -143,7 +152,7 @@ typedef struct ecma_object_t *replacer_function_p; } ecma_json_stringify_context_t; -bool ecma_has_object_value_in_collection (ecma_collection_header_t *collection_p, ecma_value_t object_value); +bool ecma_json_has_object_in_stack (ecma_json_occurence_stack_item_t *stack_p, ecma_object_t *object_p); bool ecma_has_string_value_in_collection (ecma_collection_header_t *collection_p, ecma_value_t string_value); ecma_string_t * diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-json.c b/jerry-core/ecma/builtin-objects/ecma-builtin-json.c index eafe6fe13..22ce41b5a 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-json.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-json.c @@ -728,13 +728,12 @@ ecma_builtin_json_walk (ecma_object_t *reviver_p, /**< reviver function */ ecma_collection_header_t *props_p = ecma_op_object_get_property_names (object_p, false, true, false); - ecma_collection_iterator_t iter; - ecma_collection_iterator_init (&iter, props_p); + ecma_value_t *ecma_value_p = ecma_collection_iterator_init (props_p); - while (ecma_collection_iterator_next (&iter) - && ecma_is_value_empty (ret_value)) + while (ecma_value_p != NULL && ecma_is_value_empty (ret_value)) { - ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p); + ecma_string_t *property_name_p = ecma_get_string_from_value (*ecma_value_p); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); ECMA_TRY_CATCH (value_walk, ecma_builtin_json_walk (reviver_p, @@ -901,7 +900,7 @@ ecma_builtin_json_stringify (ecma_value_t this_arg, /**< 'this' argument */ ecma_json_stringify_context_t context; /* 1. */ - context.occurence_stack_p = ecma_new_values_collection (NULL, 0, false); + context.occurence_stack_last_p = NULL; /* 2. */ context.indent_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); @@ -1138,7 +1137,6 @@ ecma_builtin_json_stringify (ecma_value_t this_arg, /**< 'this' argument */ ecma_deref_ecma_string (context.indent_str_p); ecma_free_values_collection (context.property_list_p, true); - ecma_free_values_collection (context.occurence_stack_p, true); return ret_value; } /* ecma_builtin_json_stringify */ @@ -1459,10 +1457,8 @@ static ecma_value_t ecma_builtin_json_object (ecma_object_t *obj_p, /**< the object*/ ecma_json_stringify_context_t *context_p) /**< context*/ { - ecma_value_t obj_value = ecma_make_object_value (obj_p); - /* 1. */ - if (ecma_has_object_value_in_collection (context_p->occurence_stack_p, obj_value)) + if (ecma_json_has_object_in_stack (context_p->occurence_stack_last_p, obj_p)) { return ecma_raise_type_error (ECMA_ERR_MSG ("The structure is cyclical.")); } @@ -1470,7 +1466,10 @@ ecma_builtin_json_object (ecma_object_t *obj_p, /**< the object*/ ecma_value_t ret_value = ECMA_VALUE_EMPTY; /* 2. */ - ecma_append_to_values_collection (context_p->occurence_stack_p, obj_value, true); + ecma_json_occurence_stack_item_t stack_item; + stack_item.next_p = context_p->occurence_stack_last_p; + stack_item.object_p = obj_p; + context_p->occurence_stack_last_p = &stack_item; /* 3. */ ecma_string_t *stepback_p = context_p->indent_str_p; @@ -1482,7 +1481,7 @@ ecma_builtin_json_object (ecma_object_t *obj_p, /**< the object*/ ecma_collection_header_t *property_keys_p; /* 5. */ - if (context_p->property_list_p->unit_number > 0) + if (context_p->property_list_p->item_count > 0) { property_keys_p = context_p->property_list_p; } @@ -1493,12 +1492,11 @@ ecma_builtin_json_object (ecma_object_t *obj_p, /**< the object*/ ecma_collection_header_t *props_p = ecma_op_object_get_property_names (obj_p, false, true, false); - ecma_collection_iterator_t iter; - ecma_collection_iterator_init (&iter, props_p); + ecma_value_t *ecma_value_p = ecma_collection_iterator_init (props_p); - while (ecma_collection_iterator_next (&iter)) + while (ecma_value_p != NULL) { - ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p); + ecma_string_t *property_name_p = ecma_get_string_from_value (*ecma_value_p); ecma_property_t property = ecma_op_object_get_own_property (obj_p, property_name_p, @@ -1509,8 +1507,10 @@ ecma_builtin_json_object (ecma_object_t *obj_p, /**< the object*/ if (ECMA_PROPERTY_GET_TYPE (property) == ECMA_PROPERTY_TYPE_NAMEDDATA) { - ecma_append_to_values_collection (property_keys_p, *iter.current_value_p, true); + ecma_append_to_values_collection (property_keys_p, *ecma_value_p, true); } + + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); } ecma_free_values_collection (props_p, true); @@ -1520,13 +1520,12 @@ ecma_builtin_json_object (ecma_object_t *obj_p, /**< the object*/ ecma_collection_header_t *partial_p = ecma_new_values_collection (NULL, 0, true); /* 8. */ - ecma_collection_iterator_t iterator; - ecma_collection_iterator_init (&iterator, property_keys_p); + ecma_value_t *ecma_value_p = ecma_collection_iterator_init (property_keys_p); - while (ecma_collection_iterator_next (&iterator) && ecma_is_value_empty (ret_value)) + while (ecma_value_p != NULL && ecma_is_value_empty (ret_value)) { - ecma_value_t value = *iterator.current_value_p; - ecma_string_t *key_p = ecma_get_string_from_value (value); + ecma_string_t *key_p = ecma_get_string_from_value (*ecma_value_p); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); /* 8.a */ ECMA_TRY_CATCH (str_val, @@ -1565,7 +1564,7 @@ ecma_builtin_json_object (ecma_object_t *obj_p, /**< the object*/ ECMA_FINALIZE (str_val); } - if (context_p->property_list_p->unit_number == 0) + if (context_p->property_list_p->item_count == 0) { ecma_free_values_collection (property_keys_p, true); } @@ -1578,7 +1577,7 @@ ecma_builtin_json_object (ecma_object_t *obj_p, /**< the object*/ } /* 9. */ - if (partial_p->unit_number == 0) + if (partial_p->item_count == 0) { lit_utf8_byte_t chars[2] = { LIT_CHAR_LEFT_BRACE, LIT_CHAR_RIGHT_BRACE }; @@ -1609,7 +1608,7 @@ ecma_builtin_json_object (ecma_object_t *obj_p, /**< the object*/ ecma_free_values_collection (partial_p, true); /* 11. */ - ecma_remove_last_value_from_values_collection (context_p->occurence_stack_p); + context_p->occurence_stack_last_p = stack_item.next_p; /* 12. */ ecma_deref_ecma_string (context_p->indent_str_p); @@ -1632,10 +1631,8 @@ static ecma_value_t ecma_builtin_json_array (ecma_object_t *obj_p, /**< the array object*/ ecma_json_stringify_context_t *context_p) /**< context*/ { - ecma_value_t obj_value = ecma_make_object_value (obj_p); - /* 1. */ - if (ecma_has_object_value_in_collection (context_p->occurence_stack_p, obj_value)) + if (ecma_json_has_object_in_stack (context_p->occurence_stack_last_p, obj_p)) { return ecma_raise_type_error (ECMA_ERR_MSG ("The structure is cyclical.")); } @@ -1643,7 +1640,10 @@ ecma_builtin_json_array (ecma_object_t *obj_p, /**< the array object*/ ecma_value_t ret_value = ECMA_VALUE_EMPTY; /* 2. */ - ecma_append_to_values_collection (context_p->occurence_stack_p, obj_value, true); + ecma_json_occurence_stack_item_t stack_item; + stack_item.next_p = context_p->occurence_stack_last_p; + stack_item.object_p = obj_p; + context_p->occurence_stack_last_p = &stack_item; /* 3. */ ecma_string_t *stepback_p = context_p->indent_str_p; @@ -1697,7 +1697,7 @@ ecma_builtin_json_array (ecma_object_t *obj_p, /**< the array object*/ if (ecma_is_value_empty (ret_value)) { /* 9. */ - if (partial_p->unit_number == 0) + if (partial_p->item_count == 0) { lit_utf8_byte_t chars[2] = { LIT_CHAR_LEFT_SQUARE, LIT_CHAR_RIGHT_SQUARE }; @@ -1732,7 +1732,7 @@ ecma_builtin_json_array (ecma_object_t *obj_p, /**< the array object*/ ecma_free_values_collection (partial_p, true); /* 11. */ - ecma_remove_last_value_from_values_collection (context_p->occurence_stack_p); + context_p->occurence_stack_last_p = stack_item.next_p; /* 12. */ ecma_deref_ecma_string (context_p->indent_str_p); diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-object.c b/jerry-core/ecma/builtin-objects/ecma-builtin-object.c index 8b57e4de1..4a7cb7f93 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-object.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-object.c @@ -315,13 +315,12 @@ ecma_builtin_object_object_seal (ecma_value_t this_arg, /**< 'this' argument */ ecma_collection_header_t *props_p = ecma_op_object_get_property_names (obj_p, false, false, false); - ecma_collection_iterator_t iter; - ecma_collection_iterator_init (&iter, props_p); + ecma_value_t *ecma_value_p = ecma_collection_iterator_init (props_p); - while (ecma_collection_iterator_next (&iter) - && ecma_is_value_empty (ret_value)) + while (ecma_value_p != NULL && ecma_is_value_empty (ret_value)) { - ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p); + ecma_string_t *property_name_p = ecma_get_string_from_value (*ecma_value_p); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); /* 2.a */ ecma_property_descriptor_t prop_desc; @@ -389,14 +388,12 @@ ecma_builtin_object_object_freeze (ecma_value_t this_arg, /**< 'this' argument * ecma_collection_header_t *props_p = ecma_op_object_get_property_names (obj_p, false, false, false); + ecma_value_t *ecma_value_p = ecma_collection_iterator_init (props_p); - ecma_collection_iterator_t iter; - ecma_collection_iterator_init (&iter, props_p); - - while (ecma_collection_iterator_next (&iter) - && ecma_is_value_empty (ret_value)) + while (ecma_value_p != NULL && ecma_is_value_empty (ret_value)) { - ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p); + ecma_string_t *property_name_p = ecma_get_string_from_value (*ecma_value_p); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); /* 2.a */ ecma_property_descriptor_t prop_desc; @@ -513,12 +510,12 @@ ecma_builtin_object_object_is_sealed (ecma_value_t this_arg, /**< 'this' argumen /* 2. */ ecma_collection_header_t *props_p = ecma_op_object_get_property_names (obj_p, false, false, false); - ecma_collection_iterator_t iter; - ecma_collection_iterator_init (&iter, props_p); + ecma_value_t *ecma_value_p = ecma_collection_iterator_init (props_p); - while (ecma_collection_iterator_next (&iter)) + while (ecma_value_p != NULL) { - ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p); + ecma_string_t *property_name_p = ecma_get_string_from_value (*ecma_value_p); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); /* 2.a */ ecma_property_t property = ecma_op_object_get_own_property (obj_p, @@ -583,12 +580,12 @@ ecma_builtin_object_object_is_frozen (ecma_value_t this_arg, /**< 'this' argumen /* 2. */ ecma_collection_header_t *props_p = ecma_op_object_get_property_names (obj_p, false, false, false); - ecma_collection_iterator_t iter; - ecma_collection_iterator_init (&iter, props_p); + ecma_value_t *ecma_value_p = ecma_collection_iterator_init (props_p); - while (ecma_collection_iterator_next (&iter)) + while (ecma_value_p != NULL) { - ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p); + ecma_string_t *property_name_p = ecma_get_string_from_value (*ecma_value_p); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); /* 2.a */ ecma_property_t property = ecma_op_object_get_own_property (obj_p, @@ -829,22 +826,20 @@ ecma_builtin_object_object_define_properties (ecma_value_t this_arg, /**< 'this' ecma_object_t *props_p = ecma_get_object_from_value (props); /* 3. */ ecma_collection_header_t *prop_names_p = ecma_op_object_get_property_names (props_p, false, true, false); - uint32_t property_number = prop_names_p->unit_number; + uint32_t property_number = prop_names_p->item_count; - ecma_collection_iterator_t iter; - ecma_collection_iterator_init (&iter, prop_names_p); + ecma_value_t *ecma_value_p = ecma_collection_iterator_init (prop_names_p); /* 4. */ JMEM_DEFINE_LOCAL_ARRAY (property_descriptors, property_number, ecma_property_descriptor_t); uint32_t property_descriptor_number = 0; - while (ecma_collection_iterator_next (&iter) - && ecma_is_value_empty (ret_value)) + while (ecma_value_p != NULL && ecma_is_value_empty (ret_value)) { /* 5.a */ ECMA_TRY_CATCH (desc_obj, - ecma_op_object_get (props_p, ecma_get_string_from_value (*iter.current_value_p)), + ecma_op_object_get (props_p, ecma_get_string_from_value (*ecma_value_p)), ret_value); /* 5.b */ @@ -857,25 +852,27 @@ ecma_builtin_object_object_define_properties (ecma_value_t this_arg, /**< 'this' ECMA_FINALIZE (conv_result); ECMA_FINALIZE (desc_obj); + + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); } /* 6. */ - ecma_collection_iterator_init (&iter, prop_names_p); + ecma_value_p = ecma_collection_iterator_init (prop_names_p); + for (uint32_t index = 0; index < property_number && ecma_is_value_empty (ret_value); index++) { - bool is_next = ecma_collection_iterator_next (&iter); - JERRY_ASSERT (is_next); - ECMA_TRY_CATCH (define_own_prop_ret, ecma_op_object_define_own_property (obj_p, - ecma_get_string_from_value (*iter.current_value_p), + ecma_get_string_from_value (*ecma_value_p), &property_descriptors[index], true), ret_value); ECMA_FINALIZE (define_own_prop_ret); + + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); } /* Clean up. */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-regexp-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-regexp-prototype.c index 2afa155b0..bff4b4708 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-regexp-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-regexp-prototype.c @@ -141,7 +141,7 @@ ecma_builtin_regexp_prototype_compile (ecma_value_t this_arg, /**< this argument ecma_deref_ecma_string (pattern_string_p); - re_compiled_code_t *old_bc_p = ECMA_GET_INTERNAL_VALUE_POINTER (re_compiled_code_t, *bc_prop_p); + re_compiled_code_t *old_bc_p = ECMA_GET_INTERNAL_VALUE_ANY_POINTER (re_compiled_code_t, *bc_prop_p); if (old_bc_p != NULL) { @@ -213,7 +213,7 @@ ecma_builtin_regexp_prototype_compile (ecma_value_t this_arg, /**< this argument re_compile_bytecode (&new_bc_p, pattern_string_p, flags), ret_value); - re_compiled_code_t *old_bc_p = ECMA_GET_INTERNAL_VALUE_POINTER (re_compiled_code_t, *bc_prop_p); + re_compiled_code_t *old_bc_p = ECMA_GET_INTERNAL_VALUE_ANY_POINTER (re_compiled_code_t, *bc_prop_p); if (old_bc_p != NULL) { @@ -275,7 +275,7 @@ ecma_builtin_regexp_prototype_exec (ecma_value_t this_arg, /**< this argument */ ecma_object_t *obj_p = ecma_get_object_from_value (obj_this); ecma_value_t *bytecode_prop_p = &(((ecma_extended_object_t *) obj_p)->u.class_prop.u.value); - void *bytecode_p = ECMA_GET_INTERNAL_VALUE_POINTER (void, *bytecode_prop_p); + void *bytecode_p = ECMA_GET_INTERNAL_VALUE_ANY_POINTER (void, *bytecode_prop_p); if (bytecode_p == NULL) { diff --git a/jerry-core/ecma/operations/ecma-objects.c b/jerry-core/ecma/operations/ecma-objects.c index d3cff50f9..35241bce5 100644 --- a/jerry-core/ecma/operations/ecma-objects.c +++ b/jerry-core/ecma/operations/ecma-objects.c @@ -1381,8 +1381,8 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ JERRY_ASSERT (obj_p != NULL && !ecma_is_lexical_environment (obj_p)); - ecma_collection_header_t *ret_p = ecma_new_strings_collection (NULL, 0); - ecma_collection_header_t *skipped_non_enumerable_p = ecma_new_strings_collection (NULL, 0); + ecma_collection_header_t *ret_p = ecma_new_values_collection (NULL, 0, false); + ecma_collection_header_t *skipped_non_enumerable_p = ecma_new_values_collection (NULL, 0, false); const ecma_object_type_t type = ecma_get_object_type (obj_p); const bool obj_is_builtin = ecma_get_object_is_builtin (obj_p); @@ -1400,7 +1400,7 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ ecma_length_t string_named_properties_count = 0; ecma_length_t array_index_named_properties_count = 0; - ecma_collection_header_t *prop_names_p = ecma_new_strings_collection (NULL, 0); + ecma_collection_header_t *prop_names_p = ecma_new_values_collection (NULL, 0, false); if (obj_is_builtin) { @@ -1482,15 +1482,15 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ } } - ecma_collection_iterator_t iter; - ecma_collection_iterator_init (&iter, prop_names_p); + ecma_value_t *ecma_value_p = ecma_collection_iterator_init (prop_names_p); uint32_t own_names_hashes_bitmap[ECMA_OBJECT_HASH_BITMAP_SIZE / bitmap_row_size]; memset (own_names_hashes_bitmap, 0, sizeof (own_names_hashes_bitmap)); - while (ecma_collection_iterator_next (&iter)) + while (ecma_value_p != NULL) { - ecma_string_t *name_p = ecma_get_string_from_value (*iter.current_value_p); + ecma_string_t *name_p = ecma_get_string_from_value (*ecma_value_p); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); uint8_t hash = (uint8_t) name_p->hash; uint32_t bitmap_row = (uint32_t) (hash / bitmap_row_size); @@ -1543,13 +1543,14 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ if ((own_names_hashes_bitmap[bitmap_row] & (1u << bitmap_column)) != 0) { - ecma_collection_iterator_init (&iter, prop_names_p); + ecma_value_p = ecma_collection_iterator_init (prop_names_p); - while (ecma_collection_iterator_next (&iter)) + while (ecma_value_p != NULL) { - ecma_string_t *name2_p = ecma_get_string_from_value (*iter.current_value_p); + ecma_string_t *current_name_p = ecma_get_string_from_value (*ecma_value_p); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); - if (ecma_compare_ecma_strings (name_p, name2_p)) + if (ecma_compare_ecma_strings (name_p, current_name_p)) { is_add = false; break; @@ -1583,10 +1584,12 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ prop_iter_p->next_property_cp); } - ecma_collection_iterator_init (&iter, prop_names_p); - while (ecma_collection_iterator_next (&iter)) + ecma_value_p = ecma_collection_iterator_init (prop_names_p); + + while (ecma_value_p != NULL) { - ecma_string_t *name_p = ecma_get_string_from_value (*iter.current_value_p); + ecma_string_t *name_p = ecma_get_string_from_value (*ecma_value_p); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); uint32_t index = ecma_string_get_array_index (name_p); @@ -1610,10 +1613,12 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ uint32_t name_pos = array_index_named_properties_count + string_named_properties_count; uint32_t array_index_name_pos = 0; - ecma_collection_iterator_init (&iter, prop_names_p); - while (ecma_collection_iterator_next (&iter)) + ecma_value_p = ecma_collection_iterator_init (prop_names_p); + + while (ecma_value_p != NULL) { - ecma_string_t *name_p = ecma_get_string_from_value (*iter.current_value_p); + ecma_string_t *name_p = ecma_get_string_from_value (*ecma_value_p); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); uint32_t index = ecma_string_get_array_index (name_p); @@ -1698,13 +1703,14 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ else { /* Name with same hash has already occured. */ - ecma_collection_iterator_init (&iter, ret_p); + ecma_value_p = ecma_collection_iterator_init (ret_p); - while (ecma_collection_iterator_next (&iter)) + while (ecma_value_p != NULL) { - ecma_string_t *iter_name_p = ecma_get_string_from_value (*iter.current_value_p); + ecma_string_t *current_name_p = ecma_get_string_from_value (*ecma_value_p); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); - if (ecma_compare_ecma_strings (name_p, iter_name_p)) + if (ecma_compare_ecma_strings (name_p, current_name_p)) { is_append = false; break; @@ -1714,12 +1720,14 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ if (is_append) { - ecma_collection_iterator_init (&iter, skipped_non_enumerable_p); - while (ecma_collection_iterator_next (&iter)) - { - ecma_string_t *iter_name_p = ecma_get_string_from_value (*iter.current_value_p); + ecma_value_p = ecma_collection_iterator_init (skipped_non_enumerable_p); - if (ecma_compare_ecma_strings (name_p, iter_name_p)) + while (ecma_value_p != NULL) + { + ecma_string_t *current_name_p = ecma_get_string_from_value (*ecma_value_p); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); + + if (ecma_compare_ecma_strings (name_p, current_name_p)) { is_append = false; break; diff --git a/jerry-core/ecma/operations/ecma-promise-object.c b/jerry-core/ecma/operations/ecma-promise-object.c index 04b325cd5..e09c03019 100644 --- a/jerry-core/ecma/operations/ecma-promise-object.c +++ b/jerry-core/ecma/operations/ecma-promise-object.c @@ -148,12 +148,12 @@ static void ecma_promise_trigger_reactions (ecma_collection_header_t *reactions, /**< lists of reactions */ ecma_value_t value) /**< value for resolve or reject */ { - ecma_collection_iterator_t iter; - ecma_collection_iterator_init (&iter, reactions); + ecma_value_t *ecma_value_p = ecma_collection_iterator_init (reactions); - while (ecma_collection_iterator_next (&iter)) + while (ecma_value_p != NULL) { - ecma_enqueue_promise_reaction_job (*iter.current_value_p, value); + ecma_enqueue_promise_reaction_job (*ecma_value_p, value); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); } ecma_free_values_collection (reactions, false); @@ -175,11 +175,17 @@ ecma_reject_promise (ecma_value_t promise, /**< promise */ ecma_promise_set_state (obj_p, ECMA_PROMISE_STATE_REJECTED); ecma_promise_set_result (obj_p, ecma_copy_value_if_not_object (reason)); ecma_promise_object_t *promise_p = (ecma_promise_object_t *) obj_p; - ecma_promise_trigger_reactions (promise_p->reject_reactions, reason); + + /* GC can be triggered by ecma_new_values_collection so freeing the collection + first and creating a new one might cause a heap after use event. */ + ecma_collection_header_t *reject_reactions = promise_p->reject_reactions; + ecma_collection_header_t *fulfill_reactions = promise_p->fulfill_reactions; promise_p->reject_reactions = ecma_new_values_collection (NULL, 0, false); - /* Free all fullfill_reactions. */ - ecma_free_values_collection (promise_p->fulfill_reactions, false); promise_p->fulfill_reactions = ecma_new_values_collection (NULL, 0, false); + + /* Fulfill reactions will never be triggered. */ + ecma_free_values_collection (fulfill_reactions, false); + ecma_promise_trigger_reactions (reject_reactions, reason); } /* ecma_reject_promise */ /** @@ -198,11 +204,17 @@ ecma_fulfill_promise (ecma_value_t promise, /**< promise */ ecma_promise_set_state (obj_p, ECMA_PROMISE_STATE_FULFILLED); ecma_promise_set_result (obj_p, ecma_copy_value_if_not_object (value)); ecma_promise_object_t *promise_p = (ecma_promise_object_t *) obj_p; - ecma_promise_trigger_reactions (promise_p->fulfill_reactions, value); - promise_p->fulfill_reactions = ecma_new_values_collection (NULL, 0, false); - /* Free all reject_reactions. */ - ecma_free_values_collection (promise_p->reject_reactions, false); + + /* GC can be triggered by ecma_new_values_collection so freeing the collection + first and creating a new one might cause a heap after use event. */ + ecma_collection_header_t *reject_reactions = promise_p->reject_reactions; + ecma_collection_header_t *fulfill_reactions = promise_p->fulfill_reactions; promise_p->reject_reactions = ecma_new_values_collection (NULL, 0, false); + promise_p->fulfill_reactions = ecma_new_values_collection (NULL, 0, false); + + /* Reject reactions will never be triggered. */ + ecma_free_values_collection (reject_reactions, false); + ecma_promise_trigger_reactions (fulfill_reactions, value); } /* ecma_fulfill_promise */ /** diff --git a/jerry-core/ecma/operations/ecma-regexp-object.c b/jerry-core/ecma/operations/ecma-regexp-object.c index 22c5b1d73..172b8019e 100644 --- a/jerry-core/ecma/operations/ecma-regexp-object.c +++ b/jerry-core/ecma/operations/ecma-regexp-object.c @@ -1241,8 +1241,8 @@ ecma_regexp_exec_helper (ecma_value_t regexp_value, /**< RegExp object */ JERRY_ASSERT (ecma_object_class_is (regexp_object_p, LIT_MAGIC_STRING_REGEXP_UL)); ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) regexp_object_p; - re_compiled_code_t *bc_p = ECMA_GET_INTERNAL_VALUE_POINTER (re_compiled_code_t, - ext_object_p->u.class_prop.u.value); + re_compiled_code_t *bc_p = ECMA_GET_INTERNAL_VALUE_ANY_POINTER (re_compiled_code_t, + ext_object_p->u.class_prop.u.value); if (bc_p == NULL) { diff --git a/jerry-core/parser/js/byte-code.h b/jerry-core/parser/js/byte-code.h index 511fb6099..99ab5f9f8 100644 --- a/jerry-core/parser/js/byte-code.h +++ b/jerry-core/parser/js/byte-code.h @@ -200,7 +200,7 @@ /* Stack consumption of opcodes with context. */ /* PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION must be <= 4 */ -#define PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION 3 +#define PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION 4 /* PARSER_WITH_CONTEXT_STACK_ALLOCATION must be <= 4 */ #define PARSER_WITH_CONTEXT_STACK_ALLOCATION 2 /* PARSER_TRY_CONTEXT_STACK_ALLOCATION must be <= 3 */ diff --git a/jerry-core/vm/opcodes.c b/jerry-core/vm/opcodes.c index 60648b27b..97a6534f3 100644 --- a/jerry-core/vm/opcodes.c +++ b/jerry-core/vm/opcodes.c @@ -285,15 +285,14 @@ vm_op_delete_var (jmem_cpointer_t name_literal, /**< name literal */ * See also: * ECMA-262 v5, 12.6.4 * - * @return completion value - * Returned value must be freed with ecma_free_value + * @return chain list of property names */ -ecma_collection_header_t * +ecma_collection_chunk_t * opfunc_for_in (ecma_value_t left_value, /**< left value */ ecma_value_t *result_obj_p) /**< expression object */ { ecma_value_t compl_val = ECMA_VALUE_EMPTY; - ecma_collection_header_t *prop_names_p = NULL; + ecma_collection_chunk_t *prop_names_p = NULL; /* 3. */ if (!ecma_is_value_undefined (left_value) @@ -305,18 +304,18 @@ opfunc_for_in (ecma_value_t left_value, /**< left value */ compl_val); ecma_object_t *obj_p = ecma_get_object_from_value (obj_expr_value); - prop_names_p = ecma_op_object_get_property_names (obj_p, false, true, true); + ecma_collection_header_t *prop_names_coll_p = ecma_op_object_get_property_names (obj_p, false, true, true); - if (prop_names_p->unit_number != 0) + if (prop_names_coll_p->item_count != 0) { + prop_names_p = ECMA_GET_POINTER (ecma_collection_chunk_t, + prop_names_coll_p->first_chunk_cp); + ecma_ref_object (obj_p); *result_obj_p = ecma_make_object_value (obj_p); } - else - { - ecma_dealloc_collection_header (prop_names_p); - prop_names_p = NULL; - } + + jmem_heap_free_block (prop_names_coll_p, sizeof (ecma_collection_header_t)); ECMA_FINALIZE (obj_expr_value); } diff --git a/jerry-core/vm/opcodes.h b/jerry-core/vm/opcodes.h index f2c73c3ec..56128e494 100644 --- a/jerry-core/vm/opcodes.h +++ b/jerry-core/vm/opcodes.h @@ -93,7 +93,7 @@ vm_op_delete_prop (ecma_value_t object, ecma_value_t property, bool is_strict); ecma_value_t vm_op_delete_var (jmem_cpointer_t name_literal, ecma_object_t *lex_env_p); -ecma_collection_header_t * +ecma_collection_chunk_t * opfunc_for_in (ecma_value_t left_value, ecma_value_t *result_obj_p); /** diff --git a/jerry-core/vm/vm-stack.c b/jerry-core/vm/vm-stack.c index 004001ff8..d0278b798 100644 --- a/jerry-core/vm/vm-stack.c +++ b/jerry-core/vm/vm-stack.c @@ -67,21 +67,30 @@ vm_stack_context_abort (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ } case VM_CONTEXT_FOR_IN: { - jmem_cpointer_t current = (jmem_cpointer_t) vm_stack_top_p[-2]; + ecma_collection_chunk_t *chunk_p; + chunk_p = ECMA_GET_INTERNAL_VALUE_ANY_POINTER (ecma_collection_chunk_t, vm_stack_top_p[-2]); + uint32_t index = vm_stack_top_p[-3]; - while (current != JMEM_CP_NULL) + while (chunk_p != NULL) { - ecma_collection_chunk_t *chunk_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_collection_chunk_t, - current); + ecma_value_t value = chunk_p->items[index]; - lit_utf8_byte_t *data_ptr = chunk_p->data; - ecma_free_value (*(ecma_value_t *) data_ptr); + if (unlikely (ecma_is_value_collection_chunk (value))) + { + ecma_collection_chunk_t *next_chunk_p = ecma_get_collection_chunk_from_value (value); + jmem_heap_free_block (chunk_p, sizeof (ecma_collection_chunk_t)); - current = chunk_p->next_chunk_cp; - ecma_dealloc_collection_chunk (chunk_p); + chunk_p = next_chunk_p; + index = 0; + } + else + { + ecma_free_value (value); + index++; + } } - ecma_free_value (vm_stack_top_p[-3]); + ecma_free_value (vm_stack_top_p[-4]); VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION); vm_stack_top_p -= PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION; diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index 3dd634615..c99805d15 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -2274,10 +2274,10 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p); ecma_value_t expr_obj_value = ECMA_VALUE_UNDEFINED; - ecma_collection_header_t *header_p = opfunc_for_in (value, &expr_obj_value); + ecma_collection_chunk_t *prop_names_p = opfunc_for_in (value, &expr_obj_value); ecma_free_value (value); - if (header_p == NULL) + if (prop_names_p == NULL) { byte_code_p = byte_code_start_p + branch_offset; continue; @@ -2288,62 +2288,92 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ VM_PLUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION); stack_top_p += PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION; stack_top_p[-1] = (ecma_value_t) VM_CREATE_CONTEXT (VM_CONTEXT_FOR_IN, branch_offset); - stack_top_p[-2] = header_p->first_chunk_cp; - stack_top_p[-3] = expr_obj_value; + ECMA_SET_INTERNAL_VALUE_ANY_POINTER (stack_top_p[-2], prop_names_p); + stack_top_p[-3] = 0; + stack_top_p[-4] = expr_obj_value; - ecma_dealloc_collection_header (header_p); continue; } case VM_OC_FOR_IN_GET_NEXT: { ecma_value_t *context_top_p = frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth; - ecma_collection_chunk_t *chunk_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_collection_chunk_t, context_top_p[-2]); + + ecma_collection_chunk_t *chunk_p; + chunk_p = ECMA_GET_INTERNAL_VALUE_ANY_POINTER (ecma_collection_chunk_t, context_top_p[-2]); JERRY_ASSERT (VM_GET_CONTEXT_TYPE (context_top_p[-1]) == VM_CONTEXT_FOR_IN); - lit_utf8_byte_t *data_ptr = chunk_p->data; - result = *(ecma_value_t *) data_ptr; - context_top_p[-2] = chunk_p->next_chunk_cp; + uint32_t index = context_top_p[-3]; - ecma_dealloc_collection_chunk (chunk_p); + JERRY_ASSERT (!ecma_is_value_collection_chunk (chunk_p->items[index])); - *stack_top_p++ = result; + *stack_top_p++ = chunk_p->items[index]; + index++; + + if (likely (!ecma_is_value_collection_chunk (chunk_p->items[index]))) + { + context_top_p[-3] = index; + continue; + } + + context_top_p[-3] = 0; + + ecma_collection_chunk_t *next_chunk_p = ecma_get_collection_chunk_from_value (chunk_p->items[index]); + ECMA_SET_INTERNAL_VALUE_ANY_POINTER (context_top_p[-2], next_chunk_p); + + jmem_heap_free_block (chunk_p, sizeof (ecma_collection_chunk_t)); continue; } case VM_OC_FOR_IN_HAS_NEXT: { JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p); + ecma_collection_chunk_t *chunk_p; + chunk_p = ECMA_GET_INTERNAL_VALUE_ANY_POINTER (ecma_collection_chunk_t, stack_top_p[-2]); + + uint32_t index = stack_top_p[-3]; + ecma_object_t *object_p = ecma_get_object_from_value (stack_top_p[-4]); + while (true) { - if (stack_top_p[-2] == JMEM_CP_NULL) + if (chunk_p == NULL) { - ecma_free_value (stack_top_p[-3]); + ecma_deref_object (object_p); VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION); stack_top_p -= PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION; break; } - ecma_collection_chunk_t *chunk_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_collection_chunk_t, stack_top_p[-2]); + ecma_string_t *prop_name_p = ecma_get_string_from_value (chunk_p->items[index]); - lit_utf8_byte_t *data_ptr = chunk_p->data; - ecma_string_t *prop_name_p = ecma_get_string_from_value (*(ecma_value_t *) data_ptr); - - if (!ecma_op_object_has_property (ecma_get_object_from_value (stack_top_p[-3]), - prop_name_p)) - { - stack_top_p[-2] = chunk_p->next_chunk_cp; - ecma_deref_ecma_string (prop_name_p); - ecma_dealloc_collection_chunk (chunk_p); - } - else + if (likely (ecma_op_object_has_property (object_p, prop_name_p))) { byte_code_p = byte_code_start_p + branch_offset; break; } - } + index++; + ecma_value_t value = chunk_p->items[index]; + + if (likely (!ecma_is_value_collection_chunk (value))) + { + stack_top_p[-3] = index; + } + else + { + index = 0; + stack_top_p[-3] = 0; + + ecma_collection_chunk_t *next_chunk_p = ecma_get_collection_chunk_from_value (value); + ECMA_SET_INTERNAL_VALUE_ANY_POINTER (stack_top_p[-2], next_chunk_p); + + jmem_heap_free_block (chunk_p, sizeof (ecma_collection_chunk_t)); + chunk_p = next_chunk_p; + } + + ecma_deref_ecma_string (prop_name_p); + } continue; } case VM_OC_TRY: