-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
fix pure_funcs
& improve side_effects
#1494
Conversation
test/compress/pure_funcs.js
Outdated
} | ||
expect: { | ||
function f(a, b) { | ||
console.log(a()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If console.log
is deemed to be pure and its return value is not used, shouldn't the expected result should be the following?
function f(a, b) {
a();
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's because AST_SimpleStatement
isn't smart enough at the moment.
I'll investigate if this is the only site that needs improvement for AST_Call
optimisation. Hopefully I won't end up with nasty surprises like I did in #1477.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@alexlamsl Could you please add a [WIP] prefix to the title while this is sorted out?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the real problem is that the concepts of "side effects" and "pure function" are used interchangeably in the code, when they are different things. As we see above, a pure function can have arguments with side effects.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That isn't an issue per se, because it makes sense when asking AST_Node.has_side_effects()
to consider the expression as a whole and return true
if any of its components have side effects.
Optimisation of individual side-effect-free components are scattered across compress.js
, and in this particular case, I think OPT(AST_SimpleStatement)
needs to be augmented as it's the site where we know the evaluated value of its body
is being discarded.
Can you add an additional test like the following and add function foo() {
var u = pure(1);
var x = pure(2);
var y = pure(x);
var z = pure(pure(side_effect()));
return pure(3);
} it ought to compress to: function foo() {
side_effect();
return pure(3);
} |
@kzc added test as suggested above. Right now it will return: function foo() {
pure(pure(side_effects()));
return pure(3);
} I'm contemplating on whether to open a separate PR for the further optimisation or group it all in this one. |
pure_funcs
with side effects argumentspure_funcs
with side effects arguments
Might as well put it into this one. |
FYI, one of the most frequent uses of
That probably should be a test case. |
@kzc took me a while, but here it is 😅 Please check the |
lib/compress.js
Outdated
@@ -1729,12 +1734,131 @@ merge(Compressor.prototype, { | |||
return self; | |||
}); | |||
|
|||
(function(def){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please put a comment above this line?
// drop_value()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done with an extra line to try and explain what it does 😉
test/compress/pure_funcs.js
Outdated
@@ -11,7 +11,6 @@ array: { | |||
} | |||
expect: { | |||
function f(a, b) { | |||
Math.floor(c / b); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't the expected result be the following?
function f(a, b) {
c;
}
Since c
is global then its access could throw if not defined.
$ cat foo.js
"use strict";
try {
c;
} catch (x) {
console.log("caught exception: ", x);
}
$ node ./foo.js
caught exception: ReferenceError: c is not defined
Just confirming - in ECMAScript there are no "divide by zero" exceptions, correct? It would produce Infinity or NaN or whatever so no issue removing the divisions here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah! I forgot the undefined error case.
Thanks for catching that!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
test/compress/pure_funcs.js
Outdated
if (!(instance instanceof Constructor)) | ||
throw new TypeError("Cannot call a class as a function"); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please remove this empty line
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
Nice job. The babel test looks correct. Your other PR for I noted a different test result that I had issue with. |
Thanks for catching that - I'm having a slow/distracted day 😓 |
test/compress/drop-unused.js
Outdated
} | ||
expect: { | ||
function foo() { | ||
var b; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would have expected to see the global c
here:
c;
c;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
} | ||
} | ||
expect: { | ||
function f(a, b) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
c;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
@alexlamsl The speed and quality of your code continues to impress me. |
I lumped this PR on top of #1485 locally to test this theory. For starters, even without any extra options, With |
|
Run into a curious issue with |
Employed similar logic as #1451 to fix it. |
These unmerged PRs are completely inter-tangled now. |
Bug:
I think a distinct test is needed for every node type listed in |
lib/compress.js
Outdated
return null; | ||
} | ||
|
||
function trim(nodes, compressor, first_in_statement) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please comment what this function does and what it returns?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
This warning is not needed - it is too common:
|
Not optimal:
should be:
|
Done. |
Oh, I was hoping |
Fixed. |
lib/compress.js
Outdated
@@ -1745,6 +1745,7 @@ merge(Compressor.prototype, { | |||
return null; | |||
} | |||
|
|||
// drop side-effect-free elements an array of expressions |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// Drop side-effect-free elements from an array of expressions.
// Returns an array of expressions with side-effects or null
// if all elements were dropped. Note: original array may be
// returned if nothing changed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated - thanks! 👍
Even without pure functions, the AST_SimpleStatement |
Improved.
This is similar to what I wanted to do in #1451 (comment) |
lib/compress.js
Outdated
}); | ||
}); | ||
})(function(node, func){ | ||
node.DEFMETHOD("drop_value", func); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it bother you to change the name of the function to something more descriptive like drop_irrelevant
or drop_side_effect_free
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
drop_side_effect_free
sounds good as it reduces the vocabulary surface area 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
Would you mind adding that under a new |
It is added under |
I must have missed it - it's fine. Thanks. |
(1, [2, foo()], 3, {a:1, b:bar()}); | ||
} | ||
expect: { | ||
foo(), bar(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 super_awesome++
This PR alone shaved 4,201 bytes off a 2MB app bundle I had kicking around. Not bad at all. |
|
Oh Shoo—
|
Seems like this PR is interfering with
|
|
c7616d6
to
9ab10d9
Compare
pure_funcs
with side effects argumentspure_funcs
& improve side_effects
- only drops side-effect-free arguments - drop side-effect-free parts with discarded value from `AST_Seq` & `AST_SimpleStatement` closes mishoo#1494
- only drops side-effect-free arguments - drop side-effect-free parts with discarded value from `AST_Seq` & `AST_SimpleStatement`
9ab10d9
to
6cd98c7
Compare
operator: "||", | ||
left: this.condition, | ||
right: alternative | ||
}) : this.condition.drop_side_effect_free(compressor); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
condition
was returned without optimised for side-effects before
}); | ||
var node = this.clone(); | ||
node.consequent = consequent; | ||
node.alternative = alternative; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These were accidentally modifying this
instead of node
before.
} | ||
} | ||
|
||
conditional: { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tests beefed up to cover aforementioned changes.
- only drops side-effect-free arguments - drop side-effect-free parts with discarded value from `AST_Seq` & `AST_SimpleStatement` closes mishoo#1494
#1399 (comment)
Added some tests for
pure_funcs
in general while I'm at this./cc @kzc