aboutsummaryrefslogtreecommitdiff
path: root/lib/compress.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/compress.js')
-rw-r--r--lib/compress.js54
1 files changed, 45 insertions, 9 deletions
diff --git a/lib/compress.js b/lib/compress.js
index 9fdfc43a..b0f1bfba 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -312,8 +312,22 @@ merge(Compressor.prototype, {
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) {
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);
if (lhs) return lhs;
if (!immutable
@@ -344,7 +358,7 @@ merge(Compressor.prototype, {
def.assignments = 0;
def.chained = false;
def.direct_access = false;
- def.escaped = false;
+ def.escaped = [];
def.fixed = !def.scope.pinned()
&& !compressor.exposed(def)
&& !(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_Exit && node === parent.value && node.scope !== d.scope
|| parent instanceof AST_VarDef && node === parent.value) {
+ d.escaped.push(parent);
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;
} else if (parent instanceof AST_Array
|| parent instanceof AST_Binary && lazy_op[parent.operator]
@@ -742,8 +757,8 @@ merge(Compressor.prototype, {
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;
if (d.fixed instanceof AST_Defun
&& !((parent = tw.parent()) instanceof AST_Call && parent.expression === this)) {
@@ -1579,9 +1594,14 @@ merge(Compressor.prototype, {
lvalues[candidate.name.name] = lhs;
}
var tw = new TreeWalker(function(node) {
- var sym = root_expr(node);
- if (sym instanceof AST_SymbolRef || sym instanceof AST_This) {
- lvalues[sym.name] = lvalues[sym.name] || is_modified(compressor, tw, node, node, 0);
+ var value;
+ if (node instanceof AST_SymbolRef) {
+ 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);
@@ -2847,9 +2867,25 @@ merge(Compressor.prototype, {
}
if (value && typeof value == "object") {
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;
+
+ 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 = {
Array: Array,
@@ -3983,7 +4019,7 @@ merge(Compressor.prototype, {
var def = sym.definition();
if (def.assignments != count) 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.single_use) 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));
if (single_use && fixed instanceof AST_Lambda) {
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;
} else if (recursive_ref(compressor, def)) {
single_use = false;