From 1b07f640573494d1f8625f8926868caeaeaaaa9e Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Sun, 5 Apr 2020 03:42:23 +0100 Subject: [PATCH] enhance `inline` (#3760) --- lib/compress.js | 27 +++++++- test/compress/functions.js | 130 ++++++++++++++++++++++++++++++++++--- test/input/rename/input.js | 2 +- test/mocha/cli.js | 8 +-- test/ufuzz/index.js | 1 + 5 files changed, 151 insertions(+), 17 deletions(-) diff --git a/lib/compress.js b/lib/compress.js index 72690fef..f03e0eef 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -5813,12 +5813,24 @@ merge(Compressor.prototype, { var is_func = fn instanceof AST_Lambda; var stat = is_func && fn.first_statement(); var can_inline = compressor.option("inline") && !self.is_expr_pure(compressor); - if (exp === fn && can_inline && stat instanceof AST_Return) { + if (can_inline && stat instanceof AST_Return) { var value = stat.value; - if (!value || value.is_constant_expression()) { + if (exp === fn && (!value || value.is_constant_expression())) { var args = self.args.concat(value || make_node(AST_Undefined, self)); return make_sequence(self, args).optimize(compressor); } + var funarg, pos; + if (value instanceof AST_SymbolRef + && (funarg = resolve_funarg(value.definition().orig)) + && (pos = fn.argnames.indexOf(funarg)) >= 0 + && (pos >= self.args.length - 1 || all(self.args.slice(pos), function(funarg) { + return !funarg.has_side_effects(compressor); + }))) { + var args = self.args.slice(); + args.push(args.splice(pos, 1)[0] || make_node(AST_Undefined, self)); + var node = make_sequence(self, args).optimize(compressor); + return maintain_this_binding(compressor, compressor.parent(), compressor.self(), node); + } } if (is_func) { var def, value, scope, in_loop, level = -1; @@ -5837,7 +5849,8 @@ merge(Compressor.prototype, { && can_inject_symbols()) { fn._squeezed = true; if (exp !== fn) fn.parent_scope = exp.scope; - return make_sequence(self, flatten_fn()).optimize(compressor); + var node = make_sequence(self, flatten_fn()).optimize(compressor); + return maintain_this_binding(compressor, compressor.parent(), compressor.self(), node); } if (compressor.option("side_effects") && all(fn.body, is_empty) @@ -5864,6 +5877,14 @@ merge(Compressor.prototype, { } return try_evaluate(compressor, self); + function resolve_funarg(orig) { + var funarg; + for (var i = 0; orig[i] instanceof AST_SymbolFunarg; i++) { + funarg = orig[i]; + } + return funarg; + } + function return_value(stat) { if (!stat) return make_node(AST_Undefined, self); if (stat instanceof AST_Return) { diff --git a/test/compress/functions.js b/test/compress/functions.js index 0cf01792..b1a44ffa 100644 --- a/test/compress/functions.js +++ b/test/compress/functions.js @@ -342,11 +342,7 @@ inner_ref: { }(2)); } expect: { - console.log(function(a) { - return a; - }(1), function(a) { - return a; - }()); + console.log(1, void 0); } expect_stdout: "1 undefined" } @@ -1577,7 +1573,23 @@ issue_2663_3: { ] } -duplicate_argnames: { +duplicate_argnames_1: { + options = { + inline: true, + side_effects: true, + } + input: { + console.log(function(a, a, a) { + return a; + }("FAIL", 42, "PASS")); + } + expect: { + console.log("PASS"); + } + expect_stdout: "PASS" +} + +duplicate_argnames_2: { options = { inline: true, reduce_vars: true, @@ -1857,10 +1869,9 @@ use_before_init_in_loop: { expect_stdout: "PASS" } -duplicate_arg_var: { +duplicate_arg_var_1: { options = { inline: true, - toplevel: true, } input: { console.log(function(b) { @@ -1869,7 +1880,24 @@ duplicate_arg_var: { }("PASS")); } expect: { - console.log((b = "PASS", b)); + console.log("PASS"); + } + expect_stdout: "PASS" +} + +duplicate_arg_var_2: { + options = { + inline: true, + toplevel: true, + } + input: { + console.log(function(b) { + return b + "SS"; + var b; + }("PA")); + } + expect: { + console.log((b = "PA", b + "SS")); var b; } expect_stdout: "PASS" @@ -3785,3 +3813,87 @@ issue_3679_3: { } expect_stdout: "PASS" } + +preceding_side_effects: { + options = { + inline: true, + } + input: { + console.log(function(a, b, c) { + return b; + }(console, "PASS", 42)); + } + expect: { + console.log((console, 42, "PASS")); + } + expect_stdout: "PASS" +} + +trailing_side_effects: { + options = { + inline: true, + } + input: { + console.log(function(a, b, c) { + return b; + }(42, "PASS", console)); + } + expect: { + console.log(function(a, b, c) { + return b; + }(42, "PASS", console)); + } + expect_stdout: "PASS" +} + +preserve_binding_1: { + options = { + inline: true, + } + input: { + var o = { + f: function() { + return this === o ? "FAIL" : "PASS"; + }, + }; + console.log(function(a) { + return a; + }(o.f)()); + } + expect: { + var o = { + f: function() { + return this === o ? "FAIL" : "PASS"; + }, + }; + console.log((0, o.f)()); + } + expect_stdout: "PASS" +} + +preserve_binding_2: { + options = { + collapse_vars: true, + inline: true, + unused: true, + } + input: { + var o = { + f: function() { + return this === o ? "FAIL" : "PASS"; + }, + }; + console.log(function(a) { + return a; + }(o.f)()); + } + expect: { + var o = { + f: function() { + return this === o ? "FAIL" : "PASS"; + }, + }; + console.log((0, o.f)()); + } + expect_stdout: "PASS" +} diff --git a/test/input/rename/input.js b/test/input/rename/input.js index ef6daed2..3008433a 100644 --- a/test/input/rename/input.js +++ b/test/input/rename/input.js @@ -1,6 +1,6 @@ function f(x) { return g(x); function g(x) { - return x; + return x + 1; } } diff --git a/test/mocha/cli.js b/test/mocha/cli.js index 0347797e..2e68fbf3 100644 --- a/test/mocha/cli.js +++ b/test/mocha/cli.js @@ -674,7 +674,7 @@ describe("bin/uglifyjs", function() { var command = uglifyjscmd + " test/input/rename/input.js --rename"; exec(command, function(err, stdout, stderr) { if (err) throw err; - assert.strictEqual(stdout, "function f(a){return b(a);function b(c){return c}}\n"); + assert.strictEqual(stdout, "function f(a){return b(a);function b(c){return c+1}}\n"); done(); }); }); @@ -682,7 +682,7 @@ describe("bin/uglifyjs", function() { var command = uglifyjscmd + " test/input/rename/input.js -mc passes=2 --no-rename"; exec(command, function(err, stdout, stderr) { if (err) throw err; - assert.strictEqual(stdout, "function f(n){return function(n){return n}(n)}\n"); + assert.strictEqual(stdout, "function f(n){return function(n){return n+1}(n)}\n"); done(); }); }); @@ -690,7 +690,7 @@ describe("bin/uglifyjs", function() { var command = uglifyjscmd + " test/input/rename/input.js -mc passes=2"; exec(command, function(err, stdout, stderr) { if (err) throw err; - assert.strictEqual(stdout, "function f(n){return n}\n"); + assert.strictEqual(stdout, "function f(n){return n+1}\n"); done(); }); }); @@ -698,7 +698,7 @@ describe("bin/uglifyjs", function() { var command = uglifyjscmd + " test/input/rename/input.js -c passes=2"; exec(command, function(err, stdout, stderr) { if (err) throw err; - assert.strictEqual(stdout, "function f(x){return function(x){return x}(x)}\n"); + assert.strictEqual(stdout, "function f(x){return function(x){return x+1}(x)}\n"); done(); }); }); diff --git a/test/ufuzz/index.js b/test/ufuzz/index.js index f1fce6a1..76a782ef 100644 --- a/test/ufuzz/index.js +++ b/test/ufuzz/index.js @@ -704,6 +704,7 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) { break; } VAR_NAMES.length = nameLenBefore; + if (canThrow && rng(8) == 0 && !/^new /.test(s[0])) s[s.length - 1] += "()"; return filterDirective(s).join("\n"); case p++: case p++: -- 2.34.1