From: Alex Lam S.L Date: Tue, 10 Apr 2018 18:48:15 +0000 (+0800) Subject: extend `hoist_props` (#3073) X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=4dd7d0e39baacdd3bf7dc87fc547df66e327f206;p=UglifyJS.git extend `hoist_props` (#3073) - handle `AST_Assign` the same way as `AST_VarDef` - inject `AST_Var` as succeeding statement fixes #3071 --- diff --git a/lib/compress.js b/lib/compress.js index 7660e677..66dc10cf 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -3639,28 +3639,47 @@ merge(Compressor.prototype, { var top_retain = self instanceof AST_Toplevel && compressor.top_retain || return_false; var defs_by_id = Object.create(null); return self.transform(new TreeTransformer(function(node, descend) { - if (node instanceof AST_VarDef) { - var sym = node.name, def, value; - if (sym.scope === self - && (def = sym.definition()).escaped != 1 - && !def.assignments - && !def.direct_access - && !def.single_use - && !top_retain(def) - && (value = sym.fixed_value()) === node.value - && value instanceof AST_Object) { - descend(node, this); - var defs = new Dictionary(); - var assignments = []; - value.properties.forEach(function(prop) { - assignments.push(make_node(AST_VarDef, node, { - name: make_sym(prop.key), - value: prop.value - })); + if (node instanceof AST_Assign && node.operator == "=" && can_hoist(node.left, node.right, 1)) { + descend(node, this); + var defs = new Dictionary(); + var assignments = []; + var decls = []; + node.right.properties.forEach(function(prop) { + var decl = make_sym(node.left, prop.key); + decls.push(make_node(AST_VarDef, node, { + name: decl, + value: null + })); + var sym = make_node(AST_SymbolRef, node, { + name: decl.name, + scope: self, + thedef: decl.definition() }); - defs_by_id[def.id] = defs; - return MAP.splice(assignments); - } + sym.reference({}); + assignments.push(make_node(AST_Assign, node, { + operator: "=", + left: sym, + right: prop.value + })); + }); + defs_by_id[node.left.definition().id] = defs; + self.body.splice(self.body.indexOf(this.stack[1]) + 1, 0, make_node(AST_Var, node, { + definitions: decls + })); + return make_sequence(node, assignments); + } + if (node instanceof AST_VarDef && can_hoist(node.name, node.value, 0)) { + descend(node, this); + var defs = new Dictionary(); + var var_defs = []; + node.value.properties.forEach(function(prop) { + var_defs.push(make_node(AST_VarDef, node, { + name: make_sym(node.name, prop.key), + value: prop.value + })); + }); + defs_by_id[node.name.definition().id] = defs; + return MAP.splice(var_defs); } if (node instanceof AST_PropAccess && node.expression instanceof AST_SymbolRef) { var defs = defs_by_id[node.expression.definition().id]; @@ -3676,8 +3695,20 @@ merge(Compressor.prototype, { } } - function make_sym(key) { - var new_var = make_node(sym.CTOR, sym, { + function can_hoist(sym, right, count) { + if (sym.scope !== self) return; + var def = sym.definition(); + if (def.assignments != count) return; + if (def.direct_access) return; + if (def.escaped == 1) return; + if (def.single_use) return; + if (top_retain(def)) return; + if (sym.fixed_value() !== right) return; + return right instanceof AST_Object; + } + + function make_sym(sym, key) { + var new_var = make_node(AST_SymbolVar, sym, { name: self.make_var_name(sym.name + "_" + key), scope: self }); diff --git a/test/compress/hoist_props.js b/test/compress/hoist_props.js index b16f7425..0e399167 100644 --- a/test/compress/hoist_props.js +++ b/test/compress/hoist_props.js @@ -742,3 +742,85 @@ issue_3046: { } expect_stdout: "1" } + +issue_3071_1: { + options = { + evaluate: true, + inline: true, + join_vars: true, + hoist_props: true, + passes: 3, + reduce_vars: true, + sequences: true, + side_effects: true, + toplevel: true, + unused: true, + } + input: { + (function() { + var obj = {}; + obj.one = 1; + obj.two = 2; + console.log(obj.one); + })(); + } + expect: { + console.log(1); + } + expect_stdout: "1" +} + +issue_3071_2: { + options = { + evaluate: true, + inline: true, + join_vars: true, + hoist_props: true, + passes: 3, + reduce_vars: true, + sequences: true, + side_effects: true, + unused: true, + } + input: { + (function() { + obj = {}; + obj.one = 1; + obj.two = 2; + console.log(obj.one); + var obj; + })(); + } + expect: { + console.log(1); + } + expect_stdout: "1" +} + +issue_3071_2_toplevel: { + options = { + evaluate: true, + inline: true, + join_vars: true, + hoist_props: true, + passes: 3, + reduce_vars: true, + sequences: true, + side_effects: true, + toplevel: true, + unused: true, + } + input: { + (function() { + obj = {}; + obj.one = 1; + obj.two = 2; + console.log(obj.one); + var obj; + })(); + } + expect: { + console.log(1); + } + expect_stdout: "1" +}