From 1c3453999705c1088338fdfeeec62deeb65cbb29 Mon Sep 17 00:00:00 2001 From: Robert Fancsik Date: Tue, 29 Oct 2019 10:10:25 +0100 Subject: [PATCH] Rework array hole calculation for fast access mode arrays (#3248) This patch gives possibility to Array.prototype builtin routine optimizations. JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik frobert@inf.u-szeged.hu --- jerry-core/api/jerry.c | 12 +- jerry-core/debugger/debugger.c | 9 +- jerry-core/ecma/base/ecma-gc.c | 23 +- jerry-core/ecma/base/ecma-globals.h | 12 +- .../base/ecma-helpers-external-pointers.c | 9 +- jerry-core/ecma/base/ecma-helpers.c | 13 +- jerry-core/ecma/base/ecma-init-finalize.c | 8 +- .../ecma-builtin-array-prototype.c | 9 +- .../builtin-objects/ecma-builtin-helpers.c | 2 +- .../ecma-builtin-string-prototype.c | 3 +- .../ecma/builtin-objects/ecma-builtins.c | 4 +- .../ecma/operations/ecma-array-object.c | 265 +++++++++--------- .../ecma/operations/ecma-array-object.h | 28 +- .../ecma/operations/ecma-container-object.c | 3 +- .../ecma/operations/ecma-objects-general.c | 3 +- jerry-core/ecma/operations/ecma-objects.c | 30 +- jerry-core/vm/opcodes.c | 75 ++++- jerry-core/vm/opcodes.h | 3 + jerry-core/vm/vm-utils.c | 2 +- jerry-core/vm/vm.c | 67 +---- 20 files changed, 293 insertions(+), 287 deletions(-) diff --git a/jerry-core/api/jerry.c b/jerry-core/api/jerry.c index 74f7bbe6f..9ffa9d7ba 100644 --- a/jerry-core/api/jerry.c +++ b/jerry-core/api/jerry.c @@ -2055,8 +2055,7 @@ jerry_has_internal_property (const jerry_value_t obj_val, /**< object value */ ecma_string_t *internal_string_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_API_INTERNAL); - if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_ARRAY - && ((ecma_extended_object_t *) obj_p)->u.array.is_fast_mode) + if (ecma_op_object_is_fast_array (obj_p)) { return false; } @@ -2146,8 +2145,7 @@ jerry_delete_internal_property (const jerry_value_t obj_val, /**< object value * ecma_string_t *internal_string_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_API_INTERNAL); - if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_ARRAY - && ((ecma_extended_object_t *) obj_p)->u.array.is_fast_mode) + if (ecma_op_object_is_fast_array (obj_p)) { return true; } @@ -2249,8 +2247,7 @@ jerry_get_internal_property (const jerry_value_t obj_val, /**< object value */ ecma_string_t *internal_string_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_API_INTERNAL); - if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_ARRAY - && ((ecma_extended_object_t *) obj_p)->u.array.is_fast_mode) + if (ecma_op_object_is_fast_array (obj_p)) { return jerry_return (ECMA_VALUE_UNDEFINED); } @@ -2360,8 +2357,7 @@ jerry_set_internal_property (const jerry_value_t obj_val, /**< object value */ ecma_string_t *internal_string_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_API_INTERNAL); - if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_ARRAY - && ((ecma_extended_object_t *) obj_p)->u.array.is_fast_mode) + if (ecma_op_object_is_fast_array (obj_p)) { ecma_fast_array_convert_to_normal (obj_p); } diff --git a/jerry-core/debugger/debugger.c b/jerry-core/debugger/debugger.c index 1f56bea41..4751c1b91 100644 --- a/jerry-core/debugger/debugger.c +++ b/jerry-core/debugger/debugger.c @@ -458,14 +458,9 @@ jerry_debugger_send_scope_variables (const uint8_t *recv_buffer_p) /**< pointer JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND); ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); - if (JERRY_UNLIKELY (ecma_get_object_type (binding_obj_p) == ECMA_OBJECT_TYPE_ARRAY)) + if (JERRY_UNLIKELY (ecma_op_object_is_fast_array (binding_obj_p))) { - ecma_extended_object_t *ext_binding_obj_p = (ecma_extended_object_t *) binding_obj_p; - - if (ext_binding_obj_p->u.array.is_fast_mode) - { - ecma_fast_array_convert_to_normal (binding_obj_p); - } + ecma_fast_array_convert_to_normal (binding_obj_p); } prop_iter_cp = binding_obj_p->u1.property_list_cp; diff --git a/jerry-core/ecma/base/ecma-gc.c b/jerry-core/ecma/base/ecma-gc.c index 879d94999..84ceafea2 100644 --- a/jerry-core/ecma/base/ecma-gc.c +++ b/jerry-core/ecma/base/ecma-gc.c @@ -18,6 +18,7 @@ */ #include "ecma-alloc.h" +#include "ecma-array-object.h" #include "ecma-container-object.h" #include "ecma-globals.h" #include "ecma-gc.h" @@ -482,7 +483,7 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ { ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; - if (ext_object_p->u.array.is_fast_mode) + if (ecma_op_array_is_fast_array (ext_object_p)) { if (object_p->u1.property_list_cp != JMEM_CP_NULL) { @@ -611,11 +612,9 @@ ecma_gc_free_native_pointer (ecma_property_t *property_p) /**< property */ static void ecma_free_fast_access_array (ecma_object_t *object_p) /**< fast access mode array object to free */ { - JERRY_ASSERT (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_ARRAY); + JERRY_ASSERT (ecma_op_object_is_fast_array (object_p)); + ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; - - JERRY_ASSERT (ext_object_p->u.array.is_fast_mode); - const uint32_t aligned_length = ECMA_FAST_ARRAY_ALIGN_LENGTH (ext_object_p->u.array.length); if (object_p->u1.property_list_cp != JMEM_CP_NULL) @@ -651,15 +650,10 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ if (obj_is_not_lex_env || ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) { - if (obj_is_not_lex_env && ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_ARRAY) + if (obj_is_not_lex_env && ecma_op_object_is_fast_array (object_p)) { - ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; - - if (ext_object_p->u.array.is_fast_mode) - { - ecma_free_fast_access_array (object_p); - return; - } + ecma_free_fast_access_array (object_p); + return; } jmem_cpointer_t prop_iter_cp = object_p->u1.property_list_cp; @@ -1203,8 +1197,7 @@ ecma_free_unused_memory (jmem_pressure_t pressure) /**< current pressure */ || ecma_get_lex_env_type (obj_iter_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) { if (!ecma_is_lexical_environment (obj_iter_p) - && ecma_get_object_type (obj_iter_p) == ECMA_OBJECT_TYPE_ARRAY - && ((ecma_extended_object_t *) obj_iter_p)->u.array.is_fast_mode) + && ecma_op_object_is_fast_array (obj_iter_p)) { obj_iter_cp = obj_iter_p->gc_next_cp; continue; diff --git a/jerry-core/ecma/base/ecma-globals.h b/jerry-core/ecma/base/ecma-globals.h index a123bad79..d6222098a 100644 --- a/jerry-core/ecma/base/ecma-globals.h +++ b/jerry-core/ecma/base/ecma-globals.h @@ -837,10 +837,13 @@ typedef struct struct { uint32_t length; /**< length property value */ - ecma_property_t length_prop; /**< length property */ - bool is_fast_mode; /**< true - if the array is a fast access mode array - * false - otherwise */ - uint8_t hole_count; /**< Number of array holes in a fast access mode array */ + union + { + ecma_property_t length_prop; /**< length property */ + uint32_t hole_count; /**< number of array holes in a fast access mode array + * multiplied ECMA_FAST_ACCESS_HOLE_ONE */ + } u; + } array; /** @@ -900,7 +903,6 @@ typedef struct #define ECMA_FAST_ARRAY_ALIGN_LENGTH(length) \ (uint32_t) ((((length)) + ECMA_FAST_ARRAY_ALIGNMENT - 1) / ECMA_FAST_ARRAY_ALIGNMENT * ECMA_FAST_ARRAY_ALIGNMENT) - /** * Compiled byte code data. */ diff --git a/jerry-core/ecma/base/ecma-helpers-external-pointers.c b/jerry-core/ecma/base/ecma-helpers-external-pointers.c index b9a20d6be..12d41641f 100644 --- a/jerry-core/ecma/base/ecma-helpers-external-pointers.c +++ b/jerry-core/ecma/base/ecma-helpers-external-pointers.c @@ -39,8 +39,7 @@ ecma_create_native_pointer_property (ecma_object_t *obj_p, /**< object to create { ecma_string_t *name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER); - if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_ARRAY - && ((ecma_extended_object_t *) obj_p)->u.array.is_fast_mode) + if (ecma_op_object_is_fast_array (obj_p)) { ecma_fast_array_convert_to_normal (obj_p); } @@ -115,8 +114,7 @@ ecma_native_pointer_t * ecma_get_native_pointer_value (ecma_object_t *obj_p, /**< object to get property value from */ void *info_p) /**< native pointer's type info */ { - if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_ARRAY - && ((ecma_extended_object_t *) obj_p)->u.array.is_fast_mode) + if (ecma_op_object_is_fast_array (obj_p)) { /* Fast access mode array can not have native pointer properties */ return NULL; @@ -164,8 +162,7 @@ bool ecma_delete_native_pointer_property (ecma_object_t *obj_p, /**< object to delete property from */ void *info_p) /**< native pointer's type info */ { - if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_ARRAY - && ((ecma_extended_object_t *) obj_p)->u.array.is_fast_mode) + if (ecma_op_object_is_fast_array (obj_p)) { /* Fast access mode array can not have native pointer properties */ return false; diff --git a/jerry-core/ecma/base/ecma-helpers.c b/jerry-core/ecma/base/ecma-helpers.c index 003c72785..10c59ca4d 100644 --- a/jerry-core/ecma/base/ecma-helpers.c +++ b/jerry-core/ecma/base/ecma-helpers.c @@ -14,6 +14,7 @@ */ #include "ecma-alloc.h" +#include "ecma-array-object.h" #include "ecma-gc.h" #include "ecma-globals.h" #include "ecma-helpers.h" @@ -473,8 +474,7 @@ ecma_create_named_data_property (ecma_object_t *object_p, /**< object */ { JERRY_ASSERT (object_p != NULL && name_p != NULL); JERRY_ASSERT (ecma_is_lexical_environment (object_p) - || ecma_get_object_type (object_p) != ECMA_OBJECT_TYPE_ARRAY - || !((ecma_extended_object_t *) object_p)->u.array.is_fast_mode); + || !ecma_op_object_is_fast_array (object_p)); JERRY_ASSERT (ecma_find_named_property (object_p, name_p) == NULL); JERRY_ASSERT ((prop_attributes & ~ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE) == 0); @@ -502,8 +502,7 @@ ecma_create_named_accessor_property (ecma_object_t *object_p, /**< object */ { JERRY_ASSERT (object_p != NULL && name_p != NULL); JERRY_ASSERT (ecma_is_lexical_environment (object_p) - || ecma_get_object_type (object_p) != ECMA_OBJECT_TYPE_ARRAY - || !((ecma_extended_object_t *) object_p)->u.array.is_fast_mode); + || !ecma_op_object_is_fast_array (object_p)); JERRY_ASSERT (ecma_find_named_property (object_p, name_p) == NULL); JERRY_ASSERT ((prop_attributes & ~ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE) == 0); @@ -537,8 +536,7 @@ ecma_find_named_property (ecma_object_t *obj_p, /**< object to find property in JERRY_ASSERT (obj_p != NULL); JERRY_ASSERT (name_p != NULL); JERRY_ASSERT (ecma_is_lexical_environment (obj_p) - || ecma_get_object_type (obj_p) != ECMA_OBJECT_TYPE_ARRAY - || !((ecma_extended_object_t *) obj_p)->u.array.is_fast_mode); + || !ecma_op_object_is_fast_array (obj_p)); ecma_property_t *property_p = NULL; @@ -696,8 +694,7 @@ ecma_get_named_data_property (ecma_object_t *obj_p, /**< object to find property JERRY_ASSERT (obj_p != NULL); JERRY_ASSERT (name_p != NULL); JERRY_ASSERT (ecma_is_lexical_environment (obj_p) - || ecma_get_object_type (obj_p) != ECMA_OBJECT_TYPE_ARRAY - || !((ecma_extended_object_t *) obj_p)->u.array.is_fast_mode); + || !ecma_op_object_is_fast_array (obj_p)); ecma_property_t *property_p = ecma_find_named_property (obj_p, name_p); diff --git a/jerry-core/ecma/base/ecma-init-finalize.c b/jerry-core/ecma/base/ecma-init-finalize.c index 5a78cc2cc..2a85d54f6 100644 --- a/jerry-core/ecma/base/ecma-init-finalize.c +++ b/jerry-core/ecma/base/ecma-init-finalize.c @@ -35,6 +35,10 @@ void ecma_init (void) { +#if (JERRY_GC_MARK_LIMIT != 0) + JERRY_CONTEXT (ecma_gc_mark_recursion_limit) = JERRY_GC_MARK_LIMIT; +#endif /* (JERRY_GC_MARK_LIMIT != 0) */ + ecma_init_global_lex_env (); #if ENABLED (JERRY_PROPRETY_HASHMAP) @@ -47,10 +51,6 @@ ecma_init (void) JERRY_CONTEXT (stack_base) = (uintptr_t)&sp; #endif /* (JERRY_STACK_LIMIT != 0) */ -#if (JERRY_GC_MARK_LIMIT != 0) - JERRY_CONTEXT (ecma_gc_mark_recursion_limit) = JERRY_GC_MARK_LIMIT; -#endif /* (JERRY_GC_MARK_LIMIT != 0) */ - #if ENABLED (JERRY_ES2015_BUILTIN_PROMISE) ecma_job_queue_init (); #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */ 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 48bbcc949..d6ab10324 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c @@ -425,8 +425,7 @@ ecma_builtin_array_prototype_object_pop (ecma_object_t *obj_p, /**< array object return get_value; } - if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_ARRAY - && ((ecma_extended_object_t *) obj_p)->u.array.is_fast_mode) + if (ecma_op_object_is_fast_array (obj_p)) { if (!ecma_get_object_extensible (obj_p)) { @@ -478,8 +477,7 @@ ecma_builtin_array_prototype_object_push (const ecma_value_t *argument_list_p, / { ecma_number_t n = (ecma_number_t) length; - if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_ARRAY - && ((ecma_extended_object_t *) obj_p)->u.array.is_fast_mode) + if (ecma_op_object_is_fast_array (obj_p)) { if (!ecma_get_object_extensible (obj_p)) { @@ -497,6 +495,7 @@ ecma_builtin_array_prototype_object_push (const ecma_value_t *argument_list_p, / } uint32_t new_length = length + arguments_number; + ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) obj_p; ecma_value_t *buffer_p = ecma_fast_array_extend (obj_p, new_length) + length; for (uint32_t index = 0; index < arguments_number; index++) @@ -504,6 +503,8 @@ ecma_builtin_array_prototype_object_push (const ecma_value_t *argument_list_p, / buffer_p[index] = ecma_copy_value_if_not_object (argument_list_p[index]); } + ext_obj_p->u.array.u.hole_count -= ECMA_FAST_ARRAY_HOLE_ONE * arguments_number; + return ecma_make_uint32_value (new_length); } diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.c b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.c index 428656a0f..4dc768072 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.c @@ -293,7 +293,7 @@ ecma_builtin_helper_object_get_properties (ecma_object_t *obj_p, /**< object */ return new_array; } - JERRY_ASSERT (((ecma_extended_object_t *) new_array_p)->u.array.is_fast_mode); + JERRY_ASSERT (ecma_op_object_is_fast_array (new_array_p)); ecma_value_t *buffer_p = props_p->buffer_p; ecma_value_t *values_p = ecma_fast_array_extend (new_array_p, props_p->item_count); diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.c index 49851ed68..cfa6df617 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.c @@ -1460,8 +1460,7 @@ ecma_builtin_string_prototype_object_split (ecma_value_t this_to_string_val, /** if (separator_is_regexp) { - JERRY_ASSERT (ecma_get_object_type (match_obj_p) != ECMA_OBJECT_TYPE_ARRAY - || !((ecma_extended_object_t *) match_obj_p)->u.array.is_fast_mode); + JERRY_ASSERT (!ecma_op_object_is_fast_array (match_obj_p)); ecma_property_value_t *index_prop_value_p = ecma_get_named_data_property (match_obj_p, magic_index_str_p); ecma_number_t index_num = ecma_get_number_from_value (index_prop_value_p->value); diff --git a/jerry-core/ecma/builtin-objects/ecma-builtins.c b/jerry-core/ecma/builtin-objects/ecma-builtins.c index 809812505..e2b00cc58 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtins.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtins.c @@ -431,9 +431,7 @@ ecma_instantiate_builtin (ecma_builtin_id_t obj_builtin_id) /**< built-in id */ ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p; ext_object_p->u.array.length = 0; - ext_object_p->u.array.length_prop = ECMA_PROPERTY_FLAG_WRITABLE | ECMA_PROPERTY_TYPE_VIRTUAL; - ext_object_p->u.array.is_fast_mode = false; - ext_object_p->u.array.hole_count = 0; + ext_object_p->u.array.u.length_prop = ECMA_PROPERTY_FLAG_WRITABLE | ECMA_PROPERTY_TYPE_VIRTUAL; break; } #endif /* ENABLED (JERRY_BUILTIN_ARRAY) */ diff --git a/jerry-core/ecma/operations/ecma-array-object.c b/jerry-core/ecma/operations/ecma-array-object.c index 6d126f984..6aae44696 100644 --- a/jerry-core/ecma/operations/ecma-array-object.c +++ b/jerry-core/ecma/operations/ecma-array-object.c @@ -34,6 +34,32 @@ * @{ */ +#if ENABLED (JERRY_CPOINTER_32_BIT) +/** + * Maximum length of the array length to allocate fast mode access for it + * e.g. new Array(5000) is constructed as fast mode access array, + * but new Array(50000000) is consturcted as normal property list based array + */ +#define ECMA_FAST_ARRAY_MAX_INITIAL_LENGTH (1 << 17) +#else /* ENABLED (JERRY_CPOINTER_32_BIT) */ +/** + * Maximum length of the array length to allocate fast mode access for it + * e.g. new Array(5000) is constructed as fast mode access array, + * but new Array(50000000) is consturcted as normal property list based array + */ +#define ECMA_FAST_ARRAY_MAX_INITIAL_LENGTH (1 << 13) +#endif /* ENABLED (JERRY_CPOINTER_32_BIT) */ + +/** + * Property name type flag for array indices. + */ +#define ECMA_FAST_ARRAY_UINT32_DIRECT_STRING_PROP_TYPE 0x80 + +/** + * Property attribute for the array 'length' virtual property to indicate fast access mode array + */ +#define ECMA_FAST_ARRAY_FLAG (ECMA_DIRECT_STRING_MAGIC << ECMA_PROPERTY_NAME_TYPE_SHIFT) + /** * Allocate a new array object with the given length * @@ -60,13 +86,38 @@ ecma_op_new_array_object (ecma_length_t length) /**< length of the new array */ ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p; ext_obj_p->u.array.length = length; - ext_obj_p->u.array.length_prop = ECMA_PROPERTY_FLAG_WRITABLE | ECMA_PROPERTY_TYPE_VIRTUAL; - ext_obj_p->u.array.is_fast_mode = false; - ext_obj_p->u.array.hole_count = 0; + ext_obj_p->u.array.u.length_prop = ECMA_PROPERTY_FLAG_WRITABLE | ECMA_PROPERTY_TYPE_VIRTUAL; return object_p; } /* ecma_op_new_array_object */ +/** + * Check whether the given object is fast-access mode array + * + * @return true - if the object is fast-access mode array + * false, otherwise + */ +inline bool JERRY_ATTR_ALWAYS_INLINE +ecma_op_object_is_fast_array (ecma_object_t *object_p) /**< ecma-object */ +{ + return (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_ARRAY && + ecma_op_array_is_fast_array ((ecma_extended_object_t *) object_p)); +} /* ecma_op_object_is_fast_array */ + +/** + * Check whether the given array object is fast-access mode array + * + * @return true - if the array object is fast-access mode array + * false, otherwise + */ +inline bool JERRY_ATTR_ALWAYS_INLINE +ecma_op_array_is_fast_array (ecma_extended_object_t *array_p) /**< ecma-array-object */ +{ + JERRY_ASSERT (ecma_get_object_type ((ecma_object_t *) array_p) == ECMA_OBJECT_TYPE_ARRAY); + + return array_p->u.array.u.length_prop & ECMA_FAST_ARRAY_FLAG; +} /* ecma_op_array_is_fast_array */ + /** * Allocate a new fast access mode array object with the given length * @@ -90,9 +141,10 @@ ecma_op_new_fast_array_object (ecma_length_t length) /**< length of the new fast } ecma_object_t *object_p = ecma_op_new_array_object (length); - ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p; - ext_obj_p->u.array.is_fast_mode = true; + + ext_obj_p->u.array.u.length_prop = (uint8_t) (ext_obj_p->u.array.u.length_prop | ECMA_FAST_ARRAY_FLAG); + ext_obj_p->u.array.u.hole_count += length * ECMA_FAST_ARRAY_HOLE_ONE; JERRY_ASSERT (object_p->u1.property_list_cp == JMEM_CP_NULL); @@ -105,26 +157,19 @@ ecma_op_new_fast_array_object (ecma_length_t length) /**< length of the new fast return object_p; } /* ecma_op_new_fast_array_object */ -/** - * Property name type flag for array indices. - */ -#define ECMA_FAST_ARRAY_UINT32_DIRECT_STRING_PROP_TYPE 0x80 - /** * Converts a fast access mode array back to a normal property list based array */ void ecma_fast_array_convert_to_normal (ecma_object_t *object_p) /**< fast access mode array object */ { - JERRY_ASSERT (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_ARRAY); + JERRY_ASSERT (ecma_op_object_is_fast_array (object_p)); ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p; - JERRY_ASSERT (ext_obj_p->u.array.is_fast_mode); - if (object_p->u1.property_list_cp == JMEM_CP_NULL) { - ext_obj_p->u.array.is_fast_mode = false; + ext_obj_p->u.array.u.length_prop = (uint8_t) (ext_obj_p->u.array.u.length_prop & ~ECMA_FAST_ARRAY_FLAG); return; } @@ -132,15 +177,6 @@ ecma_fast_array_convert_to_normal (ecma_object_t *object_p) /**< fast access mod const uint32_t aligned_length = ECMA_FAST_ARRAY_ALIGN_LENGTH (length); ecma_value_t *values_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, object_p->u1.property_list_cp); - /* Check whether the buffer contains only array holes */ - if (JERRY_UNLIKELY (ext_obj_p->u.array.length == ext_obj_p->u.array.hole_count)) - { - ext_obj_p->u.array.is_fast_mode = false; - jmem_heap_free_block (values_p, aligned_length * sizeof (ecma_value_t)); - object_p->u1.property_list_cp = JMEM_CP_NULL; - return; - } - ecma_ref_object (object_p); ecma_property_pair_t *property_pair_p = NULL; @@ -179,29 +215,13 @@ ecma_fast_array_convert_to_normal (ecma_object_t *object_p) /**< fast access mod prop_index = !prop_index; } - ext_obj_p->u.array.is_fast_mode = false; + ext_obj_p->u.array.u.length_prop = (uint8_t) (ext_obj_p->u.array.u.length_prop & ~ECMA_FAST_ARRAY_FLAG); jmem_heap_free_block (values_p, aligned_length * sizeof (ecma_value_t)); ECMA_SET_POINTER (object_p->u1.property_list_cp, property_pair_p); ecma_deref_object (object_p); } /* ecma_fast_array_convert_to_normal */ -#if ENABLED (JERRY_SYSTEM_ALLOCATOR) -/** - * Maximum length of the array length to allocate fast mode access for it - * e.g. new Array(5000) is constructed as fast mode access array, - * but new Array(50000000) is consturcted as normal property list based array - */ -#define ECMA_FAST_ARRAY_MAX_INITIAL_LENGTH (1 << 17) -#else -/** - * Maximum length of the array length to allocate fast mode access for it - * e.g. new Array(5000) is constructed as fast mode access array, - * but new Array(50000000) is consturcted as normal property list based array - */ -#define ECMA_FAST_ARRAY_MAX_INITIAL_LENGTH (1 << 13) -#endif - /** * [[Put]] operation for a fast access mode array * @@ -215,13 +235,13 @@ ecma_fast_array_set_property (ecma_object_t *object_p, /**< fast access mode arr uint32_t index, /**< property name index */ ecma_value_t value) /**< value to be set */ { - JERRY_ASSERT (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_ARRAY); + JERRY_ASSERT (ecma_op_object_is_fast_array (object_p)); ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p; - JERRY_ASSERT (ext_obj_p->u.array.is_fast_mode); + uint32_t old_length = ext_obj_p->u.array.length; ecma_value_t *values_p; - if (JERRY_LIKELY (index < ext_obj_p->u.array.length)) + if (JERRY_LIKELY (index < old_length)) { JERRY_ASSERT (object_p->u1.property_list_cp != JMEM_CP_NULL); @@ -229,7 +249,7 @@ ecma_fast_array_set_property (ecma_object_t *object_p, /**< fast access mode arr if (ecma_is_value_array_hole (values_p[index])) { - ext_obj_p->u.array.hole_count = (uint8_t) JERRY_MAX (ext_obj_p->u.array.hole_count - 1, 0); + ext_obj_p->u.array.u.hole_count -= ECMA_FAST_ARRAY_HOLE_ONE; } else { @@ -241,10 +261,21 @@ ecma_fast_array_set_property (ecma_object_t *object_p, /**< fast access mode arr return true; } - uint32_t new_holes = index - ext_obj_p->u.array.length; - uint32_t old_length = ext_obj_p->u.array.length; + uint32_t old_holes = ext_obj_p->u.array.u.hole_count; + uint32_t new_holes = index - old_length; + + if (JERRY_UNLIKELY (new_holes > ECMA_FAST_ARRAY_MAX_NEW_HOLES_COUNT + || ((old_holes >> ECMA_FAST_ARRAY_HOLE_SHIFT) + new_holes) > ECMA_FAST_ARRAY_MAX_HOLE_COUNT)) + { + ecma_fast_array_convert_to_normal (object_p); + + return false; + } + uint32_t new_length = index + 1; + JERRY_ASSERT (new_length < UINT32_MAX); + const uint32_t aligned_length = ECMA_FAST_ARRAY_ALIGN_LENGTH (old_length); if (JERRY_LIKELY (index < aligned_length)) @@ -252,24 +283,15 @@ ecma_fast_array_set_property (ecma_object_t *object_p, /**< fast access mode arr JERRY_ASSERT (object_p->u1.property_list_cp != JMEM_CP_NULL); values_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, object_p->u1.property_list_cp); + /* This area is filled with ECMA_VALUE_ARRAY_HOLE, but not counted in u.array.u.hole_count */ JERRY_ASSERT (ecma_is_value_array_hole (values_p[index])); + ext_obj_p->u.array.u.hole_count += new_holes * ECMA_FAST_ARRAY_HOLE_ONE; ext_obj_p->u.array.length = new_length; - ext_obj_p->u.array.hole_count = (uint8_t) JERRY_MIN (ext_obj_p->u.array.hole_count + new_holes, - ECMA_FAST_ARRAY_MAX_HOLE_COUNT); } else { - JERRY_ASSERT (ext_obj_p->u.array.hole_count <= ECMA_FAST_ARRAY_MAX_HOLE_COUNT); - - if (new_holes > (uint32_t) (ECMA_FAST_ARRAY_MAX_HOLE_COUNT - ext_obj_p->u.array.hole_count)) - { - ecma_fast_array_convert_to_normal (object_p); - - return false; - } - values_p = ecma_fast_array_extend (object_p, new_length); - ext_obj_p->u.array.hole_count = (uint8_t) (ext_obj_p->u.array.hole_count + new_holes); + ext_obj_p->u.array.u.hole_count -= ECMA_FAST_ARRAY_HOLE_ONE; } values_p[index] = ecma_copy_value_if_not_object (value); @@ -287,11 +309,10 @@ ecma_value_t * ecma_fast_array_extend (ecma_object_t *object_p, /**< fast access mode array object */ uint32_t new_length) /**< new length of the fast access mode array */ { - JERRY_ASSERT (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_ARRAY); + JERRY_ASSERT (ecma_op_object_is_fast_array (object_p)); ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p; uint32_t old_length = ext_obj_p->u.array.length; - JERRY_ASSERT (ext_obj_p->u.array.is_fast_mode); JERRY_ASSERT (old_length < new_length); ecma_ref_object (object_p); @@ -317,6 +338,7 @@ ecma_fast_array_extend (ecma_object_t *object_p, /**< fast access mode array obj new_values_p[i] = ECMA_VALUE_ARRAY_HOLE; } + ext_obj_p->u.array.u.hole_count += (new_length - old_length) * ECMA_FAST_ARRAY_HOLE_ONE; ext_obj_p->u.array.length = new_length; ECMA_SET_NON_NULL_POINTER (object_p->u1.property_list_cp, new_values_p); @@ -338,7 +360,7 @@ ecma_array_object_delete_property (ecma_object_t *object_p, /**< object */ JERRY_ASSERT (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_ARRAY); ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p; - if (!ext_obj_p->u.array.is_fast_mode) + if (!ecma_op_object_is_fast_array (object_p)) { ecma_delete_property (object_p, prop_value_p); return; @@ -360,22 +382,8 @@ ecma_array_object_delete_property (ecma_object_t *object_p, /**< object */ ecma_free_value_if_not_object (values_p[index]); - if (JERRY_UNLIKELY (ext_obj_p->u.array.length == 1)) - { - const uint32_t old_length_aligned = ECMA_FAST_ARRAY_ALIGN_LENGTH (ext_obj_p->u.array.length); - jmem_heap_free_block (values_p, old_length_aligned * sizeof (ecma_value_t)); - ext_obj_p->u.array.hole_count = 0; - ext_obj_p->u.array.length = 0; - object_p->u1.property_list_cp = JMEM_CP_NULL; - return; - } - values_p[index] = ECMA_VALUE_ARRAY_HOLE; - - if (++ext_obj_p->u.array.hole_count > ECMA_FAST_ARRAY_MAX_HOLE_COUNT) - { - ecma_fast_array_convert_to_normal (object_p); - } + ext_obj_p->u.array.u.hole_count += ECMA_FAST_ARRAY_HOLE_ONE; } /* ecma_array_object_delete_property */ /** @@ -387,39 +395,22 @@ uint32_t ecma_delete_fast_array_properties (ecma_object_t *object_p, /**< fast access mode array */ uint32_t new_length) /**< new length of the fast access mode array */ { - JERRY_ASSERT (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_ARRAY); + JERRY_ASSERT (ecma_op_object_is_fast_array (object_p)); ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p; - JERRY_ASSERT (ext_obj_p->u.array.is_fast_mode); - ecma_ref_object (object_p); ecma_value_t *values_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, object_p->u1.property_list_cp); uint32_t old_length = ext_obj_p->u.array.length; const uint32_t old_aligned_length = ECMA_FAST_ARRAY_ALIGN_LENGTH (old_length); JERRY_ASSERT (new_length < old_length); - JERRY_ASSERT (ext_obj_p->u.array.is_fast_mode); - - if (new_length == 0) - { - for (uint32_t i = 0; i < old_length; i++) - { - ecma_free_value_if_not_object (values_p[i]); - } - - jmem_heap_free_block (values_p, old_aligned_length * sizeof (ecma_value_t)); - object_p->u1.property_list_cp = JMEM_CP_NULL; - ext_obj_p->u.array.length = new_length; - ecma_deref_object (object_p); - return new_length; - } for (uint32_t i = new_length; i < old_length; i++) { if (ecma_is_value_array_hole (values_p[i])) { - ext_obj_p->u.array.hole_count = (uint8_t) JERRY_MAX (ext_obj_p->u.array.hole_count - 1, 0); + ext_obj_p->u.array.u.hole_count -= ECMA_FAST_ARRAY_HOLE_ONE; } else { @@ -427,21 +418,33 @@ ecma_delete_fast_array_properties (ecma_object_t *object_p, /**< fast access mod } } - const uint32_t new_aligned_length = ECMA_FAST_ARRAY_ALIGN_LENGTH (new_length); + jmem_cpointer_t new_property_list_cp; - ecma_value_t *new_values_p; - new_values_p = (ecma_value_t *) jmem_heap_realloc_block (values_p, - old_aligned_length * sizeof (ecma_value_t), - new_aligned_length * sizeof (ecma_value_t)); - - for (uint32_t i = new_length; i < new_aligned_length; i++) + if (new_length == 0) { - new_values_p[i] = ECMA_VALUE_ARRAY_HOLE; + jmem_heap_free_block (values_p, old_aligned_length * sizeof (ecma_value_t)); + new_property_list_cp = JMEM_CP_NULL; + } + else + { + const uint32_t new_aligned_length = ECMA_FAST_ARRAY_ALIGN_LENGTH (new_length); + + ecma_value_t *new_values_p; + new_values_p = (ecma_value_t *) jmem_heap_realloc_block (values_p, + old_aligned_length * sizeof (ecma_value_t), + new_aligned_length * sizeof (ecma_value_t)); + + for (uint32_t i = new_length; i < new_aligned_length; i++) + { + new_values_p[i] = ECMA_VALUE_ARRAY_HOLE; + } + + ECMA_SET_NON_NULL_POINTER (new_property_list_cp, new_values_p); } ext_obj_p->u.array.length = new_length; + object_p->u1.property_list_cp = new_property_list_cp; - ECMA_SET_POINTER (object_p->u1.property_list_cp, new_values_p); ecma_deref_object (object_p); return new_length; @@ -457,12 +460,11 @@ static void ecma_fast_array_set_length (ecma_object_t *object_p, /**< fast access mode array object */ uint32_t new_length) /**< new length of the fast access mode array object*/ { - JERRY_ASSERT (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_ARRAY); + JERRY_ASSERT (ecma_op_object_is_fast_array (object_p)); ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p; uint32_t old_length = ext_obj_p->u.array.length; - JERRY_ASSERT (ext_obj_p->u.array.is_fast_mode); JERRY_ASSERT (new_length >= old_length); if (new_length == old_length) @@ -470,18 +472,18 @@ ecma_fast_array_set_length (ecma_object_t *object_p, /**< fast access mode array return; } - uint32_t new_holes = new_length - old_length - 1; + uint32_t old_holes = ext_obj_p->u.array.u.hole_count; + uint32_t new_holes = new_length - old_length; - JERRY_ASSERT (ext_obj_p->u.array.hole_count <= ECMA_FAST_ARRAY_MAX_HOLE_COUNT); - - if (new_holes > (uint32_t) (ECMA_FAST_ARRAY_MAX_HOLE_COUNT - ext_obj_p->u.array.hole_count)) + if (JERRY_UNLIKELY (new_holes > ECMA_FAST_ARRAY_MAX_NEW_HOLES_COUNT + || ((old_holes >> ECMA_FAST_ARRAY_HOLE_SHIFT) + new_holes) > ECMA_FAST_ARRAY_MAX_HOLE_COUNT)) { ecma_fast_array_convert_to_normal (object_p); - return; } - - ecma_fast_array_extend (object_p, new_length); - ext_obj_p->u.array.hole_count = (uint8_t) (ext_obj_p->u.array.hole_count + new_holes); + else + { + ecma_fast_array_extend (object_p, new_length); + } return; } /* ecma_fast_array_set_length */ @@ -498,11 +500,9 @@ ecma_collection_t * ecma_fast_array_get_property_names (ecma_object_t *object_p, /**< fast access mode array object */ uint32_t opts) /**< any combination of ecma_list_properties_options_t values */ { - JERRY_ASSERT (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_ARRAY); + JERRY_ASSERT (ecma_op_object_is_fast_array (object_p)); ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p; - JERRY_ASSERT (ext_obj_p->u.array.is_fast_mode); - ecma_collection_t *ret_p = ecma_new_collection (); #if ENABLED (JERRY_ES2015) @@ -610,7 +610,7 @@ ecma_op_create_array_object (const ecma_value_t *arguments_list_p, /**< list of return ecma_make_object_value (ecma_op_new_array_object (length)); } - JERRY_ASSERT (((ecma_extended_object_t *) object_p)->u.array.is_fast_mode); + JERRY_ASSERT (ecma_op_object_is_fast_array (object_p)); return ecma_make_object_value (object_p); } @@ -637,6 +637,7 @@ ecma_op_create_array_object (const ecma_value_t *arguments_list_p, /**< list of } ecma_value_t *values_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, object_p->u1.property_list_cp); + ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p; for (uint32_t index = 0; index < array_items_count; @@ -646,6 +647,8 @@ ecma_op_create_array_object (const ecma_value_t *arguments_list_p, /**< list of values_p[index] = ecma_copy_value_if_not_object (array_items_p[index]); } + ext_obj_p->u.array.u.hole_count -= ECMA_FAST_ARRAY_HOLE_ONE * array_items_count; + return ecma_make_object_value (object_p); } /* ecma_op_create_array_object */ @@ -697,9 +700,7 @@ ecma_delete_array_properties (ecma_object_t *object_p, /**< object */ JERRY_ASSERT (new_length < old_length); JERRY_ASSERT (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_ARRAY); - ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p; - - if (ext_obj_p->u.array.is_fast_mode) + if (ecma_op_object_is_fast_array (object_p)) { return ecma_delete_fast_array_properties (object_p, new_length); } @@ -906,17 +907,17 @@ ecma_op_array_object_set_length (ecma_object_t *object_p, /**< the array object { if (!(flags & ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_WRITABLE)) { - uint8_t new_prop_value = (uint8_t) (ext_object_p->u.array.length_prop & ~ECMA_PROPERTY_FLAG_WRITABLE); - ext_object_p->u.array.length_prop = new_prop_value; + uint8_t new_prop_value = (uint8_t) (ext_object_p->u.array.u.length_prop & ~ECMA_PROPERTY_FLAG_WRITABLE); + ext_object_p->u.array.u.length_prop = new_prop_value; } - else if (!ecma_is_property_writable (ext_object_p->u.array.length_prop)) + else if (!ecma_is_property_writable (ext_object_p->u.array.u.length_prop)) { return ecma_reject (is_throw); } } return ECMA_VALUE_TRUE; } - else if (!ecma_is_property_writable (ext_object_p->u.array.length_prop)) + else if (!ecma_is_property_writable (ext_object_p->u.array.u.length_prop)) { return ecma_reject (is_throw); } @@ -927,7 +928,7 @@ ecma_op_array_object_set_length (ecma_object_t *object_p, /**< the array object { current_len_uint32 = ecma_delete_array_properties (object_p, new_len_uint32, old_len_uint32); } - else if (ext_object_p->u.array.is_fast_mode) + else if (ecma_op_object_is_fast_array (object_p)) { ecma_fast_array_set_length (object_p, new_len_uint32); } @@ -937,8 +938,8 @@ ecma_op_array_object_set_length (ecma_object_t *object_p, /**< the array object if ((flags & ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_WRITABLE_DEFINED) && !(flags & ECMA_ARRAY_OBJECT_SET_LENGTH_FLAG_WRITABLE)) { - uint8_t new_prop_value = (uint8_t) (ext_object_p->u.array.length_prop & ~ECMA_PROPERTY_FLAG_WRITABLE); - ext_object_p->u.array.length_prop = new_prop_value; + uint8_t new_prop_value = (uint8_t) (ext_object_p->u.array.u.length_prop & ~ECMA_PROPERTY_FLAG_WRITABLE); + ext_object_p->u.array.u.length_prop = new_prop_value; } if (current_len_uint32 == new_len_uint32) @@ -1027,7 +1028,7 @@ ecma_op_array_object_define_own_property (ecma_object_t *object_p, /**< the arra ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; - if (ext_object_p->u.array.is_fast_mode) + if (ecma_op_object_is_fast_array (object_p)) { if ((property_desc_p->flags & ECMA_FAST_ARRAY_DATA_PROP_FLAGS) == ECMA_FAST_ARRAY_DATA_PROP_FLAGS) { @@ -1042,7 +1043,7 @@ ecma_op_array_object_define_own_property (ecma_object_t *object_p, /**< the arra return ECMA_VALUE_TRUE; } - JERRY_ASSERT (!ext_object_p->u.array.is_fast_mode); + JERRY_ASSERT (!ecma_op_array_is_fast_array (ext_object_p)); } else { @@ -1050,7 +1051,7 @@ ecma_op_array_object_define_own_property (ecma_object_t *object_p, /**< the arra } } - JERRY_ASSERT (!ext_object_p->u.array.is_fast_mode); + JERRY_ASSERT (!ecma_op_object_is_fast_array (object_p)); uint32_t index = ecma_string_get_array_index (property_name_p); if (index == ECMA_STRING_NOT_ARRAY_INDEX) @@ -1060,7 +1061,7 @@ ecma_op_array_object_define_own_property (ecma_object_t *object_p, /**< the arra bool update_length = (index >= ext_object_p->u.array.length); - if (update_length && !ecma_is_property_writable (ext_object_p->u.array.length_prop)) + if (update_length && !ecma_is_property_writable (ext_object_p->u.array.u.length_prop)) { return ecma_reject (property_desc_p->flags & ECMA_PROP_IS_THROW); } diff --git a/jerry-core/ecma/operations/ecma-array-object.h b/jerry-core/ecma/operations/ecma-array-object.h index d105d8974..0204e81c3 100644 --- a/jerry-core/ecma/operations/ecma-array-object.h +++ b/jerry-core/ecma/operations/ecma-array-object.h @@ -25,12 +25,28 @@ * @{ */ + /** - * Maximum number of array holes in a fast mode access array. - * If the number of holes exceeds this limit, the array is converted back + * Maximum number of new array holes in a fast mode access array. + * If the number of new holes exceeds this limit, the array is converted back * to normal property list based array. */ -#define ECMA_FAST_ARRAY_MAX_HOLE_COUNT 32 +#define ECMA_FAST_ARRAY_MAX_NEW_HOLES_COUNT 32 + +/** + * Bitshift index for fast array hole count representation + */ +#define ECMA_FAST_ARRAY_HOLE_SHIFT 8 + +/** + * This number represents 1 array hole in underlying buffer of a fast acces mode array + */ +#define ECMA_FAST_ARRAY_HOLE_ONE (1 << ECMA_FAST_ARRAY_HOLE_SHIFT) + +/** + * Maximum number of array holes in a fast access mode array + */ +#define ECMA_FAST_ARRAY_MAX_HOLE_COUNT (1 << 24) /** * Flags for ecma_op_array_object_set_length @@ -52,6 +68,12 @@ ecma_op_new_array_object (ecma_length_t length); ecma_object_t * ecma_op_new_fast_array_object (ecma_length_t length); +bool +ecma_op_object_is_fast_array (ecma_object_t *object_p); + +bool +ecma_op_array_is_fast_array (ecma_extended_object_t *array_p); + ecma_value_t * ecma_fast_array_extend (ecma_object_t *object_p, uint32_t new_lengt); diff --git a/jerry-core/ecma/operations/ecma-container-object.c b/jerry-core/ecma/operations/ecma-container-object.c index d42850b3e..c01b3d7d0 100644 --- a/jerry-core/ecma/operations/ecma-container-object.c +++ b/jerry-core/ecma/operations/ecma-container-object.c @@ -247,8 +247,7 @@ ecma_op_container_to_key (ecma_value_t key_arg) /**< key argument */ ecma_object_t *obj_p = ecma_get_object_from_value (key_arg); ecma_string_t *key_string_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_MAP_KEY); - if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_ARRAY - && ((ecma_extended_object_t *) obj_p)->u.array.is_fast_mode) + if (ecma_op_object_is_fast_array (obj_p)) { ecma_fast_array_convert_to_normal (obj_p); } diff --git a/jerry-core/ecma/operations/ecma-objects-general.c b/jerry-core/ecma/operations/ecma-objects-general.c index b8b2ebc89..b1ea9aa40 100644 --- a/jerry-core/ecma/operations/ecma-objects-general.c +++ b/jerry-core/ecma/operations/ecma-objects-general.c @@ -284,8 +284,7 @@ ecma_op_general_object_define_own_property (ecma_object_t *object_p, /**< the ob { JERRY_ASSERT (object_p != NULL && !ecma_is_lexical_environment (object_p)); - JERRY_ASSERT (ecma_get_object_type (object_p) != ECMA_OBJECT_TYPE_ARRAY - || !((ecma_extended_object_t *) object_p)->u.array.is_fast_mode); + JERRY_ASSERT (!ecma_op_object_is_fast_array (object_p)); JERRY_ASSERT (property_name_p != NULL); ecma_property_types_t property_desc_type = ECMA_PROPERTY_TYPE_GENERIC; diff --git a/jerry-core/ecma/operations/ecma-objects.c b/jerry-core/ecma/operations/ecma-objects.c index 0288c1553..3b7ed2a8f 100644 --- a/jerry-core/ecma/operations/ecma-objects.c +++ b/jerry-core/ecma/operations/ecma-objects.c @@ -134,10 +134,10 @@ ecma_op_object_get_own_property (ecma_object_t *object_p, /**< the object */ property_ref_p->virtual_value = ecma_make_uint32_value (ext_object_p->u.array.length); } - return ext_object_p->u.array.length_prop; + return ext_object_p->u.array.u.length_prop & (ECMA_PROPERTY_TYPE_VIRTUAL | ECMA_PROPERTY_FLAG_WRITABLE); } - if (ext_object_p->u.array.is_fast_mode) + if (ecma_op_array_is_fast_array (ext_object_p)) { uint32_t index = ecma_string_get_array_index (property_name_p); @@ -492,7 +492,7 @@ ecma_op_object_find_own (ecma_value_t base_value, /**< base value */ return ecma_make_uint32_value (ext_object_p->u.array.length); } - if (JERRY_LIKELY (ext_object_p->u.array.is_fast_mode)) + if (JERRY_LIKELY (ecma_op_array_is_fast_array (ext_object_p))) { uint32_t index = ecma_string_get_array_index (property_name_p); @@ -765,8 +765,7 @@ ecma_op_object_get_own_data_prop (ecma_object_t *object_p, /**< the object */ ecma_string_t *property_name_p) /**< property name */ { JERRY_ASSERT (ecma_is_lexical_environment (object_p) - || ecma_get_object_type (object_p) != ECMA_OBJECT_TYPE_ARRAY - || !((ecma_extended_object_t *) object_p)->u.array.is_fast_mode); + || !ecma_op_object_is_fast_array (object_p)); ecma_value_t result = ecma_op_object_find_own (ecma_make_object_value (object_p), object_p, @@ -1066,7 +1065,7 @@ ecma_op_object_put (ecma_object_t *object_p, /**< the object */ if (ecma_string_is_length (property_name_p)) { - if (ecma_is_property_writable (ext_object_p->u.array.length_prop)) + if (ecma_is_property_writable (ext_object_p->u.array.u.length_prop)) { return ecma_op_array_object_set_length (object_p, value, 0); } @@ -1074,7 +1073,7 @@ ecma_op_object_put (ecma_object_t *object_p, /**< the object */ return ecma_reject (is_throw); } - if (JERRY_LIKELY (ext_object_p->u.array.is_fast_mode)) + if (JERRY_LIKELY (ecma_op_array_is_fast_array (ext_object_p))) { if (JERRY_UNLIKELY (!ecma_get_object_extensible (object_p))) { @@ -1093,7 +1092,7 @@ ecma_op_object_put (ecma_object_t *object_p, /**< the object */ } } - JERRY_ASSERT (!(ext_object_p->u.array.is_fast_mode)); + JERRY_ASSERT (!ecma_op_object_is_fast_array (object_p)); break; } @@ -1313,7 +1312,7 @@ ecma_op_object_put (ecma_object_t *object_p, /**< the object */ if (index < UINT32_MAX && index >= ext_object_p->u.array.length) { - if (!ecma_is_property_writable (ext_object_p->u.array.length_prop)) + if (!ecma_is_property_writable (ext_object_p->u.array.u.length_prop)) { return ecma_reject (is_throw); } @@ -1756,14 +1755,9 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ JERRY_ASSERT (obj_p != NULL && !ecma_is_lexical_environment (obj_p)); - if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_ARRAY) + if (ecma_op_object_is_fast_array (obj_p)) { - ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p; - - if (ext_object_p->u.array.is_fast_mode) - { - return ecma_fast_array_get_property_names (obj_p, opts); - } + return ecma_fast_array_get_property_names (obj_p, opts); } ecma_collection_t *ret_p = ecma_new_collection (); @@ -1905,9 +1899,7 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ jmem_cpointer_t prop_iter_cp = prototype_chain_iter_p->u1.property_list_cp; - if (ecma_get_object_type (prototype_chain_iter_p) == ECMA_OBJECT_TYPE_ARRAY - && ((ecma_extended_object_t *) prototype_chain_iter_p)->u.array.is_fast_mode - && prop_iter_cp != JMEM_CP_NULL) + if (ecma_op_object_is_fast_array (prototype_chain_iter_p) && prop_iter_cp != JMEM_CP_NULL) { ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) prototype_chain_iter_p; diff --git a/jerry-core/vm/opcodes.c b/jerry-core/vm/opcodes.c index 485f102b4..95c576b46 100644 --- a/jerry-core/vm/opcodes.c +++ b/jerry-core/vm/opcodes.c @@ -14,6 +14,7 @@ */ #include "ecma-alloc.h" +#include "ecma-array-object.h" #include "ecma-builtins.h" #include "ecma-conversion.h" #include "ecma-exceptions.h" @@ -92,8 +93,7 @@ opfunc_set_accessor (bool is_getter, /**< is getter accessor */ { ecma_object_t *object_p = ecma_get_object_from_value (object); - JERRY_ASSERT (ecma_get_object_type (object_p) != ECMA_OBJECT_TYPE_ARRAY - || !((ecma_extended_object_t *) object_p)->u.array.is_fast_mode); + JERRY_ASSERT (!ecma_op_object_is_fast_array (object_p)); ecma_property_t *property_p = ecma_find_named_property (object_p, accessor_name_p); @@ -256,6 +256,77 @@ opfunc_for_in (ecma_value_t left_value, /**< left value */ return NULL; } /* opfunc_for_in */ +/** + * 'VM_OC_APPEND_ARRAY' opcode handler, for setting array object properties + */ +void JERRY_ATTR_NOINLINE +opfunc_append_array (ecma_value_t *stack_top_p, /**< current stack top */ + uint8_t values_length) /**< number of elements to set */ +{ + ecma_object_t *array_obj_p = ecma_get_object_from_value (stack_top_p[-1]); + + JERRY_ASSERT (ecma_get_object_type (array_obj_p) == ECMA_OBJECT_TYPE_ARRAY); + + ecma_extended_object_t *ext_array_obj_p = (ecma_extended_object_t *) array_obj_p; + uint32_t old_length = ext_array_obj_p->u.array.length; + + if (JERRY_LIKELY (ecma_op_array_is_fast_array (ext_array_obj_p))) + { + uint32_t filled_holes = 0; + ecma_value_t *values_p = ecma_fast_array_extend (array_obj_p, old_length + values_length); + + for (uint32_t i = 0; i < values_length; i++) + { + values_p[old_length + i] = stack_top_p[i]; + + if (!ecma_is_value_array_hole (stack_top_p[i])) + { + filled_holes++; + + if (ecma_is_value_object (stack_top_p[i])) + { + ecma_deref_object (ecma_get_object_from_value (stack_top_p[i])); + } + } + } + + ext_array_obj_p->u.array.u.hole_count -= filled_holes * ECMA_FAST_ARRAY_HOLE_ONE; + + if (JERRY_UNLIKELY ((values_length - filled_holes) > ECMA_FAST_ARRAY_MAX_NEW_HOLES_COUNT)) + { + ecma_fast_array_convert_to_normal (array_obj_p); + } + } + else + { + for (uint32_t i = 0; i < values_length; i++) + { + if (!ecma_is_value_array_hole (stack_top_p[i])) + { + ecma_string_t *index_str_p = ecma_new_ecma_string_from_uint32 (old_length + i); + + ecma_property_value_t *prop_value_p; + + prop_value_p = ecma_create_named_data_property (array_obj_p, + index_str_p, + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE, + NULL); + + ecma_deref_ecma_string (index_str_p); + prop_value_p->value = stack_top_p[i]; + + if (ecma_is_value_object (stack_top_p[i])) + { + ecma_free_value (stack_top_p[i]); + } + + } + + ext_array_obj_p->u.array.length = old_length + values_length; + } + } +} /* opfunc_append_array */ + /** * @} * @} diff --git a/jerry-core/vm/opcodes.h b/jerry-core/vm/opcodes.h index 48af585fe..ec657c55e 100644 --- a/jerry-core/vm/opcodes.h +++ b/jerry-core/vm/opcodes.h @@ -93,6 +93,9 @@ vm_op_delete_var (ecma_value_t name_literal, ecma_object_t *lex_env_p); ecma_collection_t * opfunc_for_in (ecma_value_t left_value, ecma_value_t *result_obj_p); +void +opfunc_append_array (ecma_value_t *stack_top_p, uint8_t values_length); + /** * @} * @} diff --git a/jerry-core/vm/vm-utils.c b/jerry-core/vm/vm-utils.c index 8cf64224d..845d7b3f0 100644 --- a/jerry-core/vm/vm-utils.c +++ b/jerry-core/vm/vm-utils.c @@ -70,7 +70,7 @@ vm_get_backtrace (uint32_t max_depth) /**< maximum backtrace depth, 0 = unlimite vm_frame_ctx_t *context_p = JERRY_CONTEXT (vm_top_context_p); ecma_object_t *array_p = ecma_get_object_from_value (result_array); - JERRY_ASSERT (((ecma_extended_object_t *) array_p)->u.array.is_fast_mode); + JERRY_ASSERT (ecma_op_object_is_fast_array (array_p)); uint32_t index = 0; while (context_p != NULL) diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index 49d23b1c6..f0064f338 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -67,7 +67,7 @@ vm_op_get_value (ecma_value_t object, /**< base object */ { ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; - if (JERRY_LIKELY (ext_object_p->u.array.is_fast_mode + if (JERRY_LIKELY (ecma_op_array_is_fast_array (ext_object_p) && (uint32_t) int_value < ext_object_p->u.array.length)) { ecma_value_t *values_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, object_p->u1.property_list_cp); @@ -1305,8 +1305,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ ecma_object_t *object_p = ecma_get_object_from_value (stack_top_p[index]); - JERRY_ASSERT (ecma_get_object_type (object_p) != ECMA_OBJECT_TYPE_ARRAY - || !((ecma_extended_object_t *) object_p)->u.array.is_fast_mode); + JERRY_ASSERT (!ecma_op_object_is_fast_array (object_p)); ecma_property_t *property_p = ecma_find_named_property (object_p, prop_name_p); @@ -1711,67 +1710,9 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } case VM_OC_APPEND_ARRAY: { - ecma_object_t *array_obj_p; - uint32_t values_length = *byte_code_p++; - + uint8_t values_length = *byte_code_p++; stack_top_p -= values_length; - - array_obj_p = ecma_get_object_from_value (stack_top_p[-1]); - ecma_extended_object_t *ext_array_obj_p = (ecma_extended_object_t *) array_obj_p; - uint32_t old_length = ext_array_obj_p->u.array.length; - - if (JERRY_LIKELY (ext_array_obj_p->u.array.is_fast_mode)) - { - ecma_value_t *values_p = ecma_fast_array_extend (array_obj_p, old_length + values_length); - - for (uint32_t i = 0; i < values_length; i++) - { - values_p[old_length + i] = stack_top_p[i]; - - if (JERRY_UNLIKELY (ecma_is_value_array_hole (stack_top_p[i]))) - { - ext_array_obj_p->u.array.hole_count++; - } - else if (ecma_is_value_object (stack_top_p[i])) - { - ecma_deref_object (ecma_get_object_from_value (stack_top_p[i])); - } - } - - if (JERRY_UNLIKELY (ext_array_obj_p->u.array.length > ECMA_FAST_ARRAY_MAX_HOLE_COUNT)) - { - ecma_fast_array_convert_to_normal (array_obj_p); - } - } - else - { - for (uint32_t i = 0; i < values_length; i++) - { - if (!ecma_is_value_array_hole (stack_top_p[i])) - { - ecma_string_t *index_str_p = ecma_new_ecma_string_from_uint32 (old_length + i); - - ecma_property_value_t *prop_value_p; - - prop_value_p = ecma_create_named_data_property (array_obj_p, - index_str_p, - ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE, - NULL); - - ecma_deref_ecma_string (index_str_p); - prop_value_p->value = stack_top_p[i]; - - if (ecma_is_value_object (stack_top_p[i])) - { - ecma_free_value (stack_top_p[i]); - } - - } - } - - ext_array_obj_p->u.array.length = old_length + values_length; - } - + opfunc_append_array (stack_top_p, values_length); continue; } case VM_OC_PUSH_UNDEFINED_BASE: