From c79659d3b2ec6e432e6aaab6a2a9cf8c3e2b49ca Mon Sep 17 00:00:00 2001 From: Robert Fancsik Date: Mon, 9 Sep 2019 10:36:48 +0200 Subject: [PATCH] Fix array initialization with array holes (#3076) Fast mode access arrays must be converted back to normal if the array hole count reaches the limit during the initializtaion. This patch fixes #3075. JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik frobert@inf.u-szeged.hu --- .../ecma/operations/ecma-array-object.c | 7 --- .../ecma/operations/ecma-array-object.h | 7 +++ jerry-core/vm/vm.c | 55 +++++++++++++++---- tests/jerry/regression-test-issue-3072.js | 18 ++++++ 4 files changed, 70 insertions(+), 17 deletions(-) create mode 100644 tests/jerry/regression-test-issue-3072.js diff --git a/jerry-core/ecma/operations/ecma-array-object.c b/jerry-core/ecma/operations/ecma-array-object.c index b3853e229..7e42c6257 100644 --- a/jerry-core/ecma/operations/ecma-array-object.c +++ b/jerry-core/ecma/operations/ecma-array-object.c @@ -186,13 +186,6 @@ ecma_fast_array_convert_to_normal (ecma_object_t *object_p) /**< fast access mod ecma_deref_object (object_p); } /* ecma_fast_array_convert_to_normal */ -/** - * Maximum number of array holes in a fast mode access array. - * If the number of holes exceeds this limit, the array is converted back - * to normal property list based array. - */ -#define ECMA_FAST_ARRAY_MAX_HOLE_COUNT 32 - #if ENABLED (JERRY_SYSTEM_ALLOCATOR) /** * Maximum length of the array length to allocate fast mode access for it diff --git a/jerry-core/ecma/operations/ecma-array-object.h b/jerry-core/ecma/operations/ecma-array-object.h index 17865bccc..876878be7 100644 --- a/jerry-core/ecma/operations/ecma-array-object.h +++ b/jerry-core/ecma/operations/ecma-array-object.h @@ -25,6 +25,13 @@ * @{ */ +/** + * Maximum number of array holes in a fast mode access array. + * If the number of holes exceeds this limit, the array is converted back + * to normal property list based array. + */ +#define ECMA_FAST_ARRAY_MAX_HOLE_COUNT 32 + /** * Flags for ecma_op_array_object_set_length */ diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index c2ca112c1..0cc62e00f 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -1668,23 +1668,58 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ 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; - JERRY_ASSERT (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++) + if (JERRY_LIKELY (ext_array_obj_p->u.array.is_fast_mode)) { - values_p[old_length + i] = stack_top_p[i]; + ecma_value_t *values_p = ecma_fast_array_extend (array_obj_p, old_length + values_length); - if (JERRY_UNLIKELY (ecma_is_value_array_hole (stack_top_p[i]))) + for (uint32_t i = 0; i < values_length; i++) { - ext_array_obj_p->u.array.hole_count++; + 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])); + } } - else if (ecma_is_value_object (stack_top_p[i])) + + if (JERRY_UNLIKELY (ext_array_obj_p->u.array.length > ECMA_FAST_ARRAY_MAX_HOLE_COUNT)) { - ecma_deref_object (ecma_get_object_from_value (stack_top_p[i])); + 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; + } + continue; } case VM_OC_PUSH_UNDEFINED_BASE: diff --git a/tests/jerry/regression-test-issue-3072.js b/tests/jerry/regression-test-issue-3072.js new file mode 100644 index 000000000..4defdee63 --- /dev/null +++ b/tests/jerry/regression-test-issue-3072.js @@ -0,0 +1,18 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var arr = [ , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ]; +arr [4294967294] = 0 +assert (arr.length === 4294967295); +assert (arr[4294967294] === 0);