From 00f509405b44882bab5d63d97caacb21691cdad6 Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Wed, 20 Sep 2017 05:23:20 +0800 Subject: [PATCH 1/4] suppress `collapse_vars` of `this` into "use strict" (#2326) fixes #2319 --- lib/ast.js | 6 +-- lib/compress.js | 4 +- test/compress/collapse_vars.js | 70 ++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 5 deletions(-) diff --git a/lib/ast.js b/lib/ast.js index 0918574d..9b243f16 100644 --- a/lib/ast.js +++ b/lib/ast.js @@ -134,11 +134,10 @@ var AST_Debugger = DEFNODE("Debugger", null, { $documentation: "Represents a debugger statement", }, AST_Statement); -var AST_Directive = DEFNODE("Directive", "value scope quote", { +var AST_Directive = DEFNODE("Directive", "value quote", { $documentation: "Represents a directive, like \"use strict\";", $propdoc: { value: "[string] The value of this directive as a plain string (it's not an AST_String!)", - scope: "[AST_Scope/S] The scope that this directive affects", quote: "[string] the original quote character" }, }, AST_Statement); @@ -299,10 +298,9 @@ var AST_With = DEFNODE("With", "expression", { /* -----[ scope and functions ]----- */ -var AST_Scope = DEFNODE("Scope", "directives variables functions uses_with uses_eval parent_scope enclosed cname", { +var AST_Scope = DEFNODE("Scope", "variables functions uses_with uses_eval parent_scope enclosed cname", { $documentation: "Base class for all statements introducing a lexical scope", $propdoc: { - directives: "[string*/S] an array of directives declared in this scope", variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope", functions: "[Object/S] like `variables`, but only lists function declarations", uses_with: "[boolean/S] tells whether this scope uses the `with` statement", diff --git a/lib/compress.js b/lib/compress.js index 3164c5a0..9e516a89 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -842,6 +842,8 @@ merge(Compressor.prototype, { && !fn.uses_eval && (iife = compressor.parent()) instanceof AST_Call && iife.expression === fn) { + var fn_strict = compressor.has_directive("use strict"); + if (fn_strict && fn.body.indexOf(fn_strict) < 0) fn_strict = false; var names = Object.create(null); for (var i = fn.argnames.length; --i >= 0;) { var sym = fn.argnames[i]; @@ -859,7 +861,7 @@ merge(Compressor.prototype, { } arg = null; } - if (node instanceof AST_This && !tw.find_parent(AST_Scope)) { + if (node instanceof AST_This && (fn_strict || !tw.find_parent(AST_Scope))) { arg = null; return true; } diff --git a/test/compress/collapse_vars.js b/test/compress/collapse_vars.js index 5e7e982e..ecd18610 100644 --- a/test/compress/collapse_vars.js +++ b/test/compress/collapse_vars.js @@ -2451,3 +2451,73 @@ issue_2313_2: { } expect_stdout: "0" } + +issue_2319_1: { + options = { + collapse_vars: true, + unused: true, + } + input: { + console.log(function(a) { + return a; + }(!function() { + return this; + }())); + } + expect: { + console.log(function(a) { + return !function() { + return this; + }(); + }()); + } + expect_stdout: "false" +} + +issue_2319_2: { + options = { + collapse_vars: true, + unused: true, + } + input: { + console.log(function(a) { + "use strict"; + return a; + }(!function() { + return this; + }())); + } + expect: { + console.log(function(a) { + "use strict"; + return a; + }(!function() { + return this; + }())); + } + expect_stdout: "false" +} + +issue_2319_3: { + options = { + collapse_vars: true, + unused: true, + } + input: { + "use strict"; + console.log(function(a) { + return a; + }(!function() { + return this; + }())); + } + expect: { + "use strict"; + console.log(function(a) { + return !function() { + return this; + }(); + }()); + } + expect_stdout: "true" +} From 7e3e9da860d9da4fa3d5e37bea4d3bd399194c02 Mon Sep 17 00:00:00 2001 From: kzc Date: Wed, 20 Sep 2017 12:52:48 -0400 Subject: [PATCH 2/4] fix "use asm" numeric output (#2328) fixes #2324 --- lib/output.js | 16 +++++++----- test/compress/asm.js | 62 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 6 deletions(-) diff --git a/lib/output.js b/lib/output.js index 315bfafd..1aa63450 100644 --- a/lib/output.js +++ b/lib/output.js @@ -482,13 +482,17 @@ function OutputStream(options) { nodetype.DEFMETHOD("_codegen", generator); }; - var use_asm = false; var in_directive = false; + var active_scope = null; + var use_asm = null; AST_Node.DEFMETHOD("print", function(stream, force_parens){ - var self = this, generator = self._codegen, prev_use_asm = use_asm; - if (self instanceof AST_Directive && self.value == "use asm" && stream.parent() instanceof AST_Scope) { - use_asm = true; + var self = this, generator = self._codegen; + if (self instanceof AST_Scope) { + active_scope = self; + } + else if (!use_asm && self instanceof AST_Directive && self.value == "use asm") { + use_asm = active_scope; } function doit() { self.add_comments(stream); @@ -502,8 +506,8 @@ function OutputStream(options) { doit(); } stream.pop_node(); - if (self instanceof AST_Scope) { - use_asm = prev_use_asm; + if (self === use_asm) { + use_asm = null; } }); AST_Node.DEFMETHOD("_print", AST_Node.prototype.print); diff --git a/test/compress/asm.js b/test/compress/asm.js index 9b227326..527e6b43 100644 --- a/test/compress/asm.js +++ b/test/compress/asm.js @@ -104,3 +104,65 @@ asm_mixed: { } } +asm_toplevel: { + options = {} + input: { + "use asm"; + 0.0; + function f() { + 0.0; + (function(){ + 0.0; + }); + } + 0.0; + } + expect_exact: '"use asm";0.0;function f(){0.0;(function(){0.0})}0.0;' +} + +asm_function_expression: { + options = {} + input: { + 0.0; + var a = function() { + "use asm"; + 0.0; + } + function f() { + 0.0; + return function(){ + "use asm"; + 0.0; + } + 0.0; + } + 0.0; + } + expect_exact: '0;var a=function(){"use asm";0.0};function f(){0;return function(){"use asm";0.0};0}0;' +} + +asm_nested_functions: { + options = {} + input: { + 0.0; + function a() { + "use asm"; + 0.0; + } + 0.0; + function b() { + 0.0; + function c(){ + "use asm"; + 0.0; + } + 0.0; + function d(){ + 0.0; + } + 0.0; + } + 0.0; + } + expect_exact: '0;function a(){"use asm";0.0}0;function b(){0;function c(){"use asm";0.0}0;function d(){0}0}0;' +} From 55387e8fd022a64b349487ca3a66c3d9c5de1907 Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Sun, 24 Sep 2017 02:02:04 +0800 Subject: [PATCH 3/4] v3.1.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2b298d3b..0dd71612 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "homepage": "http://lisperator.net/uglifyjs", "author": "Mihai Bazon (http://lisperator.net/)", "license": "BSD-2-Clause", - "version": "3.1.1", + "version": "3.1.2", "engines": { "node": ">=0.8.0" }, From aaa821283763f5f4226598b7fd2ba8d930a0a38d Mon Sep 17 00:00:00 2001 From: alexlamsl Date: Sun, 24 Sep 2017 02:23:38 +0800 Subject: [PATCH 4/4] improve test for #2316 --- test/compress/harmony.js | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/test/compress/harmony.js b/test/compress/harmony.js index 5891ee43..e48a623b 100644 --- a/test/compress/harmony.js +++ b/test/compress/harmony.js @@ -808,35 +808,34 @@ object_spread_of_sequence: { // issue 2316 class_name_can_be_preserved_with_reserved: { mangle = { - reserved: ['Foo'] + reserved: [ "Foo" ], } input: { function x() { - class Foo {}; + class Foo {} Foo.bar; - class Bar {}; + class Bar {} Bar.foo; } - function y() { var Foo = class Foo {}; - Foo.bar(); + Foo.bar; var Bar = class Bar {}; - Bar.bar(); + Bar.bar; } } expect: { function x() { class Foo {} Foo.bar; - class a{} - a.foo + class a {} + a.foo; } function y() { var Foo = class Foo {}; - Foo.bar(); - var a = class a{}; - a.bar() + Foo.bar; + var a = class a {}; + a.bar; } } }