aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/compress.js85
-rw-r--r--lib/utils.js4
-rw-r--r--test/compress/arguments.js134
-rw-r--r--test/compress/drop-unused.js28
4 files changed, 207 insertions, 44 deletions
diff --git a/lib/compress.js b/lib/compress.js
index 56c8fc47..0268e07f 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -518,14 +518,15 @@ merge(Compressor.prototype, {
var sym = node.left;
if (!(sym instanceof AST_SymbolRef)) return;
var d = sym.definition();
+ var safe = safe_to_assign(tw, d, sym.scope, node.right);
+ d.assignments++;
+ if (!safe) return;
var fixed = d.fixed;
if (!fixed && node.operator != "=") return;
- if (!safe_to_assign(tw, d, sym.scope, node.right)) return;
var eq = node.operator == "=";
var value = eq ? node.right : node;
if (is_modified(compressor, tw, node, value, 0)) return;
d.references.push(sym);
- d.assignments++;
if (!eq) d.chained = true;
d.fixed = eq ? function() {
return node.right;
@@ -657,7 +658,7 @@ merge(Compressor.prototype, {
// So existing transformation rules can work on them.
node.argnames.forEach(function(arg, i) {
var d = arg.definition();
- if (!node.uses_arguments && d.fixed === undefined) {
+ if (d.fixed === undefined && (!node.uses_arguments || tw.has_directive("use strict"))) {
d.fixed = function() {
return iife.args[i] || make_node(AST_Undefined, iife);
};
@@ -760,11 +761,12 @@ merge(Compressor.prototype, {
var exp = node.expression;
if (!(exp instanceof AST_SymbolRef)) return;
var d = exp.definition();
+ var safe = safe_to_assign(tw, d, exp.scope, true);
+ d.assignments++;
+ if (!safe) return;
var fixed = d.fixed;
if (!fixed) return;
- if (!safe_to_assign(tw, d, exp.scope, true)) return;
d.references.push(exp);
- d.assignments++;
d.chained = true;
d.fixed = function() {
return make_node(AST_Binary, node, {
@@ -3289,6 +3291,15 @@ merge(Compressor.prototype, {
// this scope (not in nested scopes).
var scope = this;
var tw = new TreeWalker(function(node, descend) {
+ if (node instanceof AST_Lambda && node.uses_arguments && !tw.has_directive("use strict")) {
+ node.argnames.forEach(function(argname) {
+ var def = argname.definition();
+ if (!(def.id in in_use_ids)) {
+ in_use_ids[def.id] = true;
+ in_use.push(def);
+ }
+ });
+ }
if (node === self) return;
if (node instanceof AST_Defun) {
var node_def = node.name.definition();
@@ -3376,8 +3387,7 @@ merge(Compressor.prototype, {
// any declarations with same name will overshadow
// name of this anonymous function and can therefore
// never be used anywhere
- if (!(def.id in in_use_ids) || def.orig.length > 1)
- node.name = null;
+ if (!(def.id in in_use_ids) || def.orig.length > 1) node.name = null;
}
if (node instanceof AST_Lambda && !(node instanceof AST_Accessor)) {
var trim = !compressor.option("keep_fargs");
@@ -3389,8 +3399,7 @@ merge(Compressor.prototype, {
a.pop();
compressor[sym.unreferenced() ? "warn" : "info"]("Dropping unused function argument {name} [{file}:{line},{col}]", template(sym));
}
- }
- else {
+ } else {
trim = false;
}
}
@@ -6208,6 +6217,39 @@ merge(Compressor.prototype, {
}
}
}
+ var fn;
+ if (compressor.option("arguments")
+ && expr instanceof AST_SymbolRef
+ && expr.name == "arguments"
+ && expr.definition().orig.length == 1
+ && (fn = expr.scope) instanceof AST_Lambda
+ && prop instanceof AST_Number) {
+ var index = prop.getValue();
+ var argname = fn.argnames[index];
+ if (argname && compressor.has_directive("use strict")) {
+ var def = argname.definition();
+ if (!compressor.option("reduce_vars") || def.assignments || def.orig.length > 1) {
+ argname = null;
+ }
+ } else if (!argname && !compressor.option("keep_fargs") && index < fn.argnames.length + 5) {
+ while (index >= fn.argnames.length) {
+ argname = make_node(AST_SymbolFunarg, fn, {
+ name: fn.make_var_name("argument_" + fn.argnames.length),
+ scope: fn
+ });
+ fn.argnames.push(argname);
+ fn.enclosed.push(fn.def_variable(argname));
+ }
+ }
+ if (argname && find_if(function(node) {
+ return node.name === argname.name;
+ }, fn.argnames) === argname) {
+ var sym = make_node(AST_SymbolRef, self, argname);
+ sym.reference({});
+ delete argname.__unused;
+ return sym;
+ }
+ }
if (is_lhs(self, compressor.parent())) return self;
if (key !== prop) {
var sub = self.flatten_object(property, compressor);
@@ -6251,31 +6293,6 @@ merge(Compressor.prototype, {
});
}
}
- var fn;
- if (compressor.option("arguments")
- && expr instanceof AST_SymbolRef
- && expr.name == "arguments"
- && expr.definition().orig.length == 1
- && (fn = expr.scope) instanceof AST_Lambda
- && prop instanceof AST_Number) {
- var index = prop.getValue();
- var argname = fn.argnames[index];
- if (!argname && !compressor.option("keep_fargs")) {
- while (index >= fn.argnames.length) {
- argname = make_node(AST_SymbolFunarg, fn, {
- name: fn.make_var_name("argument_" + fn.argnames.length),
- scope: fn
- });
- fn.argnames.push(argname);
- fn.enclosed.push(fn.def_variable(argname));
- }
- }
- if (argname) {
- var sym = make_node(AST_SymbolRef, self, argname);
- sym.reference({});
- return sym;
- }
- }
var ev = self.evaluate(compressor);
if (ev !== self) {
ev = make_node_from_constant(ev, self).optimize(compressor);
diff --git a/lib/utils.js b/lib/utils.js
index ca4b2d4b..7a51fb80 100644
--- a/lib/utils.js
+++ b/lib/utils.js
@@ -52,9 +52,7 @@ function member(name, array) {
}
function find_if(func, array) {
- for (var i = 0, n = array.length; i < n; ++i) {
- if (func(array[i])) return array[i];
- }
+ for (var i = array.length; --i >= 0;) if (func(array[i])) return array[i];
}
function repeat_string(str, i) {
diff --git a/test/compress/arguments.js b/test/compress/arguments.js
index e8cc690f..04857441 100644
--- a/test/compress/arguments.js
+++ b/test/compress/arguments.js
@@ -5,7 +5,8 @@ replace_index: {
properties: true,
}
input: {
- console.log(arguments && arguments[0]);
+ var arguments = [];
+ console.log(arguments[0]);
(function() {
console.log(arguments[1], arguments["1"], arguments["foo"]);
})("bar", 42);
@@ -21,7 +22,8 @@ replace_index: {
})("bar", 42);
}
expect: {
- console.log(arguments && arguments[0]);
+ var arguments = [];
+ console.log(arguments[0]);
(function() {
console.log(arguments[1], arguments[1], arguments.foo);
})("bar", 42);
@@ -45,6 +47,37 @@ replace_index: {
]
}
+replace_index_strict: {
+ options = {
+ arguments: true,
+ evaluate: true,
+ properties: true,
+ reduce_vars: true,
+ }
+ input: {
+ "use strict";
+ (function() {
+ console.log(arguments[1], arguments["1"], arguments["foo"]);
+ })("bar", 42);
+ (function(a, b) {
+ console.log(arguments[1], arguments["1"], arguments["foo"]);
+ })("bar", 42);
+ }
+ expect: {
+ "use strict";
+ (function() {
+ console.log(arguments[1], arguments[1], arguments.foo);
+ })("bar", 42);
+ (function(a, b) {
+ console.log(b, b, arguments.foo);
+ })("bar", 42);
+ }
+ expect_stdout: [
+ "42 42 undefined",
+ "42 42 undefined",
+ ]
+}
+
replace_index_keep_fargs: {
options = {
arguments: true,
@@ -53,7 +86,8 @@ replace_index_keep_fargs: {
properties: true,
}
input: {
- console.log(arguments && arguments[0]);
+ var arguments = [];
+ console.log(arguments[0]);
(function() {
console.log(arguments[1], arguments["1"], arguments["foo"]);
})("bar", 42);
@@ -69,7 +103,8 @@ replace_index_keep_fargs: {
})("bar", 42);
}
expect: {
- console.log(arguments && arguments[0]);
+ var arguments = [];
+ console.log(arguments[0]);
(function(argument_0, argument_1) {
console.log(argument_1, argument_1, arguments.foo);
})("bar", 42);
@@ -93,6 +128,38 @@ replace_index_keep_fargs: {
]
}
+replace_index_keep_fargs_strict: {
+ options = {
+ arguments: true,
+ evaluate: true,
+ keep_fargs: false,
+ properties: true,
+ reduce_vars: true,
+ }
+ input: {
+ "use strict";
+ (function() {
+ console.log(arguments[1], arguments["1"], arguments["foo"]);
+ })("bar", 42);
+ (function(a, b) {
+ console.log(arguments[1], arguments["1"], arguments["foo"]);
+ })("bar", 42);
+ }
+ expect: {
+ "use strict";
+ (function(argument_0, argument_1) {
+ console.log(argument_1, argument_1, arguments.foo);
+ })("bar", 42);
+ (function(a, b) {
+ console.log(b, b, arguments.foo);
+ })("bar", 42);
+ }
+ expect_stdout: [
+ "42 42 undefined",
+ "42 42 undefined",
+ ]
+}
+
modified: {
options = {
arguments: true,
@@ -101,8 +168,10 @@ modified: {
(function(a, b) {
var c = arguments[0];
var d = arguments[1];
- a = "foo";
+ var a = "foo";
b++;
+ arguments[0] = "moo";
+ arguments[1] *= 2;
console.log(a, b, c, d, arguments[0], arguments[1]);
})("bar", 42);
}
@@ -110,10 +179,61 @@ modified: {
(function(a, b) {
var c = a;
var d = b;
- a = "foo";
+ var a = "foo";
b++;
+ a = "moo";
+ b *= 2;
console.log(a, b, c, d, a, b);
})("bar", 42);
}
- expect_stdout: "foo 43 bar 42 foo 43"
+ expect_stdout: "moo 86 bar 42 moo 86"
+}
+
+modified_strict: {
+ options = {
+ arguments: true,
+ reduce_vars: true,
+ }
+ input: {
+ "use strict";
+ (function(a, b) {
+ var c = arguments[0];
+ var d = arguments[1];
+ var a = "foo";
+ b++;
+ arguments[0] = "moo";
+ arguments[1] *= 2;
+ console.log(a, b, c, d, arguments[0], arguments[1]);
+ })("bar", 42);
+ }
+ expect: {
+ "use strict";
+ (function(a, b) {
+ var c = arguments[0];
+ var d = arguments[1];
+ var a = "foo";
+ b++;
+ arguments[0] = "moo";
+ arguments[1] *= 2;
+ console.log(a, b, c, d, arguments[0], arguments[1]);
+ })("bar", 42);
+ }
+ expect_stdout: "foo 43 bar 42 moo 84"
+}
+
+duplicate_argname: {
+ options = {
+ arguments: true,
+ }
+ input: {
+ (function(a, b, a) {
+ console.log(a, b, arguments[0], arguments[1], arguments[2]);
+ })("foo", 42, "bar");
+ }
+ expect: {
+ (function(a, b, a) {
+ console.log(a, b, arguments[0], b, a);
+ })("foo", 42, "bar");
+ }
+ expect_stdout: "bar 42 foo 42 bar"
}
diff --git a/test/compress/drop-unused.js b/test/compress/drop-unused.js
index 59990b58..e4daa4fc 100644
--- a/test/compress/drop-unused.js
+++ b/test/compress/drop-unused.js
@@ -1926,3 +1926,31 @@ issue_3146_4: {
}
expect_stdout: "PASS"
}
+
+issue_3192: {
+ options = {
+ unused: true,
+ }
+ input: {
+ (function(a) {
+ console.log(a = "foo", arguments[0]);
+ })("bar");
+ (function(a) {
+ "use strict";
+ console.log(a = "foo", arguments[0]);
+ })("bar");
+ }
+ expect: {
+ (function(a) {
+ console.log(a = "foo", arguments[0]);
+ })("bar");
+ (function(a) {
+ "use strict";
+ console.log("foo", arguments[0]);
+ })("bar");
+ }
+ expect_stdout: [
+ "foo foo",
+ "foo bar",
+ ]
+}