aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Lam S.L <alexlamsl@gmail.com>2017-03-09 19:11:05 +0800
committerGitHub <noreply@github.com>2017-03-09 19:11:05 +0800
commitb633706ce42576b7e2aa85a96c5691bde87e71ac (patch)
tree524e6ab7980d86f0837c188cdb35fe8aa77b7487
parente9920f7ca162ce062cc481b876be293d7324a714 (diff)
downloadtracifyjs-b633706ce42576b7e2aa85a96c5691bde87e71ac.tar.gz
tracifyjs-b633706ce42576b7e2aa85a96c5691bde87e71ac.zip
fix & improve function argument compression (#1584)
- one-use function call => IIFE should take `eval()` & `arguments` into account - if unused parameter cannot be eliminated, replace it with `0` fixes #1583
-rw-r--r--lib/compress.js46
-rw-r--r--test/compress/drop-unused.js30
-rw-r--r--test/compress/reduce_vars.js108
3 files changed, 171 insertions, 13 deletions
diff --git a/lib/compress.js b/lib/compress.js
index f6b76ec2..3964636f 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -281,6 +281,9 @@ merge(Compressor.prototype, {
if (node instanceof AST_Function
&& (iife = tw.parent()) instanceof AST_Call
&& iife.expression === node) {
+ // Virtually turn IIFE parameters into variable definitions:
+ // (function(a,b) {...})(c,d) => (function() {var a=c,b=d; ...})()
+ // So existing transformation rules can work on them.
node.argnames.forEach(function(arg, i) {
var d = arg.definition();
d.fixed = iife.args[i] || make_node(AST_Undefined, iife);
@@ -1810,10 +1813,12 @@ merge(Compressor.prototype, {
node.name = null;
}
if (node instanceof AST_Lambda && !(node instanceof AST_Accessor)) {
- if (!compressor.option("keep_fargs")) {
- for (var a = node.argnames, i = a.length; --i >= 0;) {
- var sym = a[i];
- if (!(sym.definition().id in in_use_ids)) {
+ var trim = !compressor.option("keep_fargs");
+ for (var a = node.argnames, i = a.length; --i >= 0;) {
+ var sym = a[i];
+ if (!(sym.definition().id in in_use_ids)) {
+ sym.__unused = true;
+ if (trim) {
a.pop();
compressor.warn("Dropping unused function argument {name} [{file}:{line},{col}]", {
name : sym.name,
@@ -1822,7 +1827,9 @@ merge(Compressor.prototype, {
col : sym.start.col
});
}
- else break;
+ }
+ else {
+ trim = false;
}
}
}
@@ -2609,6 +2616,9 @@ merge(Compressor.prototype, {
exp = def.fixed;
if (compressor.option("unused")
&& def.references.length == 1
+ && !(def.scope.uses_arguments
+ && def.orig[0] instanceof AST_SymbolFunarg)
+ && !def.scope.uses_eval
&& compressor.find_parent(AST_Scope) === def.scope) {
self.expression = exp;
}
@@ -2617,16 +2627,26 @@ merge(Compressor.prototype, {
if (compressor.option("unused")
&& exp instanceof AST_Function
&& !exp.uses_arguments
- && !exp.uses_eval
- && self.args.length > exp.argnames.length) {
- var end = exp.argnames.length;
- for (var i = end, len = self.args.length; i < len; i++) {
- var node = self.args[i].drop_side_effect_free(compressor);
- if (node) {
- self.args[end++] = node;
+ && !exp.uses_eval) {
+ var pos = 0, last = 0;
+ for (var i = 0, len = self.args.length; i < len; i++) {
+ var trim = i >= exp.argnames.length;
+ if (trim || exp.argnames[i].__unused) {
+ var node = self.args[i].drop_side_effect_free(compressor);
+ if (node) {
+ self.args[pos++] = node;
+ } else if (!trim) {
+ self.args[pos++] = make_node(AST_Number, self.args[i], {
+ value: 0
+ });
+ continue;
+ }
+ } else {
+ self.args[pos++] = self.args[i];
}
+ last = pos;
}
- self.args.length = end;
+ self.args.length = last;
}
if (compressor.option("unsafe")) {
if (exp instanceof AST_SymbolRef && exp.undeclared()) {
diff --git a/test/compress/drop-unused.js b/test/compress/drop-unused.js
index 728557a6..9f3bf77d 100644
--- a/test/compress/drop-unused.js
+++ b/test/compress/drop-unused.js
@@ -761,3 +761,33 @@ assign_chain: {
}
}
}
+
+issue_1583: {
+ options = {
+ keep_fargs: true,
+ reduce_vars: true,
+ unused: true,
+ }
+ input: {
+ function m(t) {
+ (function(e) {
+ t = e();
+ })(function() {
+ return (function(a) {
+ return a;
+ })(function(a) {});
+ });
+ }
+ }
+ expect: {
+ function m(t) {
+ (function(e) {
+ t = (function() {
+ return (function(a) {
+ return a;
+ })(function(a) {});
+ })();
+ })();
+ }
+ }
+}
diff --git a/test/compress/reduce_vars.js b/test/compress/reduce_vars.js
index 10dc9d98..734ce4ed 100644
--- a/test/compress/reduce_vars.js
+++ b/test/compress/reduce_vars.js
@@ -1144,3 +1144,111 @@ double_reference: {
}
}
}
+
+iife_arguments_1: {
+ options = {
+ reduce_vars: true,
+ unused: true,
+ }
+ input: {
+ (function(x) {
+ console.log(x() === arguments[0]);
+ })(function f() {
+ return f;
+ });
+ }
+ expect: {
+ (function(x) {
+ console.log(x() === arguments[0]);
+ })(function f() {
+ return f;
+ });
+ }
+}
+
+iife_arguments_2: {
+ options = {
+ reduce_vars: true,
+ unused: true,
+ }
+ input: {
+ (function() {
+ var x = function f() {
+ return f;
+ };
+ console.log(x() === arguments[0]);
+ })();
+ }
+ expect: {
+ (function() {
+ console.log(function f() {
+ return f;
+ }() === arguments[0]);
+ })();
+ }
+}
+
+iife_eval_1: {
+ options = {
+ reduce_vars: true,
+ unused: true,
+ }
+ input: {
+ (function(x) {
+ console.log(x() === eval("x"));
+ })(function f() {
+ return f;
+ });
+ }
+ expect: {
+ (function(x) {
+ console.log(x() === eval("x"));
+ })(function f() {
+ return f;
+ });
+ }
+}
+
+iife_eval_2: {
+ options = {
+ reduce_vars: true,
+ unused: true,
+ }
+ input: {
+ (function() {
+ var x = function f() {
+ return f;
+ };
+ console.log(x() === eval("x"));
+ })();
+ }
+ expect: {
+ (function() {
+ var x = function f() {
+ return f;
+ };
+ console.log(x() === eval("x"));
+ })();
+ }
+}
+
+iife_func_side_effects: {
+ options = {
+ reduce_vars: true,
+ unused: true,
+ }
+ input: {
+ (function(a, b, c) {
+ return b();
+ })(x(), function() {
+ return y();
+ }, z());
+ }
+ expect: {
+ (function(a, b, c) {
+ return function() {
+ return y();
+ }();
+ })(x(), 0, z());
+ }
+}