aboutsummaryrefslogtreecommitdiff
path: root/lib/compress.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/compress.js')
-rw-r--r--lib/compress.js114
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)) {