diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.cpp b/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.cpp index 9bdcd573a..10302c060 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.cpp +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.cpp @@ -1448,44 +1448,65 @@ ecma_builtin_array_prototype_object_sort (ecma_value_t this_arg, /**< this argum uint32_t len = ecma_number_to_uint32 (len_number); - MEM_DEFINE_LOCAL_ARRAY (values_buffer, len, ecma_value_t); + uint32_t defined_prop_count = 0; + /* Count number of defined properties. */ + for (ecma_property_t *property_p = ecma_get_property_list (obj_p); + property_p != NULL; + property_p = ECMA_GET_POINTER (ecma_property_t, property_p->next_property_p)) + { + defined_prop_count++; + } + + MEM_DEFINE_LOCAL_ARRAY (values_buffer, defined_prop_count, ecma_value_t); uint32_t copied_num = 0; /* Copy unsorted array into a native c array. */ for (uint32_t index = 0; index < len && ecma_is_completion_value_empty (ret_value); index++) { ecma_string_t *index_string_p = ecma_new_ecma_string_from_uint32 (index); - ECMA_TRY_CATCH (index_value, ecma_op_object_get (obj_p, index_string_p), ret_value); + if (ecma_op_object_get_property (obj_p, index_string_p) != NULL) + { + ECMA_TRY_CATCH (index_value, ecma_op_object_get (obj_p, index_string_p), ret_value); - values_buffer[index] = ecma_copy_value (index_value, true); - copied_num++; + values_buffer[copied_num++] = ecma_copy_value (index_value, true); - ECMA_FINALIZE (index_value); + ECMA_FINALIZE (index_value); + } ecma_deref_ecma_string (index_string_p); } - JERRY_ASSERT (copied_num == len || !ecma_is_completion_value_empty (ret_value)); + JERRY_ASSERT (copied_num <= defined_prop_count); /* Sorting. */ if (len > 1 && ecma_is_completion_value_empty (ret_value)) { ECMA_TRY_CATCH (sort_value, ecma_builtin_array_prototype_object_array_heap_sort_helper (values_buffer, - (int)(len - 1), + (int)(copied_num - 1), arg1), ret_value); ECMA_FINALIZE (sort_value); } - if (ecma_is_completion_value_empty (ret_value)) + /* Put sorted values to the front of the array. */ + uint32_t index; + for (index = 0; index < copied_num && ecma_is_completion_value_empty (ret_value); index++) { - /* - * FIXME: Casting len to ecma_length_t may overflow, but since ecma_length_t is still at least - * 16 bits long, with an array of that size, we would run out of memory way before this happens. - */ - JERRY_ASSERT ((ecma_length_t) len == len); - /* Copy the sorted array into a new array. */ - ret_value = ecma_op_create_array_object (values_buffer, (ecma_length_t) len, false); + ecma_string_t *index_string_p = ecma_new_ecma_string_from_uint32 (index); + ECMA_TRY_CATCH (put_value, + ecma_op_object_put (obj_p, index_string_p, values_buffer[index], true), + ret_value); + ECMA_FINALIZE (put_value); + ecma_deref_ecma_string (index_string_p); + } + + /* Undefined properties should be in the back of the array. */ + for (;index < len && ecma_is_completion_value_empty (ret_value); index++) + { + ecma_string_t *index_string_p = ecma_new_ecma_string_from_uint32 (index); + ECMA_TRY_CATCH (del_value, ecma_op_object_delete (obj_p, index_string_p, true), ret_value); + ECMA_FINALIZE (del_value); + ecma_deref_ecma_string (index_string_p); } /* Free values that were copied to the local array. */ @@ -1494,6 +1515,11 @@ ecma_builtin_array_prototype_object_sort (ecma_value_t this_arg, /**< this argum ecma_free_value (values_buffer[index], true); } + if (ecma_is_completion_value_empty (ret_value)) + { + ret_value = ecma_make_normal_completion_value (ecma_copy_value (this_arg, true)); + } + MEM_FINALIZE_LOCAL_ARRAY (values_buffer); ECMA_OP_TO_NUMBER_FINALIZE (len_number); diff --git a/tests/jerry/array-prototype-sort.js b/tests/jerry/array-prototype-sort.js index 703f33499..0c3a3e102 100644 --- a/tests/jerry/array-prototype-sort.js +++ b/tests/jerry/array-prototype-sort.js @@ -14,22 +14,22 @@ // limitations under the License. var array = ["Peach", "Apple", "Orange", "Grape", "Cherry", "Apricot", "Grapefruit"]; -var sorted = array.sort(); +array.sort(); -assert(sorted[0] === "Apple"); -assert(sorted[1] === "Apricot"); -assert(sorted[2] === "Cherry"); -assert(sorted[3] === "Grape"); -assert(sorted[4] === "Grapefruit"); -assert(sorted[5] === "Orange"); -assert(sorted[6] === "Peach"); +assert(array[0] === "Apple"); +assert(array[1] === "Apricot"); +assert(array[2] === "Cherry"); +assert(array[3] === "Grape"); +assert(array[4] === "Grapefruit"); +assert(array[5] === "Orange"); +assert(array[6] === "Peach"); var array = [6, 4, 5, 1, 2, 9, 7, 3, 0, 8]; // Default comparison -var sorted = array.sort(); +array.sort(); for (i = 0; i < array.length; i++) { - assert(sorted[i] === i); + assert(array[i] === i); } // Using custom comparison function @@ -43,9 +43,21 @@ function f(arg1, arg2) { } } -var sorted = array.sort(f); +array.sort(f); for (i = 0; i < array.length; i++) { - assert(sorted[sorted.length - i - 1] === i); + assert(array[array.length - i - 1] === i); +} + +// Sorting sparse array +var array = [1,,2,,3,,4,undefined,5]; +var expected = [1,2,3,4,5,undefined,,,,]; + +array.sort(); + +assert(array.length === expected.length); +for (i = 0; i < array.length; i++) { + assert(expected.hasOwnProperty (i) === array.hasOwnProperty (i)); + assert(array[i] === expected[i]); } // Checking behavior when provided comparefn is not callable