From 1dbe97c655e85a27f807ec5ec2285b6728fdd12a Mon Sep 17 00:00:00 2001 From: alexlamsl Date: Tue, 2 Jan 2018 08:14:24 +0800 Subject: [PATCH] implement `inline` levels add tests update docs --- README.md | 8 +- lib/compress.js | 9 +- test/compress/functions.js | 207 +++++++++++++++++++++++++++++++++++++ 3 files changed, 220 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 43793dcd..d7c47d72 100644 --- a/README.md +++ b/README.md @@ -640,7 +640,13 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u - `if_return` (default: `true`) -- optimizations for if/return and if/continue -- `inline` (default: `true`) -- embed simple functions +- `inline` (default: `true`) -- inline calls to function with simple/`return` statement: + - `false` -- same as `0` + - `0` -- disabled inlining + - `1` -- inline simple functions + - `2` -- inline functions with arguments + - `3` -- inline functions with arguments and variables + - `true` -- same as `3` - `join_vars` (default: `true`) -- join consecutive `var` statements diff --git a/lib/compress.js b/lib/compress.js index 20928db3..5a06572f 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -99,6 +99,7 @@ function Compressor(options, false_by_default) { }); } } + if (this.options["inline"] === true) this.options["inline"] = 3; var pure_funcs = this.options["pure_funcs"]; if (typeof pure_funcs == "function") { this.pure_funcs = pure_funcs; @@ -4073,6 +4074,7 @@ merge(Compressor.prototype, { function can_flatten_body() { var len = fn.body.length; if (len == 1) return true; + if (compressor.option("inline") < 3) return false; stat = null; for (var i = 0; i < len; i++) { var line = fn.body[i]; @@ -4139,9 +4141,10 @@ merge(Compressor.prototype, { if (scope.fixed_value() instanceof AST_Scope) return false; } } while (!(scope instanceof AST_Scope)); - var safe_to_inject = compressor.toplevel.vars || !(scope instanceof AST_Toplevel); - if (!can_inject_vars(catches, in_loop, safe_to_inject)) return false; - if (!can_inject_args(catches, in_loop, safe_to_inject)) return false; + var safe_to_inject = !(scope instanceof AST_Toplevel) || compressor.toplevel.vars; + var inline = compressor.option("inline"); + if (!can_inject_vars(catches, in_loop, inline >= 3 && safe_to_inject)) return false; + if (!can_inject_args(catches, in_loop, inline >= 2 && safe_to_inject)) return false; return !in_loop || in_loop.length == 0 || !is_reachable(fn, in_loop); } diff --git a/test/compress/functions.js b/test/compress/functions.js index dd98ba60..7f5d048b 100644 --- a/test/compress/functions.js +++ b/test/compress/functions.js @@ -1694,3 +1694,210 @@ loop_init_arg: { } expect_stdout: "PASS" } + +inline_false: { + options = { + inline: false, + side_effects: true, + toplevel: true, + } + input: { + (function() { + console.log(1); + })(); + (function(a) { + console.log(a); + })(2); + (function(b) { + var c = b; + console.log(c); + })(3); + } + expect: { + (function() { + console.log(1); + })(); + (function(a) { + console.log(a); + })(2); + (function(b) { + var c = b; + console.log(c); + })(3); + } + expect_stdout: [ + "1", + "2", + "3", + ] +} + +inline_0: { + options = { + inline: 0, + side_effects: true, + toplevel: true, + } + input: { + (function() { + console.log(1); + })(); + (function(a) { + console.log(a); + })(2); + (function(b) { + var c = b; + console.log(c); + })(3); + } + expect: { + (function() { + console.log(1); + })(); + (function(a) { + console.log(a); + })(2); + (function(b) { + var c = b; + console.log(c); + })(3); + } + expect_stdout: [ + "1", + "2", + "3", + ] +} + +inline_1: { + options = { + inline: 1, + side_effects: true, + toplevel: true, + } + input: { + (function() { + console.log(1); + })(); + (function(a) { + console.log(a); + })(2); + (function(b) { + var c = b; + console.log(c); + })(3); + } + expect: { + console.log(1); + (function(a) { + console.log(a); + })(2); + (function(b) { + var c = b; + console.log(c); + })(3); + } + expect_stdout: [ + "1", + "2", + "3", + ] +} + +inline_2: { + options = { + inline: 2, + side_effects: true, + toplevel: true, + } + input: { + (function() { + console.log(1); + })(); + (function(a) { + console.log(a); + })(2); + (function(b) { + var c = b; + console.log(c); + })(3); + } + expect: { + console.log(1); + a = 2, console.log(a); + var a; + (function(b) { + var c = b; + console.log(c); + })(3); + } + expect_stdout: [ + "1", + "2", + "3", + ] +} + +inline_3: { + options = { + inline: 3, + side_effects: true, + toplevel: true, + } + input: { + (function() { + console.log(1); + })(); + (function(a) { + console.log(a); + })(2); + (function(b) { + var c = b; + console.log(c); + })(3); + } + expect: { + console.log(1); + a = 2, console.log(a); + var a; + b = 3, c = b, console.log(c); + var b, c; + } + expect_stdout: [ + "1", + "2", + "3", + ] +} + +inline_true: { + options = { + inline: true, + side_effects: true, + toplevel: true, + } + input: { + (function() { + console.log(1); + })(); + (function(a) { + console.log(a); + })(2); + (function(b) { + var c = b; + console.log(c); + })(3); + } + expect: { + console.log(1); + a = 2, console.log(a); + var a; + b = 3, c = b, console.log(c); + var b, c; + } + expect_stdout: [ + "1", + "2", + "3", + ] +}