improve compress efficiency (#5220)

This commit is contained in:
Alex Lam S.L
2021-12-15 00:08:24 +00:00
committed by GitHub
parent 7fe7c39a01
commit 509896a410
7 changed files with 100 additions and 96 deletions

View File

@@ -7929,12 +7929,17 @@ Compressor.prototype.compress = function(node) {
function drop_returns(compressor, exp) {
var arrow = is_arrow(exp);
var async = is_async(exp);
var changed = false;
var drop_body = false;
if (arrow && compressor.option("arrows")) {
if (!exp.value) {
drop_body = true;
} else if (!async || is_primitive(compressor, exp.value)) {
exp.value = exp.value.drop_side_effect_free(compressor);
var dropped = exp.value.drop_side_effect_free(compressor);
if (dropped !== exp.value) {
changed = true;
exp.value = dropped;
}
}
} else if (exp instanceof AST_AsyncFunction || exp instanceof AST_Function) {
if (exp.name) {
@@ -7951,6 +7956,7 @@ Compressor.prototype.compress = function(node) {
if (async && !is_primitive(compressor, value)) return node;
value = value.drop_side_effect_free(compressor, true);
}
changed = true;
if (!value) return make_node(AST_EmptyStatement, node);
return make_node(AST_SimpleStatement, node, { body: value });
});
@@ -7958,7 +7964,11 @@ Compressor.prototype.compress = function(node) {
var value = node.value;
if (value) {
if (async && !is_primitive(compressor, value)) return;
node.value = value.drop_side_effect_free(compressor);
var dropped = value.drop_side_effect_free(compressor);
if (dropped !== value) {
changed = true;
node.value = dropped;
}
}
});
}
@@ -7967,6 +7977,7 @@ Compressor.prototype.compress = function(node) {
var body = node.body;
if (body instanceof AST_Await) {
if (is_primitive(compressor, body.expression)) {
changed = true;
body = body.expression.drop_side_effect_free(compressor, true);
if (!body) return make_node(AST_EmptyStatement, node);
node.body = body;
@@ -7976,8 +7987,10 @@ Compressor.prototype.compress = function(node) {
for (var i = exprs.length; --i >= 0;) {
var tail = exprs[i];
if (!(tail instanceof AST_Await)) break;
if (!is_primitive(compressor, tail.expression)) break;
if (exprs[i] = tail.expression.drop_side_effect_free(compressor)) break;
var value = tail.expression;
if (!is_primitive(compressor, value)) break;
changed = true;
if (exprs[i] = value.drop_side_effect_free(compressor)) break;
}
switch (i) {
case -1:
@@ -8021,7 +8034,7 @@ Compressor.prototype.compress = function(node) {
return make_node(ctor, exp, exp);
}
}
return drop_body && exp.clone();
return changed && exp.clone();
}
def(AST_Call, function(compressor, first_in_statement) {
var self = this;
@@ -10369,42 +10382,46 @@ Compressor.prototype.compress = function(node) {
OPT(AST_UnaryPrefix, function(self, compressor) {
var op = self.operator;
var exp = self.expression;
if (compressor.option("evaluate") && op == "delete" && !may_not_delete(exp)) {
return make_sequence(self, [ exp, make_node(AST_True, self) ]).optimize(compressor);
}
if (compressor.option("sequences") && can_lift()) {
var seq = lift_sequence_in_expression(self, compressor);
if (seq !== self) return seq.optimize(compressor);
}
if (compressor.option("side_effects") && op == "void") {
switch (op) {
case "-":
if (exp instanceof AST_Infinity) exp = exp.transform(compressor);
// avoids infinite recursion of numerals
if (exp instanceof AST_Number || exp instanceof AST_Infinity) return self;
break;
case "!":
if (!compressor.option("booleans")) break;
if (exp.is_truthy()) return make_sequence(self, [ exp, make_node(AST_False, self) ]).optimize(compressor);
if (compressor.in_boolean_context()) {
// !!foo ---> foo, if we're in boolean context
if (exp instanceof AST_UnaryPrefix && exp.operator == "!") return exp.expression;
if (exp instanceof AST_Binary) {
self = best_of(compressor, self, exp.negate(compressor, first_in_statement(compressor)));
}
}
break;
case "delete":
if (!compressor.option("evaluate")) break;
if (may_not_delete(exp)) break;
return make_sequence(self, [ exp, make_node(AST_True, self) ]).optimize(compressor);
case "typeof":
if (!compressor.option("booleans")) break;
if (!compressor.in_boolean_context()) break;
// typeof always returns a non-empty string, thus always truthy
AST_Node.warn("Boolean expression always true [{file}:{line},{col}]", self.start);
var exprs = [ make_node(AST_True, self) ];
if (!(exp instanceof AST_SymbolRef && can_drop_symbol(exp, compressor))) exprs.unshift(exp);
return make_sequence(self, exprs).optimize(compressor);
case "void":
if (!compressor.option("side_effects")) break;
exp = exp.drop_side_effect_free(compressor);
if (!exp) return make_node(AST_Undefined, self).optimize(compressor);
self.expression = exp;
return self;
}
if (compressor.option("booleans")) {
if (op == "!" && exp.is_truthy()) {
return make_sequence(self, [ exp, make_node(AST_False, self) ]).optimize(compressor);
} else if (compressor.in_boolean_context()) switch (op) {
case "!":
if (exp instanceof AST_UnaryPrefix && exp.operator == "!") {
// !!foo ---> foo, if we're in boolean context
return exp.expression;
}
if (exp instanceof AST_Binary) {
self = best_of(compressor, self, exp.negate(compressor, first_in_statement(compressor)));
}
break;
case "typeof":
// typeof always returns a non-empty string, thus it's
// always true in booleans
AST_Node.warn("Boolean expression always true [{file}:{line},{col}]", self.start);
var exprs = [ make_node(AST_True, self) ];
if (!(exp instanceof AST_SymbolRef && can_drop_symbol(exp, compressor))) exprs.unshift(exp);
return make_sequence(self, exprs).optimize(compressor);
}
}
if (op == "-" && exp instanceof AST_Infinity) exp = exp.transform(compressor);
if (compressor.option("evaluate")
&& exp instanceof AST_Binary
&& SIGN_OPS[op]
@@ -10414,14 +10431,12 @@ Compressor.prototype.compress = function(node) {
operator: exp.operator,
left: make_node(AST_UnaryPrefix, exp.left, {
operator: op,
expression: exp.left
expression: exp.left,
}),
right: exp.right
right: exp.right,
});
}
// avoids infinite recursion of numerals
return op == "-" && (exp instanceof AST_Number || exp instanceof AST_Infinity)
? self : try_evaluate(compressor, self);
return try_evaluate(compressor, self);
function may_not_delete(node) {
return node instanceof AST_Infinity
@@ -10582,32 +10597,6 @@ Compressor.prototype.compress = function(node) {
}
OPT(AST_Binary, function(self, compressor) {
function reversible() {
return self.left.is_constant()
|| self.right.is_constant()
|| !self.left.has_side_effects(compressor)
&& !self.right.has_side_effects(compressor);
}
function reverse(op) {
if (reversible()) {
if (op) self.operator = op;
var tmp = self.left;
self.left = self.right;
self.right = tmp;
}
}
function swap_chain() {
var rhs = self.right;
self.left = make_node(AST_Binary, self, {
operator: self.operator,
left: self.left,
right: rhs.left,
start: self.left.start,
end: rhs.left.end
});
self.right = rhs.right;
self.left = self.left.transform(compressor);
}
if (commutativeOperators[self.operator]
&& self.right.is_constant()
&& !self.left.is_constant()
@@ -11260,6 +11249,35 @@ Compressor.prototype.compress = function(node) {
&& self.left.expression instanceof AST_Number && self.left.expression.value == 1;
}
}
function reversible() {
return self.left.is_constant()
|| self.right.is_constant()
|| !self.left.has_side_effects(compressor)
&& !self.right.has_side_effects(compressor);
}
function reverse(op) {
if (reversible()) {
if (op) self.operator = op;
var tmp = self.left;
self.left = self.right;
self.right = tmp;
}
}
function swap_chain() {
var rhs = self.right;
self.left = make_node(AST_Binary, self, {
operator: self.operator,
left: self.left,
right: rhs.left,
start: self.left.start,
end: rhs.left.end
});
self.right = rhs.right;
self.left = self.left.transform(compressor);
}
});
OPT(AST_SymbolExport, function(self) {
@@ -11593,9 +11611,7 @@ Compressor.prototype.compress = function(node) {
if (lhs && is_atomic(lhs, self)) return self;
return make_node(AST_UnaryPrefix, self, {
operator: "void",
expression: make_node(AST_Number, self, {
value: 0
})
expression: make_node(AST_Number, self, { value: 0 }),
});
});
@@ -11607,12 +11623,8 @@ Compressor.prototype.compress = function(node) {
}
return make_node(AST_Binary, self, {
operator: "/",
left: make_node(AST_Number, self, {
value: 1
}),
right: make_node(AST_Number, self, {
value: 0
})
left: make_node(AST_Number, self, { value: 1 }),
right: make_node(AST_Number, self, { value: 0 }),
});
});
@@ -11622,12 +11634,8 @@ Compressor.prototype.compress = function(node) {
if (!lhs && !find_scope(compressor).find_variable("NaN")) return self;
return make_node(AST_Binary, self, {
operator: "/",
left: make_node(AST_Number, self, {
value: 0
}),
right: make_node(AST_Number, self, {
value: 0
})
left: make_node(AST_Number, self, { value: 0 }),
right: make_node(AST_Number, self, { value: 0 }),
});
});
@@ -12199,9 +12207,7 @@ Compressor.prototype.compress = function(node) {
OPT(AST_Boolean, function(self, compressor) {
if (!compressor.option("booleans")) return self;
if (compressor.in_boolean_context()) return make_node(AST_Number, self, {
value: +self.value
});
if (compressor.in_boolean_context()) return make_node(AST_Number, self, { value: +self.value });
var p = compressor.parent();
if (p instanceof AST_Binary && (p.operator == "==" || p.operator == "!=")) {
AST_Node.warn("Non-strict equality against boolean: {operator} {value} [{file}:{line},{col}]", {
@@ -12211,15 +12217,11 @@ Compressor.prototype.compress = function(node) {
line : p.start.line,
col : p.start.col,
});
return make_node(AST_Number, self, {
value: +self.value
});
return make_node(AST_Number, self, { value: +self.value });
}
return make_node(AST_UnaryPrefix, self, {
operator: "!",
expression: make_node(AST_Number, self, {
value: 1 - self.value
})
expression: make_node(AST_Number, self, { value: 1 - self.value }),
});
});

View File

@@ -508,7 +508,7 @@ drop_value: {
((a, b) => a + b)(console.log(42));
}
expect: {
((a, b) => {})(console.log(42));
void console.log(42);
}
expect_stdout: "42"
node_version: ">=4"

View File

@@ -890,7 +890,7 @@ keep_fnames: {
issue_805_1: {
options = {
inline: true,
passes: 2,
passes: 3,
pure_getters: "strict",
reduce_vars: true,
sequences: true,
@@ -926,7 +926,7 @@ issue_805_1: {
issue_805_2: {
options = {
inline: true,
passes: 2,
passes: 3,
pure_getters: "strict",
reduce_vars: true,
sequences: true,

View File

@@ -1765,7 +1765,7 @@ issue_2846: {
issue_805_1: {
options = {
inline: true,
passes: 2,
passes: 3,
pure_getters: "strict",
reduce_vars: true,
sequences: true,
@@ -1798,7 +1798,7 @@ issue_805_1: {
issue_805_2: {
options = {
inline: true,
passes: 2,
passes: 3,
pure_getters: "strict",
reduce_vars: true,
sequences: true,

View File

@@ -3862,6 +3862,7 @@ issue_3679_1: {
options = {
collapse_vars: true,
inline: true,
passes: 2,
pure_getters: "strict",
reduce_vars: true,
side_effects: true,

View File

@@ -389,6 +389,7 @@ issue_1288_side_effects: {
options = {
conditionals: true,
negate_iife: true,
sequences: true,
side_effects: true,
}
input: {
@@ -409,10 +410,10 @@ issue_1288_side_effects: {
})(0);
}
expect: {
w;
w,
x || function() {
x = {};
}();
}(),
y;
}
}

View File

@@ -866,9 +866,9 @@ issue_4575: {
}
expect: {
(function(a) {
(function a(...d) {
(function(d) {
console.log(d.length);
})();
})([]);
})();
}
expect_stdout: "0"