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.
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.
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.
@alexlamsl Could you please add a [WIP] prefix to the title while this is sorted out?
There was a problem hiding this comment.
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.
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 |
| return self; | ||
| }); | ||
|
|
||
| (function(def){ |
There was a problem hiding this comment.
Can you please put a comment above this line?
// drop_value()
There was a problem hiding this comment.
Done with an extra line to try and explain what it does 😉
test/compress/pure_funcs.js
Outdated
| } | ||
| expect: { | ||
| function f(a, b) { | ||
| Math.floor(c / b); |
There was a problem hiding this comment.
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.
Ah! I forgot the undefined error case.
Thanks for catching that!
test/compress/pure_funcs.js
Outdated
| if (!(instance instanceof Constructor)) | ||
| throw new TypeError("Cannot call a class as a function"); | ||
| } | ||
|
|
|
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.
Would have expected to see the global c here:
c;
c;
test/compress/pure_funcs.js
Outdated
| } | ||
| } | ||
| expect: { | ||
| function f(a, b) { |
|
@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 |
| return null; | ||
| } | ||
|
|
||
| function trim(nodes, compressor, first_in_statement) { |
There was a problem hiding this comment.
Can you please comment what this function does and what it returns?
|
This warning is not needed - it is too common: |
|
Not optimal: should be: |
Done. |
Oh, I was hoping |
Fixed. |
lib/compress.js
Outdated
| return null; | ||
| } | ||
|
|
||
| // drop side-effect-free elements an array of expressions |
There was a problem hiding this comment.
// 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.
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.
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.
drop_side_effect_free sounds good as it reduces the vocabulary surface area 👍
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(); |
|
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.
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.
These were accidentally modifying this instead of node before.
| } | ||
| } | ||
|
|
||
| conditional: { |
There was a problem hiding this comment.
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_funcsin general while I'm at this./cc @kzc