diff options
Diffstat (limited to 'lib/compress.js')
-rw-r--r-- | lib/compress.js | 54 |
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; |