Compare commits

...

20 Commits

Author SHA1 Message Date
Alex Lam S.L
346fa12e0e v3.1.9 2017-11-11 15:31:13 +08:00
Alex Lam S.L
cda27b0970 extend reduce_funcs to cover cross-scope substitutions (#2469)
fixes #2468
2017-11-11 15:30:17 +08:00
Alex Lam S.L
3c74047368 implement compress option reduce_funcs (#2466)
- inline single-use function declarations as expressions when permissible
- depend on `reduce_vars`
- enabled by default
- disable for speed critical code

fixes #2464
2017-11-11 05:59:35 +08:00
Alex Lam S.L
94525d859f fix object literal tracing in reduce_vars (#2461) 2017-11-10 05:47:10 +08:00
Alex Lam S.L
1127a2caf3 fix multiple nested function substitutions (#2458)
fixes #2449
2017-11-09 23:30:00 +08:00
Alex Lam S.L
246d9d4e83 remove hack in collapse_vars (#2457)
fixes #2456
2017-11-09 20:00:58 +08:00
Alex Lam S.L
4c0b0177b6 preserve function identity in reduce_vars (#2451)
fixes #2450
2017-11-08 03:28:46 +08:00
Alex Lam S.L
38bfb73f06 v3.1.8 2017-11-07 03:55:16 +08:00
Alex Lam S.L
bbedbf4ea0 handle circular function reference gracefully (#2446)
fixes #2442
2017-11-07 02:37:23 +08:00
Alex Lam S.L
2cfb5aa7da account for eval & with in reduce_vars (#2441)
fixes #2440
2017-11-06 16:10:57 +08:00
Alex Lam S.L
6c45101870 consolidate & enhance unused (#2439)
- defer declaration removal in `collapse_vars`
- account for `AST_SymbolFunarg` in deduplication
- private accounting for `collapse_vars`
- avoid issues with identity reference due to deep cloning

fixes #2437
2017-11-06 14:25:10 +08:00
Alex Lam S.L
2c2fd89e34 inline single-use functions that are not constant expressions (#2434)
fixes #2428
2017-11-05 22:14:11 +08:00
Alex Lam S.L
f46281e2b7 v3.1.7 2017-11-05 15:03:19 +08:00
Alex Lam S.L
25a18883f5 tweak #2424 (#2432) 2017-11-05 12:49:14 +08:00
Alex Lam S.L
5b4b07e9a7 extend function inlining safety checks (#2430) 2017-11-05 06:18:45 +08:00
Alex Lam S.L
a8aa28a7a6 consolidate single-use function reduction (#2427)
fixes #2423
2017-11-05 04:27:01 +08:00
Alex Lam S.L
fe5a68f9d5 maintain call argument order in collapse_vars (#2426)
fixes #2425
2017-11-05 00:00:18 +08:00
Alex Lam S.L
71e61153b1 improve variations on call arguments for ufuzz (#2424) 2017-11-04 16:29:42 +08:00
Alex Lam S.L
c8b6f4733d reduce this within functions (#2421)
- only replace same-scope usages
- augment `test/ufuzz.js` to test for `this`


fixes #2420
2017-11-04 00:31:37 +08:00
Alex Lam S.L
a48f87abf2 compress new function containing this (#2417) 2017-10-30 23:19:27 +08:00
27 changed files with 1845 additions and 197 deletions

View File

@@ -689,6 +689,11 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
Specify `"strict"` to treat `foo.bar` as side-effect-free only when Specify `"strict"` to treat `foo.bar` as side-effect-free only when
`foo` is certain to not throw, i.e. not `null` or `undefined`. `foo` is certain to not throw, i.e. not `null` or `undefined`.
- `reduce_funcs` (default: `true`) -- Allows single-use functions
to be inlined as function expressions when permissible.
Enabled by default. Option depends on `reduce_vars` being enabled.
For speed critical code this option should be disabled.
- `reduce_vars` (default: `true`) -- Improve optimization on variables assigned with and - `reduce_vars` (default: `true`) -- Improve optimization on variables assigned with and
used as constant values. used as constant values.

View File

@@ -75,6 +75,7 @@ function Compressor(options, false_by_default) {
properties : !false_by_default, properties : !false_by_default,
pure_getters : !false_by_default && "strict", pure_getters : !false_by_default && "strict",
pure_funcs : null, pure_funcs : null,
reduce_funcs : !false_by_default,
reduce_vars : !false_by_default, reduce_vars : !false_by_default,
sequences : !false_by_default, sequences : !false_by_default,
side_effects : !false_by_default, side_effects : !false_by_default,
@@ -150,7 +151,9 @@ merge(Compressor.prototype, {
} }
var passes = +this.options.passes || 1; var passes = +this.options.passes || 1;
var last_count = 1 / 0; var last_count = 1 / 0;
var mangle = { ie8: this.option("ie8") };
for (var pass = 0; pass < passes; pass++) { for (var pass = 0; pass < passes; pass++) {
node.figure_out_scope(mangle);
if (pass > 0 || this.option("reduce_vars")) if (pass > 0 || this.option("reduce_vars"))
node.reset_opt_flags(this); node.reset_opt_flags(this);
node = node.transform(this); node = node.transform(this);
@@ -285,7 +288,7 @@ merge(Compressor.prototype, {
self.transform(tt); self.transform(tt);
}); });
AST_Node.DEFMETHOD("reset_opt_flags", function(compressor) { AST_Toplevel.DEFMETHOD("reset_opt_flags", function(compressor) {
var reduce_vars = compressor.option("reduce_vars"); var reduce_vars = compressor.option("reduce_vars");
var unused = compressor.option("unused"); var unused = compressor.option("unused");
// Stack of look-up tables to keep track of whether a `SymbolDef` has been // Stack of look-up tables to keep track of whether a `SymbolDef` has been
@@ -311,16 +314,16 @@ merge(Compressor.prototype, {
if (node instanceof AST_SymbolRef) { if (node instanceof AST_SymbolRef) {
var d = node.definition(); var d = node.definition();
d.references.push(node); d.references.push(node);
var value;
if (d.fixed === undefined || !safe_to_read(d) || d.single_use == "m") { if (d.fixed === undefined || !safe_to_read(d) || d.single_use == "m") {
d.fixed = false; d.fixed = false;
} else if (d.fixed) { } else if (d.fixed) {
var value = node.fixed_value(); value = node.fixed_value();
if (unused) { if (value && ref_once(d)) {
d.single_use = value d.single_use = value instanceof AST_Lambda
&& d.references.length == 1 || d.scope === node.scope && value.is_constant_expression();
&& loop_ids[d.id] === in_loop } else {
&& d.scope === node.scope d.single_use = false;
&& value.is_constant_expression();
} }
if (is_modified(node, value, 0, is_immutable(value))) { if (is_modified(node, value, 0, is_immutable(value))) {
if (d.single_use) { if (d.single_use) {
@@ -328,10 +331,9 @@ merge(Compressor.prototype, {
} else { } else {
d.fixed = false; d.fixed = false;
} }
} else {
mark_escaped(d, node, value, 0);
} }
} }
mark_escaped(d, node, value, 0);
} }
if (node instanceof AST_SymbolCatch) { if (node instanceof AST_SymbolCatch) {
node.definition().fixed = false; node.definition().fixed = false;
@@ -376,7 +378,9 @@ merge(Compressor.prototype, {
d.fixed = false; d.fixed = false;
} else { } else {
d.fixed = node; d.fixed = node;
loop_ids[d.id] = in_loop;
mark(d, true); mark(d, true);
d.single_use = ref_once(d);
} }
var save_ids = safe_ids; var save_ids = safe_ids;
safe_ids = Object.create(null); safe_ids = Object.create(null);
@@ -527,6 +531,7 @@ merge(Compressor.prototype, {
} }
return true; return true;
} }
return def.fixed instanceof AST_Defun;
} }
function safe_to_assign(def, value) { function safe_to_assign(def, value) {
@@ -551,7 +556,7 @@ merge(Compressor.prototype, {
function reset_def(def) { function reset_def(def) {
def.direct_access = false; def.direct_access = false;
def.escaped = false; def.escaped = false;
if (def.scope.uses_eval) { if (def.scope.uses_eval || def.scope.uses_with) {
def.fixed = false; def.fixed = false;
} else if (!compressor.exposed(def)) { } else if (!compressor.exposed(def)) {
def.fixed = undefined; def.fixed = undefined;
@@ -563,8 +568,19 @@ merge(Compressor.prototype, {
def.single_use = undefined; def.single_use = undefined;
} }
function ref_once(def) {
return unused
&& !def.scope.uses_eval
&& !def.scope.uses_with
&& def.references.length == 1
&& loop_ids[def.id] === in_loop;
}
function is_immutable(value) { function is_immutable(value) {
return value && (value.is_constant() || value instanceof AST_Lambda); if (!value) return false;
return value.is_constant()
|| value instanceof AST_Lambda
|| value instanceof AST_This;
} }
function read_property(obj, key) { function read_property(obj, key) {
@@ -592,10 +608,13 @@ merge(Compressor.prototype, {
|| !immutable || !immutable
&& parent instanceof AST_Call && parent instanceof AST_Call
&& parent.expression === node && parent.expression === node
&& (!(value instanceof AST_Function) || value.contains_this())) { && (!(value instanceof AST_Function) || value.contains_this(parent))) {
return true; return true;
} else if (parent instanceof AST_Array || parent instanceof AST_Object) { } else if (parent instanceof AST_Array) {
return is_modified(parent, parent, level + 1); return is_modified(parent, parent, level + 1);
} else if (parent instanceof AST_ObjectKeyVal && node === parent.value) {
var obj = tw.parent(level + 1);
return is_modified(obj, obj, level + 2);
} else if (parent instanceof AST_PropAccess && parent.expression === node) { } else if (parent instanceof AST_PropAccess && parent.expression === node) {
return !immutable && is_modified(parent, read_property(value, parent.property), level + 1); return !immutable && is_modified(parent, read_property(value, parent.property), level + 1);
} }
@@ -603,15 +622,19 @@ merge(Compressor.prototype, {
function mark_escaped(d, node, value, level) { function mark_escaped(d, node, value, level) {
var parent = tw.parent(level); var parent = tw.parent(level);
if (value instanceof AST_Constant || value instanceof AST_Function) return; if (value instanceof AST_Constant) return;
if (level > 0 && value instanceof AST_Function) return;
if (parent instanceof AST_Assign && parent.operator == "=" && node === parent.right if (parent instanceof AST_Assign && parent.operator == "=" && node === parent.right
|| parent instanceof AST_Call && node !== parent.expression || parent instanceof AST_Call && node !== parent.expression
|| parent instanceof AST_Return && node === parent.value && node.scope !== d.scope || parent instanceof AST_Return && node === parent.value && node.scope !== d.scope
|| parent instanceof AST_VarDef && node === parent.value) { || parent instanceof AST_VarDef && node === parent.value) {
d.escaped = true; d.escaped = true;
return; return;
} else if (parent instanceof AST_Array || parent instanceof AST_Object) { } else if (parent instanceof AST_Array) {
mark_escaped(d, parent, parent, level + 1); mark_escaped(d, parent, parent, level + 1);
} else if (parent instanceof AST_ObjectKeyVal && node === parent.value) {
var obj = tw.parent(level + 1);
mark_escaped(d, obj, obj, level + 2);
} else if (parent instanceof AST_PropAccess && node === parent.expression) { } else if (parent instanceof AST_PropAccess && node === parent.expression) {
value = read_property(value, parent.property); value = read_property(value, parent.property);
mark_escaped(d, parent, value, level + 1); mark_escaped(d, parent, value, level + 1);
@@ -772,6 +795,14 @@ merge(Compressor.prototype, {
|| compressor.option("unsafe") && global_names(this.name); || compressor.option("unsafe") && global_names(this.name);
}); });
function drop_decl(def) {
def._eliminiated = (def._eliminiated || 0) + 1;
if (def.orig.length == def._eliminiated) {
def.scope.functions.del(def.name);
def.scope.variables.del(def.name);
}
}
function tighten_body(statements, compressor) { function tighten_body(statements, compressor) {
var CHANGED, max_iter = 10; var CHANGED, max_iter = 10;
do { do {
@@ -805,6 +836,7 @@ merge(Compressor.prototype, {
function collapse(statements, compressor) { function collapse(statements, compressor) {
var scope = compressor.find_parent(AST_Scope); var scope = compressor.find_parent(AST_Scope);
if (scope.uses_eval || scope.uses_with) return statements; if (scope.uses_eval || scope.uses_with) return statements;
var args;
var candidates = []; var candidates = [];
var stat_index = statements.length; var stat_index = statements.length;
while (--stat_index >= 0) { while (--stat_index >= 0) {
@@ -825,7 +857,7 @@ merge(Compressor.prototype, {
var one_off = lhs instanceof AST_Symbol && lhs.definition().references.length == 1; var one_off = lhs instanceof AST_Symbol && lhs.definition().references.length == 1;
var side_effects = value_has_side_effects(candidate); var side_effects = value_has_side_effects(candidate);
var hit = candidate.name instanceof AST_SymbolFunarg; var hit = candidate.name instanceof AST_SymbolFunarg;
var abort = false, replaced = false; var abort = false, replaced = false, can_replace = !args || !hit;
var tt = new TreeTransformer(function(node, descend) { var tt = new TreeTransformer(function(node, descend) {
if (abort) return node; if (abort) return node;
// Skip nodes before `candidate` as quickly as possible // Skip nodes before `candidate` as quickly as possible
@@ -850,7 +882,8 @@ merge(Compressor.prototype, {
return node; return node;
} }
// Replace variable with assignment when found // Replace variable with assignment when found
if (!(node instanceof AST_SymbolDeclaration) if (can_replace
&& !(node instanceof AST_SymbolDeclaration)
&& !is_lhs(node, parent) && !is_lhs(node, parent)
&& lhs.equivalent_to(node)) { && lhs.equivalent_to(node)) {
CHANGED = replaced = abort = true; CHANGED = replaced = abort = true;
@@ -901,6 +934,12 @@ merge(Compressor.prototype, {
// Skip (non-executed) functions and (leading) default case in switch statements // Skip (non-executed) functions and (leading) default case in switch statements
if (node instanceof AST_Default || node instanceof AST_Scope) return node; if (node instanceof AST_Default || node instanceof AST_Scope) return node;
}); });
if (!can_replace) {
for (var j = compressor.self().argnames.lastIndexOf(candidate.name) + 1; j < args.length; j++) {
args[j].transform(tt);
}
can_replace = true;
}
for (var i = stat_index; !abort && i < statements.length; i++) { for (var i = stat_index; !abort && i < statements.length; i++) {
statements[i].transform(tt); statements[i].transform(tt);
} }
@@ -918,12 +957,18 @@ merge(Compressor.prototype, {
&& iife.expression === fn) { && iife.expression === fn) {
var fn_strict = compressor.has_directive("use strict"); var fn_strict = compressor.has_directive("use strict");
if (fn_strict && fn.body.indexOf(fn_strict) < 0) fn_strict = false; if (fn_strict && fn.body.indexOf(fn_strict) < 0) fn_strict = false;
var len = fn.argnames.length;
args = iife.args.slice(len);
var names = Object.create(null); var names = Object.create(null);
for (var i = fn.argnames.length; --i >= 0;) { for (var i = len; --i >= 0;) {
var sym = fn.argnames[i]; var sym = fn.argnames[i];
var arg = iife.args[i];
args.unshift(make_node(AST_VarDef, sym, {
name: sym,
value: arg
}));
if (sym.name in names) continue; if (sym.name in names) continue;
names[sym.name] = true; names[sym.name] = true;
var arg = iife.args[i];
if (!arg) arg = make_node(AST_Undefined, sym).transform(compressor); if (!arg) arg = make_node(AST_Undefined, sym).transform(compressor);
else { else {
var tw = new TreeWalker(function(node) { var tw = new TreeWalker(function(node) {
@@ -970,7 +1015,8 @@ merge(Compressor.prototype, {
function get_lhs(expr) { function get_lhs(expr) {
if (expr instanceof AST_VarDef) { if (expr instanceof AST_VarDef) {
var def = expr.name.definition(); var def = expr.name.definition();
if (def.orig.length > 1 && !(expr.name instanceof AST_SymbolFunarg) if (def.orig.length - (def._eliminiated || 0) > 1
&& !(expr.name instanceof AST_SymbolFunarg)
|| def.references.length == 1 && !compressor.exposed(def)) { || def.references.length == 1 && !compressor.exposed(def)) {
return make_node(AST_SymbolRef, expr.name, expr.name); return make_node(AST_SymbolRef, expr.name, expr.name);
} }
@@ -979,6 +1025,10 @@ merge(Compressor.prototype, {
} }
} }
function get_rvalue(expr) {
return expr[expr instanceof AST_Assign ? "right" : "value"];
}
function get_lvalues(expr) { function get_lvalues(expr) {
var lvalues = Object.create(null); var lvalues = Object.create(null);
if (expr instanceof AST_Unary) return lvalues; if (expr instanceof AST_Unary) return lvalues;
@@ -989,7 +1039,7 @@ merge(Compressor.prototype, {
lvalues[sym.name] = lvalues[sym.name] || is_lhs(node, tw.parent()); lvalues[sym.name] = lvalues[sym.name] || is_lhs(node, tw.parent());
} }
}); });
expr[expr instanceof AST_Assign ? "right" : "value"].walk(tw); get_rvalue(expr).walk(tw);
return lvalues; return lvalues;
} }
@@ -1010,10 +1060,12 @@ merge(Compressor.prototype, {
var found = false; var found = false;
return statements[stat_index].transform(new TreeTransformer(function(node, descend, in_list) { return statements[stat_index].transform(new TreeTransformer(function(node, descend, in_list) {
if (found) return node; if (found) return node;
if (node === expr) { if (node === expr || node.body === expr) {
found = true; found = true;
if (node instanceof AST_VarDef) { if (node instanceof AST_VarDef) {
remove(node.name.definition().orig, node.name); drop_decl(node.name.definition());
node.value = null;
return node;
} }
return in_list ? MAP.skip : null; return in_list ? MAP.skip : null;
} }
@@ -1022,16 +1074,12 @@ merge(Compressor.prototype, {
case 0: return null; case 0: return null;
case 1: return node.expressions[0]; case 1: return node.expressions[0];
} }
if (node instanceof AST_Definitions && node.definitions.length == 0
|| node instanceof AST_SimpleStatement && !node.body) {
return null;
}
})); }));
} }
function value_has_side_effects(expr) { function value_has_side_effects(expr) {
if (expr instanceof AST_Unary) return false; if (expr instanceof AST_Unary) return false;
return expr[expr instanceof AST_Assign ? "right" : "value"].has_side_effects(compressor); return get_rvalue(expr).has_side_effects(compressor);
} }
function references_in_scope(def) { function references_in_scope(def) {
@@ -2148,18 +2196,25 @@ merge(Compressor.prototype, {
} }
def(AST_Node, return_false); def(AST_Node, return_false);
def(AST_Constant, return_true); def(AST_Constant, return_true);
def(AST_Function, function(){ def(AST_Lambda, function(scope){
var self = this; var self = this;
var result = true; var result = true;
self.walk(new TreeWalker(function(node) { self.walk(new TreeWalker(function(node) {
if (!result) return true; if (!result) return true;
if (node instanceof AST_SymbolRef) { if (node instanceof AST_SymbolRef) {
var def = node.definition(); var def = node.definition();
if (self.enclosed.indexOf(def) >= 0 if (member(def, self.enclosed)
&& self.variables.get(def.name) !== def) { && !self.variables.has(def.name)) {
if (scope) {
var scope_def = scope.find_variable(node);
if (def.undeclared ? !scope_def : scope_def === def) {
result = "f";
return true;
}
}
result = false; result = false;
return true;
} }
return true;
} }
})); }));
return result; return result;
@@ -2269,58 +2324,63 @@ merge(Compressor.prototype, {
// this scope (not in nested scopes). // this scope (not in nested scopes).
var scope = this; var scope = this;
var tw = new TreeWalker(function(node, descend){ var tw = new TreeWalker(function(node, descend){
if (node !== self) { if (node === self) return;
if (node instanceof AST_Defun) { if (node instanceof AST_Defun) {
if (!drop_funcs && scope === self) { if (!drop_funcs && scope === self) {
var node_def = node.name.definition(); var node_def = node.name.definition();
if (!(node_def.id in in_use_ids)) {
in_use_ids[node_def.id] = true;
in_use.push(node_def);
}
}
initializations.add(node.name.name, node);
return true; // don't go in nested scopes
}
if (node instanceof AST_SymbolFunarg && scope === self) {
var_defs_by_id.add(node.definition().id, node);
}
if (node instanceof AST_Definitions && scope === self) {
node.definitions.forEach(function(def){
var node_def = def.name.definition();
if (def.name instanceof AST_SymbolVar) {
var_defs_by_id.add(node_def.id, def);
}
if (!drop_vars) {
if (!(node_def.id in in_use_ids)) { if (!(node_def.id in in_use_ids)) {
in_use_ids[node_def.id] = true; in_use_ids[node_def.id] = true;
in_use.push(node_def); in_use.push(node_def);
} }
} }
initializations.add(node.name.name, node); if (def.value) {
return true; // don't go in nested scopes initializations.add(def.name.name, def.value);
} if (def.value.has_side_effects(compressor)) {
if (node instanceof AST_Definitions && scope === self) { def.value.walk(tw);
node.definitions.forEach(function(def){
var node_def = def.name.definition();
if (def.name instanceof AST_SymbolVar) {
var_defs_by_id.add(node_def.id, def);
} }
if (!drop_vars) {
if (!(node_def.id in in_use_ids)) {
in_use_ids[node_def.id] = true;
in_use.push(node_def);
}
}
if (def.value) {
initializations.add(def.name.name, def.value);
if (def.value.has_side_effects(compressor)) {
def.value.walk(tw);
}
}
});
return true;
}
if (assign_as_unused(node) instanceof AST_SymbolRef && scope === self) {
if (node instanceof AST_Assign) node.right.walk(tw);
return true;
}
if (node instanceof AST_SymbolRef) {
var node_def = node.definition();
if (!(node_def.id in in_use_ids)) {
in_use_ids[node_def.id] = true;
in_use.push(node_def);
} }
return true; });
} return true;
if (node instanceof AST_Scope) { }
var save_scope = scope; var sym;
scope = node; if (scope === self
descend(); && (sym = assign_as_unused(node)) instanceof AST_SymbolRef
scope = save_scope; && self.variables.get(sym.name) === sym.definition()) {
return true; if (node instanceof AST_Assign) node.right.walk(tw);
return true;
}
if (node instanceof AST_SymbolRef) {
var node_def = node.definition();
if (!(node_def.id in in_use_ids)) {
in_use_ids[node_def.id] = true;
in_use.push(node_def);
} }
return true;
}
if (node instanceof AST_Scope) {
var save_scope = scope;
scope = node;
descend();
scope = save_scope;
return true;
} }
}); });
self.walk(tw); self.walk(tw);
@@ -2375,8 +2435,10 @@ merge(Compressor.prototype, {
} }
} }
if (drop_funcs && node instanceof AST_Defun && node !== self) { if (drop_funcs && node instanceof AST_Defun && node !== self) {
if (!(node.name.definition().id in in_use_ids)) { var def = node.name.definition();
if (!(def.id in in_use_ids)) {
compressor[node.name.unreferenced() ? "warn" : "info"]("Dropping unused function {name} [{file}:{line},{col}]", template(node.name)); compressor[node.name.unreferenced() ? "warn" : "info"]("Dropping unused function {name} [{file}:{line},{col}]", template(node.name));
drop_decl(def);
return make_node(AST_EmptyStatement, node); return make_node(AST_EmptyStatement, node);
} }
return node; return node;
@@ -2398,7 +2460,7 @@ merge(Compressor.prototype, {
if (var_defs.length > 1 && !def.value) { if (var_defs.length > 1 && !def.value) {
compressor.warn("Dropping duplicated definition of variable {name} [{file}:{line},{col}]", template(def.name)); compressor.warn("Dropping duplicated definition of variable {name} [{file}:{line},{col}]", template(def.name));
remove(var_defs, def); remove(var_defs, def);
remove(sym.orig, def.name); drop_decl(sym);
return; return;
} }
} }
@@ -2431,7 +2493,7 @@ merge(Compressor.prototype, {
} else { } else {
compressor[def.name.unreferenced() ? "warn" : "info"]("Dropping unused variable {name} [{file}:{line},{col}]", template(def.name)); compressor[def.name.unreferenced() ? "warn" : "info"]("Dropping unused variable {name} [{file}:{line},{col}]", template(def.name));
} }
remove(sym.orig, def.name); drop_decl(sym);
} }
}); });
if (head.length == 0 && tail.length == 1 && tail[0].name instanceof AST_SymbolVar) { if (head.length == 0 && tail.length == 1 && tail[0].name instanceof AST_SymbolVar) {
@@ -2440,7 +2502,7 @@ merge(Compressor.prototype, {
var def = tail.pop(); var def = tail.pop();
compressor.warn("Converting duplicated definition of variable {name} to assignment [{file}:{line},{col}]", template(def.name)); compressor.warn("Converting duplicated definition of variable {name} to assignment [{file}:{line},{col}]", template(def.name));
remove(var_defs, def); remove(var_defs, def);
remove(def.name.definition().orig, def.name); drop_decl(def.name.definition());
side_effects.unshift(make_node(AST_Assign, def, { side_effects.unshift(make_node(AST_Assign, def, {
operator: "=", operator: "=",
left: make_node(AST_SymbolRef, def.name, def.name), left: make_node(AST_SymbolRef, def.name, def.name),
@@ -2469,10 +2531,9 @@ merge(Compressor.prototype, {
} }
} }
if (drop_vars) { if (drop_vars) {
var def = assign_as_unused(node); var sym = assign_as_unused(node);
if (def instanceof AST_SymbolRef if (sym instanceof AST_SymbolRef
&& !((def = def.definition()).id in in_use_ids) && !(sym.definition().id in in_use_ids)) {
&& self.variables.get(def.name) === def) {
if (node instanceof AST_Assign) { if (node instanceof AST_Assign) {
return maintain_this_binding(parent, node, node.right.transform(tt)); return maintain_this_binding(parent, node, node.right.transform(tt));
} }
@@ -3242,7 +3303,7 @@ merge(Compressor.prototype, {
})); }));
if (reduce_vars) name.definition().fixed = false; if (reduce_vars) name.definition().fixed = false;
} }
remove(def.name.definition().orig, def.name); drop_decl(def.name.definition());
return a; return a;
}, []); }, []);
if (assignments.length == 0) return null; if (assignments.length == 0) return null;
@@ -3484,6 +3545,7 @@ merge(Compressor.prototype, {
&& !exp.uses_arguments && !exp.uses_arguments
&& !exp.uses_eval && !exp.uses_eval
&& exp.body.length == 1 && exp.body.length == 1
&& !exp.contains_this()
&& all(exp.argnames, function(arg) { && all(exp.argnames, function(arg) {
return arg.__unused; return arg.__unused;
}) })
@@ -3497,23 +3559,6 @@ merge(Compressor.prototype, {
expression: stat.body expression: stat.body
}); });
} }
if (value) {
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;
}
}
if (node instanceof AST_This && !tw.find_parent(AST_Scope)) {
value = null;
return true;
}
});
value.walk(tw);
}
if (value) { if (value) {
var args = self.args.concat(value); var args = self.args.concat(value);
return make_sequence(self, args).optimize(compressor); return make_sequence(self, args).optimize(compressor);
@@ -4176,6 +4221,17 @@ merge(Compressor.prototype, {
return self; return self;
}); });
function recursive_ref(compressor, def) {
var node;
for (var i = 0; node = compressor.parent(i); i++) {
if (node instanceof AST_Lambda) {
var name = node.name;
if (name && name.definition() === def) break;
}
}
return node;
}
OPT(AST_SymbolRef, function(self, compressor){ OPT(AST_SymbolRef, function(self, compressor){
var def = self.resolve_defines(compressor); var def = self.resolve_defines(compressor);
if (def) { if (def) {
@@ -4201,49 +4257,68 @@ merge(Compressor.prototype, {
if (fixed instanceof AST_Defun) { if (fixed instanceof AST_Defun) {
d.fixed = fixed = make_node(AST_Function, fixed, fixed); d.fixed = fixed = make_node(AST_Function, fixed, fixed);
} }
if (compressor.option("unused") if (d.single_use && fixed instanceof AST_Function) {
&& fixed if (!compressor.option("reduce_funcs") && d.scope !== self.scope) {
&& d.references.length == 1 d.single_use = false;
&& (d.single_use || fixed instanceof AST_Function } else if (d.escaped && d.scope !== self.scope || recursive_ref(compressor, d)) {
&& !(d.scope.uses_arguments && d.orig[0] instanceof AST_SymbolFunarg) d.single_use = false;
&& !d.scope.uses_eval } else if (d.scope !== self.scope || d.orig[0] instanceof AST_SymbolFunarg) {
&& compressor.find_parent(AST_Scope) === fixed.parent_scope)) { d.single_use = fixed.is_constant_expression(self.scope);
if (d.single_use == "f") {
var scope = self.scope;
do {
if (scope.name) scope.name.definition().single_use = false;
} while (scope = scope.parent_scope);
}
}
}
if (d.single_use && fixed) {
var value = fixed.optimize(compressor); var value = fixed.optimize(compressor);
return value === fixed ? fixed.clone(true) : value; return value === fixed ? fixed.clone(true) : value;
} }
if (compressor.option("evaluate") && fixed) { if (fixed && d.should_replace === undefined) {
if (d.should_replace === undefined) { var init;
var init = fixed.evaluate(compressor); if (fixed instanceof AST_This) {
if (init !== fixed && (compressor.option("unsafe_regexp") || !(init instanceof RegExp))) { if (!(d.orig[0] instanceof AST_SymbolFunarg)
init = make_node_from_constant(init, fixed); && all(d.references, function(ref) {
var value_length = init.optimize(compressor).print_to_string().length; return d.scope === ref.scope;
var fn; })) {
if (has_symbol_ref(fixed)) { init = fixed;
fn = function() { }
var result = init.optimize(compressor); } else {
return result === init ? result.clone(true) : result; var ev = fixed.evaluate(compressor);
}; if (ev !== fixed && (compressor.option("unsafe_regexp") || !(ev instanceof RegExp))) {
} else { init = make_node_from_constant(ev, fixed);
value_length = Math.min(value_length, fixed.print_to_string().length);
fn = function() {
var result = best_of_expression(init.optimize(compressor), fixed);
return result === init || result === fixed ? result.clone(true) : result;
};
}
var name_length = d.name.length;
var overhead = 0;
if (compressor.option("unused") && !compressor.exposed(d)) {
overhead = (name_length + 2 + value_length) / d.references.length;
}
d.should_replace = value_length <= name_length + overhead ? fn : false;
} else {
d.should_replace = false;
} }
} }
if (d.should_replace) { if (init) {
return d.should_replace(); var value_length = init.optimize(compressor).print_to_string().length;
var fn;
if (has_symbol_ref(fixed)) {
fn = function() {
var result = init.optimize(compressor);
return result === init ? result.clone(true) : result;
};
} else {
value_length = Math.min(value_length, fixed.print_to_string().length);
fn = function() {
var result = best_of_expression(init.optimize(compressor), fixed);
return result === init || result === fixed ? result.clone(true) : result;
};
}
var name_length = d.name.length;
var overhead = 0;
if (compressor.option("unused") && !compressor.exposed(d)) {
overhead = (name_length + 2 + value_length) / d.references.length;
}
d.should_replace = value_length <= name_length + overhead ? fn : false;
} else {
d.should_replace = false;
} }
} }
if (d.should_replace) {
return d.should_replace();
}
} }
return self; return self;
@@ -4561,11 +4636,11 @@ merge(Compressor.prototype, {
} }
} }
if (is_lhs(self, compressor.parent())) return self; if (is_lhs(self, compressor.parent())) return self;
if (compressor.option("properties") && key !== prop) { if (key !== prop) {
var node = self.flatten_object(property); var sub = self.flatten_object(property, compressor);
if (node) { if (sub) {
expr = self.expression = node.expression; expr = self.expression = sub.expression;
prop = self.property = node.property; prop = self.property = sub.property;
} }
} }
if (compressor.option("properties") && compressor.option("side_effects") if (compressor.option("properties") && compressor.option("side_effects")
@@ -4611,7 +4686,8 @@ merge(Compressor.prototype, {
return self; return self;
}); });
AST_Lambda.DEFMETHOD("contains_this", function() { AST_Lambda.DEFMETHOD("contains_this", function(grandparent) {
if (grandparent instanceof AST_New) return false;
var result; var result;
var self = this; var self = this;
self.walk(new TreeWalker(function(node) { self.walk(new TreeWalker(function(node) {
@@ -4622,7 +4698,8 @@ merge(Compressor.prototype, {
return result; return result;
}); });
AST_PropAccess.DEFMETHOD("flatten_object", function(key) { AST_PropAccess.DEFMETHOD("flatten_object", function(key, compressor) {
if (!compressor.option("properties")) return;
var expr = this.expression; var expr = this.expression;
if (expr instanceof AST_Object) { if (expr instanceof AST_Object) {
var props = expr.properties; var props = expr.properties;
@@ -4633,7 +4710,8 @@ merge(Compressor.prototype, {
return prop instanceof AST_ObjectKeyVal; return prop instanceof AST_ObjectKeyVal;
})) break; })) break;
var value = prop.value; var value = prop.value;
if (value instanceof AST_Function && value.contains_this()) break; if (value instanceof AST_Function
&& value.contains_this(compressor.parent())) break;
return make_node(AST_Sub, this, { return make_node(AST_Sub, this, {
expression: make_node(AST_Array, expr, { expression: make_node(AST_Array, expr, {
elements: props.map(function(prop) { elements: props.map(function(prop) {
@@ -4677,10 +4755,8 @@ merge(Compressor.prototype, {
} }
} }
if (is_lhs(self, compressor.parent())) return self; if (is_lhs(self, compressor.parent())) return self;
if (compressor.option("properties")) { var sub = self.flatten_object(self.property, compressor);
var node = self.flatten_object(self.property); if (sub) return sub.optimize(compressor);
if (node) return node.optimize(compressor);
}
var ev = self.evaluate(compressor); var ev = self.evaluate(compressor);
if (ev !== self) { if (ev !== self) {
ev = make_node_from_constant(ev, self).optimize(compressor); ev = make_node_from_constant(ev, self).optimize(compressor);

View File

@@ -137,11 +137,9 @@ function minify(files, options) {
if (options.wrap) { if (options.wrap) {
toplevel = toplevel.wrap_commonjs(options.wrap); toplevel = toplevel.wrap_commonjs(options.wrap);
} }
if (timings) timings.scope1 = Date.now();
if (options.compress) toplevel.figure_out_scope(options.mangle);
if (timings) timings.compress = Date.now(); if (timings) timings.compress = Date.now();
if (options.compress) toplevel = new Compressor(options.compress).compress(toplevel); if (options.compress) toplevel = new Compressor(options.compress).compress(toplevel);
if (timings) timings.scope2 = Date.now(); if (timings) timings.scope = Date.now();
if (options.mangle) toplevel.figure_out_scope(options.mangle); if (options.mangle) toplevel.figure_out_scope(options.mangle);
if (timings) timings.mangle = Date.now(); if (timings) timings.mangle = Date.now();
if (options.mangle) { if (options.mangle) {
@@ -199,9 +197,9 @@ function minify(files, options) {
if (timings) { if (timings) {
timings.end = Date.now(); timings.end = Date.now();
result.timings = { result.timings = {
parse: 1e-3 * (timings.scope1 - timings.parse), parse: 1e-3 * (timings.compress - timings.parse),
scope: 1e-3 * (timings.compress - timings.scope1 + timings.mangle - timings.scope2), compress: 1e-3 * (timings.scope - timings.compress),
compress: 1e-3 * (timings.scope2 - timings.compress), scope: 1e-3 * (timings.mangle - timings.scope),
mangle: 1e-3 * (timings.properties - timings.mangle), mangle: 1e-3 * (timings.properties - timings.mangle),
properties: 1e-3 * (timings.output - timings.properties), properties: 1e-3 * (timings.output - timings.properties),
output: 1e-3 * (timings.end - timings.output), output: 1e-3 * (timings.end - timings.output),

View File

@@ -4,7 +4,7 @@
"homepage": "http://lisperator.net/uglifyjs", "homepage": "http://lisperator.net/uglifyjs",
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)", "author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
"license": "BSD-2-Clause", "license": "BSD-2-Clause",
"version": "3.1.6", "version": "3.1.9",
"engines": { "engines": {
"node": ">=0.8.0" "node": ">=0.8.0"
}, },

View File

@@ -129,6 +129,7 @@ constant_join_3: {
for_loop: { for_loop: {
options = { options = {
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unsafe: true, unsafe: true,
unused: true, unused: true,
@@ -185,6 +186,7 @@ for_loop: {
index: { index: {
options = { options = {
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unsafe: true, unsafe: true,
@@ -203,6 +205,7 @@ index: {
length: { length: {
options = { options = {
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unsafe: true, unsafe: true,
@@ -221,6 +224,7 @@ length: {
index_length: { index_length: {
options = { options = {
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unsafe: true, unsafe: true,

View File

@@ -2,7 +2,8 @@ collapse_vars_side_effects_1: {
options = { options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true, reduce_vars:true keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true,
reduce_funcs: true, reduce_vars:true
} }
input: { input: {
function f1() { function f1() {
@@ -150,7 +151,8 @@ collapse_vars_issue_721: {
options = { options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true, reduce_vars:true keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true,
reduce_funcs: true, reduce_vars:true
} }
input: { input: {
define(["require", "exports", 'handlebars'], function (require, exports, hb) { define(["require", "exports", 'handlebars'], function (require, exports, hb) {
@@ -216,7 +218,8 @@ collapse_vars_properties: {
options = { options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true, reduce_vars:true keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true,
reduce_funcs: true, reduce_vars:true
} }
input: { input: {
function f1(obj) { function f1(obj) {
@@ -243,7 +246,8 @@ collapse_vars_if: {
options = { options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true, reduce_vars:true keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true,
reduce_funcs: true, reduce_vars:true
} }
input: { input: {
function f1() { function f1() {
@@ -293,7 +297,8 @@ collapse_vars_while: {
options = { options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:false, unused:true, hoist_funs:true, comparisons:true, evaluate:true, booleans:true, loops:false, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true, reduce_vars:true keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true,
reduce_funcs: true, reduce_vars:true
} }
input: { input: {
function f1(y) { function f1(y) {
@@ -712,7 +717,8 @@ collapse_vars_misc1: {
options = { options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true, reduce_vars:true keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true,
reduce_funcs: true, reduce_vars:true
} }
input: { input: {
function f0(o, a, h) { function f0(o, a, h) {
@@ -789,7 +795,8 @@ collapse_vars_repeated: {
options = { options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true, reduce_vars:true keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true,
reduce_funcs: true, reduce_vars:true
} }
input: { input: {
function f1() { function f1() {
@@ -831,7 +838,8 @@ collapse_vars_closures: {
options = { options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true, reduce_vars:true keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true,
reduce_funcs: true, reduce_vars:true
} }
input: { input: {
function constant_vars_can_be_replaced_in_any_scope() { function constant_vars_can_be_replaced_in_any_scope() {
@@ -921,7 +929,8 @@ collapse_vars_try: {
options = { options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true, reduce_vars:true keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true,
reduce_funcs: true, reduce_vars:true
} }
input: { input: {
function f1() { function f1() {
@@ -1118,7 +1127,8 @@ collapse_vars_constants: {
options = { options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true, reduce_vars:true keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true,
reduce_funcs: true, reduce_vars:true
} }
input: { input: {
function f1(x) { function f1(x) {
@@ -1156,7 +1166,7 @@ collapse_vars_arguments: {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true, keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true,
toplevel:true, reduce_vars:true toplevel:true, reduce_funcs: true, reduce_vars:true
} }
input: { input: {
var outer = function() { var outer = function() {
@@ -1280,6 +1290,7 @@ collapse_vars_regexp: {
hoist_funs: true, hoist_funs: true,
keep_fargs: true, keep_fargs: true,
loops: false, loops: false,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
unused: true, unused: true,
@@ -1355,6 +1366,7 @@ issue_1562: {
options = { options = {
collapse_vars: true, collapse_vars: true,
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -1388,6 +1400,7 @@ issue_1605_1: {
options = { options = {
collapse_vars: true, collapse_vars: true,
toplevel: false, toplevel: false,
unused: true,
} }
input: { input: {
function foo(x) { function foo(x) {
@@ -1410,6 +1423,7 @@ issue_1605_2: {
options = { options = {
collapse_vars: true, collapse_vars: true,
toplevel: "vars", toplevel: "vars",
unused: true,
} }
input: { input: {
function foo(x) { function foo(x) {
@@ -1537,6 +1551,7 @@ issue_1631_3: {
var_side_effects_1: { var_side_effects_1: {
options = { options = {
collapse_vars: true, collapse_vars: true,
unused: true,
} }
input: { input: {
var print = console.log.bind(console); var print = console.log.bind(console);
@@ -1559,6 +1574,7 @@ var_side_effects_1: {
var_side_effects_2: { var_side_effects_2: {
options = { options = {
collapse_vars: true, collapse_vars: true,
unused: true,
} }
input: { input: {
var print = console.log.bind(console); var print = console.log.bind(console);
@@ -1584,6 +1600,7 @@ var_side_effects_3: {
collapse_vars: true, collapse_vars: true,
pure_getters: true, pure_getters: true,
unsafe: true, unsafe: true,
unused: true,
} }
input: { input: {
var print = console.log.bind(console); var print = console.log.bind(console);
@@ -1606,6 +1623,7 @@ var_side_effects_3: {
reduce_vars_assign: { reduce_vars_assign: {
options = { options = {
collapse_vars: true, collapse_vars: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
} }
input: { input: {
@@ -1628,6 +1646,7 @@ reduce_vars_assign: {
iife_1: { iife_1: {
options = { options = {
collapse_vars: true, collapse_vars: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -1648,6 +1667,7 @@ iife_1: {
iife_2: { iife_2: {
options = { options = {
collapse_vars: true, collapse_vars: true,
reduce_funcs: false,
reduce_vars: false, reduce_vars: false,
toplevel: true, toplevel: true,
unused: false, unused: false,
@@ -1659,6 +1679,7 @@ iife_2: {
}(foo); }(foo);
} }
expect: { expect: {
var foo;
!function(x) { !function(x) {
console.log(x); console.log(x);
}(bar()); }(bar());
@@ -1945,6 +1966,7 @@ ref_scope: {
chained_1: { chained_1: {
options = { options = {
collapse_vars: true, collapse_vars: true,
unused: true,
} }
input: { input: {
var a = 2; var a = 2;
@@ -1961,6 +1983,7 @@ chained_1: {
chained_2: { chained_2: {
options = { options = {
collapse_vars: true, collapse_vars: true,
unused: true,
} }
input: { input: {
var a; var a;
@@ -2061,6 +2084,7 @@ inner_lvalues: {
double_def: { double_def: {
options = { options = {
collapse_vars: true, collapse_vars: true,
unused: true,
} }
input: { input: {
var a = x, a = a && y; var a = x, a = a && y;
@@ -2075,6 +2099,7 @@ double_def: {
toplevel_single_reference: { toplevel_single_reference: {
options = { options = {
collapse_vars: true, collapse_vars: true,
unused: true,
} }
input: { input: {
var a; var a;
@@ -2084,9 +2109,10 @@ toplevel_single_reference: {
} }
} }
expect: { expect: {
var a; for (var b in x) {
for (var b in x) var a;
b(a = b); b(a = b);
}
} }
} }
@@ -2094,6 +2120,7 @@ unused_orig: {
options = { options = {
collapse_vars: true, collapse_vars: true,
passes: 2, passes: 2,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@@ -2132,6 +2159,7 @@ issue_315: {
collapse_vars: true, collapse_vars: true,
evaluate: true, evaluate: true,
keep_fargs: false, keep_fargs: false,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
sequences: true, sequences: true,
unused: true, unused: true,
@@ -2358,6 +2386,7 @@ duplicate_argname: {
issue_2298: { issue_2298: {
options = { options = {
collapse_vars: true, collapse_vars: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@@ -2723,6 +2752,7 @@ issue_2364_5: {
evaluate: true, evaluate: true,
pure_getters: true, pure_getters: true,
properties: true, properties: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@@ -2889,6 +2919,7 @@ pure_getters_chain: {
options = { options = {
collapse_vars: true, collapse_vars: true,
pure_getters: true, pure_getters: true,
unused: true,
} }
input: { input: {
function o(t, r) { function o(t, r) {
@@ -2909,6 +2940,7 @@ pure_getters_chain: {
conditional_1: { conditional_1: {
options = { options = {
collapse_vars: true, collapse_vars: true,
unused: true,
} }
input: { input: {
function f(a, b) { function f(a, b) {
@@ -2933,6 +2965,7 @@ conditional_1: {
conditional_2: { conditional_2: {
options = { options = {
collapse_vars: true, collapse_vars: true,
unused: true,
} }
input: { input: {
function f(a, b) { function f(a, b) {
@@ -2949,3 +2982,119 @@ conditional_2: {
} }
expect_stdout: "5 5" expect_stdout: "5 5"
} }
issue_2425_1: {
options = {
collapse_vars: true,
unused: true,
}
input: {
var a = 8;
(function(b) {
b.toString();
})(--a, a |= 10);
console.log(a);
}
expect: {
var a = 8;
(function(b) {
b.toString();
})(--a, a |= 10);
console.log(a);
}
expect_stdout: "15"
}
issue_2425_2: {
options = {
collapse_vars: true,
unused: true,
}
input: {
var a = 8;
(function(b, c) {
b.toString();
})(--a, a |= 10);
console.log(a);
}
expect: {
var a = 8;
(function(b, c) {
b.toString();
})(--a, a |= 10);
console.log(a);
}
expect_stdout: "15"
}
issue_2425_3: {
options = {
collapse_vars: true,
unused: true,
}
input: {
var a = 8;
(function(b, b) {
b.toString();
})(--a, a |= 10);
console.log(a);
}
expect: {
var a = 8;
(function(b, b) {
(a |= 10).toString();
})(--a);
console.log(a);
}
expect_stdout: "15"
}
issue_2437: {
options = {
collapse_vars: true,
conditionals: true,
inline: true,
join_vars: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
sequences: true,
toplevel: true,
unused: true,
}
input: {
function foo() {
bar();
}
function bar() {
if (xhrDesc) {
var req = new XMLHttpRequest();
var result = !!req.onreadystatechange;
Object.defineProperty(XMLHttpRequest.prototype, 'onreadystatechange', xhrDesc || {});
return result;
}
else {
var req = new XMLHttpRequest();
var detectFunc = function () { };
req.onreadystatechange = detectFunc;
var result = req[SYMBOL_FAKE_ONREADYSTATECHANGE_1] === detectFunc;
req.onreadystatechange = null;
return result;
}
}
foo();
}
expect: {
!function() {
if (xhrDesc)
return result = !!(req = new XMLHttpRequest()).onreadystatechange,
Object.defineProperty(XMLHttpRequest.prototype, "onreadystatechange", xhrDesc || {}),
result;
var req = new XMLHttpRequest(), detectFunc = function() {};
req.onreadystatechange = detectFunc;
var result = req[SYMBOL_FAKE_ONREADYSTATECHANGE_1] === detectFunc;
req.onreadystatechange = null;
}();
}
}

View File

@@ -96,6 +96,7 @@ self_comparison_1: {
self_comparison_2: { self_comparison_2: {
options = { options = {
comparisons: true, comparisons: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
} }

View File

@@ -292,6 +292,7 @@ global_timeout_and_interval_symbols: {
issue_2233_2: { issue_2233_2: {
options = { options = {
pure_getters: "strict", pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
unsafe: true, unsafe: true,
@@ -323,6 +324,7 @@ issue_2233_2: {
issue_2233_3: { issue_2233_3: {
options = { options = {
pure_getters: "strict", pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
toplevel: true, toplevel: true,

View File

@@ -673,6 +673,7 @@ issue_1539: {
vardef_value: { vardef_value: {
options = { options = {
keep_fnames: false, keep_fnames: false,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@@ -734,6 +735,7 @@ assign_chain: {
issue_1583: { issue_1583: {
options = { options = {
keep_fargs: true, keep_fargs: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@@ -1080,6 +1082,7 @@ var_catch_toplevel: {
options = { options = {
conditionals: true, conditionals: true,
negate_iife: true, negate_iife: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
toplevel: true, toplevel: true,
@@ -1109,11 +1112,12 @@ var_catch_toplevel: {
} }
} }
issue_2105: { issue_2105_1: {
options = { options = {
collapse_vars: true, collapse_vars: true,
inline: true, inline: true,
passes: 3, passes: 3,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
unused: true, unused: true,
@@ -1139,17 +1143,51 @@ issue_2105: {
}); });
} }
expect: { expect: {
(function() { ({
var quux = function() { prop: function() {
console.log;
console.log("PASS"); console.log("PASS");
}; }
return { }).prop();
prop: function() { }
console.log; expect_stdout: "PASS"
quux(); }
issue_2105_2: {
options = {
collapse_vars: true,
inline: true,
passes: 3,
properties: true,
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unsafe: true,
unused: true,
}
input: {
!function(factory) {
factory();
}( function() {
return function(fn) {
fn()().prop();
}( function() {
function bar() {
var quux = function() {
console.log("PASS");
}, foo = function() {
console.log;
quux();
};
return { prop: foo };
} }
}; return bar;
})().prop(); } );
});
}
expect: {
console.log("PASS");
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }

View File

@@ -251,6 +251,7 @@ unsafe_constant: {
unsafe_object: { unsafe_object: {
options = { options = {
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unsafe: true, unsafe: true,
@@ -279,6 +280,7 @@ unsafe_object: {
unsafe_object_nested: { unsafe_object_nested: {
options = { options = {
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unsafe: true, unsafe: true,
@@ -307,6 +309,7 @@ unsafe_object_nested: {
unsafe_object_complex: { unsafe_object_complex: {
options = { options = {
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unsafe: true, unsafe: true,
@@ -335,6 +338,7 @@ unsafe_object_complex: {
unsafe_object_repeated: { unsafe_object_repeated: {
options = { options = {
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unsafe: true, unsafe: true,
@@ -363,6 +367,7 @@ unsafe_object_repeated: {
unsafe_object_accessor: { unsafe_object_accessor: {
options = { options = {
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unsafe: true, unsafe: true,
} }
@@ -663,6 +668,7 @@ call_args: {
options = { options = {
evaluate: true, evaluate: true,
inline: true, inline: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
} }
@@ -686,6 +692,7 @@ call_args_drop_param: {
evaluate: true, evaluate: true,
inline: true, inline: true,
keep_fargs: false, keep_fargs: false,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -1016,6 +1023,7 @@ Infinity_NaN_undefined_LHS: {
issue_1964_1: { issue_1964_1: {
options = { options = {
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unsafe_regexp: false, unsafe_regexp: false,
unused: true, unused: true,
@@ -1045,6 +1053,7 @@ issue_1964_1: {
issue_1964_2: { issue_1964_2: {
options = { options = {
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unsafe_regexp: true, unsafe_regexp: true,
unused: true, unused: true,
@@ -1201,6 +1210,7 @@ issue_2231_2: {
self_comparison_1: { self_comparison_1: {
options = { options = {
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unsafe: true, unsafe: true,
@@ -1221,6 +1231,7 @@ self_comparison_2: {
evaluate: true, evaluate: true,
hoist_props: true, hoist_props: true,
passes: 2, passes: 2,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,

View File

@@ -19,6 +19,7 @@ iifes_returning_constants_keep_fargs_true: {
booleans : true, booleans : true,
if_return : true, if_return : true,
join_vars : true, join_vars : true,
reduce_funcs : true,
reduce_vars : true, reduce_vars : true,
cascade : true, cascade : true,
inline : true, inline : true,
@@ -55,6 +56,7 @@ iifes_returning_constants_keep_fargs_false: {
booleans : true, booleans : true,
if_return : true, if_return : true,
join_vars : true, join_vars : true,
reduce_funcs : true,
reduce_vars : true, reduce_vars : true,
cascade : true, cascade : true,
inline : true, inline : true,
@@ -101,6 +103,7 @@ issue_1841_1: {
options = { options = {
keep_fargs: false, keep_fargs: false,
pure_getters: "strict", pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@@ -127,6 +130,7 @@ issue_1841_2: {
options = { options = {
keep_fargs: false, keep_fargs: false,
pure_getters: false, pure_getters: false,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@@ -154,6 +158,7 @@ function_returning_constant_literal: {
inline: true, inline: true,
passes: 2, passes: 2,
properties: true, properties: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
toplevel: true, toplevel: true,
@@ -305,6 +310,7 @@ issue_2084: {
evaluate: true, evaluate: true,
inline: true, inline: true,
passes: 2, passes: 2,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
sequences: true, sequences: true,
side_effects: true, side_effects: true,
@@ -340,6 +346,7 @@ issue_2084: {
issue_2097: { issue_2097: {
options = { options = {
negate_iife: true, negate_iife: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -508,3 +515,42 @@ issue_2114_2: {
} }
expect_stdout: "2" expect_stdout: "2"
} }
issue_2428: {
options = {
collapse_vars: true,
inline: true,
passes: 3,
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unsafe: true,
unused: true,
}
input: {
function bar(k) {
console.log(k);
}
function foo(x) {
return bar(x);
}
function baz(a) {
foo(a);
}
baz(42);
baz("PASS");
}
expect: {
function baz(a) {
console.log(a);
}
baz(42);
baz("PASS");
}
expect_stdout: [
"42",
"PASS",
]
}

View File

@@ -3,6 +3,7 @@ issue_2377_1: {
evaluate: true, evaluate: true,
inline: true, inline: true,
hoist_props: true, hoist_props: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -35,6 +36,7 @@ issue_2377_2: {
inline: true, inline: true,
hoist_props: true, hoist_props: true,
passes: 2, passes: 2,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -66,6 +68,7 @@ issue_2377_3: {
inline: true, inline: true,
hoist_props: true, hoist_props: true,
passes: 3, passes: 3,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -92,6 +95,7 @@ issue_2377_3: {
direct_access_1: { direct_access_1: {
options = { options = {
hoist_props: true, hoist_props: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -120,6 +124,7 @@ direct_access_1: {
direct_access_2: { direct_access_2: {
options = { options = {
hoist_props: true, hoist_props: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -143,6 +148,7 @@ direct_access_2: {
direct_access_3: { direct_access_3: {
options = { options = {
hoist_props: true, hoist_props: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -163,6 +169,7 @@ direct_access_3: {
single_use: { single_use: {
options = { options = {
hoist_props: true, hoist_props: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -187,6 +194,7 @@ single_use: {
name_collision_1: { name_collision_1: {
options = { options = {
hoist_props: true, hoist_props: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
} }
@@ -224,6 +232,7 @@ name_collision_1: {
name_collision_2: { name_collision_2: {
options = { options = {
hoist_props: true, hoist_props: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
} }
@@ -257,6 +266,7 @@ name_collision_2: {
name_collision_3: { name_collision_3: {
options = { options = {
hoist_props: true, hoist_props: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
} }
@@ -293,6 +303,7 @@ contains_this_1: {
hoist_props: true, hoist_props: true,
inline: true, inline: true,
passes: 2, passes: 2,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -318,6 +329,7 @@ contains_this_2: {
hoist_props: true, hoist_props: true,
inline: true, inline: true,
passes: 2, passes: 2,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -345,6 +357,7 @@ contains_this_3: {
hoist_props: true, hoist_props: true,
inline: true, inline: true,
passes: 2, passes: 2,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -369,3 +382,32 @@ contains_this_3: {
} }
expect_stdout: "1 1 true" expect_stdout: "1 1 true"
} }
new_this: {
options = {
evaluate: true,
hoist_props: true,
inline: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
a: 1,
b: 2,
f: function(a) {
this.b = a;
}
};
console.log(new o.f(o.a).b, o.b);
}
expect: {
console.log(new function(a) {
this.b = a;
}(1).b, 2);
}
expect_stdout: "1 2"
}

View File

@@ -1,6 +1,7 @@
const_pragma: { const_pragma: {
options = { options = {
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
}; };
@@ -16,6 +17,7 @@ const_pragma: {
not_const: { not_const: {
options = { options = {
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
}; };

View File

@@ -2,6 +2,7 @@ chained_evaluation_1: {
options = { options = {
collapse_vars: true, collapse_vars: true,
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@@ -28,6 +29,7 @@ chained_evaluation_2: {
options = { options = {
collapse_vars: true, collapse_vars: true,
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }

View File

@@ -15,6 +15,7 @@ f7: {
negate_iife: true, negate_iife: true,
passes: 3, passes: 3,
properties: true, properties: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
sequences: true, sequences: true,
side_effects: true, side_effects: true,

View File

@@ -1,5 +1,6 @@
side_effects_catch: { side_effects_catch: {
options = { options = {
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
unused: true, unused: true,
@@ -34,6 +35,7 @@ side_effects_catch: {
side_effects_else: { side_effects_else: {
options = { options = {
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
unused: true, unused: true,
@@ -62,6 +64,7 @@ side_effects_else: {
side_effects_finally: { side_effects_finally: {
options = { options = {
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
unused: true, unused: true,
@@ -98,6 +101,7 @@ side_effects_finally: {
side_effects_label: { side_effects_label: {
options = { options = {
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
unused: true, unused: true,
@@ -130,6 +134,7 @@ side_effects_label: {
side_effects_switch: { side_effects_switch: {
options = { options = {
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
unused: true, unused: true,

View File

@@ -2,6 +2,7 @@ unary_prefix: {
options = { options = {
evaluate: true, evaluate: true,
inline: true, inline: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }

View File

@@ -1,6 +1,7 @@
iife_for: { iife_for: {
options = { options = {
negate_iife: true, negate_iife: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -26,6 +27,7 @@ iife_for: {
iife_for_in: { iife_for_in: {
options = { options = {
negate_iife: true, negate_iife: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -51,6 +53,7 @@ iife_for_in: {
iife_do: { iife_do: {
options = { options = {
negate_iife: true, negate_iife: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -80,6 +83,7 @@ iife_do: {
iife_while: { iife_while: {
options = { options = {
negate_iife: true, negate_iife: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,

View File

@@ -3,6 +3,7 @@ collapse_vars_constants: {
collapse_vars: true, collapse_vars: true,
evaluate: true, evaluate: true,
inline: true, inline: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@@ -240,6 +241,7 @@ negate_iife_issue_1073: {
evaluate: true, evaluate: true,
inline: true, inline: true,
negate_iife: true, negate_iife: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
sequences: true, sequences: true,
unused: true, unused: true,
@@ -267,6 +269,7 @@ issue_1288_side_effects: {
evaluate: true, evaluate: true,
inline: true, inline: true,
negate_iife: true, negate_iife: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
unused: true, unused: true,
@@ -299,6 +302,7 @@ inner_var_for_in_1: {
options = { options = {
evaluate: true, evaluate: true,
inline: true, inline: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
} }
input: { input: {
@@ -330,6 +334,7 @@ issue_1595_3: {
evaluate: true, evaluate: true,
inline: true, inline: true,
passes: 2, passes: 2,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }

View File

@@ -51,6 +51,7 @@ this_binding_collapse_vars: {
options = { options = {
collapse_vars: true, collapse_vars: true,
toplevel: true, toplevel: true,
unused: true,
}; };
input: { input: {
var c = a; c(); var c = a; c();

View File

@@ -833,6 +833,7 @@ lhs_prop_2: {
evaluate: true, evaluate: true,
inline: true, inline: true,
properties: true, properties: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
unused: true, unused: true,
@@ -879,6 +880,7 @@ prop_side_effects_1: {
evaluate: true, evaluate: true,
inline: true, inline: true,
properties: true, properties: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
toplevel: true, toplevel: true,
@@ -915,6 +917,7 @@ prop_side_effects_2: {
inline: true, inline: true,
passes: 2, passes: 2,
properties: true, properties: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
toplevel: true, toplevel: true,
@@ -1006,3 +1009,22 @@ array_hole: {
} }
expect_stdout: "2 undefined 3" expect_stdout: "2 undefined 3"
} }
new_this: {
options = {
properties: true,
side_effects: true,
}
input: {
new {
f: function(a) {
this.a = a;
}
}.f(42);
}
expect: {
new function(a) {
this.a = a;
}(42);
}
}

View File

@@ -1,6 +1,7 @@
strict: { strict: {
options = { options = {
pure_getters: "strict", pure_getters: "strict",
reduce_funcs: false,
reduce_vars: false, reduce_vars: false,
side_effects: true, side_effects: true,
toplevel: true, toplevel: true,
@@ -30,6 +31,7 @@ strict: {
strict_reduce_vars: { strict_reduce_vars: {
options = { options = {
pure_getters: "strict", pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
toplevel: true, toplevel: true,
@@ -58,6 +60,7 @@ strict_reduce_vars: {
unsafe: { unsafe: {
options = { options = {
pure_getters: true, pure_getters: true,
reduce_funcs: false,
reduce_vars: false, reduce_vars: false,
side_effects: true, side_effects: true,
toplevel: true, toplevel: true,
@@ -84,6 +87,7 @@ unsafe: {
unsafe_reduce_vars: { unsafe_reduce_vars: {
options = { options = {
pure_getters: true, pure_getters: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
toplevel: true, toplevel: true,
@@ -185,6 +189,7 @@ issue_2110_1: {
pure_getters: "strict", pure_getters: "strict",
sequences: true, sequences: true,
side_effects: true, side_effects: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@@ -215,6 +220,7 @@ issue_2110_2: {
options = { options = {
collapse_vars: true, collapse_vars: true,
pure_getters: "strict", pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@@ -247,6 +253,7 @@ set_immutable_1: {
collapse_vars: true, collapse_vars: true,
evaluate: true, evaluate: true,
pure_getters: "strict", pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -270,6 +277,7 @@ set_immutable_2: {
cascade: true, cascade: true,
conditionals: true, conditionals: true,
pure_getters: "strict", pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
sequences: true, sequences: true,
side_effects: true, side_effects: true,
@@ -293,6 +301,7 @@ set_immutable_3: {
collapse_vars: true, collapse_vars: true,
evaluate: true, evaluate: true,
pure_getters: "strict", pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -318,6 +327,7 @@ set_immutable_4: {
cascade: true, cascade: true,
conditionals: true, conditionals: true,
pure_getters: "strict", pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
sequences: true, sequences: true,
side_effects: true, side_effects: true,
@@ -343,6 +353,7 @@ set_mutable_1: {
collapse_vars: true, collapse_vars: true,
evaluate: true, evaluate: true,
pure_getters: "strict", pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@@ -367,6 +378,7 @@ set_mutable_2: {
cascade: true, cascade: true,
conditionals: true, conditionals: true,
pure_getters: "strict", pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
sequences: true, sequences: true,
side_effects: true, side_effects: true,

File diff suppressed because it is too large Load Diff

View File

@@ -187,6 +187,7 @@ dont_screw_try_catch_undefined: {
reduce_vars: { reduce_vars: {
options = { options = {
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
ie8: true, ie8: true,
unused: true, unused: true,

View File

@@ -714,6 +714,7 @@ issue_1705_2: {
options = { options = {
dead_code: true, dead_code: true,
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
sequences: true, sequences: true,
side_effects: true, side_effects: true,

View File

@@ -297,4 +297,36 @@ describe("minify", function() {
assert.strictEqual(result.code, "alert({bar:42});"); assert.strictEqual(result.code, "alert({bar:42});");
}); });
}); });
describe("collapse_vars", function() {
it("Should not produce invalid AST", function() {
var code = [
"function f(a) {",
" a = x();",
" return a;",
"}",
"f();",
].join("\n");
var ast = Uglify.minify(code, {
compress: false,
mangle: false,
output: {
ast: true
},
}).ast;
assert.strictEqual(ast.TYPE, "Toplevel");
assert.strictEqual(ast.body.length, 2);
assert.strictEqual(ast.body[0].TYPE, "Defun");
assert.strictEqual(ast.body[0].body.length, 2);
assert.strictEqual(ast.body[0].body[0].TYPE, "SimpleStatement");
var stat = ast.body[0].body[0];
Uglify.minify(ast, {
compress: {
sequences: false
}
});
assert.ok(stat.body);
assert.strictEqual(stat.print_to_string(), "a=x()");
});
});
}); });

View File

@@ -162,6 +162,7 @@ var VALUES = [
'"object"', '"object"',
'"number"', '"number"',
'"function"', '"function"',
'this',
]; ];
var BINARY_OPS_NO_COMMA = [ var BINARY_OPS_NO_COMMA = [
@@ -349,10 +350,10 @@ function createParams() {
return params.join(', '); return params.join(', ');
} }
function createArgs() { function createArgs(recurmax, stmtDepth, canThrow) {
var args = []; var args = [];
for (var n = rng(4); --n >= 0;) { for (var n = rng(4); --n >= 0;) {
args.push(createValue()); args.push(rng(2) ? createValue() : createExpression(recurmax - 1, COMMA_OK, stmtDepth, canThrow));
} }
return args.join(', '); return args.join(', ');
} }
@@ -390,9 +391,10 @@ function createFunction(recurmax, inGlobal, noDecl, canThrow, stmtDepth) {
VAR_NAMES.length = namesLenBefore; VAR_NAMES.length = namesLenBefore;
if (noDecl) s = 'var ' + createVarName(MANDATORY) + ' = ' + s + '(' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ');'; if (noDecl) s = 'var ' + createVarName(MANDATORY) + ' = ' + s;
// avoid "function statements" (decl inside statements) // avoid "function statements" (decl inside statements)
else if (inGlobal || rng(10) > 0) s += 'var ' + createVarName(MANDATORY) + ' = ' + name + '(' + createArgs() + ');'; else if (inGlobal || rng(10) > 0) s += 'var ' + createVarName(MANDATORY) + ' = ' + name;
s += '(' + createArgs(recurmax, stmtDepth, canThrow) + ');';
return s; return s;
} }
@@ -626,6 +628,9 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
case p++: case p++:
case p++: case p++:
return createValue(); return createValue();
case p++:
case p++:
return getVarName();
case p++: case p++:
return createExpression(recurmax, COMMA_OK, stmtDepth, canThrow); return createExpression(recurmax, COMMA_OK, stmtDepth, canThrow);
case p++: case p++: