From: Alex Lam S.L Date: Thu, 26 Apr 2018 11:26:01 +0000 (+0800) Subject: improve `collapse_vars` (#3103) X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=82a8b6f6122d7fe887619138b6913475ce0f2093;p=UglifyJS.git improve `collapse_vars` (#3103) --- diff --git a/lib/compress.js b/lib/compress.js index 06ed35f5..dfd2f7f6 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -980,24 +980,12 @@ merge(Compressor.prototype, { } // Stop immediately if these node types are encountered var parent = scanner.parent(); - if (node instanceof AST_Assign && node.operator != "=" && lhs.equivalent_to(node.left) - || node instanceof AST_Call && lhs instanceof AST_PropAccess && lhs.equivalent_to(node.expression) - || node instanceof AST_Debugger - || node instanceof AST_IterationStatement && !(node instanceof AST_For) - || node instanceof AST_LoopControl - || node instanceof AST_Try - || node instanceof AST_With - || parent instanceof AST_For && node !== parent.init - || !replace_all - && (node instanceof AST_SymbolRef && !node.is_declared(compressor))) { + if (should_stop(node, parent)) { abort = true; return node; } // Stop only if candidate is found within conditional branches - if (!stop_if_hit - && (parent instanceof AST_Binary && lazy_op[parent.operator] && parent.left !== node - || parent instanceof AST_Conditional && parent.condition !== node - || parent instanceof AST_If && parent.condition !== node)) { + if (!stop_if_hit && in_conditional(node, parent)) { stop_if_hit = parent; } // Replace variable with assignment when found @@ -1047,20 +1035,7 @@ merge(Compressor.prototype, { // These node types have child nodes that execute sequentially, // but are otherwise not safe to scan into or beyond them. var sym; - if (node instanceof AST_Call - || node instanceof AST_Exit - && (side_effects || lhs instanceof AST_PropAccess || may_modify(lhs)) - || node instanceof AST_PropAccess - && (side_effects || node.expression.may_throw_on_access(compressor)) - || node instanceof AST_SymbolRef - && (symbol_in_lvalues(node) || side_effects && may_modify(node)) - || node instanceof AST_This && symbol_in_lvalues(node) - || node instanceof AST_VarDef && node.value - && (node.name.name in lvalues || side_effects && may_modify(node.name)) - || (sym = is_lhs(node.left, node)) - && (sym instanceof AST_PropAccess || sym.name in lvalues) - || may_throw - && (in_try ? node.has_side_effects(compressor) : side_effects_external(node))) { + if (is_last_node(node, parent) || may_throw(node)) { stop_after = node; if (node instanceof AST_Scope) abort = true; } @@ -1119,7 +1094,9 @@ merge(Compressor.prototype, { var lhs_local = is_lhs_local(lhs); if (!side_effects) side_effects = value_has_side_effects(candidate); var replace_all = replace_all_symbols(); - var may_throw = candidate.may_throw(compressor); + var may_throw = candidate.may_throw(compressor) ? in_try ? function(node) { + return node.has_side_effects(compressor); + } : side_effects_external : return_false; var funarg = candidate.name instanceof AST_SymbolFunarg; var hit = funarg; var abort = false, replaced = 0, can_replace = !args || !hit; @@ -1171,6 +1148,51 @@ merge(Compressor.prototype, { } } + function should_stop(node, parent) { + if (node instanceof AST_Assign) return node.operator != "=" && lhs.equivalent_to(node.left); + if (node instanceof AST_Call) { + return lhs instanceof AST_PropAccess && lhs.equivalent_to(node.expression); + } + if (node instanceof AST_Debugger) return true; + if (node instanceof AST_IterationStatement) return !(node instanceof AST_For); + if (node instanceof AST_LoopControl) return true; + if (node instanceof AST_Try) return true; + if (node instanceof AST_With) return true; + if (parent instanceof AST_For) return node !== parent.init; + if (replace_all) return false; + return node instanceof AST_SymbolRef && !node.is_declared(compressor); + } + + function in_conditional(node, parent) { + if (parent instanceof AST_Binary) return lazy_op[parent.operator] && parent.left !== node; + if (parent instanceof AST_Conditional) return parent.condition !== node; + return parent instanceof AST_If && parent.condition !== node; + } + + function is_last_node(node, parent) { + if (node instanceof AST_Call) return true; + if (node instanceof AST_Exit) { + return side_effects || lhs instanceof AST_PropAccess || may_modify(lhs); + } + if (node instanceof AST_PropAccess) { + return side_effects || node.expression.may_throw_on_access(compressor); + } + if (node instanceof AST_SymbolRef) { + if (symbol_in_lvalues(node, parent)) { + return !parent || parent.operator != "=" || parent.left !== node; + } + return side_effects && may_modify(node); + } + if (node instanceof AST_This) return symbol_in_lvalues(node, parent); + if (node instanceof AST_VarDef) { + if (!node.value) return false; + return node.name.name in lvalues || side_effects && may_modify(node.name); + } + var sym = is_lhs(node.left, node); + if (sym && sym.name in lvalues) return true; + if (sym instanceof AST_PropAccess) return true; + } + function extract_args() { var iife, fn = compressor.self(); if (fn instanceof AST_Function @@ -1482,10 +1504,10 @@ merge(Compressor.prototype, { return false; } - function symbol_in_lvalues(sym) { + function symbol_in_lvalues(sym, parent) { var lvalue = lvalues[sym.name]; if (!lvalue) return; - if (lvalue !== lhs) return true; + if (lvalue !== lhs) return !(parent instanceof AST_Call); scan_rhs = false; }