From f0cef8d6315d70d649fce3a183d54af3bfbd8764 Mon Sep 17 00:00:00 2001 From: alexlamsl Date: Mon, 6 Nov 2017 02:58:01 +0800 Subject: [PATCH] private accounting for `collapse_vars` - avoid issues with identity reference due to deep cloning fixes #2437 --- lib/compress.js | 31 +++++++++++----------- test/compress/collapse_vars.js | 48 ++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 15 deletions(-) diff --git a/lib/compress.js b/lib/compress.js index 9185f048..d8482337 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -788,6 +788,14 @@ merge(Compressor.prototype, { || compressor.option("unsafe") && global_names(this.name); }); + function drop_decl(def) { + def._eliminiated = (def._eliminiated || 0) + 1; + if (def.orig.length == def._eliminiated) { + def.scope.functions.del(def.name); + def.scope.variables.del(def.name); + } + } + function tighten_body(statements, compressor) { var CHANGED, max_iter = 10; do { @@ -1000,7 +1008,8 @@ merge(Compressor.prototype, { function get_lhs(expr) { if (expr instanceof AST_VarDef) { var def = expr.name.definition(); - if (def.orig.length > 1 && !(expr.name instanceof AST_SymbolFunarg) + if (def.orig.length - (def._eliminiated || 0) > 1 + && !(expr.name instanceof AST_SymbolFunarg) || def.references.length == 1 && !compressor.exposed(def)) { return make_node(AST_SymbolRef, expr.name, expr.name); } @@ -1047,7 +1056,7 @@ merge(Compressor.prototype, { if (node === expr) { found = true; if (node instanceof AST_VarDef) { - remove(node.name.definition().orig, node.name); + drop_decl(node.name.definition()); node.value = null; return node; } @@ -2420,7 +2429,7 @@ merge(Compressor.prototype, { var def = node.name.definition(); if (!(def.id in in_use_ids)) { compressor[node.name.unreferenced() ? "warn" : "info"]("Dropping unused function {name} [{file}:{line},{col}]", template(node.name)); - drop_decl(def, node.name); + drop_decl(def); return make_node(AST_EmptyStatement, node); } return node; @@ -2442,7 +2451,7 @@ merge(Compressor.prototype, { if (var_defs.length > 1 && !def.value) { compressor.warn("Dropping duplicated definition of variable {name} [{file}:{line},{col}]", template(def.name)); remove(var_defs, def); - drop_decl(sym, def.name); + drop_decl(sym); return; } } @@ -2475,7 +2484,7 @@ merge(Compressor.prototype, { } else { compressor[def.name.unreferenced() ? "warn" : "info"]("Dropping unused variable {name} [{file}:{line},{col}]", template(def.name)); } - drop_decl(sym, def.name); + drop_decl(sym); } }); if (head.length == 0 && tail.length == 1 && tail[0].name instanceof AST_SymbolVar) { @@ -2484,7 +2493,7 @@ merge(Compressor.prototype, { var def = tail.pop(); compressor.warn("Converting duplicated definition of variable {name} to assignment [{file}:{line},{col}]", template(def.name)); remove(var_defs, def); - drop_decl(def.name.definition(), def.name); + drop_decl(def.name.definition()); side_effects.unshift(make_node(AST_Assign, def, { operator: "=", left: make_node(AST_SymbolRef, def.name, def.name), @@ -2566,14 +2575,6 @@ merge(Compressor.prototype, { col : sym.start.col }; } - - function drop_decl(def, decl) { - remove(def.orig, decl); - if (!def.orig.length) { - def.scope.functions.del(def.name); - def.scope.variables.del(def.name); - } - } } ); self.transform(tt); @@ -3293,7 +3294,7 @@ merge(Compressor.prototype, { })); if (reduce_vars) name.definition().fixed = false; } - remove(def.name.definition().orig, def.name); + drop_decl(def.name.definition()); return a; }, []); if (assignments.length == 0) return null; diff --git a/test/compress/collapse_vars.js b/test/compress/collapse_vars.js index b1e89a40..fe8e4097 100644 --- a/test/compress/collapse_vars.js +++ b/test/compress/collapse_vars.js @@ -3029,3 +3029,51 @@ issue_2425_3: { } expect_stdout: "15" } + +issue_2437: { + options = { + collapse_vars: true, + conditionals: true, + inline: true, + join_vars: true, + reduce_vars: true, + side_effects: true, + sequences: true, + toplevel: true, + unused: true, + } + input: { + function foo() { + bar(); + } + function bar() { + if (xhrDesc) { + var req = new XMLHttpRequest(); + var result = !!req.onreadystatechange; + Object.defineProperty(XMLHttpRequest.prototype, 'onreadystatechange', xhrDesc || {}); + return result; + } + else { + var req = new XMLHttpRequest(); + var detectFunc = function () { }; + req.onreadystatechange = detectFunc; + var result = req[SYMBOL_FAKE_ONREADYSTATECHANGE_1] === detectFunc; + req.onreadystatechange = null; + return result; + } + } + foo(); + } + expect: { + !function() { + if (xhrDesc) + return result = !!(req = new XMLHttpRequest()).onreadystatechange, + Object.defineProperty(XMLHttpRequest.prototype, "onreadystatechange", xhrDesc || {}), + result; + var req = new XMLHttpRequest(), detectFunc = function() {}; + req.onreadystatechange = detectFunc; + var result = req[SYMBOL_FAKE_ONREADYSTATECHANGE_1] === detectFunc; + req.onreadystatechange = null; + }(); + } +}