Skip to content

Commit

Permalink
fix corner case in hoist_props (#3452)
Browse files Browse the repository at this point in the history
fixes #3440
  • Loading branch information
alexlamsl committed Oct 6, 2019
1 parent 35338a1 commit 931ac66
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 41 deletions.
86 changes: 45 additions & 41 deletions lib/compress.js
Expand Up @@ -4062,10 +4062,11 @@ merge(Compressor.prototype, {
var top_retain = self instanceof AST_Toplevel && compressor.top_retain || return_false;
var defs_by_id = Object.create(null);
self.transform(new TreeTransformer(function(node, descend) {
if (node instanceof AST_Assign
&& node.operator == "="
&& node.write_only
&& can_hoist(node.left, node.right, 1)) {
if (node instanceof AST_Assign) {
if (node.operator != "=") return;
if (!node.write_only) return;
if (node.left.scope !== self) return;
if (!can_hoist(node.left, node.right, 1)) return;
descend(node, this);
var defs = new Dictionary();
var assignments = [];
Expand Down Expand Up @@ -4094,17 +4095,9 @@ merge(Compressor.prototype, {
}));
return make_sequence(node, assignments);
}
if (node instanceof AST_Unary
&& !unary_side_effects[node.operator]
&& node.expression instanceof AST_SymbolRef
&& node.expression.definition().id in defs_by_id) {
node = node.clone();
node.expression = make_node(AST_Object, node, {
properties: []
});
return node;
}
if (node instanceof AST_VarDef && can_hoist(node.name, node.value, 0)) {
if (node instanceof AST_Scope) return node === self ? undefined : node;
if (node instanceof AST_VarDef) {
if (!can_hoist(node.name, node.value, 0)) return;
descend(node, this);
var defs = new Dictionary();
var var_defs = [];
Expand All @@ -4117,32 +4110,6 @@ merge(Compressor.prototype, {
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];
if (defs) {
var def = defs.get(node.getProperty());
var sym = make_node(AST_SymbolRef, node, {
name: def.name,
scope: node.expression.scope,
thedef: def
});
sym.reference({});
return 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.depth == 1) return;
if (def.references.length == count) 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, {
Expand All @@ -4155,6 +4122,43 @@ merge(Compressor.prototype, {
return new_var;
}
}));
self.transform(new TreeTransformer(function(node, descend) {
if (node instanceof AST_PropAccess) {
if (!(node.expression instanceof AST_SymbolRef)) return;
var defs = defs_by_id[node.expression.definition().id];
if (!defs) return;
var def = defs.get(node.getProperty());
var sym = make_node(AST_SymbolRef, node, {
name: def.name,
scope: node.expression.scope,
thedef: def
});
sym.reference({});
return sym;
}
if (node instanceof AST_Unary) {
if (unary_side_effects[node.operator]) return;
if (!(node.expression instanceof AST_SymbolRef)) return;
if (!(node.expression.definition().id in defs_by_id)) return;
var opt = node.clone();
opt.expression = make_node(AST_Object, node, {
properties: []
});
return opt;
}
}));

function can_hoist(sym, right, count) {
var def = sym.definition();
if (def.assignments != count) return;
if (def.direct_access) return;
if (def.escaped.depth == 1) return;
if (def.references.length == count) return;
if (def.single_use) return;
if (top_retain(def)) return;
if (sym.fixed_value() !== right) return;
return right instanceof AST_Object;
}
});

// drop_side_effect_free()
Expand Down
28 changes: 28 additions & 0 deletions test/compress/hoist_props.js
Expand Up @@ -886,3 +886,31 @@ issue_3411: {
}
expect_stdout: "PASS"
}

issue_3440: {
options = {
hoist_props: true,
reduce_vars: true,
unused: true,
}
input: {
(function() {
function f() {
console.log(o.p);
}
var o = {
p: "PASS",
};
return f;
})()();
}
expect: {
(function() {
var o_p = "PASS";
return function() {
console.log(o_p);
};
})()();
}
expect_stdout: "PASS"
}

0 comments on commit 931ac66

Please sign in to comment.