Skip to content

drop unused: toplevel, assign-only#1450

Closed
alexlamsl wants to merge 1 commit intomishoo:masterfrom
alexlamsl:unused-assign
Closed

drop unused: toplevel, assign-only#1450
alexlamsl wants to merge 1 commit intomishoo:masterfrom
alexlamsl:unused-assign

Conversation

@alexlamsl
Copy link
Copy Markdown
Collaborator

Only works when assignment is on the same scope level as declaration for now (see new tests in drop-unused.js).

Run against angular.js and managed to shave one extra variable off without any measureable change in performance.

This can obviously be extended in the future, but given how long I spent reading up drop_unused() let's take one step at a time. Putting it here as I run out of tests to throw at it (for now).

@kzc
Copy link
Copy Markdown
Contributor

kzc commented Jan 29, 2017

How can your optimization be disabled for the collapse_vars tests because I don't want these variables to be dropped. This tests the flow analysis of collapse_vars.

Can your optimization be put behind a new option?

var a;
a = 1;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please remove the blank lines between the functions in this test so it's easier to compare the input to the output. Thanks.

@kzc
Copy link
Copy Markdown
Contributor

kzc commented Jan 29, 2017

Perhaps a new option drop_assign_only defaulting to true? That way it can be selectively disabled for tests.

@alexlamsl
Copy link
Copy Markdown
Collaborator Author

@kzc any suggestions with a shorter option name? It's a chore adding white spaces to all the other options... 😝

@kzc
Copy link
Copy Markdown
Contributor

kzc commented Jan 29, 2017

Feel free to come up with a shorter name. drop_unused or assign_only maybe?

@kzc
Copy link
Copy Markdown
Contributor

kzc commented Jan 29, 2017

Those suggested names are not the greatest. What's the longest option name currently?

@alexlamsl
Copy link
Copy Markdown
Collaborator Author

drop_debugger and collapse_vars are tied.

@kzc
Copy link
Copy Markdown
Contributor

kzc commented Jan 29, 2017

I'm stumped to come up with a better, shorter name.

@alexlamsl
Copy link
Copy Markdown
Collaborator Author

@kzc no worries - I'll think of something after/while updating the code and tests 😉

@kzc
Copy link
Copy Markdown
Contributor

kzc commented Jan 29, 2017

What if unused can be overloaded with an integer value 2 indicating to not use this optimization?

If it's any other true-ish value then it was as it was before.
If it's any other true-ish value then it will drop the unused var.

@alexlamsl
Copy link
Copy Markdown
Collaborator Author

@kzc sounds pretty cool actually, which makes this new feature off by default as well.

@kzc
Copy link
Copy Markdown
Contributor

kzc commented Jan 29, 2017

We can have the new feature enabled by default with true.
Setting unused=2 can disable the new feature.

@alexlamsl
Copy link
Copy Markdown
Collaborator Author

@kzc yes, I misread your previous comment (again)

@kzc
Copy link
Copy Markdown
Contributor

kzc commented Jan 29, 2017

People tend use default options. Not many people set collapse_vars=true, for example.

@kzc yes, I misread your previous comment (again)

You didn't misread it - I rewrote it. Sorry about that.

@kzc
Copy link
Copy Markdown
Contributor

kzc commented Jan 29, 2017

What if there was yet another option setting that can remove unused top level vars?

$ echo 'var a = foo();' | bin/uglifyjs -c
var a=foo();

var a was not dropped because it was top-level.

This should be off by default as some people expect this grandfathered behavior in uglified scripts in the wild.

function f2(x) { var z = x, a = ++z; return z += a; }
function f3(x) { var a = (x -= 3); return x + a; }
function f4(x) { var a = (x -= 3); return x + a; }
function f5(x) { var w = e1(), v = e2(), c = v = --x; return (w = x) - c; }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can you please set unused: 2 in the collapse_vars tests with different results?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I copied these original tests to the bottom with unused=2 - guess I should do it the other way round 😅

var a = 2;
do {
fn(a = 7);
fn(7);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can you please set unused: 2 in the collapse_vars tests with different results?

}
}

keep_assign: {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I see what you've done. Please keep the original test names in the original place. Just change unused to 2 in the original tests that have different results.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You may add a new test below the original.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Would you like me to copy the whole section below each of the two original blocks of tests, or just the affected case?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The latest collapse_vars test changes look good - thanks!

lib/compress.js Outdated
if (node instanceof AST_Assign && node.operator == "="
&& node.left instanceof AST_SymbolRef
&& scope === self
&& assign_as_unused) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Would you mind making assign_as_unused the first condition in the if? It's faster if assign_as_unused is not in effect, and the same speed otherwise.

lib/compress.js Outdated
}
if (node instanceof AST_Assign && node.operator == "="
&& node.left instanceof AST_SymbolRef
&& assign_as_unused) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Would you mind making assign_as_unused the first condition in the if? It's faster if assign_as_unused is not in effect, and the same speed otherwise.

}

collapse_vars_regexp: {
options = {
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Ooops!

}
}

