@@ -2485,6 +2485,60 @@ merge(Compressor.prototype, {
|
|||||||
node.DEFMETHOD("is_truthy", func);
|
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()
|
// may_throw_on_access()
|
||||||
// returns true if this node may be null, undefined or contain `AST_Accessor`
|
// returns true if this node may be null, undefined or contain `AST_Accessor`
|
||||||
(function(def) {
|
(function(def) {
|
||||||
@@ -6111,7 +6165,6 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
var indexFns = makePredicate("indexOf lastIndexOf");
|
var indexFns = makePredicate("indexOf lastIndexOf");
|
||||||
var minus_zero_op = makePredicate("- * / %");
|
|
||||||
var commutativeOperators = makePredicate("== === != !== * & | ^");
|
var commutativeOperators = makePredicate("== === != !== * & | ^");
|
||||||
function is_object(node) {
|
function is_object(node) {
|
||||||
return node instanceof AST_Array
|
return node instanceof AST_Array
|
||||||
@@ -6533,6 +6586,7 @@ merge(Compressor.prototype, {
|
|||||||
&& (self.operator != "+"
|
&& (self.operator != "+"
|
||||||
|| self.right.left.is_boolean(compressor)
|
|| self.right.left.is_boolean(compressor)
|
||||||
|| self.right.left.is_number(compressor))
|
|| self.right.left.is_number(compressor))
|
||||||
|
&& (self.operator != "-" || !self.left.is_negative_zero())
|
||||||
&& (self.right.left.is_constant_expression()
|
&& (self.right.left.is_constant_expression()
|
||||||
|| !self.right.right.has_side_effects(compressor))) {
|
|| !self.right.right.has_side_effects(compressor))) {
|
||||||
self = make_node(AST_Binary, self, {
|
self = make_node(AST_Binary, self, {
|
||||||
@@ -6567,9 +6621,14 @@ merge(Compressor.prototype, {
|
|||||||
self = make_binary(self, self.left.operator, lhs, self.left.right);
|
self = make_binary(self, self.left.operator, lhs, self.left.right);
|
||||||
} else if (self.left.right instanceof AST_Constant) {
|
} 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);
|
var rhs = make_binary(self.left, align(self.left.operator, self.operator), self.left.right, self.right, self.left.right.start, self.right.end);
|
||||||
|
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);
|
self = make_binary(self, self.left.operator, self.left.left, rhs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (self.left instanceof AST_Number && !self.right.is_constant()) switch (self.operator) {
|
if (self.left instanceof AST_Number && !self.right.is_constant()) switch (self.operator) {
|
||||||
@@ -6580,7 +6639,7 @@ merge(Compressor.prototype, {
|
|||||||
operator: "+",
|
operator: "+",
|
||||||
expression: self.right
|
expression: self.right
|
||||||
}).optimize(compressor);
|
}).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;
|
break;
|
||||||
// 1 * n => n
|
// 1 * n => n
|
||||||
@@ -6601,7 +6660,7 @@ merge(Compressor.prototype, {
|
|||||||
operator: "+",
|
operator: "+",
|
||||||
expression: self.left
|
expression: self.left
|
||||||
}).optimize(compressor);
|
}).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;
|
break;
|
||||||
// n - 0 => n
|
// n - 0 => n
|
||||||
@@ -6756,20 +6815,6 @@ merge(Compressor.prototype, {
|
|||||||
&& self.left.expression instanceof AST_Number && self.left.expression.value == 1;
|
&& 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) {
|
function recursive_ref(compressor, def) {
|
||||||
|
|||||||
@@ -1075,11 +1075,11 @@ issue_3653: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
console.log(0 - (console && 0));
|
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 - (0 - (console && 0)));
|
||||||
console.log(0 - (console && 0));
|
console.log(0 - (console && 0));
|
||||||
console.log(1 / (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));
|
console.log(0 - (console && 0));
|
||||||
console.log(0 - (console && 0));
|
console.log(0 - (console && 0));
|
||||||
@@ -1167,3 +1167,51 @@ issue_3676_2: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "NaN"
|
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"
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user