aboutsummaryrefslogtreecommitdiff
path: root/lib/compress.js
diff options
context:
space:
mode:
authorAlex Lam S.L <alexlamsl@gmail.com>2018-03-02 04:04:29 +0800
committerGitHub <noreply@github.com>2018-03-02 04:04:29 +0800
commit38f2b4579fc2c8f7fa4e31b544dc93be9dcb031e (patch)
tree89089eb4b03de1ee227d164d51278a2f156cf959 /lib/compress.js
parent56e2a369d0b522c315a3b146bdf7581d8e71d9cc (diff)
downloadtracifyjs-38f2b4579fc2c8f7fa4e31b544dc93be9dcb031e.tar.gz
tracifyjs-38f2b4579fc2c8f7fa4e31b544dc93be9dcb031e.zip
fix value reference caching in `evaluate` (#2969)
fixes #2968
Diffstat (limited to 'lib/compress.js')
-rw-r--r--lib/compress.js53
1 files changed, 29 insertions, 24 deletions
diff --git a/lib/compress.js b/lib/compress.js
index 504d270b..97e4c11d 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -2365,7 +2365,11 @@ merge(Compressor.prototype, {
// descendant of AST_Node.
AST_Node.DEFMETHOD("evaluate", function(compressor){
if (!compressor.option("evaluate")) return this;
- var val = this._eval(compressor, 1);
+ var cached = [];
+ var val = this._eval(compressor, cached, 1);
+ cached.forEach(function(node) {
+ delete node._eval;
+ });
if (!val || val instanceof RegExp) return val;
if (typeof val == "function" || typeof val == "object") return this;
return val;
@@ -2401,12 +2405,12 @@ merge(Compressor.prototype, {
}
return this;
});
- def(AST_Array, function(compressor, depth) {
+ def(AST_Array, function(compressor, cached, depth) {
if (compressor.option("unsafe")) {
var elements = [];
for (var i = 0, len = this.elements.length; i < len; i++) {
var element = this.elements[i];
- var value = element._eval(compressor, depth);
+ var value = element._eval(compressor, cached, depth);
if (element === value) return this;
elements.push(value);
}
@@ -2414,7 +2418,7 @@ merge(Compressor.prototype, {
}
return this;
});
- def(AST_Object, function(compressor, depth) {
+ def(AST_Object, function(compressor, cached, depth) {
if (compressor.option("unsafe")) {
var val = {};
for (var i = 0, len = this.properties.length; i < len; i++) {
@@ -2423,14 +2427,14 @@ merge(Compressor.prototype, {
if (key instanceof AST_Symbol) {
key = key.name;
} else if (key instanceof AST_Node) {
- key = key._eval(compressor, depth);
+ key = key._eval(compressor, cached, depth);
if (key === prop.key) return this;
}
if (typeof Object.prototype[key] === 'function') {
return this;
}
if (prop.value instanceof AST_Function) continue;
- val[key] = prop.value._eval(compressor, depth);
+ val[key] = prop.value._eval(compressor, cached, depth);
if (val[key] === prop.value) return this;
}
return val;
@@ -2438,7 +2442,7 @@ merge(Compressor.prototype, {
return this;
});
var non_converting_unary = makePredicate("! typeof void");
- def(AST_UnaryPrefix, function(compressor, depth) {
+ def(AST_UnaryPrefix, function(compressor, cached, depth) {
var e = this.expression;
// Function would be evaluated to an array and so typeof would
// incorrectly return 'object'. Hence making is a special case.
@@ -2450,7 +2454,7 @@ merge(Compressor.prototype, {
return typeof function(){};
}
if (!non_converting_unary(this.operator)) depth++;
- e = e._eval(compressor, depth);
+ e = e._eval(compressor, cached, depth);
if (e === this.expression) return this;
switch (this.operator) {
case "!": return !e;
@@ -2467,11 +2471,11 @@ merge(Compressor.prototype, {
return this;
});
var non_converting_binary = makePredicate("&& || === !==");
- def(AST_Binary, function(compressor, depth) {
+ def(AST_Binary, function(compressor, cached, depth) {
if (!non_converting_binary(this.operator)) depth++;
- var left = this.left._eval(compressor, depth);
+ var left = this.left._eval(compressor, cached, depth);
if (left === this.left) return this;
- var right = this.right._eval(compressor, depth);
+ var right = this.right._eval(compressor, cached, depth);
if (right === this.right) return this;
var result;
switch (this.operator) {
@@ -2505,27 +2509,28 @@ merge(Compressor.prototype, {
}
return result;
});
- def(AST_Conditional, function(compressor, depth) {
- var condition = this.condition._eval(compressor, depth);
+ def(AST_Conditional, function(compressor, cached, depth) {
+ var condition = this.condition._eval(compressor, cached, depth);
if (condition === this.condition) return this;
var node = condition ? this.consequent : this.alternative;
- var value = node._eval(compressor, depth);
+ var value = node._eval(compressor, cached, depth);
return value === node ? this : value;
});
- def(AST_SymbolRef, function(compressor, depth) {
+ def(AST_SymbolRef, function(compressor, cached, depth) {
var fixed = this.fixed_value();
if (!fixed) return this;
var value;
- if (HOP(fixed, "_eval")) {
+ if (cached.indexOf(fixed) >= 0) {
value = fixed._eval();
} else {
this._eval = return_this;
- value = fixed._eval(compressor, depth);
+ value = fixed._eval(compressor, cached, depth);
delete this._eval;
if (value === fixed) return this;
fixed._eval = function() {
return value;
};
+ cached.push(fixed);
}
if (value && typeof value == "object") {
var escaped = this.definition().escaped;
@@ -2560,11 +2565,11 @@ merge(Compressor.prototype, {
],
};
convert_to_predicate(static_values);
- def(AST_PropAccess, function(compressor, depth) {
+ def(AST_PropAccess, function(compressor, cached, depth) {
if (compressor.option("unsafe")) {
var key = this.property;
if (key instanceof AST_Node) {
- key = key._eval(compressor, depth);
+ key = key._eval(compressor, cached, depth);
if (key === this.property) return this;
}
var exp = this.expression;
@@ -2573,7 +2578,7 @@ merge(Compressor.prototype, {
if (!(static_values[exp.name] || return_false)(key)) return this;
val = global_objs[exp.name];
} else {
- val = exp._eval(compressor, depth + 1);
+ val = exp._eval(compressor, cached, depth + 1);
if (!val || val === exp || !HOP(val, key)) return this;
if (typeof val == "function") switch (key) {
case "name":
@@ -2588,12 +2593,12 @@ merge(Compressor.prototype, {
}
return this;
});
- def(AST_Call, function(compressor, depth) {
+ def(AST_Call, function(compressor, cached, depth) {
var exp = this.expression;
if (compressor.option("unsafe") && exp instanceof AST_PropAccess) {
var key = exp.property;
if (key instanceof AST_Node) {
- key = key._eval(compressor, depth);
+ key = key._eval(compressor, cached, depth);
if (key === exp.property) return this;
}
var val;
@@ -2602,13 +2607,13 @@ merge(Compressor.prototype, {
if (!(static_fns[e.name] || return_false)(key)) return this;
val = global_objs[e.name];
} else {
- val = e._eval(compressor, depth + 1);
+ val = e._eval(compressor, cached, depth + 1);
if (val === e || !(val && native_fns[val.constructor.name] || return_false)(key)) return this;
}
var args = [];
for (var i = 0, len = this.args.length; i < len; i++) {
var arg = this.args[i];
- var value = arg._eval(compressor, depth);
+ var value = arg._eval(compressor, cached, depth);
if (arg === value) return this;
args.push(value);
}