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

Replace mergeSort with Array.prototype.sort #355

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open

Replace mergeSort with Array.prototype.sort #355

wants to merge 1 commit into from

Conversation

L2jLiga
Copy link
Contributor

@L2jLiga L2jLiga commented Jun 1, 2019

No description provided.

@MattiasBuelens
Copy link
Contributor

MattiasBuelens commented Jun 15, 2019

Uglify switched from the built-in sort to a hand-rolled merge sort in 8e82d8d. I believe this was probably done because the built-in sort was unstable. It's only since this January that the built-in sort is required to be a stable sort.

Array.prototype.sort is stable since V8 7.0, which shipped in Node 11.0. That means older versions of Node still have an unstable sort. Therefore, I don't think it's safe to switch to the built-in sort just yet... 😕

@L2jLiga
Copy link
Contributor Author

L2jLiga commented Jun 15, 2019

Sorry, I didn't get what is actually wrong with Array.prototype.sort and how it can affect Terser😶

@MattiasBuelens
Copy link
Contributor

It's still just a guess, but I can't think of any other reason why they would have switched to a hand-rolled merge sort.

A stable sorting algorithm ensures the output is deterministic. That's important for a minifier: running Terser on the same input code with the same options should always result in the same output code. If Terser used an unstable sort algorithm for sorting mangling characters by their frequency, then the mangled names could change in different runs.

Even if you're using an unstable sort, it's very hard to actually get a different output. Often, it just happens to return the same output as a stable sort would. That's made even more difficult by the fact that V8 uses an adaptive sorting algorithm: for small inputs, it uses insertion sort which is stable. I suspect that's why all tests are still passing on this branch: even though Node 6, 8 and 10 use an unstable sort, we have no tests with sufficiently large, carefully crafted input code that could result in different output code.

Copy link
Contributor Author

@L2jLiga L2jLiga left a comment

Choose a reason for hiding this comment

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

I think it will work fine with various code independent of size

const freq = new Map();

const digits = init("0123456789");
const leading = init("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_");
Copy link
Contributor Author

Choose a reason for hiding this comment

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

sort method only used for two arrays above which have 10 and 54 elements

Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like the threshold between insert sort (stable) and quick sort (unstable) is 10 elements. So digits would always use insertion sort, but leading wouldn't. 😕

@fabiosantoscode
Copy link
Collaborator

fabiosantoscode commented Dec 30, 2019

Looks like Array sort stability is now part of the spec. But it's only on node 12+

@MattiasBuelens has mentioned node 11, but we don't need to check because node 10 will become EOL after node 11 does.

@MattiasBuelens
Copy link
Contributor

@MattiasBuelens has mentioned node 11, but we don't need to check because node 10 will become EOL after node 11 does.

Good point! Indeed, only even-numbered releases become LTS. 👍

Still, it's way too early to drop support for Node versions <= 10. We would have to wait until Node 10 becomes EOL, which is still more than a year away (currently scheduled for April 2021).

@L2jLiga
Copy link
Contributor Author

L2jLiga commented Dec 30, 2019

hmmm.. according to nodejs release cycle 6, 7, 9 and 11 alread EOL, node v8 one day left, I think we can drop node 6-9 support already but it really early to drop support for 10 since it will be EOL at April 2021 :)

Release Status Codename Initial Release Active LTS Start Maintenance LTS Start End-of-life
v8 Maintenance LTS Carbon 2017-05-30 2017-10-31 2019-01-01 2019-12-31
v10 Active LTS Dubnium 2018-04-24 2018-10-30 2020-04-01 2021-04-30
v12 Active LTS Erbium 2019-04-23 2019-10-21 2020-10-21 2022-04-30
v13 Current   2019-10-22   2020-04-01 2020-06-01
v14 Pending   2020-04-21 2020-10-20 2021-10-20 2023-04-30

@koundinya-goparaju-wcar
Copy link

koundinya-goparaju-wcar commented Nov 16, 2021

Can this be merged now since node v10 has reached EOL?

@MattiasBuelens
Copy link
Contributor

MattiasBuelens commented Nov 16, 2021

Correct, Node 10 is now EOL. However, Terser 5 still supports Node 10 or higher, see package.json and CHANGELOG.md.

I agree that Terser should drop support for EOL versions of Node, but that will require a major version bump. That's a decision for the maintainers to make. 🙂

@fabiosantoscode
Copy link
Collaborator

I think I'm still not happy to merge even with node 10 far out of EOL because that would rely on non-spec behaviour.

Terser also runs on the web, and that means it can run on non-v8 engines.

However I am happy to get rid of a bespoke sort implementation if we can replace it with another stable sort such as lodash's sortBy.

@ehoogeveen-medweb
Copy link

I think I'm still not happy to merge even with node 10 far out of EOL because that would rely on non-spec behaviour.

I might be misunderstanding you here, but Array.prototype.sort is specced to be stable since ES2019: tc39/ecma262#1340 (and in practice all engines use a stable sort since late 2018).

@fabiosantoscode
Copy link
Collaborator

Interesting @ehoogeveen-medweb! I wasn't aware of this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants