Skip to content

Commit 0231028

Browse files
committed
Array.prototype.sort() should sort in place.
JerryScript-DCO-1.0-Signed-off-by: Dániel Bátyai dbatyai.u-szeged@partner.samsung.com
1 parent 01c4325 commit 0231028

File tree

2 files changed

+65
-27
lines changed

2 files changed

+65
-27
lines changed

jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.cpp

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1448,44 +1448,65 @@ ecma_builtin_array_prototype_object_sort (ecma_value_t this_arg, /**< this argum
14481448

14491449
uint32_t len = ecma_number_to_uint32 (len_number);
14501450

1451-
MEM_DEFINE_LOCAL_ARRAY (values_buffer, len, ecma_value_t);
1451+
uint32_t defined_prop_count = 0;
1452+
/* Count number of defined properties. */
1453+
for (ecma_property_t *property_p = ecma_get_property_list (obj_p);
1454+
property_p != NULL;
1455+
property_p = ECMA_GET_POINTER (ecma_property_t, property_p->next_property_p))
1456+
{
1457+
defined_prop_count++;
1458+
}
1459+
1460+
MEM_DEFINE_LOCAL_ARRAY (values_buffer, defined_prop_count, ecma_value_t);
14521461
uint32_t copied_num = 0;
14531462

14541463
/* Copy unsorted array into a native c array. */
14551464
for (uint32_t index = 0; index < len && ecma_is_completion_value_empty (ret_value); index++)
14561465
{
14571466
ecma_string_t *index_string_p = ecma_new_ecma_string_from_uint32 (index);
1458-
ECMA_TRY_CATCH (index_value, ecma_op_object_get (obj_p, index_string_p), ret_value);
1467+
if (ecma_op_object_get_property (obj_p, index_string_p) != NULL)
1468+
{
1469+
ECMA_TRY_CATCH (index_value, ecma_op_object_get (obj_p, index_string_p), ret_value);
14591470

1460-
values_buffer[index] = ecma_copy_value (index_value, true);
1461-
copied_num++;
1471+
values_buffer[copied_num++] = ecma_copy_value (index_value, true);
14621472

1463-
ECMA_FINALIZE (index_value);
1473+
ECMA_FINALIZE (index_value);
1474+
}
14641475
ecma_deref_ecma_string (index_string_p);
14651476
}
14661477

1467-
JERRY_ASSERT (copied_num == len || !ecma_is_completion_value_empty (ret_value));
1478+
JERRY_ASSERT (copied_num <= defined_prop_count);
14681479

14691480
/* Sorting. */
14701481
if (len > 1 && ecma_is_completion_value_empty (ret_value))
14711482
{
14721483
ECMA_TRY_CATCH (sort_value,
14731484
ecma_builtin_array_prototype_object_array_heap_sort_helper (values_buffer,
1474-
(int)(len - 1),
1485+
(int)(copied_num - 1),
14751486
arg1),
14761487
ret_value);
14771488
ECMA_FINALIZE (sort_value);
14781489
}
14791490

1480-
if (ecma_is_completion_value_empty (ret_value))
1491+
/* Put sorted values to the front of the array. */
1492+
uint32_t index;
1493+
for (index = 0; index < copied_num && ecma_is_completion_value_empty (ret_value); index++)
14811494
{
1482-
/*
1483-
* FIXME: Casting len to ecma_length_t may overflow, but since ecma_length_t is still at least
1484-
* 16 bits long, with an array of that size, we would run out of memory way before this happens.
1485-
*/
1486-
JERRY_ASSERT ((ecma_length_t) len == len);
1487-
/* Copy the sorted array into a new array. */
1488-
ret_value = ecma_op_create_array_object (values_buffer, (ecma_length_t) len, false);
1495+
ecma_string_t *index_string_p = ecma_new_ecma_string_from_uint32 (index);
1496+
ECMA_TRY_CATCH (put_value,
1497+
ecma_op_object_put (obj_p, index_string_p, values_buffer[index], true),
1498+
ret_value);
1499+
ECMA_FINALIZE (put_value);
1500+
ecma_deref_ecma_string (index_string_p);
1501+
}
1502+
1503+
/* Undefined properties should be in the back of the array. */
1504+
for (;index < len && ecma_is_completion_value_empty (ret_value); index++)
1505+
{
1506+
ecma_string_t *index_string_p = ecma_new_ecma_string_from_uint32 (index);
1507+
ECMA_TRY_CATCH (del_value, ecma_op_object_delete (obj_p, index_string_p, true), ret_value);
1508+
ECMA_FINALIZE (del_value);
1509+
ecma_deref_ecma_string (index_string_p);
14891510
}
14901511

14911512
/* 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
14941515
ecma_free_value (values_buffer[index], true);
14951516
}
14961517

1518+
if (ecma_is_completion_value_empty (ret_value))
1519+
{
1520+
ret_value = ecma_make_normal_completion_value (ecma_copy_value (this_arg, true));
1521+
}
1522+
14971523
MEM_FINALIZE_LOCAL_ARRAY (values_buffer);
14981524

14991525
ECMA_OP_TO_NUMBER_FINALIZE (len_number);

tests/jerry/array-prototype-sort.js

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,22 @@
1414
// limitations under the License.
1515

1616
var array = ["Peach", "Apple", "Orange", "Grape", "Cherry", "Apricot", "Grapefruit"];
17-
var sorted = array.sort();
17+
array.sort();
1818

19-
assert(sorted[0] === "Apple");
20-
assert(sorted[1] === "Apricot");
21-
assert(sorted[2] === "Cherry");
22-
assert(sorted[3] === "Grape");
23-
assert(sorted[4] === "Grapefruit");
24-
assert(sorted[5] === "Orange");
25-
assert(sorted[6] === "Peach");
19+
assert(array[0] === "Apple");
20+
assert(array[1] === "Apricot");
21+
assert(array[2] === "Cherry");
22+
assert(array[3] === "Grape");
23+
assert(array[4] === "Grapefruit");
24+
assert(array[5] === "Orange");
25+
assert(array[6] === "Peach");
2626

2727
var array = [6, 4, 5, 1, 2, 9, 7, 3, 0, 8];
2828

2929
// Default comparison
30-
var sorted = array.sort();
30+
array.sort();
3131
for (i = 0; i < array.length; i++) {
32-
assert(sorted[i] === i);
32+
assert(array[i] === i);
3333
}
3434

3535
// Using custom comparison function
@@ -43,9 +43,21 @@ function f(arg1, arg2) {
4343
}
4444
}
4545

46-
var sorted = array.sort(f);
46+
array.sort(f);
4747
for (i = 0; i < array.length; i++) {
48-
assert(sorted[sorted.length - i - 1] === i);
48+
assert(array[array.length - i - 1] === i);
49+
}
50+
51+
// Sorting sparse array
52+
var array = [1,,2,,3,,4,undefined,5];
53+
var expected = [1,2,3,4,5,undefined,,,,];
54+
55+
array.sort();
56+
57+
assert(array.length === expected.length);
58+
for (i = 0; i < array.length; i++) {
59+
assert(expected.hasOwnProperty (i) === array.hasOwnProperty (i));
60+
assert(array[i] === expected[i]);
4961
}
5062

5163
// Checking behavior when provided comparefn is not callable

0 commit comments

Comments
 (0)