From f2286c33f1245ba20f82a9429464c88c5c15b47f Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Wed, 20 Mar 2019 06:37:51 +0800 Subject: [PATCH] enhance `unsafe` for `Array` (#3349) --- lib/compress.js | 36 +++++++++--- test/compress/arrays.js | 110 +++++++++++++++++++++++++++++++++++ test/compress/reduce_vars.js | 21 +++++++ 3 files changed, 158 insertions(+), 9 deletions(-) diff --git a/lib/compress.js b/lib/compress.js index 4e276528..72f8e636 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -4003,17 +4003,17 @@ merge(Compressor.prototype, { return this; }); def(AST_Binary, function(compressor, first_in_statement) { - var right = this.right.drop_side_effect_free(compressor); + var right = this.right.drop_side_effect_free(compressor, first_in_statement); if (!right) return this.left.drop_side_effect_free(compressor, first_in_statement); if (lazy_op[this.operator]) { if (right === this.right) return this; var node = this.clone(); - node.right = right; + node.right = right.drop_side_effect_free(compressor); return node; } else { var left = this.left.drop_side_effect_free(compressor, first_in_statement); - if (!left) return this.right.drop_side_effect_free(compressor, first_in_statement); - return make_sequence(this, [ left, right ]); + if (!left) return right; + return make_sequence(this, [ left, right.drop_side_effect_free(compressor) ]); } }); def(AST_Call, function(compressor, first_in_statement) { @@ -4666,12 +4666,30 @@ merge(Compressor.prototype, { if (compressor.option("unsafe")) { if (is_undeclared_ref(exp)) switch (exp.name) { case "Array": - if (self.args.length != 1) { - return make_node(AST_Array, self, { - elements: self.args - }).optimize(compressor); + if (self.args.length == 1) { + var first = self.args[0]; + if (first instanceof AST_Number) try { + var length = first.getValue(); + if (length > 6) break; + var elements = Array(length); + for (var i = 0; i < length; i++) elements[i] = make_node(AST_Hole, self); + return make_node(AST_Array, self, { + elements: elements + }); + } catch (ex) { + compressor.warn("Invalid array length: {length} [{file}:{line},{col}]", { + length: length, + file: self.start.file, + line: self.start.line, + col: self.start.col + }); + break; + } + if (!first.is_boolean(compressor) && !first.is_string(compressor)) break; } - break; + return make_node(AST_Array, self, { + elements: self.args + }); case "Object": if (self.args.length == 0) { return make_node(AST_Object, self, { diff --git a/test/compress/arrays.js b/test/compress/arrays.js index 36292206..497e96c4 100644 --- a/test/compress/arrays.js +++ b/test/compress/arrays.js @@ -239,3 +239,113 @@ index_length: { } expect_stdout: "1 2" } + +constructor_bad: { + options = { + unsafe: true + } + input: { + try { + Array(NaN); + console.log("FAIL1"); + } catch (ex) { + try { + new Array(NaN); + console.log("FAIL2"); + } catch (ex) { + console.log("PASS"); + } + } + try { + Array(3.14); + console.log("FAIL1"); + } catch (ex) { + try { + new Array(3.14); + console.log("FAIL2"); + } catch (ex) { + console.log("PASS"); + } + } + } + expect: { + try { + Array(NaN); + console.log("FAIL1"); + } catch (ex) { + try { + Array(NaN); + console.log("FAIL2"); + } catch (ex) { + console.log("PASS"); + } + } + try { + Array(3.14); + console.log("FAIL1"); + } catch (ex) { + try { + Array(3.14); + console.log("FAIL2"); + } catch (ex) { + console.log("PASS"); + } + } + } + expect_stdout: [ + "PASS", + "PASS", + ] + expect_warnings: [ + "WARN: Invalid array length: 3.14 [test/compress/arrays.js:13,12]", + "WARN: Invalid array length: 3.14 [test/compress/arrays.js:17,16]", + ] +} + +constructor_good: { + options = { + unsafe: true + } + input: { + console.log(Array()); + console.log(Array(0)); + console.log(Array(1)); + console.log(Array(6)); + console.log(Array(7)); + console.log(Array(1, 2)); + console.log(Array(false)); + console.log(Array("foo")); + console.log(Array(Array)); + console.log(new Array()); + console.log(new Array(0)); + console.log(new Array(1)); + console.log(new Array(6)); + console.log(new Array(7)); + console.log(new Array(1, 2)); + console.log(new Array(false)); + console.log(new Array("foo")); + console.log(new Array(Array)); + } + expect: { + console.log([]); + console.log([]); + console.log([,]); + console.log([,,,,,,]); + console.log(Array(7)); + console.log([ 1, 2 ]); + console.log([ false ]); + console.log([ "foo" ]); + console.log(Array(Array)); + console.log([]); + console.log([]); + console.log([,]); + console.log([,,,,,,]); + console.log(Array(7)); + console.log([ 1, 2 ]); + console.log([ false ]); + console.log([ "foo" ]); + console.log(Array(Array)); + } + expect_stdout: true + expect_warnings: [] +} diff --git a/test/compress/reduce_vars.js b/test/compress/reduce_vars.js index 27e53452..fb5038b5 100644 --- a/test/compress/reduce_vars.js +++ b/test/compress/reduce_vars.js @@ -6716,3 +6716,24 @@ issue_3297: { } expect_stdout: "true" } + +drop_side_effect_free: { + options = { + collapse_vars: true, + evaluate: true, + reduce_vars: true, + side_effects: true, + toplevel: true, + } + input: { + var a = 123; + "" + (a && (a.b = 0) || a); + console.log(a); + } + expect: { + var a = 123; + a.b = 0; + console.log(a); + } + expect_stdout: "123" +} -- 2.34.1