diff options
Diffstat (limited to 'lib/compress.js')
-rw-r--r-- | lib/compress.js | 114 |
1 files changed, 62 insertions, 52 deletions
diff --git a/lib/compress.js b/lib/compress.js index 352be282..dffdd6ed 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -714,15 +714,23 @@ merge(Compressor.prototype, { var candidates = []; var stat_index = statements.length; while (--stat_index >= 0) { + // Treat parameters as collapsible in IIFE, i.e. + // function(a, b){ ... }(x()); + // would be translated into equivalent assignments: + // var a = x(), b = undefined; + if (stat_index == 0 && compressor.option("unused")) extract_args(); + // Find collapsible assignments extract_candidates(statements[stat_index]); while (candidates.length > 0) { var candidate = candidates.pop(); var lhs = get_lhs(candidate); if (!lhs || is_lhs_read_only(lhs)) continue; + // Locate symbols which may execute code outside of scanning range var lvalues = get_lvalues(candidate); if (lhs instanceof AST_SymbolRef) lvalues[lhs.name] = false; var side_effects = value_has_side_effects(candidate); - var hit = false, abort = false, replaced = false; + var hit = candidate.name instanceof AST_SymbolFunarg; + var abort = false, replaced = false; var tt = new TreeTransformer(function(node, descend) { if (abort) return node; // Skip nodes before `candidate` as quickly as possible @@ -803,6 +811,35 @@ merge(Compressor.prototype, { } } + function extract_args() { + var iife, fn = compressor.self(); + if (fn instanceof AST_Function + && !fn.name + && !fn.uses_arguments + && !fn.uses_eval + && (iife = compressor.parent()) instanceof AST_Call + && iife.expression === fn) { + fn.argnames.forEach(function(sym, i) { + var arg = iife.args[i]; + if (!arg) arg = make_node(AST_Undefined, sym); + else arg.walk(new TreeWalker(function(node) { + if (!arg) return true; + if (node instanceof AST_SymbolRef && fn.variables.has(node.name)) { + var s = node.definition().scope; + if (s !== scope) while (s = s.parent_scope) { + if (s === scope) return true; + } + arg = null; + } + })); + if (arg) candidates.push(make_node(AST_VarDef, sym, { + name: sym, + value: arg + })); + }); + } + } + function extract_candidates(expr) { if (expr instanceof AST_Assign && !expr.left.has_side_effects(compressor) || expr instanceof AST_Unary && (expr.operator == "++" || expr.operator == "--")) { @@ -823,7 +860,7 @@ merge(Compressor.prototype, { function get_lhs(expr) { if (expr instanceof AST_VarDef) { var def = expr.name.definition(); - if (def.orig.length > 1 + if (def.orig.length > 1 && !(expr.name instanceof AST_SymbolFunarg) || def.references.length == 1 && !compressor.exposed(def)) { return make_node(AST_SymbolRef, expr.name, expr.name); } @@ -3174,69 +3211,42 @@ merge(Compressor.prototype, { if (exp instanceof AST_Function) { if (compressor.option("inline") && !exp.name - && exp.body.length == 1 && !exp.uses_arguments && !exp.uses_eval + && exp.body.length == 1 + && all(exp.argnames, function(arg) { + return arg.__unused; + }) && !self.has_pure_annotation(compressor)) { var value; if (stat instanceof AST_Return) { - value = stat.value.clone(true); + value = stat.value; } else if (stat instanceof AST_SimpleStatement) { value = make_node(AST_UnaryPrefix, stat, { operator: "void", - expression: stat.body.clone(true) + expression: stat.body }); } if (value) { - var fn = exp.clone(); - fn.argnames = []; - fn.body = []; - if (exp.argnames.length > 0) { - fn.body.push(make_node(AST_Var, self, { - definitions: exp.argnames.map(function(sym, i) { - var arg = self.args[i]; - return make_node(AST_VarDef, sym, { - name: sym, - value: arg ? arg.clone(true) : make_node(AST_Undefined, self) - }); - }) - })); - } - if (self.args.length > exp.argnames.length) { - fn.body.push(make_node(AST_SimpleStatement, self, { - body: make_sequence(self, self.args.slice(exp.argnames.length).map(function(node) { - return node.clone(true); - })) - })); - } - fn.body.push(make_node(AST_Return, self, { - value: value - })); - var body = fn.transform(compressor).body; - if (body.length == 0) return make_node(AST_Undefined, self); - if (body.length == 1 && body[0] instanceof AST_Return) { - value = body[0].value; - if (!value) return make_node(AST_Undefined, self); - var tw = new TreeWalker(function(node) { - if (value === self) return true; - if (node instanceof AST_SymbolRef) { - var ref = node.scope.find_variable(node); - if (ref && ref.scope.parent_scope === fn.parent_scope) { - value = self; - return true; - } - } - if (node instanceof AST_This && !tw.find_parent(AST_Scope)) { - value = self; + var tw = new TreeWalker(function(node) { + if (!value) return true; + if (node instanceof AST_SymbolRef) { + var ref = node.scope.find_variable(node); + if (ref && ref.scope.parent_scope === fn.parent_scope) { + value = null; return true; } - }); - value.walk(tw); - if (value !== self) value = best_of(compressor, value, self); - } else { - value = self; - } - if (value !== self) return value; + } + if (node instanceof AST_This && !tw.find_parent(AST_Scope)) { + value = null; + return true; + } + }); + value.walk(tw); + } + if (value) { + var args = self.args.concat(value); + return make_sequence(self, args).transform(compressor); } } if (compressor.option("side_effects") && all(exp.body, is_empty)) { |