aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/compress.js106
-rw-r--r--test/compress/assignments.js (renamed from test/compress/assignment.js)54
-rw-r--r--test/compress/collapse_vars.js1
-rw-r--r--test/compress/drop-unused.js35
-rw-r--r--test/compress/evaluate.js18
-rw-r--r--test/compress/join_vars.js4
-rw-r--r--test/compress/keep_fargs.js1
-rw-r--r--test/compress/reduce_vars.js170
-rw-r--r--test/compress/side_effects.js3
9 files changed, 317 insertions, 75 deletions
diff --git a/lib/compress.js b/lib/compress.js
index f3fc5e0e..17b3ecf7 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -384,10 +384,10 @@ merge(Compressor.prototype, {
reset_def(tw, compressor, def);
if (def.fixed === null) {
def.safe_ids = tw.safe_ids;
- mark(tw, def, true);
+ mark(tw, def);
} else if (def.fixed) {
tw.loop_ids[def.id] = tw.in_loop;
- mark(tw, def, true);
+ mark(tw, def);
}
});
scope.may_call_this = function() {
@@ -446,8 +446,8 @@ merge(Compressor.prototype, {
tw.safe_ids = Object.getPrototypeOf(tw.safe_ids);
}
- function mark(tw, def, safe) {
- tw.safe_ids[def.id] = safe && {};
+ function mark(tw, def) {
+ tw.safe_ids[def.id] = {};
}
function push_ref(def, ref) {
@@ -459,10 +459,11 @@ merge(Compressor.prototype, {
if (def.single_use == "m") return false;
var safe = tw.safe_ids[def.id];
if (safe) {
- if (!HOP(tw.safe_ids, def.id)) safe.read = safe.read ? true : tw.safe_ids;
+ if (!HOP(tw.safe_ids, def.id)) safe.read = safe.read && safe.read !== tw.safe_ids ? true : tw.safe_ids;
if (def.fixed == null) {
if (is_arguments(def)) return false;
if (def.global && def.name == "arguments") return false;
+ tw.loop_ids[def.id] = null;
def.fixed = make_node(AST_Undefined, def.orig[0]);
return true;
}
@@ -478,20 +479,23 @@ merge(Compressor.prototype, {
delete def.safe_ids;
return true;
}
+ if (def.fixed === false) return false;
var safe = tw.safe_ids[def.id];
if (!HOP(tw.safe_ids, def.id)) {
if (!safe) return false;
- safe.assign = safe.assign ? true : tw.safe_ids;
+ if (safe.read && def.scope !== tw.find_parent(AST_Scope)) return false;
+ safe.assign = safe.assign && safe.assign !== tw.safe_ids ? true : tw.safe_ids;
}
- if (!safe_to_read(tw, def)) return false;
- if (def.fixed === false) return false;
- if (def.fixed != null && safe.read && safe.read !== tw.safe_ids) return false;
- return all(def.orig, function(sym) {
+ if (def.fixed != null && safe.read) {
+ if (safe.read !== tw.safe_ids) return false;
+ if (tw.loop_ids[def.id] !== tw.in_loop) return false;
+ }
+ return safe_to_read(tw, def) && all(def.orig, function(sym) {
return !(sym instanceof AST_SymbolLambda);
});
}
- function ref_once(tw, compressor, def) {
+ function ref_once(compressor, def) {
return compressor.option("unused")
&& !def.scope.pinned()
&& def.references.length - def.recursive_refs == 1;
@@ -568,22 +572,17 @@ merge(Compressor.prototype, {
}
var d = sym.definition();
d.assignments++;
+ var fixed = d.fixed;
var eq = node.operator == "=";
var value = eq ? node.right : node;
if (is_modified(compressor, tw, node, value, 0)) return;
- var safe = (eq || safe_to_read(tw, d)) && safe_to_assign(tw, d);
- var fixed = d.fixed;
- if (safe) {
+ node.right.walk(tw);
+ if ((eq || safe_to_read(tw, d)) && safe_to_assign(tw, d)) {
push_ref(d, sym);
- mark(tw, d, false);
- node.right.walk(tw);
- mark(tw, d, true);
- if (eq) mark_escaped(tw, d, sym.scope, node, value, 0, 1);
- } else {
- descend();
- }
- if (fixed !== false && d.fixed !== false) {
+ mark(tw, d);
if (eq) {
+ tw.loop_ids[d.id] = tw.in_loop;
+ mark_escaped(tw, d, sym.scope, node, value, 0, 1);
sym.fixed = d.fixed = function() {
return node.right;
};
@@ -600,6 +599,9 @@ merge(Compressor.prototype, {
}
sym.fixed.assigns = eq || !fixed.assigns ? [] : fixed.assigns.slice();
sym.fixed.assigns.push(node);
+ } else {
+ sym.walk(tw);
+ d.fixed = false;
}
return true;
});
@@ -739,7 +741,7 @@ merge(Compressor.prototype, {
var d = arg.definition();
if (d.fixed === undefined && (!fn.uses_arguments || tw.has_directive("use strict"))) {
tw.loop_ids[d.id] = tw.in_loop;
- mark(tw, d, true);
+ mark(tw, d);
var value = iife.args[i];
d.fixed = function() {
var j = fn.argnames.indexOf(arg);
@@ -800,7 +802,7 @@ merge(Compressor.prototype, {
var recursive = recursive_ref(tw, d);
if (recursive) {
d.recursive_refs++;
- } else if (value && ref_once(tw, compressor, d)) {
+ } else if (value && ref_once(compressor, d)) {
d.in_loop = tw.loop_ids[d.id] !== tw.in_loop;
d.single_use = value instanceof AST_Lambda
&& !value.pinned()
@@ -864,15 +866,10 @@ merge(Compressor.prototype, {
}
var d = exp.definition();
d.assignments++;
- var safe = safe_to_read(tw, d) && safe_to_assign(tw, d);
var fixed = d.fixed;
- if (safe) {
+ if (safe_to_read(tw, d) && safe_to_assign(tw, d)) {
push_ref(d, exp);
- mark(tw, d, true);
- } else {
- descend();
- }
- if (fixed !== false && d.fixed !== false) {
+ mark(tw, d);
if (fixed == null) fixed = make_node(AST_Undefined, d.orig[0]);
d.fixed = function() {
var value = fixed instanceof AST_Node ? fixed : fixed();
@@ -901,29 +898,28 @@ merge(Compressor.prototype, {
};
exp.fixed.assigns = fixed.assigns;
}
+ } else {
+ exp.walk(tw);
+ d.fixed = false;
}
return true;
});
def(AST_VarDef, function(tw, descend) {
var node = this;
+ if (!node.value) return;
+ descend();
var d = node.name.definition();
- if (node.value) {
- if (safe_to_assign(tw, d)) {
- tw.loop_ids[d.id] = tw.in_loop;
- mark(tw, d, false);
- descend();
- mark(tw, d, true);
- if (d.fixed !== false) {
- d.fixed = function() {
- return node.value;
- };
- d.fixed.assigns = [ node ];
- }
- return true;
- } else {
- d.fixed = false;
- }
+ if (safe_to_assign(tw, d)) {
+ mark(tw, d);
+ tw.loop_ids[d.id] = tw.in_loop;
+ d.fixed = function() {
+ return node.value;
+ };
+ d.fixed.assigns = [ node ];
+ } else {
+ d.fixed = false;
}
+ return true;
});
def(AST_While, function(tw, descend) {
var saved_loop = tw.in_loop;
@@ -4710,7 +4706,7 @@ merge(Compressor.prototype, {
}
}
}
- track_assigns(node_def, sym);
+ if (track_assigns(node_def, sym) && is_lhs(sym, node) !== sym) add_assigns(node_def, sym);
return true;
}
if (node instanceof AST_SymbolRef) {
@@ -7885,16 +7881,22 @@ merge(Compressor.prototype, {
&& self.right.left.name == self.left.name
&& ASSIGN_OPS[self.right.operator]) {
// x = x - 2 => x -= 2
- self.operator = self.right.operator + "=";
- self.right = self.right.right;
+ return make_node(AST_Assign, self, {
+ operator: self.right.operator + "=",
+ left: self.left,
+ right: self.right.right,
+ }).optimize(compressor);
}
else if (self.right.right instanceof AST_SymbolRef
&& self.right.right.name == self.left.name
&& ASSIGN_OPS_COMMUTATIVE[self.right.operator]
&& !self.right.left.has_side_effects(compressor)) {
// x = 2 & x => x &= 2
- self.operator = self.right.operator + "=";
- self.right = self.right.left;
+ return make_node(AST_Assign, self, {
+ operator: self.right.operator + "=",
+ left: self.left,
+ right: self.right.left,
+ }).optimize(compressor);
}
}
if ((self.operator == "-=" || self.operator == "+="
diff --git a/test/compress/assignment.js b/test/compress/assignments.js
index 2230272a..0f87f9a0 100644
--- a/test/compress/assignment.js
+++ b/test/compress/assignments.js
@@ -407,3 +407,57 @@ issue_3429_2: {
}
expect_stdout: "undefined"
}
+
+issue_3949_1: {
+ options = {
+ assignments: true,
+ evaluate: true,
+ reduce_vars: true,
+ }
+ input: {
+ var a = 42;
+ function f() {
+ var b = a;
+ b = b >> 2;
+ return 100 + b;
+ }
+ console.log(f());
+ }
+ expect: {
+ var a = 42;
+ function f() {
+ var b = a;
+ b >>= 2;
+ return 100 + b;
+ }
+ console.log(f());
+ }
+ expect_stdout: "110"
+}
+
+issue_3949_2: {
+ options = {
+ assignments: true,
+ evaluate: true,
+ reduce_vars: true,
+ }
+ input: {
+ var a = 42;
+ function f() {
+ var b = a;
+ b = 5 & b;
+ return 100 + b;
+ }
+ console.log(f());
+ }
+ expect: {
+ var a = 42;
+ function f() {
+ var b = a;
+ b &= 5;
+ return 100 + b;
+ }
+ console.log(f());
+ }
+ expect_stdout: "100"
+}
diff --git a/test/compress/collapse_vars.js b/test/compress/collapse_vars.js
index 546e0d3b..cea5ca84 100644
--- a/test/compress/collapse_vars.js
+++ b/test/compress/collapse_vars.js
@@ -3001,6 +3001,7 @@ issue_2298: {
expect: {
!function() {
(function() {
+ 0;
try {
!function(b) {
(void 0)[1] = "foo";
diff --git a/test/compress/drop-unused.js b/test/compress/drop-unused.js
index b21ca399..f3aeab21 100644
--- a/test/compress/drop-unused.js
+++ b/test/compress/drop-unused.js
@@ -2285,7 +2285,7 @@ issue_3598: {
try {
(function() {
a = "PASS";
- var c = (void (c.p = 0))[!1];
+ (void ((void 0).p = 0))[!1];
})();
} catch (e) {}
console.log(a);
@@ -2557,10 +2557,9 @@ issue_3899: {
console.log(typeof a);
}
expect: {
- 0;
- var a = function() {
+ function a() {
return 2;
- };
+ }
console.log(typeof a);
}
expect_stdout: "function"
@@ -2625,3 +2624,31 @@ assign_if_assign_read: {
}
expect_stdout: "PASS"
}
+
+issue_3951: {
+ options = {
+ pure_getters: "strict",
+ reduce_vars: true,
+ side_effects: true,
+ toplevel: true,
+ unused: true,
+ }
+ input: {
+ var a = console.log("PASS");
+ console.log(a);
+ a = "0";
+ console.log(a.p = 0);
+ a && a;
+ }
+ expect: {
+ var a = console.log("PASS");
+ console.log(a);
+ a = "0";
+ console.log(a.p = 0);
+ }
+ expect_stdout: [
+ "PASS",
+ "undefined",
+ "0",
+ ]
+}
diff --git a/test/compress/evaluate.js b/test/compress/evaluate.js
index 4e3bc725..fd8deab5 100644
--- a/test/compress/evaluate.js
+++ b/test/compress/evaluate.js
@@ -1579,9 +1579,9 @@ issue_2968_1: {
expect: {
var c = "FAIL";
(function() {
- b = -(a = 42),
- void ((a <<= 0) && (a[(c = "PASS", 0 >>> (b += 1))] = 0));
- var a, b;
+ a = 42,
+ void ((a <<= 0) && (a[(c = "PASS", 0)] = 0));
+ var a;
})();
console.log(c);
}
@@ -2341,10 +2341,7 @@ issue_3878_1: {
console.log(b ? "PASS" : "FAIL");
}
expect: {
- var b = function(a) {
- return (a = 0) == (a && this > (a += 0));
- }();
- console.log(b ? "PASS" : "FAIL");
+ console.log(true ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
}
@@ -2435,12 +2432,11 @@ issue_3903: {
console.log(d);
}
expect: {
- var a = "PASS";
function f(b, c) {
return console, c;
}
- var d = f(f(), a = a);
- console.log(d);
+ f(f(), "PASS");
+ console.log("PASS");
}
expect_stdout: "PASS"
}
@@ -2649,7 +2645,7 @@ issue_3933: {
}
expect: {
(function(a, b) {
- 1, (b ^= 1), console.log("PASS");
+ 1, 1, console.log("PASS");
})();
}
expect_stdout: "PASS"
diff --git a/test/compress/join_vars.js b/test/compress/join_vars.js
index 590f9970..9f0b35b7 100644
--- a/test/compress/join_vars.js
+++ b/test/compress/join_vars.js
@@ -808,9 +808,9 @@ issue_3795: {
}
expect: {
var a = "FAIL", d = function() {
- if (a = 42, d) return -1;
+ if (void 0) return -1;
a = "PASS";
- }();
+ }(a = 42);
console.log(a, d);
}
expect_stdout: "PASS undefined"
diff --git a/test/compress/keep_fargs.js b/test/compress/keep_fargs.js
index e1737081..e42b3978 100644
--- a/test/compress/keep_fargs.js
+++ b/test/compress/keep_fargs.js
@@ -306,6 +306,7 @@ issue_2298: {
expect: {
!function() {
(function() {
+ 0;
try {
!function() {
(void 0)[1] = "foo";
diff --git a/test/compress/reduce_vars.js b/test/compress/reduce_vars.js
index cb7599a9..3368cc6f 100644
--- a/test/compress/reduce_vars.js
+++ b/test/compress/reduce_vars.js
@@ -1520,8 +1520,7 @@ func_inline: {
}
expect: {
function f() {
- console.log(1 + h());
- var h;
+ console.log(1 + (void 0)());
}
}
}
@@ -2671,8 +2670,8 @@ var_assign_6: {
}
expect: {
!function() {
- var a = function(){}(a = 1);
- console.log(a);
+ (function(){}());
+ console.log(void 0);
}();
}
expect_stdout: "undefined"
@@ -7111,3 +7110,166 @@ issue_3922: {
}
expect_stdout: "PASS"
}
+
+issue_3949_1: {
+ options = {
+ evaluate: true,
+ reduce_vars: true,
+ }
+ input: {
+ (function f(a) {
+ var a = void (a = 0, g);
+ function g() {
+ console.log(typeof a);
+ }
+ g();
+ })();
+ }
+ expect: {
+ (function f(a) {
+ var a = void (a = 0, g);
+ function g() {
+ console.log(typeof a);
+ }
+ g();
+ })();
+ }
+ expect_stdout: "undefined"
+}
+
+issue_3949_2: {
+ options = {
+ reduce_vars: true,
+ unused: true,
+ }
+ input: {
+ (function f(a) {
+ var a = void (a = 0, g);
+ function g() {
+ console.log(typeof a);
+ }
+ g();
+ })();
+ }
+ expect: {
+ (function(a) {
+ a = void (a = 0, g);
+ function g() {
+ console.log(typeof a);
+ }
+ g();
+ })();
+ }
+ expect_stdout: "undefined"
+}
+
+issue_3949_3: {
+ options = {
+ evaluate: true,
+ reduce_vars: true,
+ toplevel: true,
+ }
+ input: {
+ function f() {}
+ for (var a, i = 3; 0 <= --i; ) {
+ a = f;
+ console.log(a === b);
+ var b = a;
+ }
+ }
+ expect: {
+ function f() {}
+ for (var a, i = 3; 0 <= --i; ) {
+ a = f;
+ console.log(a === b);
+ var b = a;
+ }
+ }
+ expect_stdout: [
+ "false",
+ "true",
+ "true",
+ ]
+}
+
+issue_3949_4: {
+ options = {
+ reduce_vars: true,
+ unused: true,
+ toplevel: true,
+ }
+ input: {
+ function f() {}
+ for (var a, i = 3; 0 <= --i; ) {
+ a = f;
+ console.log(a === b);
+ var b = a;
+ }
+ }
+ expect: {
+ function f() {}
+ for (var a, i = 3; 0 <= --i; ) {
+ a = f;
+ console.log(a === b);
+ var b = a;
+ }
+ }
+ expect_stdout: [
+ "false",
+ "true",
+ "true",
+ ]
+}
+
+local_assignment_lambda: {
+ options = {
+ evaluate: true,
+ reduce_vars: true,
+ sequences: true,
+ toplevel: true,
+ unused: true,
+ }
+ input: {
+ var a = "FAIL";
+ function f() {
+ a = "PASS";
+ console.log(a);
+ }
+ f();
+ f();
+ }
+ expect: {
+ function f() {
+ console.log("PASS");
+ }
+ f(),
+ f();
+ }
+ expect_stdout: [
+ "PASS",
+ "PASS",
+ ]
+}
+
+local_assignment_loop: {
+ options = {
+ evaluate: true,
+ reduce_vars: true,
+ sequences: true,
+ toplevel: true,
+ unused: true,
+ }
+ input: {
+ var a = "FAIL";
+ do {
+ a = "PASS";
+ console.log(a);
+ } while (!console);
+ }
+ expect: {
+ do {
+ console.log("PASS");
+ } while (!console);
+ }
+ expect_stdout: "PASS"
+}
diff --git a/test/compress/side_effects.js b/test/compress/side_effects.js
index 8c263d47..63282660 100644
--- a/test/compress/side_effects.js
+++ b/test/compress/side_effects.js
@@ -97,9 +97,8 @@ issue_2233_2: {
var RegExp;
UndeclaredGlobal;
function foo() {
- var Number;
AnotherUndeclaredGlobal;
- Number.isNaN;
+ (void 0).isNaN;
}
}
}