aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Lam S.L <alexlamsl@gmail.com>2017-04-05 21:06:42 +0800
committerGitHub <noreply@github.com>2017-04-05 21:06:42 +0800
commitff289b90a92739641dcb7fc7f6c8ecf8ee74d15f (patch)
tree5fdcaa56885b3a20659009a854329b5d256f8fa3
parent9b6bc67c3393507d0621eb3debbe8845b0eff52d (diff)
downloadtracifyjs-ff289b90a92739641dcb7fc7f6c8ecf8ee74d15f.tar.gz
tracifyjs-ff289b90a92739641dcb7fc7f6c8ecf8ee74d15f.zip
implement delayed resolution for `reduce_vars` (#1788)
Although it would be nice to enforce `AST_Node` cloning during transformation, that ship has sailed a long time ago. We now get the assigned value when resolving `AST_SymbolRef` instead of `reset_opt_flags()`, which has the added advantage of improved compressor efficiency. fixes #1787
-rw-r--r--lib/compress.js50
-rw-r--r--test/compress/issue-1609.js7
-rw-r--r--test/compress/issue-1787.js19
3 files changed, 53 insertions, 23 deletions
diff --git a/lib/compress.js b/lib/compress.js
index 14083fe8..ef7f0441 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -273,7 +273,7 @@ merge(Compressor.prototype, {
var d = node.definition();
d.references.push(node);
if (d.fixed === undefined || !is_safe(d)
- || is_modified(node, 0, d.fixed instanceof AST_Lambda)) {
+ || is_modified(node, 0, node.fixed_value() instanceof AST_Lambda)) {
d.fixed = false;
}
}
@@ -283,7 +283,9 @@ merge(Compressor.prototype, {
if (node instanceof AST_VarDef) {
var d = node.name.definition();
if (d.fixed == null) {
- d.fixed = node.value;
+ d.fixed = node.value && function() {
+ return node.value;
+ };
mark_as_safe(d);
} else if (node.value) {
d.fixed = false;
@@ -314,7 +316,9 @@ merge(Compressor.prototype, {
// So existing transformation rules can work on them.
node.argnames.forEach(function(arg, i) {
var d = arg.definition();
- d.fixed = iife.args[i] || make_node(AST_Undefined, iife);
+ d.fixed = function() {
+ return iife.args[i] || make_node(AST_Undefined, iife);
+ };
mark_as_safe(d);
});
}
@@ -409,6 +413,12 @@ merge(Compressor.prototype, {
}
});
+ AST_SymbolRef.DEFMETHOD("fixed_value", function() {
+ var fixed = this.definition().fixed;
+ if (!fixed || fixed instanceof AST_Node) return fixed;
+ return fixed();
+ });
+
function find_variable(compressor, name) {
var scope, i = 0;
while (scope = compressor.parent(i++)) {
@@ -1487,15 +1497,15 @@ merge(Compressor.prototype, {
if (this._evaluating) throw def;
this._evaluating = true;
try {
- var d = this.definition();
- if (compressor.option("reduce_vars") && d.fixed) {
+ var fixed = this.fixed_value();
+ if (compressor.option("reduce_vars") && fixed) {
if (compressor.option("unsafe")) {
- if (!HOP(d.fixed, "_evaluated")) {
- d.fixed._evaluated = ev(d.fixed, compressor);
+ if (!HOP(fixed, "_evaluated")) {
+ fixed._evaluated = ev(fixed, compressor);
}
- return d.fixed._evaluated;
+ return fixed._evaluated;
}
- return ev(d.fixed, compressor);
+ return ev(fixed, compressor);
}
} finally {
this._evaluating = false;
@@ -2689,11 +2699,12 @@ merge(Compressor.prototype, {
if (compressor.option("reduce_vars")
&& exp instanceof AST_SymbolRef) {
var def = exp.definition();
- if (def.fixed instanceof AST_Defun) {
- def.fixed = make_node(AST_Function, def.fixed, def.fixed).clone(true);
+ var fixed = exp.fixed_value();
+ if (fixed instanceof AST_Defun) {
+ def.fixed = fixed = make_node(AST_Function, fixed, fixed).clone(true);
}
- if (def.fixed instanceof AST_Function) {
- exp = def.fixed;
+ if (fixed instanceof AST_Function) {
+ exp = fixed;
if (compressor.option("unused")
&& def.references.length == 1
&& !(def.scope.uses_arguments
@@ -3080,7 +3091,7 @@ merge(Compressor.prototype, {
&& (e.operator == "*" || e.operator == "/" || e.operator == "%")) {
self.expression = e.left;
e.left = self;
- return e.optimize(compressor);
+ return e;
}
// avoids infinite recursion of numerals
if (self.operator != "-"
@@ -3511,12 +3522,13 @@ merge(Compressor.prototype, {
}
if (compressor.option("evaluate") && compressor.option("reduce_vars")) {
var d = self.definition();
- if (d.fixed) {
+ var fixed = self.fixed_value();
+ if (fixed) {
if (d.should_replace === undefined) {
- var init = d.fixed.evaluate(compressor);
- if (init !== d.fixed) {
- init = make_node_from_constant(init, d.fixed).optimize(compressor);
- init = best_of_expression(init, d.fixed);
+ var init = fixed.evaluate(compressor);
+ if (init !== fixed) {
+ init = make_node_from_constant(init, fixed).optimize(compressor);
+ init = best_of_expression(init, fixed);
var value = init.print_to_string().length;
var name = d.name.length;
var freq = d.references.length;
diff --git a/test/compress/issue-1609.js b/test/compress/issue-1609.js
index 577a3ee1..da4b54a2 100644
--- a/test/compress/issue-1609.js
+++ b/test/compress/issue-1609.js
@@ -45,11 +45,10 @@ chained_evaluation_2: {
}
expect: {
(function() {
- var a = "long piece of string";
(function() {
- var c;
- c = f(a);
- c.bar = a;
+ var c, b = "long piece of string";
+ c = f(b);
+ c.bar = b;
})();
})();
}
diff --git a/test/compress/issue-1787.js b/test/compress/issue-1787.js
new file mode 100644
index 00000000..43d1f1be
--- /dev/null
+++ b/test/compress/issue-1787.js
@@ -0,0 +1,19 @@
+unary_prefix: {
+ options = {
+ evaluate: true,
+ reduce_vars: true,
+ unused: true,
+ }
+ input: {
+ console.log(function() {
+ var x = -(2 / 3);
+ return x;
+ }());
+ }
+ expect: {
+ console.log(function() {
+ return -2 / 3;
+ }());
+ }
+ expect_stdout: true
+}