enable collapsing within AST_Definitions

This commit is contained in:
alexlamsl 2017-04-18 15:08:29 +08:00
parent 7dd1e0f34b
commit 761792e2e5
2 changed files with 125 additions and 115 deletions

View File

@ -647,30 +647,41 @@ merge(Compressor.prototype, {
for (var stat_index = statements.length; --stat_index >= 0;) { for (var stat_index = statements.length; --stat_index >= 0;) {
var stat = statements[stat_index]; var stat = statements[stat_index];
// The variable definition must precede a statement. var var_names_seen = Object.create(null);
if (stat_index <= 0) break;
var prev_stat_index = stat_index - 1;
var prev_stat = statements[prev_stat_index];
if (!(prev_stat instanceof AST_Definitions)) continue;
var var_defs = prev_stat.definitions;
if (var_defs == null) continue;
var var_names_seen = {};
var side_effects_encountered = false; var side_effects_encountered = false;
var lvalues_encountered = false; var lvalues_encountered = false;
var lvalues = {}; var lvalues = Object.create(null);
var prev_stat_index, var_defs, var_defs_index;
// Scan variable definitions from right to left. // Scan variable definitions from right to left.
for (var var_defs_index = var_defs.length; --var_defs_index >= 0;) { if (stat instanceof AST_Definitions) {
prev_stat_index = stat_index;
var_defs = stat.definitions;
for (var_defs_index = var_defs.length - 1; --var_defs_index >= 0;) {
if (collapse(var_defs[var_defs_index + 1])) break;
}
} else if (stat_index > 0) {
// The variable definition must precede a statement.
prev_stat_index = stat_index - 1;
var prev_stat = statements[prev_stat_index];
if (!(prev_stat instanceof AST_Definitions)) continue;
var_defs = prev_stat.definitions;
for (var_defs_index = var_defs.length; --var_defs_index >= 0;) {
if (collapse(stat)) break;
}
}
}
// Obtain var declaration and var name with basic sanity check. return statements;
function collapse(stat) {
var var_decl = var_defs[var_defs_index]; var var_decl = var_defs[var_defs_index];
if (var_decl.value == null) break; if (var_decl.value == null) return true;
var var_name = var_decl.name.name; var var_name = var_decl.name.name;
if (!var_name || !var_name.length) break; if (!var_name || !var_name.length) return true;
// Bail if we've seen a var definition of same name before. // Bail if we've seen a var definition of same name before.
if (var_name in var_names_seen) break; if (var_name in var_names_seen) return true;
var_names_seen[var_name] = true; var_names_seen[var_name] = true;
// Only interested in cases with just one reference to the variable. // Only interested in cases with just one reference to the variable.
@ -678,12 +689,12 @@ merge(Compressor.prototype, {
if (def.references.length !== 1 if (def.references.length !== 1
|| var_name == "arguments" || (!toplevel && def.global)) { || var_name == "arguments" || (!toplevel && def.global)) {
side_effects_encountered = true; side_effects_encountered = true;
continue; return;
} }
var ref = def.references[0]; var ref = def.references[0];
// Don't replace ref if eval() or with statement in scope. // Don't replace ref if eval() or with statement in scope.
if (ref.scope.uses_eval || ref.scope.uses_with) break; if (ref.scope.uses_eval || ref.scope.uses_with) return true;
// Constant single use vars can be replaced in any scope. // Constant single use vars can be replaced in any scope.
if (var_decl.value.is_constant()) { if (var_decl.value.is_constant()) {
@ -694,20 +705,20 @@ merge(Compressor.prototype, {
return node; return node;
} }
if (node === ref) if (node === ref)
return replace_var(node, parent, true); return replace_var(var_decl, node, parent, true);
}); });
stat.transform(ctt); stat.transform(ctt);
continue; return;
} }
// Restrict var replacement to constants if side effects encountered. // Restrict var replacement to constants if side effects encountered.
if (side_effects_encountered |= lvalues_encountered) continue; if (side_effects_encountered |= lvalues_encountered) return;
var value_has_side_effects = var_decl.value.has_side_effects(compressor); var value_has_side_effects = var_decl.value.has_side_effects(compressor);
// Non-constant single use vars can only be replaced in same scope. // Non-constant single use vars can only be replaced in same scope.
if (ref.scope !== scope) { if (ref.scope !== scope) {
side_effects_encountered |= value_has_side_effects; side_effects_encountered |= value_has_side_effects;
continue; return;
} }
// Detect lvalues in var value. // Detect lvalues in var value.
@ -754,7 +765,7 @@ merge(Compressor.prototype, {
function postorder(node) { function postorder(node) {
if (unwind) return node; if (unwind) return node;
if (node === ref) if (node === ref)
return unwind = true, replace_var(node, tt.parent(), false); return unwind = true, replace_var(var_decl, node, tt.parent(), false);
if (side_effects_encountered |= node.has_side_effects(compressor)) if (side_effects_encountered |= node.has_side_effects(compressor))
return unwind = true, node; return unwind = true, node;
if (lvalues_encountered && node instanceof AST_SymbolRef && node.name in lvalues) { if (lvalues_encountered && node instanceof AST_SymbolRef && node.name in lvalues) {
@ -765,14 +776,12 @@ merge(Compressor.prototype, {
); );
stat.transform(tt); stat.transform(tt);
} }
}
return statements;
function is_lvalue(node, parent) { function is_lvalue(node, parent) {
return node instanceof AST_SymbolRef && is_lhs(node, parent); return node instanceof AST_SymbolRef && is_lhs(node, parent);
} }
function replace_var(node, parent, is_constant) {
function replace_var(var_decl, node, parent, is_constant) {
if (is_lvalue(node, parent)) return node; if (is_lvalue(node, parent)) return node;
// Remove var definition and return its value to the TreeTransformer to replace. // Remove var definition and return its value to the TreeTransformer to replace.
@ -789,7 +798,7 @@ merge(Compressor.prototype, {
compressor.info("Collapsing {type} {name} [{file}:{line},{col}]", { compressor.info("Collapsing {type} {name} [{file}:{line},{col}]", {
type: is_constant ? "constant" : "variable", type: is_constant ? "constant" : "variable",
name: var_name, name: var_decl.name.name,
file: node.start.file, file: node.start.file,
line: node.start.line, line: node.start.line,
col: node.start.col col: node.start.col
@ -1737,6 +1746,7 @@ merge(Compressor.prototype, {
def(AST_SymbolRef, function(compressor){ def(AST_SymbolRef, function(compressor){
return this.undeclared(); return this.undeclared();
}); });
def(AST_SymbolDeclaration, return_false);
def(AST_Object, function(compressor){ def(AST_Object, function(compressor){
return any(this.properties, compressor); return any(this.properties, compressor);
}); });

View File

@ -667,7 +667,7 @@ collapse_vars_lvalues: {
function f4(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; } function f5(x) { var w = e1(), v = e2(), c = v = --x; return (w = x) - c; }
function f6(x) { var w = e1(), v = e2(); return (v = --x) - (w = x); } function f6(x) { var w = e1(), v = e2(); return (v = --x) - (w = x); }
function f7(x) { var w = e1(), v = e2(), c = v - x; return (w = x) - c; } function f7(x) { var w = e1(), c = e2() - x; return (w = x) - c; }
function f8(x) { var w = e1(), v = e2(); return (w = x) - (v - x); } function f8(x) { var w = e1(), v = e2(); return (w = x) - (v - x); }
function f9(x) { var w = e1(); return e2() - x - (w = x); } function f9(x) { var w = e1(); return e2() - x - (w = x); }
} }
@ -699,7 +699,7 @@ collapse_vars_lvalues_drop_assign: {
function f4(x) { var a = (x -= 3); return x + a; } function f4(x) { var a = (x -= 3); return x + a; }
function f5(x) { var v = (e1(), e2()), c = v = --x; return x - c; } function f5(x) { var v = (e1(), e2()), c = v = --x; return x - c; }
function f6(x) { e1(), e2(); return --x - x; } function f6(x) { e1(), e2(); return --x - x; }
function f7(x) { var v = (e1(), e2()), c = v - x; return x - c; } function f7(x) { var c = (e1(), e2() - x); return x - c; }
function f8(x) { var v = (e1(), e2()); return x - (v - x); } function f8(x) { var v = (e1(), e2()); return x - (v - x); }
function f9(x) { e1(); return e2() - x - x; } function f9(x) { e1(); return e2() - x - x; }
} }