fix function inlining within loops (#2675)

fixes #2663
This commit is contained in:
Alex Lam S.L
2017-12-28 02:53:14 +08:00
committed by GitHub
parent f30790b11b
commit cb62bd98d3
2 changed files with 191 additions and 30 deletions

View File

@@ -3982,23 +3982,30 @@ merge(Compressor.prototype, {
return self;
function can_flatten_args(fn) {
var catches = Object.create(null);
var catches = Object.create(null), defs;
do {
scope = compressor.parent(++level);
if (scope instanceof AST_SymbolRef) {
if (scope.fixed_value() instanceof AST_Scope) return false;
} else if (scope instanceof AST_Catch) {
if (scope instanceof AST_Catch) {
catches[scope.argname.name] = true;
} else if (scope instanceof AST_IterationStatement) {
defs = [];
} else if (scope instanceof AST_SymbolRef) {
if (scope.fixed_value() instanceof AST_Scope) return false;
}
} while (!(scope instanceof AST_Scope));
var safe_to_inject = compressor.toplevel.vars || !(scope instanceof AST_Toplevel);
return all(fn.argnames, function(arg) {
return arg.__unused
|| safe_to_inject
&& !catches[arg.name]
&& !identifier_atom(arg.name)
&& !scope.var_names()[arg.name];
});
for (var i = 0, len = fn.argnames.length; i < len; i++) {
var arg = fn.argnames[i];
if (arg.__unused) continue;
if (!safe_to_inject
|| catches[arg.name]
|| identifier_atom(arg.name)
|| scope.var_names()[arg.name]) {
return false;
}
if (defs) defs.push(arg.definition());
}
return !defs || defs.length == 0 || !is_reachable(fn.body[0], defs);
}
function flatten_args(fn) {
@@ -4838,6 +4845,28 @@ merge(Compressor.prototype, {
return self;
});
function is_reachable(node, defs) {
var reachable = false;
var find_ref = new TreeWalker(function(node) {
if (reachable) return true;
if (node instanceof AST_SymbolRef && member(node.definition(), defs)) {
return reachable = true;
}
});
var scan_scope = new TreeWalker(function(node) {
if (reachable) return true;
if (node instanceof AST_Scope) {
var parent = scan_scope.parent();
if (!(parent instanceof AST_Call && parent.expression === node)) {
node.walk(find_ref);
}
return true;
}
});
node.walk(scan_scope);
return reachable;
}
var ASSIGN_OPS = [ '+', '-', '/', '*', '%', '>>', '<<', '>>>', '|', '^', '&' ];
var ASSIGN_OPS_COMMUTATIVE = [ '*', '|', '^', '&' ];
OPT(AST_Assign, function(self, compressor){
@@ -4851,7 +4880,7 @@ merge(Compressor.prototype, {
parent = compressor.parent(level++);
if (parent instanceof AST_Exit) {
if (in_try(level, parent instanceof AST_Throw)) break;
if (is_reachable(def)) break;
if (is_reachable(self, [ def ])) break;
if (self.operator == "=") return self.right;
return make_node(AST_Binary, self, {
operator: self.operator.slice(0, -1),
@@ -4893,24 +4922,6 @@ merge(Compressor.prototype, {
}
}
}
function is_reachable(def) {
var reachable = false;
var find_ref = new TreeWalker(function(node) {
if (reachable) return true;
if (node instanceof AST_SymbolRef && node.definition() === def) {
return reachable = true;
}
});
self.right.walk(new TreeWalker(function(node) {
if (reachable) return true;
if (node instanceof AST_Scope) {
node.walk(find_ref);
return true;
}
}));
return reachable;
}
});
OPT(AST_Conditional, function(self, compressor){