aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/compress.js43
-rw-r--r--lib/scope.js1
-rw-r--r--test/compress/drop-unused.js31
-rw-r--r--test/compress/functions.js39
-rw-r--r--test/compress/ie8.js105
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
+}