From: Alex Lam S.L Date: Thu, 30 Apr 2020 20:33:46 +0000 (+0100) Subject: enhance `inline` (#3832) X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=f80d5b8c9ec0de7b3e7f99981da9f2d39ece66c4;p=UglifyJS.git enhance `inline` (#3832) --- diff --git a/lib/compress.js b/lib/compress.js index c679a8b2..15db2332 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -225,7 +225,7 @@ merge(Compressor.prototype, { // output and performance. descend(node, this); var opt = node.optimize(this); - if (is_scope) { + if (is_scope && opt === node) { opt.drop_unused(this); descend(opt, this); } @@ -3981,6 +3981,38 @@ merge(Compressor.prototype, { return self; }); + OPT(AST_Function, function(self, compressor) { + self.body = tighten_body(self.body, compressor); + if (compressor.option("inline")) for (var i = 0; i < self.body.length; i++) { + var stat = self.body[i]; + if (stat instanceof AST_Directive) continue; + if (stat instanceof AST_Return) { + var call = stat.value; + if (!call || call.TYPE != "Call") break; + var fn = call.expression; + if (fn instanceof AST_SymbolRef) { + fn = fn.fixed_value(); + } + if (!(fn instanceof AST_Lambda)) break; + if (fn.uses_arguments) break; + if (fn.contains_this()) break; + var j = fn.argnames.length; + if (j > 0 && compressor.option("inline") < 2) break; + if (j > self.argnames.length) break; + if (j < self.argnames.length && !compressor.drop_fargs(fn, call)) break; + while (--j >= 0) { + var arg = call.args[j]; + if (!(arg instanceof AST_SymbolRef)) break; + if (arg.definition() !== self.argnames[j].definition()) break; + } + if (j >= 0) break; + return call.expression; + } + break; + } + return self; + }); + AST_Scope.DEFMETHOD("drop_unused", function(compressor) { if (!compressor.option("unused")) return; if (compressor.has_directive("use asm")) return; @@ -6133,7 +6165,7 @@ merge(Compressor.prototype, { function can_substitute_directly() { if (var_assigned) return; - if (compressor.option("inline") <= 1 && fn.argnames.length) return; + if (compressor.option("inline") < 2 && fn.argnames.length) return; if (!fn.variables.all(function(def) { return def.references.length < 2 && def.orig[0] instanceof AST_SymbolFunarg; })) return; diff --git a/test/compress/functions.js b/test/compress/functions.js index b088ca87..262bb6ac 100644 --- a/test/compress/functions.js +++ b/test/compress/functions.js @@ -2877,7 +2877,7 @@ issue_2437: { } } -issue_2485: { +issue_2485_1: { options = { functions: true, reduce_funcs: true, @@ -2926,6 +2926,54 @@ issue_2485: { expect_stdout: "6" } +issue_2485_2: { + options = { + functions: true, + inline: true, + reduce_funcs: true, + reduce_vars: true, + unused: true, + } + input: { + var foo = function(bar) { + var n = function(a, b) { + return a + b; + }; + var sumAll = function(arg) { + return arg.reduce(n, 0); + }; + var runSumAll = function(arg) { + return sumAll(arg); + }; + bar.baz = function(arg) { + var n = runSumAll(arg); + return (n.get = 1), n; + }; + return bar; + }; + var bar = foo({}); + console.log(bar.baz([1, 2, 3])); + } + expect: { + var foo = function(bar) { + function n(a, b) { + return a + b; + } + function runSumAll(arg) { + return arg.reduce(n, 0); + } + bar.baz = function(arg) { + var n = runSumAll(arg); + return (n.get = 1), n; + }; + return bar; + }; + var bar = foo({}); + console.log(bar.baz([1, 2, 3])); + } + expect_stdout: "6" +} + issue_3364: { options = { functions: true, @@ -3113,9 +3161,7 @@ issue_3400_1: { return console.log(o[g]), o; } function e() { - return [ 42 ].map(function(v) { - return h(v); - }); + return [ 42 ].map(h); } return e(); }()[0].p); @@ -3130,7 +3176,7 @@ issue_3400_2: { options = { collapse_vars: true, inline: true, - passes: 2, + passes: 3, reduce_funcs: true, reduce_vars: true, unused: true, @@ -3158,11 +3204,11 @@ issue_3400_2: { } expect: { void console.log(function g() { - return [ 42 ].map(function(v) { - return o = { - p: v - }, console.log(o[g]), o; - var o; + return [ 42 ].map(function(u) { + var o = { + p: u + }; + return console.log(o[g]), o; }); }()[0].p); } @@ -3568,8 +3614,8 @@ pr_3592_2: { var g = [ "PASS" ]; console.log((z = "PASS", function(problem) { return g[problem]; - }((y = z, problem(y))))); - var z, y; + }(problem(z)))); + var z; } expect_stdout: "PASS" } @@ -3635,9 +3681,7 @@ pr_3595_1: { } console.log((arg = "PASS", function(problem) { return g[problem]; - }(function(arg) { - return problem(arg); - }(arg)))); + }(problem(arg)))); var arg; } expect_stdout: "PASS" @@ -3678,9 +3722,7 @@ pr_3595_2: { } console.log(function(problem) { return g[problem]; - }(function(arg) { - return problem(arg); - }("PASS"))); + }(problem("PASS"))); } expect_stdout: "PASS" } @@ -4108,3 +4150,443 @@ issue_3821_2: { } expect_stdout: "PASS" } + +substitude: { + options = { + inline: true, + reduce_vars: true, + toplevel: true, + } + input: { + var o = {}; + function f(a) { + return a === o ? "PASS" : "FAIL"; + } + [ + function() { + return f; + }, + function() { + return function(b) { + return f(b); + }; + }, + function() { + "use strict"; + return function(c) { + return f(c); + }; + }, + function() { + return function(c) { + "use strict"; + return f(c); + }; + }, + function() { + return function(d, e) { + return f(d, e); + }; + }, + ].forEach(function(g) { + console.log(g()(o)); + console.log(g().call(o, o)); + }); + } + expect: { + var o = {}; + function f(a) { + return a === o ? "PASS" : "FAIL"; + } + [ + function() { + return f; + }, + function() { + return f; + }, + function() { + "use strict"; + return f; + }, + function() { + return f; + }, + function() { + return function(d, e) { + return f(d, e); + }; + }, + ].forEach(function(g) { + console.log(g()(o)); + console.log(g().call(o, o)); + }); + } + expect_stdout: [ + "PASS", + "PASS", + "PASS", + "PASS", + "PASS", + "PASS", + "PASS", + "PASS", + "PASS", + "PASS", + ] +} + +substitude_arguments: { + options = { + inline: true, + reduce_vars: true, + toplevel: true, + } + input: { + var o = {}; + function f() { + return arguments[0] === o ? "PASS" : "FAIL"; + } + [ + function() { + return f; + }, + function() { + return function(b) { + return f(b); + }; + }, + function() { + "use strict"; + return function(c) { + return f(c); + }; + }, + function() { + return function(c) { + "use strict"; + return f(c); + }; + }, + function() { + return function(d, e) { + return f(d, e); + }; + }, + ].forEach(function(g) { + console.log(g()(o)); + console.log(g().call(o, o)); + }); + } + expect: { + var o = {}; + function f() { + return arguments[0] === o ? "PASS" : "FAIL"; + } + [ + function() { + return f; + }, + function() { + return function(b) { + return f(b); + }; + }, + function() { + "use strict"; + return function(c) { + return f(c); + }; + }, + function() { + return function(c) { + "use strict"; + return f(c); + }; + }, + function() { + return function(d, e) { + return f(d, e); + }; + }, + ].forEach(function(g) { + console.log(g()(o)); + console.log(g().call(o, o)); + }); + } + expect_stdout: [ + "PASS", + "PASS", + "PASS", + "PASS", + "PASS", + "PASS", + "PASS", + "PASS", + "PASS", + "PASS", + ] +} + +substitude_drop_fargs: { + options = { + inline: true, + keep_fargs: false, + reduce_vars: true, + toplevel: true, + } + input: { + var o = {}; + function f(a) { + return a === o ? "PASS" : "FAIL"; + } + [ + function() { + return f; + }, + function() { + return function(b) { + return f(b); + }; + }, + function() { + "use strict"; + return function(c) { + return f(c); + }; + }, + function() { + return function(c) { + "use strict"; + return f(c); + }; + }, + function() { + return function(d, e) { + return f(d, e); + }; + }, + ].forEach(function(g) { + console.log(g()(o)); + console.log(g().call(o, o)); + }); + } + expect: { + var o = {}; + function f(a) { + return a === o ? "PASS" : "FAIL"; + } + [ + function() { + return f; + }, + function() { + return f; + }, + function() { + "use strict"; + return f; + }, + function() { + return f; + }, + function() { + return f; + }, + ].forEach(function(g) { + console.log(g()(o)); + console.log(g().call(o, o)); + }); + } + expect_stdout: [ + "PASS", + "PASS", + "PASS", + "PASS", + "PASS", + "PASS", + "PASS", + "PASS", + "PASS", + "PASS", + ] +} + +substitude_this: { + options = { + inline: true, + reduce_vars: true, + toplevel: true, + } + input: { + var o = {}; + function f(a) { + return a === o ? this === o : "FAIL"; + } + [ + function() { + return f; + }, + function() { + return function(b) { + return f(b); + }; + }, + function() { + "use strict"; + return function(c) { + return f(c); + }; + }, + function() { + return function(c) { + "use strict"; + return f(c); + }; + }, + function() { + return function(d, e) { + return f(d, e); + }; + }, + ].forEach(function(g) { + console.log(g()(o)); + console.log(g().call(o, o)); + }); + } + expect: { + var o = {}; + function f(a) { + return a === o ? this === o : "FAIL"; + } + [ + function() { + return f; + }, + function() { + return function(b) { + return f(b); + }; + }, + function() { + "use strict"; + return function(c) { + return f(c); + }; + }, + function() { + return function(c) { + "use strict"; + return f(c); + }; + }, + function() { + return function(d, e) { + return f(d, e); + }; + }, + ].forEach(function(g) { + console.log(g()(o)); + console.log(g().call(o, o)); + }); + } + expect_stdout: [ + "false", + "true", + "false", + "false", + "false", + "false", + "false", + "false", + "false", + "false", + ] +} + +substitude_use_strict: { + options = { + inline: true, + reduce_vars: true, + toplevel: true, + } + input: { + var o = {}; + function f(a) { + "use strict"; + return a === o ? "PASS" : "FAIL"; + } + [ + function() { + return f; + }, + function() { + return function(b) { + return f(b); + }; + }, + function() { + "use strict"; + return function(c) { + return f(c); + }; + }, + function() { + return function(c) { + "use strict"; + return f(c); + }; + }, + function() { + return function(d, e) { + return f(d, e); + }; + }, + ].forEach(function(g) { + console.log(g()(o)); + console.log(g().call(o, o)); + }); + } + expect: { + var o = {}; + function f(a) { + "use strict"; + return a === o ? "PASS" : "FAIL"; + } + [ + function() { + return f; + }, + function() { + return f; + }, + function() { + "use strict"; + return f; + }, + function() { + return f; + }, + function() { + return function(d, e) { + return f(d, e); + }; + }, + ].forEach(function(g) { + console.log(g()(o)); + console.log(g().call(o, o)); + }); + } + expect_stdout: [ + "PASS", + "PASS", + "PASS", + "PASS", + "PASS", + "PASS", + "PASS", + "PASS", + "PASS", + "PASS", + ] +} diff --git a/test/compress/reduce_vars.js b/test/compress/reduce_vars.js index 25108cae..8cc301cc 100644 --- a/test/compress/reduce_vars.js +++ b/test/compress/reduce_vars.js @@ -4589,7 +4589,7 @@ perf_8: { expect_stdout: "348150" } -issue_2485: { +issue_2485_1: { options = { reduce_funcs: true, reduce_vars: true, @@ -4637,6 +4637,53 @@ issue_2485: { expect_stdout: "6" } +issue_2485_2: { + options = { + inline: true, + reduce_funcs: true, + reduce_vars: true, + unused: true, + } + input: { + var foo = function(bar) { + var n = function(a, b) { + return a + b; + }; + var sumAll = function(arg) { + return arg.reduce(n, 0); + }; + var runSumAll = function(arg) { + return sumAll(arg); + }; + bar.baz = function(arg) { + var n = runSumAll(arg); + return (n.get = 1), n; + }; + return bar; + }; + var bar = foo({}); + console.log(bar.baz([1, 2, 3])); + } + expect: { + var foo = function(bar) { + var n = function(a, b) { + return a + b; + }; + var runSumAll = function(arg) { + return arg.reduce(n, 0); + }; + bar.baz = function(arg) { + var n = runSumAll(arg); + return (n.get = 1), n; + }; + return bar; + }; + var bar = foo({}); + console.log(bar.baz([1, 2, 3])); + } + expect_stdout: "6" +} + issue_2455: { options = { reduce_vars: true,