From 27eedbc302dea6a2af558bbf6bc8865fd2410837 Mon Sep 17 00:00:00 2001 From: Richard van Velzen Date: Tue, 17 May 2016 22:34:38 +0200 Subject: [PATCH 1/3] Never produce -0 when evaluating expressions (like -"") Fix for #1085. The major case was already there, but more expressions can result in -0. --- lib/compress.js | 6 +++--- test/compress/evaluate.js | 9 +++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 test/compress/evaluate.js diff --git a/lib/compress.js b/lib/compress.js index 6436796f..e8c42c04 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -1029,9 +1029,9 @@ merge(Compressor.prototype, { case "void": return void ev(e, compressor); case "~": return ~ev(e, compressor); case "-": - e = ev(e, compressor); - if (e === 0) throw def; - return -e; + e = -ev(e, compressor); + if (e === -0) throw def; + return e; case "+": return +ev(e, compressor); } throw def; diff --git a/test/compress/evaluate.js b/test/compress/evaluate.js new file mode 100644 index 00000000..9aa6b3d3 --- /dev/null +++ b/test/compress/evaluate.js @@ -0,0 +1,9 @@ +negative_zero: { + options = { evaluate: true } + input: { + assert.sameValue(-"", -0, '-""'); + } + expect: { + assert.sameValue(-"", -0, '-""'); + } +} From bc49dfd27a800cfa2070464c236a1d56ed30bfca Mon Sep 17 00:00:00 2001 From: Richard van Velzen Date: Wed, 18 May 2016 18:49:55 +0200 Subject: [PATCH 2/3] Completely allow evaluating -0 --- lib/compress.js | 20 +++++++++++++------- test/compress/evaluate.js | 34 ++++++++++++++++++++++++++++++++-- 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/lib/compress.js b/lib/compress.js index e8c42c04..419c6a25 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -183,9 +183,18 @@ merge(Compressor.prototype, { value: val }).optimize(compressor); case "number": - return make_node(isNaN(val) ? AST_NaN : AST_Number, orig, { - value: val - }).optimize(compressor); + if (isNaN(val)) { + return make_node(AST_NaN, orig); + } + + if ((1 / val) < 0) { + return make_node(AST_UnaryPrefix, orig, { + operator: "-", + expression: make_node(AST_Number, null, { value: -val }) + }); + } + + return make_node(AST_Number, orig, { value: val }).optimize(compressor); case "boolean": return make_node(val ? AST_True : AST_False, orig).optimize(compressor); case "undefined": @@ -1028,10 +1037,7 @@ merge(Compressor.prototype, { return typeof e; case "void": return void ev(e, compressor); case "~": return ~ev(e, compressor); - case "-": - e = -ev(e, compressor); - if (e === -0) throw def; - return e; + case "-": return -ev(e, compressor); case "+": return +ev(e, compressor); } throw def; diff --git a/test/compress/evaluate.js b/test/compress/evaluate.js index 9aa6b3d3..d27582f3 100644 --- a/test/compress/evaluate.js +++ b/test/compress/evaluate.js @@ -1,9 +1,39 @@ negative_zero: { options = { evaluate: true } input: { - assert.sameValue(-"", -0, '-""'); + console.log( + -"", + - -"", + 1 / (-0), + 1 / (-"") + ); } expect: { - assert.sameValue(-"", -0, '-""'); + console.log( + -0, + 0, + 1 / (-0), + 1 / (-0) + ); + } +} + +positive_zero: { + options = { evaluate: true } + input: { + console.log( + +"", + + -"", + 1 / (+0), + 1 / (+"") + ); + } + expect: { + console.log( + 0, + -0, + 1 / (0), + 1 / (0) + ); } } From 1e390269d47e2a555f511556590d826938d572f9 Mon Sep 17 00:00:00 2001 From: kzc Date: Sun, 22 May 2016 11:35:41 -0400 Subject: [PATCH 3/3] Optimize if_return for single if/return cases. Fixes #1089 --- lib/compress.js | 15 ++- test/compress/if_return.js | 207 +++++++++++++++++++++++++++++++++++++ 2 files changed, 221 insertions(+), 1 deletion(-) create mode 100644 test/compress/if_return.js diff --git a/lib/compress.js b/lib/compress.js index 419c6a25..e78ee32b 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -535,6 +535,7 @@ merge(Compressor.prototype, { function handle_if_return(statements, compressor) { var self = compressor.self(); + var multiple_if_returns = has_multiple_if_returns(statements); var in_lambda = self instanceof AST_Lambda; var ret = []; loop: for (var i = statements.length; --i >= 0;) { @@ -572,7 +573,8 @@ merge(Compressor.prototype, { } //--- // if (foo()) return x; [ return ; ] ==> return foo() ? x : undefined; - if ((ret.length == 0 || ret[0] instanceof AST_Return) && stat.body.value && !stat.alternative && in_lambda) { + if (multiple_if_returns && (ret.length == 0 || ret[0] instanceof AST_Return) + && stat.body.value && !stat.alternative && in_lambda) { CHANGED = true; stat = stat.clone(); stat.alternative = ret[0] || make_node(AST_Return, stat, { @@ -664,6 +666,17 @@ merge(Compressor.prototype, { } } return ret; + + function has_multiple_if_returns(statements) { + var n = 0; + for (var i = statements.length; --i >= 0;) { + var stat = statements[i]; + if (stat instanceof AST_If && stat.body instanceof AST_Return) { + if (++n > 1) return true; + } + } + return false; + } }; function eliminate_dead_code(statements, compressor) { diff --git a/test/compress/if_return.js b/test/compress/if_return.js new file mode 100644 index 00000000..78a6e818 --- /dev/null +++ b/test/compress/if_return.js @@ -0,0 +1,207 @@ +if_return_1: { + options = { + if_return : true, + sequences : true, + conditionals : true, + comparisons : true, + evaluate : true, + booleans : true, + unused : true, + side_effects : true, + dead_code : true, + } + input: { + function f(x) { + if (x) { + return true; + } + } + } + expect: { + function f(x){if(x)return!0} + } +} + +if_return_2: { + options = { + if_return : true, + sequences : true, + conditionals : true, + comparisons : true, + evaluate : true, + booleans : true, + unused : true, + side_effects : true, + dead_code : true, + } + input: { + function f(x, y) { + if (x) + return 3; + if (y) + return c(); + } + } + expect: { + function f(x,y){return x?3:y?c():void 0} + } +} + +if_return_3: { + options = { + if_return : true, + sequences : true, + conditionals : true, + comparisons : true, + evaluate : true, + booleans : true, + unused : true, + side_effects : true, + dead_code : true, + } + input: { + function f(x) { + a(); + if (x) { + b(); + return false; + } + } + } + expect: { + function f(x){if(a(),x)return b(),!1} + } +} + +if_return_4: { + options = { + if_return : true, + sequences : true, + conditionals : true, + comparisons : true, + evaluate : true, + booleans : true, + unused : true, + side_effects : true, + dead_code : true, + } + input: { + function f(x, y) { + a(); + if (x) return 3; + b(); + if (y) return c(); + } + } + expect: { + function f(x,y){return a(),x?3:(b(),y?c():void 0)} + } +} + +if_return_5: { + options = { + if_return : true, + sequences : true, + conditionals : true, + comparisons : true, + evaluate : true, + booleans : true, + unused : true, + side_effects : true, + dead_code : true, + } + input: { + function f() { + if (x) + return; + return 7; + if (y) + return j; + } + } + expect: { + function f(){if(!x)return 7} + } +} + +if_return_6: { + options = { + if_return : true, + sequences : true, + conditionals : true, + comparisons : true, + evaluate : true, + booleans : true, + unused : true, + side_effects : true, + dead_code : true, + } + input: { + function f(x) { + return x ? true : void 0; + return y; + } + } + expect: { + // suboptimal + function f(x){return!!x||void 0} + } +} + +if_return_7: { + options = { + if_return : true, + sequences : true, + conditionals : true, + comparisons : true, + evaluate : true, + booleans : true, + unused : true, + side_effects : true, + dead_code : true, + } + input: { + function f(x) { + if (x) { + return true; + } + foo(); + bar(); + } + } + expect: { + // suboptimal + function f(x){return!!x||(foo(),void bar())} + } +} + +issue_1089: { + options = { + if_return : true, + sequences : true, + conditionals : true, + comparisons : true, + evaluate : true, + booleans : true, + unused : true, + side_effects : true, + dead_code : true, + } + input: { + function x() { + var f = document.getElementById("fname"); + if (f.files[0].size > 12345) { + alert("alert"); + f.focus(); + return false; + } + } + } + expect: { + function x() { + var f = document.getElementById("fname"); + if (f.files[0].size > 12345) + return alert("alert"), f.focus(), !1; + } + } +}