diff options
-rw-r--r-- | lib/compress.js | 43 | ||||
-rw-r--r-- | lib/scope.js | 1 | ||||
-rw-r--r-- | test/compress/drop-unused.js | 31 | ||||
-rw-r--r-- | test/compress/functions.js | 39 | ||||
-rw-r--r-- | test/compress/ie8.js | 105 |
5 files changed, 193 insertions, 26 deletions
diff --git a/lib/compress.js b/lib/compress.js index d60482f8..27ddd22f 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -1037,18 +1037,6 @@ merge(Compressor.prototype, { return false; } - function find_variable(compressor, name) { - var scope, i = 0; - while (scope = compressor.parent(i++)) { - if (scope instanceof AST_Scope) break; - if (scope instanceof AST_Catch) { - scope = scope.argname.definition().scope; - break; - } - } - return scope.find_variable(name); - } - function make_node(ctor, orig, props) { if (!props) props = {}; if (orig) { @@ -4177,13 +4165,7 @@ merge(Compressor.prototype, { var scopes = []; self.walk(new TreeWalker(function(node, descend) { if (!result) return true; - if (node instanceof AST_Catch) { - scopes.push(node.argname.scope); - descend(); - scopes.pop(); - return true; - } - if (node instanceof AST_Scope) { + if (node instanceof AST_BlockScope) { if (node === self) return; scopes.push(node); descend(); @@ -4191,14 +4173,14 @@ merge(Compressor.prototype, { return true; } if (node instanceof AST_SymbolRef) { - if (self.inlined) { + if (self.inlined || node.redef) { result = false; return true; } if (self.variables.has(node.name)) return true; var def = node.definition(); if (member(def.scope, scopes)) return true; - if (scope) { + if (scope && !def.redefined()) { var scope_def = scope.find_variable(node); if (def.undeclared ? !scope_def : scope_def === def) { result = "f"; @@ -5173,6 +5155,13 @@ merge(Compressor.prototype, { if (!(node_def.id in in_use_ids)) { in_use_ids[node_def.id] = true; in_use.push(node_def); + if (node.scope !== node_def.scope) { + var redef = node_def.redefined(); + if (redef && !(redef.id in in_use_ids)) { + in_use_ids[redef.id] = true; + in_use.push(redef); + } + } } if (track_assigns(node_def, node)) add_assigns(node_def, node); return true; @@ -6814,7 +6803,7 @@ merge(Compressor.prototype, { && !fn.pinned() && !(fn.name && fn instanceof AST_Function) && (exp === fn || !recursive_ref(compressor, def = exp.definition()) - && fn.is_constant_expression(compressor.find_parent(AST_Scope))) + && fn.is_constant_expression(compressor.find_parent(AST_BlockScope))) && (value = can_flatten_body(stat)) && !fn.contains_this()) { var replacing = exp === fn || compressor.option("unused") && def.references.length - def.replaced == 1; @@ -8081,7 +8070,9 @@ merge(Compressor.prototype, { single_use = false; } else if (fixed.name && fixed.name.definition() !== def) { single_use = false; - } else if (def.scope !== self.scope || def.orig[0] instanceof AST_SymbolFunarg) { + } else if (fixed.parent_scope !== self.scope + || !(self.scope instanceof AST_Scope) + || def.orig[0] instanceof AST_SymbolFunarg) { single_use = fixed.is_constant_expression(self.scope); if (single_use == "f") { var scope = self.scope; @@ -8229,7 +8220,7 @@ merge(Compressor.prototype, { OPT(AST_Undefined, function(self, compressor) { if (compressor.option("unsafe_undefined")) { - var undef = find_variable(compressor, "undefined"); + var undef = compressor.find_parent(AST_BlockScope).find_variable("undefined"); if (undef) { var ref = make_node(AST_SymbolRef, self, { name : "undefined", @@ -8255,7 +8246,7 @@ merge(Compressor.prototype, { if (lhs && is_atomic(lhs, self)) return self; if (compressor.option("keep_infinity") && !(lhs && !is_atomic(lhs, self)) - && !find_variable(compressor, "Infinity")) + && !compressor.find_parent(AST_BlockScope).find_variable("Infinity")) return self; return make_node(AST_Binary, self, { operator: "/", @@ -8271,7 +8262,7 @@ merge(Compressor.prototype, { OPT(AST_NaN, function(self, compressor) { var lhs = is_lhs(compressor.self(), compressor.parent()); if (lhs && !is_atomic(lhs, self) - || find_variable(compressor, "NaN")) { + || compressor.find_parent(AST_BlockScope).find_variable("NaN")) { return make_node(AST_Binary, self, { operator: "/", left: make_node(AST_Number, self, { diff --git a/lib/scope.js b/lib/scope.js index af888008..27acf20f 100644 --- a/lib/scope.js +++ b/lib/scope.js @@ -228,6 +228,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) { } old_def.defun = new_def.scope; old_def.orig.concat(old_def.references).forEach(function(node) { + node.redef = true; node.thedef = new_def; node.reference(options); }); diff --git a/test/compress/drop-unused.js b/test/compress/drop-unused.js index 0b76f6f6..160b96b4 100644 --- a/test/compress/drop-unused.js +++ b/test/compress/drop-unused.js @@ -2992,3 +2992,34 @@ issue_4146: { } expect_stdout: "function" } + +single_use_catch_redefined: { + options = { + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + var a = 1; + try { + throw 2; + } catch (a) { + function g() { + return a; + } + } + console.log(g()); + } + expect: { + var a = 1; + try { + throw 2; + } catch (a) { + function g() { + return a; + } + } + console.log(g()); + } + expect_stdout: true +} diff --git a/test/compress/functions.js b/test/compress/functions.js index 0cd07dda..13368169 100644 --- a/test/compress/functions.js +++ b/test/compress/functions.js @@ -4853,3 +4853,42 @@ direct_inline: { } expect_stdout: "21" } + +direct_inline_catch_redefined: { + options = { + inline: true, + reduce_vars: true, + toplevel: true, + } + input: { + var a = 1; + function f() { + return a; + } + try { + throw 2; + } catch (a) { + function g() { + return a; + } + console.log(a, f(), g()); + } + console.log(a, f(), g()); + } + expect: { + var a = 1; + function f() { + return a; + } + try { + throw 2; + } catch (a) { + function g() { + return a; + } + console.log(a, f(), g()); + } + console.log(a, a, g()); + } + expect_stdout: true +} diff --git a/test/compress/ie8.js b/test/compress/ie8.js index 6c0aa9e8..4d74d44e 100644 --- a/test/compress/ie8.js +++ b/test/compress/ie8.js @@ -2714,3 +2714,108 @@ issue_2737: { } expect_stdout: "function" } + +single_use_catch_redefined: { + options = { + ie8: true, + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + var a = 1; + try { + throw 2; + } catch (a) { + function g() { + return a; + } + } + console.log(g()); + } + expect: { + var a = 1; + try { + throw 2; + } catch (a) { + function g() { + return a; + } + } + console.log(g()); + } + expect_stdout: true +} + +single_use_inline_catch_redefined: { + options = { + ie8: true, + inline: true, + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + var a = 1; + try { + throw 2; + } catch (a) { + function g() { + return a; + } + } + console.log(g()); + } + expect: { + var a = 1; + try { + throw 2; + } catch (a) { + function g() { + return a; + } + } + console.log(g()); + } + expect_stdout: true +} + +direct_inline_catch_redefined: { + options = { + ie8: true, + inline: true, + reduce_vars: true, + toplevel: true, + } + input: { + var a = 1; + function f() { + return a; + } + try { + throw 2; + } catch (a) { + function g() { + return a; + } + console.log(a, f(), g()); + } + console.log(a, f(), g()); + } + expect: { + var a = 1; + function f() { + return a; + } + try { + throw 2; + } catch (a) { + function g() { + return a; + } + console.log(a, f(), g()); + } + console.log(a, a, g()); + } + expect_stdout: true +} |