From a8785fb6943e9cf8e370e19f29945e544b3be4b2 Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Sun, 27 Dec 2020 05:32:18 +0000 Subject: [PATCH] workaround v8 bug with labels (#4467) closes #4466 --- README.md | 8 ++- lib/minify.js | 3 + lib/scope.js | 11 +++- test/compress/labels.js | 120 ++++++++++++++++++++++++++++++++++++++++ test/ufuzz/index.js | 6 ++ 5 files changed, 145 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 59aec09b..e084fffa 100644 --- a/README.md +++ b/README.md @@ -135,6 +135,10 @@ a double dash to prevent input files being used as option arguments: `//# sourceMappingURL`. --timings Display operations run time on STDERR. --toplevel Compress and/or mangle variables in top level scope. + --v8 Support non-standard Chrome & Node.js + Equivalent to setting `v8: true` in `minify()` + for `mangle` and `output` options. + By default UglifyJS will not try to be v8-proof. --verbose Print diagnostic messages. --warn Print warning messages. --webkit Support non-standard Safari/Webkit. @@ -522,6 +526,8 @@ if (result.error) throw result.error; - `toplevel` (default `false`) -- set to `true` if you wish to enable top level variable and function name mangling and to drop unused variables and functions. +- `v8` (default `false`) -- enable workarounds for Chrome & Node.js bugs. + - `warnings` (default `false`) — pass `true` to return compressor warnings in `result.warnings`. Use the value `"verbose"` for more detailed warnings. @@ -921,8 +927,6 @@ can pass additional arguments that control the code output: - `shebang` (default `true`) -- preserve shebang `#!` in preamble (bash scripts) -- `v8` (default `false`) -- enable workarounds for Chrome & Node.js bugs - - `width` (default `80`) -- only takes effect when beautification is on, this specifies an (orientative) line width that the beautifier will try to obey. It refers to the width of the line text (excluding indentation). diff --git a/lib/minify.js b/lib/minify.js index 678fbca9..13f8d6a7 100644 --- a/lib/minify.js +++ b/lib/minify.js @@ -87,6 +87,7 @@ function minify(files, options) { sourceMap: false, timings: false, toplevel: false, + v8: false, validate: false, warnings: false, webkit: false, @@ -102,6 +103,7 @@ function minify(files, options) { set_shorthand("ie8", options, [ "compress", "mangle", "output" ]); set_shorthand("keep_fnames", options, [ "compress", "mangle" ]); set_shorthand("toplevel", options, [ "compress", "mangle" ]); + set_shorthand("v8", options, [ "mangle", "output" ]); set_shorthand("webkit", options, [ "mangle", "output" ]); var quoted_props; if (options.mangle) { @@ -113,6 +115,7 @@ function minify(files, options) { properties: false, reserved: [], toplevel: false, + v8: false, webkit: false, }, true); if (options.mangle.properties) { diff --git a/lib/scope.js b/lib/scope.js index c59dc0a7..0c35b0dd 100644 --- a/lib/scope.js +++ b/lib/scope.js @@ -512,6 +512,7 @@ function _default_mangler_options(options) { keep_fnames : false, reserved : [], toplevel : false, + v8 : false, webkit : false, }); if (!Array.isArray(options.reserved)) options.reserved = []; @@ -543,7 +544,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) { // lname is incremented when we get to the AST_Label var save_nesting = lname; descend(); - lname = save_nesting; + if (!options.v8 || !in_label(tw)) lname = save_nesting; return true; } if (node instanceof AST_BlockScope) { @@ -616,6 +617,14 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) { sym.thedef = def; } } + + function in_label(tw) { + var level = 0, parent; + while (parent = tw.parent(level++)) { + if (parent instanceof AST_Block) return parent instanceof AST_Toplevel && !options.toplevel; + if (parent instanceof AST_LabeledStatement) return true; + } + } }); AST_Toplevel.DEFMETHOD("find_colliding_names", function(options) { diff --git a/test/compress/labels.js b/test/compress/labels.js index 13ac8e38..6b7c5a3d 100644 --- a/test/compress/labels.js +++ b/test/compress/labels.js @@ -207,3 +207,123 @@ labels_10: { } } } + +issue_4466_1: { + mangle = { + v8: false, + } + input: { + A: if (console.log("PASS")) + B:; + else + C:; + } + expect: { + e: if (console.log("PASS")) + l:; + else + l:; + } + expect_stdout: "PASS" + node_version: ">=12" +} + +issue_4466_1_v8: { + mangle = { + v8: true, + } + input: { + A: if (console.log("PASS")) + B:; + else + C:; + } + expect: { + e: if (console.log("PASS")) + l:; + else + o:; + } + expect_stdout: "PASS" + node_version: ">=12" +} + +issue_4466_2: { + mangle = { + toplevel: false, + v8: false, + } + input: { + if (console.log("PASS")) + A:; + else + B:; + } + expect: { + if (console.log("PASS")) + e:; + else + e:; + } + expect_stdout: "PASS" +} + +issue_4466_2_v8: { + mangle = { + toplevel: false, + v8: true, + } + input: { + if (console.log("PASS")) + A:; + else + B:; + } + expect: { + if (console.log("PASS")) + e:; + else + l:; + } + expect_stdout: "PASS" +} + +issue_4466_2_toplevel: { + mangle = { + toplevel: true, + v8: false, + } + input: { + if (console.log("PASS")) + A:; + else + B:; + } + expect: { + if (console.log("PASS")) + e:; + else + e:; + } + expect_stdout: "PASS" +} + +issue_4466_2_toplevel_v8: { + mangle = { + toplevel: true, + v8: true, + } + input: { + if (console.log("PASS")) + A:; + else + B:; + } + expect: { + if (console.log("PASS")) + e:; + else + e:; + } + expect_stdout: "PASS" +} diff --git a/test/ufuzz/index.js b/test/ufuzz/index.js index d4c83d88..2eac44f0 100644 --- a/test/ufuzz/index.js +++ b/test/ufuzz/index.js @@ -1799,6 +1799,12 @@ var beautify_options = { }, }; var minify_options = require("./options.json"); +if (typeof sandbox.run_code("A:if (0) B:; else B:;") != "string") { + minify_options.forEach(function(o) { + if (!("mangle" in o)) o.mangle = {}; + if (o.mangle) o.mangle.v8 = true; + }); +} if (SUPPORT.destructuring && typeof sandbox.run_code("console.log([ 1 ], {} = 2);") != "string") { beautify_options.output.v8 = true; minify_options.forEach(function(o) { -- 2.34.1