collapse_vars_regexp: {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why was this regex test dropped?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

PEBKAC

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This test was added originally as result of a bug fix. Just because the implementation with respect to is_const changed does not mean the test should be dropped.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

it's cool. i was just confused.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I was trying to remove my own tests at the end of the file, and forgot I've done so already 🙄

Tests restored.

@kzc
Copy link
Copy Markdown
Contributor

kzc commented Jan 29, 2017

There's a comment above that might have been lost in the shuffle: #1450 (comment)

Would welcome your thoughts on the best option to remove unused top level vars.

@alexlamsl
Copy link
Copy Markdown
Collaborator Author

@kzc yeah I am still chewing on that thought - the code change seems trivial (famous last words...)

@alexlamsl
Copy link
Copy Markdown
Collaborator Author

Recycling PR state to re-run timed-out CI tests.

@alexlamsl alexlamsl closed this Jan 29, 2017
@alexlamsl alexlamsl reopened this Jan 29, 2017
@kzc
Copy link
Copy Markdown
Contributor

kzc commented Jan 29, 2017

Dropping unused top-level vars may warrant its own option.

@alexlamsl
Copy link
Copy Markdown
Collaborator Author

@kzc I've given it a go with string-based option value. Worse case, we can just break both of these features back out as separate flags.

I was hoping the code is the more challenging part of this exercise...

@kzc
Copy link
Copy Markdown
Contributor

kzc commented Jan 29, 2017

So I guess the only outstanding things are top_retain RegExp support and implicitly setting -c toplevel=true when top_retain is used and toplevel is undefined.

@alexlamsl
Copy link
Copy Markdown
Collaborator Author

@kzc ah so it's just a CLI limitation then. On that note I did have an urge to rewrite that in commander like I did for html-minifier 😛

I've just finished updating the docs - will update code now and push in a moment.

@kzc
Copy link
Copy Markdown
Contributor

kzc commented Jan 30, 2017

Ah, I see now - this is how one enters a string argument into yargs from the CLI:

$ echo 'function y(){}' | bin/uglifyjs -c top_retain='"x,y,z"',toplevel
function y(){}
$ echo 'function y(){}' | bin/uglifyjs -c top_retain='"x,z"',toplevel
WARN: Dropping unused function y [-:1,9]

@alexlamsl
Copy link
Copy Markdown
Collaborator Author

So it's all a big eval()... ❗️

PTAL at the latest changes.

@kzc
Copy link
Copy Markdown
Contributor

kzc commented Jan 30, 2017

The CLI and the various options work perfectly. Uglify users will definitely benefit from this new functionality.

Great work!

- assign statement does not count towards variable usage by default
- only works with assignments on the same scope level as declaration
- can be disabled with `unused` set to "keep_assign"
- `toplevel` to drop unused top-level variables and/or functions
- `top_retain` to whitelist top-level exceptions
@alexlamsl alexlamsl changed the title [WIP] drop unused: toplevel, assign-only drop unused: toplevel, assign-only Jan 30, 2017
@alexlamsl
Copy link
Copy Markdown
Collaborator Author

@kzc thanks for all the help, as always 👍

This was referenced Feb 9, 2017
alexlamsl added a commit to alexlamsl/UglifyJS that referenced this pull request Feb 18, 2017
- assign statement does not count towards variable usage by default
- only works with assignments on the same scope level as declaration
- can be disabled with `unused` set to "keep_assign"
- `toplevel` to drop unused top-level variables and/or functions
- `top_retain` to whitelist top-level exceptions

closes mishoo#1450
alexlamsl added a commit to alexlamsl/UglifyJS that referenced this pull request Feb 18, 2017
alexlamsl added a commit to alexlamsl/UglifyJS that referenced this pull request Feb 19, 2017
@alexlamsl alexlamsl mentioned this pull request Feb 21, 2017
@alexlamsl alexlamsl closed this in 148047f Feb 23, 2017
@alexlamsl alexlamsl deleted the unused-assign branch February 24, 2017 00:18
alexlamsl added a commit to alexlamsl/UglifyJS that referenced this pull request Mar 2, 2017
When mishoo#1450 optimises `a=b=42`, it stops after the first variable even if both are unused.

fixes mishoo#1539
alexlamsl added a commit that referenced this pull request Mar 2, 2017
When #1450 optimises `a=b=42`, it stops after the first variable even if both are unused.

fixes #1539
alexlamsl added a commit to alexlamsl/UglifyJS that referenced this pull request Mar 8, 2017
similar case as mishoo#1578 but against mishoo#1450 instead

closes mishoo#1580
This was referenced Mar 8, 2017
alexlamsl added a commit to alexlamsl/UglifyJS that referenced this pull request Mar 8, 2017
- similar case as mishoo#1578 but against mishoo#1450 instead
- fix `this` binding in mishoo#1450 as well

closes mishoo#1580
alexlamsl added a commit that referenced this pull request Mar 8, 2017
- similar case as #1578 but against #1450 instead
- fix `this` binding in #1450 as well

closes #1580
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.

2 participants