Skip to content

Commit

Permalink
fix corner case in unsafe_math (#3683)
Browse files Browse the repository at this point in the history
fixes #3682
  • Loading branch information
alexlamsl committed Jan 14, 2020
1 parent 5beb7e4 commit 91d87ae
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 20 deletions.
81 changes: 63 additions & 18 deletions lib/compress.js
Expand Up @@ -2485,6 +2485,60 @@ merge(Compressor.prototype, {
node.DEFMETHOD("is_truthy", func);
});

// is_negative_zero()
// return true if the node may represent -0
(function(def) {
def(AST_Node, return_true);
def(AST_Array, return_false);
function binary(op, left, right) {
switch (op) {
case "-":
return left.is_negative_zero()
&& (!(right instanceof AST_Constant) || right.value == 0);
case "&&":
case "||":
case "*":
return left.is_negative_zero() || right.is_negative_zero();
case "/":
case "%":
return left.is_negative_zero();
default:
return false;
}
}
def(AST_Assign, function() {
var op = this.operator;
if (op == "=") return this.right.is_negative_zero();
return binary(op.slice(0, -1), this.left, this.right);
});
def(AST_Binary, function() {
return binary(this.operator, this.left, this.right);
});
def(AST_Constant, function() {
return this.value == 0 && 1 / this.value < 0;
});
def(AST_Lambda, return_false);
def(AST_Object, return_false);
def(AST_RegExp, return_false);
def(AST_Sequence, function() {
return this.tail_node().is_negative_zero();
});
def(AST_SymbolRef, function() {
var fixed = this.fixed_value();
if (!fixed) return true;
this.is_negative_zero = return_true;
var result = fixed.is_negative_zero();
delete this.is_negative_zero;
return result;
});
def(AST_UnaryPrefix, function() {
return this.operator == "+" && this.expression.is_negative_zero()
|| this.operator == "-";
});
})(function(node, func) {
node.DEFMETHOD("is_negative_zero", func);
});

// may_throw_on_access()
// returns true if this node may be null, undefined or contain `AST_Accessor`
(function(def) {
Expand Down Expand Up @@ -6111,7 +6165,6 @@ merge(Compressor.prototype, {
});

var indexFns = makePredicate("indexOf lastIndexOf");
var minus_zero_op = makePredicate("- * / %");
var commutativeOperators = makePredicate("== === != !== * & | ^");
function is_object(node) {
return node instanceof AST_Array
Expand Down Expand Up @@ -6533,6 +6586,7 @@ merge(Compressor.prototype, {
&& (self.operator != "+"
|| self.right.left.is_boolean(compressor)
|| self.right.left.is_number(compressor))
&& (self.operator != "-" || !self.left.is_negative_zero())
&& (self.right.left.is_constant_expression()
|| !self.right.right.has_side_effects(compressor))) {
self = make_node(AST_Binary, self, {
Expand Down Expand Up @@ -6567,7 +6621,12 @@ merge(Compressor.prototype, {
self = make_binary(self, self.left.operator, lhs, self.left.right);
} else if (self.left.right instanceof AST_Constant) {
var rhs = make_binary(self.left, align(self.left.operator, self.operator), self.left.right, self.right, self.left.right.start, self.right.end);
self = make_binary(self, self.left.operator, self.left.left, rhs);
if (self.left.operator != "-"
|| !self.right.value
|| rhs.evaluate(compressor)
|| !self.left.left.is_negative_zero()) {
self = make_binary(self, self.left.operator, self.left.left, rhs);
}
}
}
break;
Expand All @@ -6580,7 +6639,7 @@ merge(Compressor.prototype, {
operator: "+",
expression: self.right
}).optimize(compressor);
if (self.right.is_number(compressor) && !may_be_minus_zero(self.right)) return self.right;
if (self.right.is_number(compressor) && !self.right.is_negative_zero()) return self.right;
}
break;
// 1 * n => n
Expand All @@ -6601,7 +6660,7 @@ merge(Compressor.prototype, {
operator: "+",
expression: self.left
}).optimize(compressor);
if (self.left.is_number(compressor) && !may_be_minus_zero(self.left)) return self.left;
if (self.left.is_number(compressor) && !self.left.is_negative_zero()) return self.left;
}
break;
// n - 0 => n
Expand Down Expand Up @@ -6756,20 +6815,6 @@ merge(Compressor.prototype, {
&& self.left.expression instanceof AST_Number && self.left.expression.value == 1;
}
}

function may_be_minus_zero(node) {
var ev = node.evaluate(compressor);
if (ev instanceof AST_Node) {
var op = ev.operator;
if (!op) return true;
if (ev instanceof AST_Assign) {
if (op == "=") return may_be_minus_zero(ev.right);
op = op.slice(0, -1);
}
if (minus_zero_op[op]) return true;
if (ev instanceof AST_UnaryPrefix && op == "+") return true;
} else if (ev == 0 && 1 / ev < 0) return true;
}
});

function recursive_ref(compressor, def) {
Expand Down
52 changes: 50 additions & 2 deletions test/compress/numbers.js
Expand Up @@ -1075,11 +1075,11 @@ issue_3653: {
}
expect: {
console.log(0 - (console && 0));
console.log(0 - (console && 0) + 0);
console.log(0 - (console && 0));
console.log(0 - (0 - (console && 0)));
console.log(0 - (console && 0));
console.log(1 / (0 - (console && 0)));
console.log(0 - (console && 0) + 0);
console.log(0 - (console && 0));
console.log(0 - (console && 0));
console.log(0 - (console && 0));
console.log(0 - (console && 0));
Expand Down Expand Up @@ -1167,3 +1167,51 @@ issue_3676_2: {
}
expect_stdout: "NaN"
}

issue_3682_1: {
options = {
evaluate: true,
unsafe_math: true,
}
input: {
var a = -0;
console.log(1 / (a - 1 + 1));
}
expect: {
var a = -0;
console.log(1 / (a - 1 + 1));
}
expect_stdout: "Infinity"
}

issue_3682_2: {
options = {
evaluate: true,
unsafe_math: true,
}
input: {
var a = -0, b = 1;
console.log(1 / (a - (b - b)));
}
expect: {
var a = -0, b = 1;
console.log(1 / (a - (b - b)));
}
expect_stdout: "-Infinity"
}

issue_3682_3: {
options = {
evaluate: true,
unsafe_math: true,
}
input: {
var a = -0, b = 1, c = -1;
console.log(1 / (a - (+b + +c)));
}
expect: {
var a = -0, b = 1, c = -1;
console.log(1 / (a - (+b + +c)));
}
expect_stdout: "-Infinity"
}

0 comments on commit 91d87ae

Please sign in to comment.