swc icon indicating copy to clipboard operation
swc copied to clipboard

Compressing makes output bigger

Open mischnic opened this issue 3 years ago • 3 comments

Describe the bug

A case where function inlining made the output bigger instead of smaller

Input code

function $parcel$export(a, b, c){a[b] = c;}
$parcel$export(module.exports, "A", function () { return A; });
$parcel$export(module.exports, "B", function () { return B; });
$parcel$export(module.exports, "C", function () { return C; });
const A = "A", B = "B", C = "C";

Config

{
  "jsc": {
    "parser": {
      "syntax": "typescript",
      "tsx": false
    },
    "target": "es2020",
    "loose": false,
    "minify": {
      "compress": {
        "arguments": false,
        "arrows": true,
        "booleans": true,
        "booleans_as_integers": false,
        "collapse_vars": true,
        "comparisons": true,
        "computed_props": true,
        "conditionals": true,
        "dead_code": true,
        "directives": true,
        "drop_console": false,
        "drop_debugger": true,
        "evaluate": true,
        "expression": false,
        "hoist_funs": false,
        "hoist_props": true,
        "hoist_vars": false,
        "if_return": true,
        "join_vars": true,
        "keep_classnames": false,
        "keep_fargs": true,
        "keep_fnames": false,
        "keep_infinity": false,
        "loops": true,
        "negate_iife": true,
        "properties": true,
        "reduce_funcs": false,
        "reduce_vars": false,
        "side_effects": true,
        "switches": true,
        "typeofs": true,
        "unsafe": false,
        "unsafe_arrows": false,
        "unsafe_comps": false,
        "unsafe_Function": false,
        "unsafe_math": false,
        "unsafe_symbols": false,
        "unsafe_methods": false,
        "unsafe_proto": false,
        "unsafe_regexp": false,
        "unsafe_undefined": false,
        "unused": true,
        "const_to_let": true,
        "pristine_globals": true
      },
      "mangle": {
        "toplevel": false,
        "keep_classnames": false,
        "keep_fnames": false,
        "keep_private_props": false,
        "ie8": false,
        "safari10": false
      }
    }
  },
  "module": {
    "type": "commonjs"
  },
  "minify": true,
  "isModule": true
}

Playground link

https://play.swc.rs/?version=1.2.223&code=H4sIAAAAAAAAA0srzUsuyczPU1ApSCxKTs1RSa0oyC8q0UjUUUjSUUjWrE6MTopVsFVItq7lQlOSm59SmpOqB%2BEV6ygoOSrpKKTBzNPQVKhWKEotKS3KU3C0VqjVtCao3wmXfifi9Dvj0u8M0Z%2Bcn1dcouAI9A3YqU4gBshOZxDDWcmaCwCaGsxoDQEAAA%3D%3D&config=H4sIAAAAAAAAA3VUQZLjIAz8C%2Bc5ZOa0NQ%2BY276BIkY4ZDByIeGJK5W%2Fr4htiJPZm9W0REtqc1Vn6tTnVY0mEaTyRXNkc1GfiucRqEt%2BZPWmmARyJhDcJDCpBxYK0Mfh4yDHAZFgJbypwUfv5lKsw2FMQFS%2BJSkPEJkqz6SEPxJyyhIdEQOY%2BBJrQ9pHhh5SS%2B0wBDMS6MmkmlFuM8kTxh2UGaweE44PaLSePUYptmEWjNUdWqiAT9Cxn6BRpIZQIomwquQOWjjmvi8DXJgwmZAN11pwuY9Bbqx5J%2FTE2uVIT9BO6QItTa4s73QCzilunDP6uJvDN4DoDIYomgFa5h13soc90%2F3C8tHJEnmuqGy4qYrQS3Pae1c7LKohsW%2FTSmBzB6XDrhVfwV1D5C1ocE6mXZPpx3N3asWKGdHVUKZmXNvBEurNT3u0WOAF%2FBJV%2FLiOFR8Mn54xmocjhpcSA%2FAJ7Qssg2B8BpO49zI%2BozlakDGDfTjIVMJqU1k%2Bow7lb9vmLIaQHN0HPFb7yk85mNgXW14V4xhggrDf6H%2F98Asml0xlwasVN%2BPBn7YzIz7y74ftUbgVBWjzqkC2Jc%2BDTH7AeCZ1a2%2FC0oWnvyv5rv4fybKGM4cEAAA%3D

Expected behavior

Output is smaller or has same size

Actual behavior

Enabling compress makes output bigger

Version

1.2.223

Additional context

No response

mischnic avatar Aug 05 '22 14:08 mischnic

Some thoughts, not actual work.

Inlining a function call is a two phase action in swc: first you replace the function ident with the actual function, then you evaluate it.

Two kinds of function would be inlined: those only used one times, and those are simple enough. The first kind of inlining is always right, but the second causes this issue. It's inlined, but evaluation failed, maybe because its arguments contain side effect(accessing global variable module) or contain function. So the solution seems to be distinguish between these two kinds of function, and bail out inlining if the latter kind is called with bad arguments.

However, is it really not impossible to evaluate this function? Maybe not, as gcc advanced mode could. If we take a look at the function body, one could see that evalution order is preseved, as a is always accessed first. However such capability doesn't seem to exist at this point in swc.

Anyway, the way to fix this issue would be long and tormenting.

Austaras avatar Aug 09 '22 12:08 Austaras

I think we can adjust inline cost logic by calculating argument cost in the analyzer and by using unresolved_ctxt

If we do so, the inline cost of module.exports will be very high so it will not be inlined

kdy1 avatar Aug 10 '22 02:08 kdy1

No, the cost of module.exports doesn't change before and after inling unless it's referenced multiple times, which is rare as we only inline small functions

Austaras avatar Aug 10 '22 06:08 Austaras

Oh, this case seems to be caused by function as a parameter would prevent iife invoke. We could optimise this easily.

Austaras avatar Sep 01 '22 10:09 Austaras

This closed issue has been automatically locked because it had no new activity for a month. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

github-actions[bot] avatar Oct 16 '22 00:10 github-actions[bot]