enhance unsafe evaluate (#3370)
This commit is contained in:
@@ -312,8 +312,22 @@ merge(Compressor.prototype, {
|
|||||||
return value instanceof AST_SymbolRef && value.fixed_value() || value;
|
return value instanceof AST_SymbolRef && value.fixed_value() || value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function is_read_only_fn(value, name) {
|
||||||
|
if (value instanceof AST_Boolean) return native_fns.Boolean[name];
|
||||||
|
if (value instanceof AST_Number) return native_fns.Number[name];
|
||||||
|
if (value instanceof AST_String) return native_fns.String[name];
|
||||||
|
if (name == "valueOf") return false;
|
||||||
|
if (value instanceof AST_Array) return native_fns.Array[name];
|
||||||
|
if (value instanceof AST_Function) return native_fns.Function[name];
|
||||||
|
if (value instanceof AST_Object) return native_fns.Object[name];
|
||||||
|
if (value instanceof AST_RegExp) return native_fns.RegExp[name];
|
||||||
|
}
|
||||||
|
|
||||||
function is_modified(compressor, tw, node, value, level, immutable) {
|
function is_modified(compressor, tw, node, value, level, immutable) {
|
||||||
var parent = tw.parent(level);
|
var parent = tw.parent(level);
|
||||||
|
if (compressor.option("unsafe") && parent instanceof AST_Dot && is_read_only_fn(value, parent.property)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
var lhs = is_lhs(node, parent);
|
var lhs = is_lhs(node, parent);
|
||||||
if (lhs) return lhs;
|
if (lhs) return lhs;
|
||||||
if (!immutable
|
if (!immutable
|
||||||
@@ -344,7 +358,7 @@ merge(Compressor.prototype, {
|
|||||||
def.assignments = 0;
|
def.assignments = 0;
|
||||||
def.chained = false;
|
def.chained = false;
|
||||||
def.direct_access = false;
|
def.direct_access = false;
|
||||||
def.escaped = false;
|
def.escaped = [];
|
||||||
def.fixed = !def.scope.pinned()
|
def.fixed = !def.scope.pinned()
|
||||||
&& !compressor.exposed(def)
|
&& !compressor.exposed(def)
|
||||||
&& !(def.init instanceof AST_Function && def.init !== def.scope)
|
&& !(def.init instanceof AST_Function && def.init !== def.scope)
|
||||||
@@ -483,8 +497,9 @@ merge(Compressor.prototype, {
|
|||||||
|| parent instanceof AST_Call && (node !== parent.expression || parent instanceof AST_New)
|
|| parent instanceof AST_Call && (node !== parent.expression || parent instanceof AST_New)
|
||||||
|| parent instanceof AST_Exit && node === parent.value && node.scope !== d.scope
|
|| parent instanceof AST_Exit && node === parent.value && node.scope !== d.scope
|
||||||
|| parent instanceof AST_VarDef && node === parent.value) {
|
|| parent instanceof AST_VarDef && node === parent.value) {
|
||||||
|
d.escaped.push(parent);
|
||||||
if (depth > 1 && !(value && value.is_constant_expression(scope))) depth = 1;
|
if (depth > 1 && !(value && value.is_constant_expression(scope))) depth = 1;
|
||||||
if (!d.escaped || d.escaped > depth) d.escaped = depth;
|
if (!d.escaped.depth || d.escaped.depth > depth) d.escaped.depth = depth;
|
||||||
return;
|
return;
|
||||||
} else if (parent instanceof AST_Array
|
} else if (parent instanceof AST_Array
|
||||||
|| parent instanceof AST_Binary && lazy_op[parent.operator]
|
|| parent instanceof AST_Binary && lazy_op[parent.operator]
|
||||||
@@ -742,8 +757,8 @@ merge(Compressor.prototype, {
|
|||||||
d.fixed = false;
|
d.fixed = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
mark_escaped(tw, d, this.scope, this, value, 0, 1);
|
mark_escaped(tw, d, this.scope, this, value, 0, 1);
|
||||||
|
}
|
||||||
var parent;
|
var parent;
|
||||||
if (d.fixed instanceof AST_Defun
|
if (d.fixed instanceof AST_Defun
|
||||||
&& !((parent = tw.parent()) instanceof AST_Call && parent.expression === this)) {
|
&& !((parent = tw.parent()) instanceof AST_Call && parent.expression === this)) {
|
||||||
@@ -1579,9 +1594,14 @@ merge(Compressor.prototype, {
|
|||||||
lvalues[candidate.name.name] = lhs;
|
lvalues[candidate.name.name] = lhs;
|
||||||
}
|
}
|
||||||
var tw = new TreeWalker(function(node) {
|
var tw = new TreeWalker(function(node) {
|
||||||
var sym = root_expr(node);
|
var value;
|
||||||
if (sym instanceof AST_SymbolRef || sym instanceof AST_This) {
|
if (node instanceof AST_SymbolRef) {
|
||||||
lvalues[sym.name] = lvalues[sym.name] || is_modified(compressor, tw, node, node, 0);
|
value = node.fixed_value() || node;
|
||||||
|
} else if (node instanceof AST_This) {
|
||||||
|
value = node;
|
||||||
|
}
|
||||||
|
if (value && !lvalues[node.name]) {
|
||||||
|
lvalues[node.name] = is_modified(compressor, tw, node, value, 0);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
expr.walk(tw);
|
expr.walk(tw);
|
||||||
@@ -2847,9 +2867,25 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
if (value && typeof value == "object") {
|
if (value && typeof value == "object") {
|
||||||
var escaped = this.definition().escaped;
|
var escaped = this.definition().escaped;
|
||||||
if (escaped && depth > escaped) return this;
|
switch (escaped.length) {
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if (contains_ref(escaped[0], this)) break;
|
||||||
|
default:
|
||||||
|
if (depth > escaped.depth) return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
|
|
||||||
|
function contains_ref(expr, ref) {
|
||||||
|
var found = false;
|
||||||
|
expr.walk(new TreeWalker(function(node) {
|
||||||
|
if (found) return true;
|
||||||
|
if (node === ref) return found = true;
|
||||||
|
}));
|
||||||
|
return found;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
var global_objs = {
|
var global_objs = {
|
||||||
Array: Array,
|
Array: Array,
|
||||||
@@ -3983,7 +4019,7 @@ merge(Compressor.prototype, {
|
|||||||
var def = sym.definition();
|
var def = sym.definition();
|
||||||
if (def.assignments != count) return;
|
if (def.assignments != count) return;
|
||||||
if (def.direct_access) return;
|
if (def.direct_access) return;
|
||||||
if (def.escaped == 1) return;
|
if (def.escaped.depth == 1) return;
|
||||||
if (def.references.length == count) return;
|
if (def.references.length == count) return;
|
||||||
if (def.single_use) return;
|
if (def.single_use) return;
|
||||||
if (top_retain(def)) return;
|
if (top_retain(def)) return;
|
||||||
@@ -5863,7 +5899,7 @@ merge(Compressor.prototype, {
|
|||||||
var single_use = def.single_use && !(parent instanceof AST_Call && parent.is_expr_pure(compressor));
|
var single_use = def.single_use && !(parent instanceof AST_Call && parent.is_expr_pure(compressor));
|
||||||
if (single_use && fixed instanceof AST_Lambda) {
|
if (single_use && fixed instanceof AST_Lambda) {
|
||||||
if (def.scope !== self.scope
|
if (def.scope !== self.scope
|
||||||
&& (!compressor.option("reduce_funcs") || def.escaped == 1 || fixed.inlined)) {
|
&& (!compressor.option("reduce_funcs") || def.escaped.depth == 1 || fixed.inlined)) {
|
||||||
single_use = false;
|
single_use = false;
|
||||||
} else if (recursive_ref(compressor, def)) {
|
} else if (recursive_ref(compressor, def)) {
|
||||||
single_use = false;
|
single_use = false;
|
||||||
|
|||||||
@@ -1687,3 +1687,28 @@ try_increment: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "1"
|
expect_stdout: "1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe_escaped: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
inline: true,
|
||||||
|
passes: 3,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
unsafe: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function(a) {
|
||||||
|
console.log(function(index) {
|
||||||
|
return a[index];
|
||||||
|
}(function(term) {
|
||||||
|
return a.indexOf(term);
|
||||||
|
}("PASS")));
|
||||||
|
})([ "PASS" ]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -281,8 +281,8 @@ unsafe_evaluate_escaped: {
|
|||||||
console.log(function(){ var o={p:3},a=[o]; console.log(a[0].p++); return o.p; }());
|
console.log(function(){ var o={p:3},a=[o]; console.log(a[0].p++); return o.p; }());
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
console.log(function(){ var o={p:1}; console.log(o, o.p); return o.p; }());
|
console.log(function(){ var o={p:1}; console.log(o, 1); return o.p; }());
|
||||||
console.log(function(){ var o={p:2}; console.log(o.p, o); return o.p; }());
|
console.log(function(){ var o={p:2}; console.log(2, o); return o.p; }());
|
||||||
console.log(function(){ var o={p:3},a=[o]; console.log(a[0].p++); return o.p; }());
|
console.log(function(){ var o={p:3},a=[o]; console.log(a[0].p++); return o.p; }());
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
|
|||||||
Reference in New Issue
Block a user