enhance collapse_vars (#5268)

This commit is contained in:
Alex Lam S.L
2022-01-06 21:13:37 +00:00
committed by GitHub
parent d46eb69320
commit 10a1523ee6
4 changed files with 119 additions and 29 deletions

View File

@@ -1943,16 +1943,46 @@ Compressor.prototype.compress = function(node) {
if (stop_after === node) abort = true; if (stop_after === node) abort = true;
return node; return node;
} }
// Stop immediately if these node types are encountered
var parent = scanner.parent(); var parent = scanner.parent();
if (should_stop(node, parent)) {
abort = true;
return node;
}
// Stop only if candidate is found within conditional branches // Stop only if candidate is found within conditional branches
if (!stop_if_hit && in_conditional(node, parent)) { if (!stop_if_hit && in_conditional(node, parent)) {
stop_if_hit = parent; stop_if_hit = parent;
} }
// Cascade compound assignments
if (compound && scan_lhs && can_replace && !stop_if_hit
&& node instanceof AST_Assign && node.operator != "=" && node.left.equivalent_to(lhs)) {
replaced++;
changed = true;
AST_Node.info("Cascading {node} [{file}:{line},{col}]", {
node: node,
file: node.start.file,
line: node.start.line,
col: node.start.col,
});
can_replace = false;
node.right.transform(scanner);
clear_write_only(candidate);
var assign = make_node(AST_Assign, node, {
operator: "=",
left: node.left,
right: make_node(AST_Binary, node, {
operator: node.operator.slice(0, -1),
left: abort ? candidate : make_node(AST_Binary, candidate, {
operator: compound,
left: lhs,
right: rvalue,
}),
right: node.right,
}),
});
abort = true;
return assign;
}
// Stop immediately if these node types are encountered
if (should_stop(node, parent)) {
abort = true;
return node;
}
// Skip transient nodes caused by single-use variable replacement // Skip transient nodes caused by single-use variable replacement
if (node.single_use && parent instanceof AST_VarDef && parent.value === node) return node; if (node.single_use && parent instanceof AST_VarDef && parent.value === node) return node;
// Replace variable with assignment when found // Replace variable with assignment when found
@@ -2006,13 +2036,8 @@ Compressor.prototype.compress = function(node) {
right: rvalue, right: rvalue,
}); });
} }
var assign = candidate; clear_write_only(candidate);
while (assign.write_only) { var assign = candidate.clone();
assign.write_only = false;
if (!(assign instanceof AST_Assign)) break;
assign = assign.right;
}
assign = candidate.clone();
assign.right = rvalue; assign.right = rvalue;
return assign; return assign;
} }
@@ -2095,6 +2120,12 @@ Compressor.prototype.compress = function(node) {
if (node instanceof AST_SymbolRef && node.definition() === def) { if (node instanceof AST_SymbolRef && node.definition() === def) {
if (is_lhs(node, multi_replacer.parent())) return node; if (is_lhs(node, multi_replacer.parent())) return node;
if (!--replaced) abort = true; if (!--replaced) abort = true;
AST_Node.info("Replacing {node} [{file}:{line},{col}]", {
node: node,
file: node.start.file,
line: node.start.line,
col: node.start.col,
});
var ref = rvalue.clone(); var ref = rvalue.clone();
ref.scope = node.scope; ref.scope = node.scope;
ref.reference(); ref.reference();
@@ -2138,6 +2169,7 @@ Compressor.prototype.compress = function(node) {
var scan_lhs = lhs && !side_effects && !is_lhs_read_only(lhs, compressor); var scan_lhs = lhs && !side_effects && !is_lhs_read_only(lhs, compressor);
var scan_rhs = foldable(candidate); var scan_rhs = foldable(candidate);
if (!scan_lhs && !scan_rhs) continue; if (!scan_lhs && !scan_rhs) continue;
var compound = candidate instanceof AST_Assign && candidate.operator.slice(0, -1);
var funarg = candidate.name instanceof AST_SymbolFunarg; var funarg = candidate.name instanceof AST_SymbolFunarg;
var may_throw = return_false; var may_throw = return_false;
if (candidate.may_throw(compressor)) { if (candidate.may_throw(compressor)) {
@@ -2154,13 +2186,7 @@ Compressor.prototype.compress = function(node) {
var lvalues = get_lvalues(candidate); var lvalues = get_lvalues(candidate);
var lhs_local = is_lhs_local(lhs); var lhs_local = is_lhs_local(lhs);
var rhs_value = get_rvalue(candidate); var rhs_value = get_rvalue(candidate);
var rvalue; var rvalue = !compound && rhs_value instanceof AST_Sequence ? rhs_value.tail_node() : rhs_value;
if (rhs_value instanceof AST_Sequence
&& !(candidate instanceof AST_Assign && candidate.operator != "=")) {
rvalue = rhs_value.tail_node();
} else {
rvalue = rhs_value;
}
if (!side_effects) side_effects = value_has_side_effects(); if (!side_effects) side_effects = value_has_side_effects();
var check_destructured = in_try || !lhs_local ? function(node) { var check_destructured = in_try || !lhs_local ? function(node) {
return node instanceof AST_Destructured; return node instanceof AST_Destructured;
@@ -2834,7 +2860,6 @@ Compressor.prototype.compress = function(node) {
function get_lhs(expr) { function get_lhs(expr) {
if (expr instanceof AST_Assign) { if (expr instanceof AST_Assign) {
var lhs = expr.left; var lhs = expr.left;
if (expr.operator != "=") return lhs;
if (!(lhs instanceof AST_SymbolRef)) return lhs; if (!(lhs instanceof AST_SymbolRef)) return lhs;
var def = lhs.definition(); var def = lhs.definition();
if (scope.uses_arguments && is_funarg(def)) return lhs; if (scope.uses_arguments && is_funarg(def)) return lhs;
@@ -2849,7 +2874,7 @@ Compressor.prototype.compress = function(node) {
assign_pos = 0; assign_pos = 0;
} }
} }
mangleable_var(expr.right); if (expr.operator == "=") mangleable_var(expr.right);
return lhs; return lhs;
} }
if (expr instanceof AST_Binary) return expr.right.left; if (expr instanceof AST_Binary) return expr.right.left;
@@ -2952,6 +2977,14 @@ Compressor.prototype.compress = function(node) {
}; };
} }
function clear_write_only(assign) {
while (assign.write_only) {
assign.write_only = false;
if (!(assign instanceof AST_Assign)) break;
assign = assign.right;
}
}
function may_be_global(node) { function may_be_global(node) {
if (node instanceof AST_SymbolRef) { if (node instanceof AST_SymbolRef) {
node = node.fixed_value(); node = node.fixed_value();
@@ -3118,12 +3151,13 @@ Compressor.prototype.compress = function(node) {
function is_lhs_local(lhs) { function is_lhs_local(lhs) {
var sym = root_expr(lhs); var sym = root_expr(lhs);
return sym instanceof AST_SymbolRef if (!(sym instanceof AST_SymbolRef)) return false;
&& sym.definition().scope.resolve() === scope if (sym.definition().scope.resolve() !== scope) return false;
&& !(in_loop if (!in_loop) return true;
&& (lvalues.has(sym.name) && lvalues.get(sym.name)[0] !== lhs if (compound) return false;
|| candidate instanceof AST_Unary if (candidate instanceof AST_Unary) return false;
|| candidate instanceof AST_Assign && candidate.operator != "=")); var lvalue = lvalues.get(sym.name);
return !lvalue || lvalue[0] === lhs;
} }
function value_has_side_effects() { function value_has_side_effects() {
@@ -7099,7 +7133,7 @@ Compressor.prototype.compress = function(node) {
log(node.name, text); log(node.name, text);
} else { } else {
AST_Node.info(text + " [{file}:{line},{col}]", { AST_Node.info(text + " [{file}:{line},{col}]", {
name: node.print_to_string(), name: node,
file: node.start.file, file: node.start.file,
line: node.start.line, line: node.start.line,
col : node.start.col, col : node.start.col,

View File

@@ -530,6 +530,25 @@ logical_collapse_vars_2: {
node_version: ">=15" node_version: ">=15"
} }
logical_collapse_vars_3: {
options = {
collapse_vars: true,
}
input: {
var a = 6;
a *= 7;
a ??= "FAIL";
console.log(a);
}
expect: {
var a = 6;
a = a * 7 ?? "FAIL";
console.log(a);
}
expect_stdout: "42"
node_version: ">=15"
}
logical_reduce_vars: { logical_reduce_vars: {
options = { options = {
evaluate: true, evaluate: true,

View File

@@ -2995,6 +2995,43 @@ compound_assignment_4: {
expect_stdout: "PASS" expect_stdout: "PASS"
} }
compound_assignment_5: {
options = {
collapse_vars: true,
}
input: {
var a = 0, b;
a += 42;
b && (a *= null);
console.log(a);
}
expect: {
var a = 0, b;
a += 42;
b && (a *= null);
console.log(a);
}
expect_stdout: "42"
}
compound_assignment_6: {
options = {
collapse_vars: true,
}
input: {
var a;
a ^= 6;
a *= a + 1;
console.log(a);
}
expect: {
var a;
a = (a ^= 6) * (a + 1);
console.log(a);
}
expect_stdout: "42"
}
issue_2187_1: { issue_2187_1: {
options = { options = {
collapse_vars: true, collapse_vars: true,

View File

@@ -774,7 +774,7 @@ side_effects_cascade_3: {
} }
expect: { expect: {
function f(a, b) { function f(a, b) {
(b += a) || (b = a) || (b -= a, b ^= a), (b += a) || (b = a) || (b = b - a ^ a),
a--; a--;
} }
} }