Skip to content
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

Object properties should be stored ordered #1539

Closed
raskad opened this issue Aug 31, 2021 · 11 comments · Fixed by #1547
Closed

Object properties should be stored ordered #1539

raskad opened this issue Aug 31, 2021 · 11 comments · Fixed by #1547
Assignees
Labels
bug Something isn't working execution Issues or PRs related to code execution performance Performance related changes and issues
Milestone

Comments

@raskad
Copy link
Member

raskad commented Aug 31, 2021

Describe the bug
String and Symbol object properties are currently returned in arbitrary order, because the underlying store is a std::collections::HashMap. The spec specifies, that String and Symbol properties should be returned in order of property creation e.g. OrdinaryOwnPropertyKeys.
Index properties should be returned in ascending numeric order. We currently achieve this by sorting the properties in the ordinary_own_property_keys function.

To Reproduce
This JavaScript code reproduces the issue:

Object.keys({b: 1, a: 2, c: 3});

This currently may return [ "c", "b", "a" ].

Expected behavior
The above code should always return [ 'b', 'a', 'c' ].

We should store the properties in data structures that preserve the expected order, so that we do not have to waste time sorting.

@raskad raskad added bug Something isn't working performance Performance related changes and issues execution Issues or PRs related to code execution labels Aug 31, 2021
@raskad raskad self-assigned this Aug 31, 2021
@jedel1043
Copy link
Member

I think this is one of the rare instances where a linked list would solve this optimally. What do you think?

@raskad
Copy link
Member Author

raskad commented Aug 31, 2021

I'm not sure about a linked list. I'm currently testing out the indexmap crate that we already use for the Map builtin.

This blog post from the V8 team covers the topic: https://v8.dev/blog/fast-properties. V8 is of course highly optimized. I think we can skip some of those optimizations for now. I was mainly looking at the Slow properties, described as some dict.

@jedel1043
Copy link
Member

I thought about indexmap but I think it just preserves the insertion order if you don't call delete on the map.

@raskad
Copy link
Member Author

raskad commented Aug 31, 2021

Ignore what I wrote here before. I think we can just Option the value and set it to None on remove().

@jedel1043
Copy link
Member

Ignore what I wrote here before. I think we can just Option the value and set it to None on remove().

I don't know if I understood completely, but wouldn't that leave big memory footprints if you insert a lot of items then delete them?

@jedel1043
Copy link
Member

jedel1043 commented Aug 31, 2021

This blog post from the V8 team covers the topic: https://v8.dev/blog/fast-properties. V8 is of course highly optimized. I think we can skip some of those optimizations for now. I was mainly looking at the Slow properties, described as some dict.

Also, those are some good optimizations we could make! Maybe it would be a good idea to open a new discussion with every idea we stumble upon to optimize the engine 😄
@Razican what do you think?

@raskad
Copy link
Member Author

raskad commented Aug 31, 2021

Ignore what I wrote here before. I think we can just Option the value and set it to None on remove().

I don't know if I understood completely, but wouldn't that leave big memory footprints if you insert a lot of items then delete them?

Yes that would be true. But never mind that; indexmap has a shift_remove function. The downside is, that it is O(n) instead of O(1). But I think that is probably the easiest way to be spec compliant with a reasonable performance. I will try to do some benchmarks with this version vs the old FxHashMap to see how this plays out.

@jedel1043
Copy link
Member

Ignore what I wrote here before. I think we can just Option the value and set it to None on remove().

I don't know if I understood completely, but wouldn't that leave big memory footprints if you insert a lot of items then delete them?

Yes that would be true. But never mind that; indexmap has a shift_remove function. The downside is, that it is O(n) instead of O(1). But I think that is probably the easiest way to be spec compliant with a reasonable performance. I will try to do some benchmarks with this version vs the old FxHashMap to see how this plays out.

If it makes OrdinaryOwnPropertyKeys spec compliant and doesn't affect too much the performance, I don't see a problem with using that structure. We can optimize later when we have most of the spec implemented and a lot less immediate goals in our plans.

@jedel1043
Copy link
Member

Made a little digging and found hasklink. Could be more performant than indexmap, and we can attach it FxHasher to see how it compares with FxHashMap.

@Razican
Copy link
Member

Razican commented Aug 31, 2021

This blog post from the V8 team covers the topic: https://v8.dev/blog/fast-properties. V8 is of course highly optimized. I think we can skip some of those optimizations for now. I was mainly looking at the Slow properties, described as some dict.

Also, those are some good optimizations we could make! Maybe it would be a good idea to open a new discussion with every idea we stumble upon to optimize the engine 😄
@Razican what do you think?

Good idea, let's open a separate discussion :) we can then create some issues for it

@raskad
Copy link
Member Author

raskad commented Sep 1, 2021

Made a little digging and found hasklink. Could be more performant than indexmap, and we can attach it FxHasher to see how it compares with FxHashMap.

I used indexmap with FxHasher in my PR. The performance looks good. I looked at hasklink and i feel like it may be a little too immature. The docs look very sparse and I did not see any good/easy examples.

@Razican Razican added this to the v0.13.0 milestone Feb 23, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working execution Issues or PRs related to code execution performance Performance related changes and issues
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants