From 69ecb5720139fb4d1e127d5cea0bb50839f0e486 Mon Sep 17 00:00:00 2001 From: alexlamsl Date: Sat, 11 Nov 2017 03:15:14 +0800 Subject: [PATCH] implement compress option `reduce_funcs` - inline single-use function declarations as expressions when permissible - depend on `reduce_vars` - enabled by default - disable for speed critical code fixes #2464 --- README.md | 5 ++ lib/compress.js | 2 + test/compress/collapse_vars.js | 2 + test/compress/drop-unused.js | 4 ++ test/compress/functions.js | 3 + test/compress/issue-1656.js | 1 + test/compress/issue-1673.js | 5 ++ test/compress/issue-1833.js | 4 ++ test/compress/pure_getters.js | 2 + test/compress/reduce_vars.js | 114 +++++++++++++++++++++++++++++++++ 10 files changed, 142 insertions(+) diff --git a/README.md b/README.md index 0d1e2368..22831b12 100644 --- a/README.md +++ b/README.md @@ -689,6 +689,11 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u Specify `"strict"` to treat `foo.bar` as side-effect-free only when `foo` is certain to not throw, i.e. not `null` or `undefined`. +- `reduce_funcs` (default: `true`) -- Allows single-use functions + to be inlined as function expressions when permissible. + Enabled by default. Option depends on `reduce_vars` being enabled. + For speed critical code this option should be disabled. + - `reduce_vars` (default: `true`) -- Improve optimization on variables assigned with and used as constant values. diff --git a/lib/compress.js b/lib/compress.js index 24c5be21..2b38ed49 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -75,6 +75,7 @@ function Compressor(options, false_by_default) { properties : !false_by_default, pure_getters : !false_by_default && "strict", pure_funcs : null, + reduce_funcs : !false_by_default, reduce_vars : !false_by_default, sequences : !false_by_default, side_effects : !false_by_default, @@ -4255,6 +4256,7 @@ merge(Compressor.prototype, { var fixed = self.fixed_value(); if (fixed instanceof AST_Defun) { d.fixed = fixed = make_node(AST_Function, fixed, fixed); + if (!compressor.option("reduce_funcs")) d.single_use = false; } if (d.single_use && fixed instanceof AST_Function) { if (d.escaped && d.scope !== self.scope || recursive_ref(compressor, d)) { diff --git a/test/compress/collapse_vars.js b/test/compress/collapse_vars.js index 34489717..e2b515e8 100644 --- a/test/compress/collapse_vars.js +++ b/test/compress/collapse_vars.js @@ -2369,6 +2369,7 @@ duplicate_argname: { issue_2298: { options = { collapse_vars: true, + reduce_funcs: true, reduce_vars: true, unused: true, } @@ -3037,6 +3038,7 @@ issue_2437: { inline: true, join_vars: true, passes: 2, + reduce_funcs: true, reduce_vars: true, side_effects: true, sequences: true, diff --git a/test/compress/drop-unused.js b/test/compress/drop-unused.js index ebb0b8fa..a7389ea4 100644 --- a/test/compress/drop-unused.js +++ b/test/compress/drop-unused.js @@ -673,6 +673,7 @@ issue_1539: { vardef_value: { options = { keep_fnames: false, + reduce_funcs: true, reduce_vars: true, unused: true, } @@ -1080,6 +1081,7 @@ var_catch_toplevel: { options = { conditionals: true, negate_iife: true, + reduce_funcs: true, reduce_vars: true, side_effects: true, toplevel: true, @@ -1114,6 +1116,7 @@ issue_2105_1: { collapse_vars: true, inline: true, passes: 3, + reduce_funcs: true, reduce_vars: true, side_effects: true, unused: true, @@ -1156,6 +1159,7 @@ issue_2105_2: { passes: 3, properties: true, pure_getters: "strict", + reduce_funcs: true, reduce_vars: true, side_effects: true, unsafe: true, diff --git a/test/compress/functions.js b/test/compress/functions.js index c5aab171..9d736d12 100644 --- a/test/compress/functions.js +++ b/test/compress/functions.js @@ -305,6 +305,7 @@ issue_2084: { evaluate: true, inline: true, passes: 2, + reduce_funcs: true, reduce_vars: true, sequences: true, side_effects: true, @@ -340,6 +341,7 @@ issue_2084: { issue_2097: { options = { negate_iife: true, + reduce_funcs: true, reduce_vars: true, toplevel: true, unused: true, @@ -515,6 +517,7 @@ issue_2428: { inline: true, passes: 3, pure_getters: "strict", + reduce_funcs: true, reduce_vars: true, side_effects: true, toplevel: true, diff --git a/test/compress/issue-1656.js b/test/compress/issue-1656.js index c4c8f863..3971ceaa 100644 --- a/test/compress/issue-1656.js +++ b/test/compress/issue-1656.js @@ -15,6 +15,7 @@ f7: { negate_iife: true, passes: 3, properties: true, + reduce_funcs: true, reduce_vars: true, sequences: true, side_effects: true, diff --git a/test/compress/issue-1673.js b/test/compress/issue-1673.js index 081b0e5f..88e1fa8d 100644 --- a/test/compress/issue-1673.js +++ b/test/compress/issue-1673.js @@ -1,5 +1,6 @@ side_effects_catch: { options = { + reduce_funcs: true, reduce_vars: true, side_effects: true, unused: true, @@ -34,6 +35,7 @@ side_effects_catch: { side_effects_else: { options = { + reduce_funcs: true, reduce_vars: true, side_effects: true, unused: true, @@ -62,6 +64,7 @@ side_effects_else: { side_effects_finally: { options = { + reduce_funcs: true, reduce_vars: true, side_effects: true, unused: true, @@ -98,6 +101,7 @@ side_effects_finally: { side_effects_label: { options = { + reduce_funcs: true, reduce_vars: true, side_effects: true, unused: true, @@ -130,6 +134,7 @@ side_effects_label: { side_effects_switch: { options = { + reduce_funcs: true, reduce_vars: true, side_effects: true, unused: true, diff --git a/test/compress/issue-1833.js b/test/compress/issue-1833.js index e46dd046..4ffa9d5c 100644 --- a/test/compress/issue-1833.js +++ b/test/compress/issue-1833.js @@ -1,6 +1,7 @@ iife_for: { options = { negate_iife: true, + reduce_funcs: true, reduce_vars: true, toplevel: true, unused: true, @@ -26,6 +27,7 @@ iife_for: { iife_for_in: { options = { negate_iife: true, + reduce_funcs: true, reduce_vars: true, toplevel: true, unused: true, @@ -51,6 +53,7 @@ iife_for_in: { iife_do: { options = { negate_iife: true, + reduce_funcs: true, reduce_vars: true, toplevel: true, unused: true, @@ -80,6 +83,7 @@ iife_do: { iife_while: { options = { negate_iife: true, + reduce_funcs: true, reduce_vars: true, toplevel: true, unused: true, diff --git a/test/compress/pure_getters.js b/test/compress/pure_getters.js index 22441d98..9b51509f 100644 --- a/test/compress/pure_getters.js +++ b/test/compress/pure_getters.js @@ -185,6 +185,7 @@ issue_2110_1: { pure_getters: "strict", sequences: true, side_effects: true, + reduce_funcs: true, reduce_vars: true, unused: true, } @@ -215,6 +216,7 @@ issue_2110_2: { options = { collapse_vars: true, pure_getters: "strict", + reduce_funcs: true, reduce_vars: true, unused: true, } diff --git a/test/compress/reduce_vars.js b/test/compress/reduce_vars.js index e84ac6cb..1eb05cea 100644 --- a/test/compress/reduce_vars.js +++ b/test/compress/reduce_vars.js @@ -1292,6 +1292,7 @@ defun_reference: { defun_inline_1: { options = { + reduce_funcs: true, reduce_vars: true, unused: true, } @@ -1320,6 +1321,7 @@ defun_inline_1: { defun_inline_2: { options = { + reduce_funcs: true, reduce_vars: true, unused: true, } @@ -1351,6 +1353,7 @@ defun_inline_3: { evaluate: true, inline: true, passes: 2, + reduce_funcs: true, reduce_vars: true, side_effects: true, unused: true, @@ -1460,6 +1463,7 @@ func_inline: { func_modified: { options = { inline: true, + reduce_funcs: true, reduce_vars: true, unused: true, } @@ -1487,6 +1491,7 @@ func_modified: { defun_label: { options = { passes: 2, + reduce_funcs: true, reduce_vars: true, unused: true, } @@ -1629,6 +1634,7 @@ iife_eval_2: { iife_func_side_effects: { options = { + reduce_funcs: true, reduce_vars: true, unused: true, } @@ -2001,6 +2007,7 @@ redefine_arguments_1: { options = { evaluate: true, keep_fargs: false, + reduce_funcs: true, reduce_vars: true, unused: true, } @@ -2041,6 +2048,7 @@ redefine_arguments_2: { evaluate: true, inline: true, keep_fargs: false, + reduce_funcs: true, reduce_vars: true, side_effects: true, toplevel: true, @@ -2079,6 +2087,7 @@ redefine_arguments_3: { inline: true, keep_fargs: false, passes: 3, + reduce_funcs: true, reduce_vars: true, side_effects: true, toplevel: true, @@ -2115,6 +2124,7 @@ redefine_farg_1: { options = { evaluate: true, keep_fargs: false, + reduce_funcs: true, reduce_vars: true, unused: true, } @@ -2154,6 +2164,7 @@ redefine_farg_2: { evaluate: true, inline: true, keep_fargs: false, + reduce_funcs: true, reduce_vars: true, side_effects: true, toplevel: true, @@ -2192,6 +2203,7 @@ redefine_farg_3: { inline: true, keep_fargs: false, passes: 2, + reduce_funcs: true, reduce_vars: true, sequences: true, side_effects: true, @@ -2701,6 +2713,7 @@ iife_assign: { issue_1850_1: { options = { + reduce_funcs: true, reduce_vars: true, toplevel: false, unused: true, @@ -2724,6 +2737,7 @@ issue_1850_1: { issue_1850_2: { options = { + reduce_funcs: true, reduce_vars: true, toplevel: "funcs", unused: true, @@ -2746,6 +2760,7 @@ issue_1850_2: { issue_1850_3: { options = { + reduce_funcs: true, reduce_vars: true, toplevel: "vars", unused: true, @@ -2769,6 +2784,7 @@ issue_1850_3: { issue_1850_4: { options = { + reduce_funcs: true, reduce_vars: true, toplevel: true, unused: true, @@ -3002,6 +3018,7 @@ obj_arg_1: { evaluate: true, inline: true, passes: 2, + reduce_funcs: true, reduce_vars: true, toplevel: true, unused: true, @@ -3033,6 +3050,7 @@ obj_arg_2: { inline: true, passes: 2, properties: true, + reduce_funcs: true, reduce_vars: true, side_effects: true, toplevel: true, @@ -3105,6 +3123,7 @@ func_arg_2: { regex_loop: { options = { + reduce_funcs: true, reduce_vars: true, toplevel: true, unused: true, @@ -3277,6 +3296,7 @@ escaped_prop_1: { evaluate: true, inline: true, pure_getters: "strict", + reduce_funcs: true, reduce_vars: true, side_effects: true, toplevel: true, @@ -3302,6 +3322,7 @@ escaped_prop_1: { escaped_prop_2: { options = { + reduce_funcs: true, reduce_vars: true, toplevel: true, unused: true, @@ -3420,6 +3441,7 @@ issue_2420_2: { issue_2423_1: { options = { + reduce_funcs: true, reduce_vars: true, toplevel: true, unused: true, @@ -3444,6 +3466,7 @@ issue_2423_1: { issue_2423_2: { options = { inline: true, + reduce_funcs: true, reduce_vars: true, toplevel: true, unused: true, @@ -3467,6 +3490,7 @@ issue_2423_2: { issue_2423_3: { options = { + reduce_funcs: true, reduce_vars: true, toplevel: true, unused: true, @@ -3485,6 +3509,7 @@ issue_2423_3: { issue_2423_4: { options = { inline: true, + reduce_funcs: true, reduce_vars: true, side_effects: true, toplevel: true, @@ -3505,6 +3530,7 @@ issue_2423_5: { options = { inline: true, passes: 2, + reduce_funcs: true, reduce_vars: true, side_effects: true, toplevel: true, @@ -3543,6 +3569,7 @@ issue_2423_6: { options = { inline: true, passes: 2, + reduce_funcs: true, reduce_vars: true, side_effects: true, toplevel: true, @@ -3583,6 +3610,7 @@ issue_2423_6: { issue_2440_eval_1: { options = { + reduce_funcs: true, reduce_vars: true, toplevel: true, unused: true, @@ -3613,6 +3641,7 @@ issue_2440_eval_1: { issue_2440_eval_2: { options = { + reduce_funcs: true, reduce_vars: true, toplevel: true, unused: true, @@ -3643,6 +3672,7 @@ issue_2440_eval_2: { issue_2440_with_1: { options = { + reduce_funcs: true, reduce_vars: true, toplevel: true, unused: true, @@ -3669,6 +3699,7 @@ issue_2440_with_1: { issue_2440_with_2: { options = { + reduce_funcs: true, reduce_vars: true, toplevel: true, unused: true, @@ -3695,6 +3726,7 @@ issue_2440_with_2: { issue_2442: { options = { + reduce_funcs: true, reduce_vars: true, toplevel: true, unused: true, @@ -3709,6 +3741,7 @@ issue_2442: { recursive_inlining_1: { options = { + reduce_funcs: true, reduce_vars: true, unused: true, } @@ -3729,6 +3762,7 @@ recursive_inlining_1: { recursive_inlining_2: { options = { + reduce_funcs: true, reduce_vars: true, unused: true, } @@ -3751,6 +3785,7 @@ recursive_inlining_2: { recursive_inlining_3: { options = { passes: 2, + reduce_funcs: true, reduce_vars: true, unused: true, } @@ -3788,6 +3823,7 @@ recursive_inlining_3: { recursive_inlining_4: { options = { + reduce_funcs: true, reduce_vars: true, unused: true, } @@ -3834,6 +3870,7 @@ recursive_inlining_4: { recursive_inlining_5: { options = { + reduce_funcs: true, reduce_vars: true, unused: true, } @@ -3887,6 +3924,7 @@ recursive_inlining_5: { issue_2450_1: { options = { + reduce_funcs: true, reduce_vars: true, toplevel: true, unused: true, @@ -3910,6 +3948,7 @@ issue_2450_1: { issue_2450_2: { options = { + reduce_funcs: true, reduce_vars: true, toplevel: true, unused: true, @@ -3932,6 +3971,7 @@ issue_2450_2: { issue_2450_3: { options = { + reduce_funcs: true, reduce_vars: true, unused: true, } @@ -3962,6 +4002,7 @@ issue_2450_3: { issue_2450_4: { options = { + reduce_funcs: true, reduce_vars: true, toplevel: true, unused: true, @@ -3995,6 +4036,7 @@ issue_2450_4: { issue_2450_5: { options = { + reduce_funcs: true, reduce_vars: true, toplevel: true, unused: true, @@ -4030,6 +4072,7 @@ issue_2450_5: { issue_2449: { options = { passes: 10, + reduce_funcs: true, reduce_vars: true, toplevel: true, unused: true, @@ -4061,3 +4104,74 @@ issue_2449: { } expect_stdout: "PASS" } + +perf_1: { + options = { + passes: 10, + reduce_funcs: true, + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + function foo(x, y, z) { + return x < y ? x * y + z : x * z - y; + } + function indirect_foo(x, y, z) { + return foo(x, y, z); + } + var sum = 0; + for (var i = 0; i < 100; ++i) { + sum += indirect_foo(i, i+1, i*3); + } + console.log(sum); + } + expect: { + function indirect_foo(x, y, z) { + return function(x, y, z) { + return x < y ? x * y + z : x * z - y; + }(x, y, z); + } + var sum = 0; + for (var i = 0; i < 100; ++i) + sum += indirect_foo(i, i + 1, 3 * i); + console.log(sum); + } + expect_stdout: "348150" +} + +perf_2: { + options = { + passes: 10, + reduce_funcs: false, + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + function foo(x, y, z) { + return x < y ? x * y + z : x * z - y; + } + function indirect_foo(x, y, z) { + return foo(x, y, z); + } + var sum = 0; + for (var i = 0; i < 100; ++i) { + sum += indirect_foo(i, i+1, i*3); + } + console.log(sum); + } + expect: { + function foo(x, y, z) { + return x < y ? x * y + z : x * z - y; + } + function indirect_foo(x, y, z) { + return foo(x, y, z); + } + var sum = 0; + for (var i = 0; i < 100; ++i) + sum += indirect_foo(i, i + 1, 3 * i); + console.log(sum); + } + expect_stdout: "348150" +}