aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Lam S.L <alexlamsl@gmail.com>2020-05-29 10:48:26 +0100
committerGitHub <noreply@github.com>2020-05-29 17:48:26 +0800
commit60c0bc1e6b1db1a7288c7924231b28a0e9f35cff (patch)
treeaf5f69f9352025975b50d35df8c17967ef22ad1b
parent6a5c63e1e324ba502b060911d54825a93e437da4 (diff)
downloadtracifyjs-60c0bc1e6b1db1a7288c7924231b28a0e9f35cff.tar.gz
tracifyjs-60c0bc1e6b1db1a7288c7924231b28a0e9f35cff.zip
fix corner case in `evaluate` (#3934)
fixes #3933
-rw-r--r--lib/compress.js95
-rw-r--r--test/compress/collapse_vars.js6
-rw-r--r--test/compress/dead-code.js2
-rw-r--r--test/compress/evaluate.js114
4 files changed, 172 insertions, 45 deletions
diff --git a/lib/compress.js b/lib/compress.js
index daf60ee8..b82ac811 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -3288,15 +3288,18 @@ merge(Compressor.prototype, {
var lhs = this.left;
if (!ignore_side_effects) {
if (!(lhs instanceof AST_SymbolRef)) return this;
- if (!HOP(lhs, "_eval") && !lhs.fixed) return this;
- var def = lhs.definition();
- if (def.undeclared) return this;
- if (def.last_ref !== lhs) return this;
- if (def.single_use == "m") return this;
+ if (!HOP(lhs, "_eval")) {
+ if (!lhs.fixed) return this;
+ var def = lhs.definition();
+ if (!def.fixed) return this;
+ if (def.undeclared) return this;
+ if (def.last_ref !== lhs) return this;
+ if (def.single_use == "m") return this;
+ }
}
var op = this.operator;
var node;
- if (HOP(lhs, "_eval") || !lhs.fixed) {
+ if (HOP(lhs, "_eval") || !(lhs instanceof AST_SymbolRef) || !lhs.fixed_value()) {
node = op == "=" ? this.right : make_node(AST_Binary, this, {
operator: op.slice(0, -1),
left: lhs,
@@ -3356,7 +3359,7 @@ merge(Compressor.prototype, {
key = key._eval(compressor, ignore_side_effects, cached, depth);
if (key === prop.key) return this;
}
- if (typeof Object.prototype[key] === 'function') {
+ if (typeof Object.prototype[key] === "function") {
return this;
}
if (prop.value instanceof AST_Function) continue;
@@ -3372,7 +3375,7 @@ merge(Compressor.prototype, {
var e = this.expression;
var op = this.operator;
// Function would be evaluated to an array and so typeof would
- // incorrectly return 'object'. Hence making is a special case.
+ // incorrectly return "object". Hence making is a special case.
if (compressor.option("typeofs")
&& op == "typeof"
&& (e instanceof AST_Lambda
@@ -3400,7 +3403,11 @@ merge(Compressor.prototype, {
case "++":
case "--":
if (!(e instanceof AST_SymbolRef)) return this;
- if (!ignore_side_effects && e.definition().last_ref !== e) return this;
+ if (!ignore_side_effects) {
+ var def = e.definition();
+ if (def.undeclared) return this;
+ if (def.last_ref !== e) return this;
+ }
if (HOP(e, "_eval")) v = +(op[0] + 1) + +v;
modified(e);
return v;
@@ -3409,8 +3416,17 @@ merge(Compressor.prototype, {
});
def(AST_UnaryPostfix, function(compressor, ignore_side_effects, cached, depth) {
var e = this.expression;
- if (!e.fixed) return this;
- if (!ignore_side_effects && e.definition().last_ref !== e) return this;
+ if (!(e instanceof AST_SymbolRef)) {
+ if (!ignore_side_effects) return this;
+ } else if (!HOP(e, "_eval")) {
+ if (!e.fixed) return this;
+ if (!ignore_side_effects) {
+ var def = e.definition();
+ if (!def.fixed) return this;
+ if (def.undeclared) return this;
+ if (def.last_ref !== e) return this;
+ }
+ }
var v = e._eval(compressor, ignore_side_effects, cached, depth + 1);
if (v === e) return this;
modified(e);
@@ -7835,34 +7851,35 @@ merge(Compressor.prototype, {
var seq = self.lift_sequences(compressor);
if (seq !== self) return seq.optimize(compressor);
}
- if (!compressor.option("assignments")) return self;
- if (self.operator == "=" && self.left instanceof AST_SymbolRef && self.right instanceof AST_Binary) {
- // x = expr1 OP expr2
- if (self.right.left instanceof AST_SymbolRef
- && self.right.left.name == self.left.name
- && ASSIGN_OPS[self.right.operator]) {
- // x = x - 2 => x -= 2
- self.operator = self.right.operator + "=";
- self.right = self.right.right;
- }
- else if (self.right.right instanceof AST_SymbolRef
- && self.right.right.name == self.left.name
- && ASSIGN_OPS_COMMUTATIVE[self.right.operator]
- && !self.right.left.has_side_effects(compressor)) {
- // x = 2 & x => x &= 2
- self.operator = self.right.operator + "=";
- self.right = self.right.left;
- }
- }
- if ((self.operator == "-=" || self.operator == "+="
- && (self.left.is_boolean(compressor) || self.left.is_number(compressor)))
- && self.right instanceof AST_Number
- && self.right.value == 1) {
- var op = self.operator.slice(0, -1);
- return make_node(AST_UnaryPrefix, self, {
- operator: op + op,
- expression: self.left
- });
+ if (compressor.option("assignments")) {
+ if (self.operator == "=" && self.left instanceof AST_SymbolRef && self.right instanceof AST_Binary) {
+ // x = expr1 OP expr2
+ if (self.right.left instanceof AST_SymbolRef
+ && self.right.left.name == self.left.name
+ && ASSIGN_OPS[self.right.operator]) {
+ // x = x - 2 => x -= 2
+ self.operator = self.right.operator + "=";
+ self.right = self.right.right;
+ }
+ else if (self.right.right instanceof AST_SymbolRef
+ && self.right.right.name == self.left.name
+ && ASSIGN_OPS_COMMUTATIVE[self.right.operator]
+ && !self.right.left.has_side_effects(compressor)) {
+ // x = 2 & x => x &= 2
+ self.operator = self.right.operator + "=";
+ self.right = self.right.left;
+ }
+ }
+ if ((self.operator == "-=" || self.operator == "+="
+ && (self.left.is_boolean(compressor) || self.left.is_number(compressor)))
+ && self.right instanceof AST_Number
+ && self.right.value == 1) {
+ var op = self.operator.slice(0, -1);
+ return make_node(AST_UnaryPrefix, self, {
+ operator: op + op,
+ expression: self.left
+ });
+ }
}
return try_evaluate(compressor, self);
diff --git a/test/compress/collapse_vars.js b/test/compress/collapse_vars.js
index 82fb057e..6244e03f 100644
--- a/test/compress/collapse_vars.js
+++ b/test/compress/collapse_vars.js
@@ -917,7 +917,7 @@ collapse_vars_lvalues_drop_assign: {
}
}
-collapse_vars_misc1: {
+collapse_vars_misc: {
options = {
booleans: true,
collapse_vars: true,
@@ -971,8 +971,8 @@ collapse_vars_misc1: {
function f7() { var b = window.a * window.z; return b + b }
function f8() { var b = window.a * window.z; return b + (5 + b) }
function f9() { var b = window.a * window.z; return bar() || b }
- function f10(x) { var a = 5; return a += 3; }
- function f11(x) { var a = 5; return a += 2; }
+ function f10(x) { return 8; }
+ function f11(x) { return 7; }
}
}
diff --git a/test/compress/dead-code.js b/test/compress/dead-code.js
index 795d1f7c..22eb0d91 100644
--- a/test/compress/dead-code.js
+++ b/test/compress/dead-code.js
@@ -236,7 +236,7 @@ collapse_vars_lvalues_drop_assign: {
}
}
-collapse_vars_misc1: {
+collapse_vars_misc: {
options = {
collapse_vars: true,
dead_code: true,
diff --git a/test/compress/evaluate.js b/test/compress/evaluate.js
index 868ad154..a7b5a4a5 100644
--- a/test/compress/evaluate.js
+++ b/test/compress/evaluate.js
@@ -2503,7 +2503,7 @@ inlined_increment_prefix: {
expect: {
var a = 0;
void ++a;
- console.log(a += 0);
+ console.log(1);
}
expect_stdout: "1"
}
@@ -2525,7 +2525,7 @@ inlined_increment_postfix: {
expect: {
var a = 0;
void a++;
- console.log(a += 0);
+ console.log(1);
}
expect_stdout: "1"
}
@@ -2544,3 +2544,113 @@ compound_assignment_to_property: {
}
expect_stdout: "PASS"
}
+
+issue_2208_assign: {
+ options = {
+ evaluate: true,
+ reduce_vars: true,
+ toplevel: true,
+ }
+ input: {
+ a = 42;
+ console.log({
+ p: function() {
+ return function() {
+ return this.a;
+ }();
+ }
+ }.p());
+ }
+ expect: {
+ a = 42;
+ console.log({
+ p: function() {
+ return function() {
+ return this.a;
+ }();
+ }
+ }.p());
+ }
+ expect_stdout: "42"
+}
+
+issue_2208_postfix: {
+ options = {
+ evaluate: true,
+ reduce_vars: true,
+ toplevel: true,
+ }
+ input: {
+ a = 41;
+ a++;
+ console.log({
+ p: function() {
+ return function() {
+ return this.a;
+ }();
+ }
+ }.p());
+ }
+ expect: {
+ a = 41;
+ a++;
+ console.log({
+ p: function() {
+ return function() {
+ return this.a;
+ }();
+ }
+ }.p());
+ }
+ expect_stdout: "42"
+}
+
+issue_2208_prefix: {
+ options = {
+ evaluate: true,
+ reduce_vars: true,
+ toplevel: true,
+ }
+ input: {
+ a = 43;
+ --a;
+ console.log({
+ p: function() {
+ return function() {
+ return this.a;
+ }();
+ }
+ }.p());
+ }
+ expect: {
+ a = 43;
+ --a;
+ console.log({
+ p: function() {
+ return function() {
+ return this.a;
+ }();
+ }
+ }.p());
+ }
+ expect_stdout: "42"
+}
+
+issue_3933: {
+ options = {
+ evaluate: true,
+ reduce_vars: true,
+ unused: true,
+ }
+ input: {
+ (function(a, b) {
+ a && (b ^= 1) && console.log("PASS");
+ })(1);
+ }
+ expect: {
+ (function(a, b) {
+ 1, (b ^= 1), console.log("PASS");
+ })();
+ }
+ expect_stdout: "PASS"
+}