Skip to content

Array.prototype.sort() should sort in place. #335

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed

Conversation

dbatyai
Copy link
Member

@dbatyai dbatyai commented Jul 8, 2015

Array.prototype.sort() should sort in place instead of creating a new Array with the sorted elements.
JerryScript-DCO-1.0-Signed-off-by: Dániel Bátyai dbatyai.u-szeged@partner.samsung.com

@dbatyai dbatyai added bug Undesired behaviour ecma builtins Related to ECMA built-in routines labels Jul 8, 2015
@dbatyai dbatyai added this to the ECMA builtins milestone Jul 8, 2015

if (ecma_is_value_undefined (values_buffer[index]))
{
ECMA_TRY_CATCH (del_value, ecma_op_object_delete (obj_p, index_string_p, true), ret_value);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the reason to have empty TRY/FINALIZE block?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my opinion this look cleaner than using if/else to check/free.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, this is current common style.
Maybe, this could be encoded in a more convenient way. I think, in the case it is better to change all the places at once.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see

@egavrin
Copy link
Contributor

egavrin commented Jul 8, 2015

No other questions. Good to me.


// Sorting sparse array
var array = [1,,2,,3,,4,undefined,5];
var expected = [1,2,3,4,5,,,,];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems that expected.length is 8, and array.length is 9. Maybe, it is incorrect.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you, please, check whether conditions in the following loop should be true?

for (i = 0; i < array.length; i++)
{
  assert (expected.hasOwnProperty (i) == array.hasOwnProperty (i));
}

Currently, some of them are not true.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

expected has 5 numbers, and then 4 empty places after those, that should be 9. Nevertheless, there's an assert for this in line 57 below.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The following test case print 8:

var expected = [1,2,3,4,5,,,,];

print (expected.length);

By the way, assertion at line 57 is incorrect, as it performs assignment, instead of comparison.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue with hasOwnProperty is related with #319, in particular, the problem is that we currently can't distinguish between "empty" values that are unset, and explicitly defined undefined values, currently both are undefined. If we do it by the standard, then empty values should be deleted, but currently that also deletes the set undefined value.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My mistake, let me re-check.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To distinguish between undefined properties and properties with undefined values, we can use ecma_op_object_get_property (...) != NULL.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, initially. But we copy the values into a local array, so that we can sort them. When we do this both will become undefined, since we don't have a way to represent them differently.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think, this is because values are copied to simple array of values without additional information.

It seems that the way also can lead to out-of-memory in case of sparse arrays. For example:

a = new Array ();
a[100000] = 1;
a[1000000] = 2;
a.sort ();

Is it correct? If so, maybe we should use some another way of intermediate value storage during operation of sort.

@dbatyai dbatyai force-pushed the array_sort_in_place branch from 1d1fb9f to 0231028 Compare July 9, 2015 08:53
@dbatyai
Copy link
Member Author

dbatyai commented Jul 9, 2015

@ruben-ayrapetyan , I've updated the PR. We no longer copy undefined properties.

@ruben-ayrapetyan ruben-ayrapetyan self-assigned this Jul 9, 2015
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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test would be executed too long, because of iteration over all values in [0.. len):

var a = new Array ();

a[100000] = 1;
a[1000000] = 2;

a.sort ();

There are also another places with the issue. For example, ecma_op_array_object_define_own_property.
Could you, please, raise an issue about this, with references to known places with the issue, and add FIXME to the code part, referencing the issue?

@ruben-ayrapetyan
Copy link
Contributor

After raising the issue and adding FIXMEs, the changes would look good to me.

@ruben-ayrapetyan
Copy link
Contributor

@dbatyai, could you, please, rebase to master?

@dbatyai dbatyai force-pushed the array_sort_in_place branch from 0231028 to 5fb673e Compare July 10, 2015 11:34
@dbatyai
Copy link
Member Author

dbatyai commented Jul 10, 2015

@ruben-ayrapetyan, rebased.

@ruben-ayrapetyan
Copy link
Contributor

@dbatyai, thank you!

@@ -962,6 +962,9 @@ ecma_builtin_array_prototype_object_index_of (ecma_value_t this_arg, /**< this a
{
JERRY_ASSERT (from_idx < len);

/* FIXME: Iterating over the whole lenght is unnecessary in case of sparse arrays,
* and could take a long time if len is large. We should only iterate
* over defined array indexes. */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there is a TODO () or similar macro somewhere.

@zherczeg
Copy link
Member

I agree that the real index based sorting should be replaced by a virtual index based sorting. What is the sorting algorithm? Quick-sort?

@ruben-ayrapetyan
Copy link
Contributor

After fixing FIXME comments and moving them to separate commit, looks good to me.

JerryScript-DCO-1.0-Signed-off-by: Dániel Bátyai dbatyai.u-szeged@partner.samsung.com
@dbatyai dbatyai force-pushed the array_sort_in_place branch from 5fb673e to 65b2361 Compare July 13, 2015 09:17
@dbatyai
Copy link
Member Author

dbatyai commented Jul 13, 2015

@zherczeg, current algorithm is heapsort.

@dbatyai dbatyai force-pushed the array_sort_in_place branch from 65b2361 to 6331555 Compare July 14, 2015 11:28
@dbatyai
Copy link
Member Author

dbatyai commented Jul 14, 2015

@ruben-ayrapetyan, please re-check
After talking with @zherczeg we decided that we should fix #362 in this patch, instead of adding FIXMEs.
After some investigation it appears that sort is actually the only candidate for #362, because other functions are required to also check the prototype chain, so iterating over their defined properties is not enough.

@ruben-ayrapetyan
Copy link
Contributor

@dbatyai, I'll check the changes today.

I think that fix of #362 in several other parts of engine (including, ecma_op_array_object_define_own_property) can significantly improve performance of sparse arrays handling. However, maybe, sort can be optimized even more, by skipping prototype chain.

@dbatyai dbatyai force-pushed the array_sort_in_place branch from 6331555 to 92cde9d Compare July 15, 2015 14:42
@dbatyai
Copy link
Member Author

dbatyai commented Jul 15, 2015

@ruben-ayrapetyan, @zherczeg, I've updated the PR.

ECMA_FINALIZE (del_value);
}

property_p = next_prop;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code infitely loops for the following example:

Array.prototype.sort();

Reason is that property_p is not updated for internal properties.

It's better to put property_p = next_prop into for's increment section.

@ruben-ayrapetyan
Copy link
Contributor

After fixing, the changes would look good to me.

JerryScript-DCO-1.0-Signed-off-by: Dániel Bátyai dbatyai.u-szeged@partner.samsung.com
@dbatyai dbatyai force-pushed the array_sort_in_place branch from 92cde9d to eca1ec4 Compare July 15, 2015 15:05
@ruben-ayrapetyan
Copy link
Contributor

Looks good to me

@zherczeg
Copy link
Member

LGTM

@dbatyai dbatyai assigned egavrin and unassigned zherczeg Jul 21, 2015
@egavrin
Copy link
Contributor

egavrin commented Jul 22, 2015

I'll merge.

@egavrin
Copy link
Contributor

egavrin commented Jul 22, 2015

Merged a2c6663

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Undesired behaviour ecma builtins Related to ECMA built-in routines
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants