improve reduce_vars and fix a bug

- update modified flag between compress() passes
- support IIFE arguments
- fix corner case with multiple definitions

closes #1473
This commit is contained in:
alexlamsl
2017-02-18 19:19:55 +08:00
parent b8b133d91a
commit a0f4fd390a
3 changed files with 161 additions and 30 deletions

View File

@@ -108,7 +108,8 @@ merge(Compressor.prototype, {
compress: function(node) {
var passes = +this.options.passes || 1;
for (var pass = 0; pass < passes && pass < 3; ++pass) {
if (pass > 0) node.clear_opt_flags();
if (pass > 0 || this.option("reduce_vars"))
node.reset_opt_flags(this);
node = node.transform(this);
}
return node;
@@ -167,19 +168,45 @@ merge(Compressor.prototype, {
return this.print_to_string() == node.print_to_string();
});
AST_Node.DEFMETHOD("clear_opt_flags", function(){
this.walk(new TreeWalker(function(node){
AST_Node.DEFMETHOD("reset_opt_flags", function(compressor){
var reduce_vars = compressor.option("reduce_vars");
var tw = new TreeWalker(function(node){
if (reduce_vars && node instanceof AST_Scope) {
node.variables.each(function(def) {
delete def.modified;
});
}
if (node instanceof AST_SymbolRef) {
var d = node.definition();
if (d && d.init) {
if (d.init) {
delete d.init._evaluated;
}
if (reduce_vars && (d.orig.length > 1 || isModified(node, 0))) {
d.modified = true;
}
}
if (reduce_vars && node instanceof AST_Call && node.expression instanceof AST_Function) {
node.expression.argnames.forEach(function(arg, i) {
arg.definition().init = node.args[i] || make_node(AST_Undefined, node);
});
}
if (!(node instanceof AST_Directive || node instanceof AST_Constant)) {
node._squeezed = false;
node._optimized = false;
}
}));
});
this.walk(tw);
function isModified(node, level) {
var parent = tw.parent(level);
if (parent instanceof AST_Unary && (parent.operator === "++" || parent.operator === "--")
|| parent instanceof AST_Assign && parent.left === node
|| parent instanceof AST_Call && parent.expression === node) {
return true;
} else if (parent instanceof AST_PropAccess && parent.expression === node) {
return isModified(parent, level + 1);
}
}
});
function make_node(ctor, orig, props) {
@@ -459,7 +486,7 @@ merge(Compressor.prototype, {
var_defs_removed = true;
}
// Further optimize statement after substitution.
stat.clear_opt_flags();
stat.reset_opt_flags(compressor);
compressor.warn("Replacing " + (is_constant ? "constant" : "variable") +
" " + var_name + " [{file}:{line},{col}]", node.start);
@@ -1158,7 +1185,7 @@ merge(Compressor.prototype, {
this._evaluating = true;
try {
var d = this.definition();
if (d && (d.constant || compressor.option("reduce_vars") && !d.modified) && d.init) {
if ((d.constant || compressor.option("reduce_vars") && !d.modified) && d.init) {
if (compressor.option("unsafe")) {
if (!HOP(d.init, '_evaluated')) {
d.init._evaluated = ev(d.init, compressor);

View File

@@ -183,17 +183,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
var func = null;
var globals = self.globals = new Dictionary();
var tw = new TreeWalker(function(node, descend){
function isModified(node, level) {
var parent = tw.parent(level);
if (parent instanceof AST_Unary && (parent.operator === "++" || parent.operator === "--")
|| parent instanceof AST_Assign && parent.left === node
|| parent instanceof AST_Call && parent.expression === node) {
return true;
} else if (parent instanceof AST_PropAccess && parent.expression === node) {
return isModified(parent, level + 1);
}
}
if (node instanceof AST_Lambda) {
var prev_func = func;
func = node;
@@ -217,21 +206,16 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
node.scope.uses_arguments = true;
}
if (!sym) {
var g;
if (globals.has(name)) {
g = globals.get(name);
sym = globals.get(name);
} else {
g = new SymbolDef(self, globals.size(), node);
g.undeclared = true;
g.global = true;
globals.set(name, g);
sym = new SymbolDef(self, globals.size(), node);
sym.undeclared = true;
sym.global = true;
globals.set(name, sym);
}
sym = g;
}
node.thedef = sym;
if (isModified(node, 0)) {
sym.modified = true;
}
node.reference(options);
return true;
}