diff options
author | Mihai Bazon <mihai@bazon.net> | 2012-12-05 12:30:25 +0200 |
---|---|---|
committer | Mihai Bazon <mihai@bazon.net> | 2012-12-05 12:30:25 +0200 |
commit | 320c110b331be9c6cb20f4db1d63aaaa98eef739 (patch) | |
tree | abe45dd2081e319e66a6079ee963fd913fe36909 /lib/compress.js | |
parent | dbe33bbfc53badf7135d0aa93b7cdac708175629 (diff) | |
download | tracifyjs-320c110b331be9c6cb20f4db1d63aaaa98eef739.tar.gz tracifyjs-320c110b331be9c6cb20f4db1d63aaaa98eef739.zip |
When hoisting variables, try to merge in assignments that follow.
Diffstat (limited to 'lib/compress.js')
-rw-r--r-- | lib/compress.js | 89 |
1 files changed, 71 insertions, 18 deletions
diff --git a/lib/compress.js b/lib/compress.js index c1cb1464..2355c5e6 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -883,18 +883,23 @@ merge(Compressor.prototype, { && !self.uses_eval ) { var in_use = []; + var initializations = new Dictionary(); // pass 1: find out which symbols are directly used in // this scope (not in nested scopes). var scope = this; var tw = new TreeWalker(function(node, descend){ if (node !== self) { if (node instanceof AST_Defun) { + initializations.add(node.name.name, node); return true; // don't go in nested scopes } if (node instanceof AST_Definitions && scope === self) { node.definitions.forEach(function(def){ - if (def.value && def.value.has_side_effects()) { - def.value.walk(tw); + if (def.value) { + initializations.add(def.name.name, def.value); + if (def.value.has_side_effects()) { + def.value.walk(tw); + } } }); return true; @@ -919,16 +924,15 @@ merge(Compressor.prototype, { for (var i = 0; i < in_use.length; ++i) { in_use[i].orig.forEach(function(decl){ // undeclared globals will be instanceof AST_SymbolRef - if (decl instanceof AST_SymbolDeclaration) { - decl.init.forEach(function(init){ - var tw = new TreeWalker(function(node){ - if (node instanceof AST_SymbolRef) { - push_uniq(in_use, node.definition()); - } - }); - init.walk(tw); + var init = initializations.get(decl.name); + if (init) init.forEach(function(init){ + var tw = new TreeWalker(function(node){ + if (node instanceof AST_SymbolRef) { + push_uniq(in_use, node.definition()); + } }); - } + init.walk(tw); + }); }); } // pass 3: we should drop declarations not in_use @@ -1100,13 +1104,62 @@ merge(Compressor.prototype, { } ); self = self.transform(tt); - if (vars_found > 0) hoisted.unshift(make_node(AST_Var, self, { - definitions: vars.map(function(def){ - def = def.clone(); - def.value = null; - return def; - }) - })); + if (vars_found > 0) { + // collect only vars which don't show up in self's arguments list + var defs = []; + vars.each(function(def, name){ + if (self instanceof AST_Lambda + && find_if(function(x){ return x.name == def.name.name }, + self.argnames)) { + vars.del(name); + } else { + def = def.clone(); + def.value = null; + defs.push(def); + vars.set(name, def); + } + }); + if (defs.length > 0) { + // try to merge in assignments + for (var i = 0; i < self.body.length;) { + if (self.body[i] instanceof AST_SimpleStatement) { + var expr = self.body[i].body, sym, assign; + if (expr instanceof AST_Assign + && expr.operator == "=" + && (sym = expr.left) instanceof AST_Symbol + && vars.has(sym.name)) + { + var def = vars.get(sym.name); + if (def.value) break; + def.value = expr.right; + remove(defs, def); + defs.push(def); + self.body.splice(i, 1); + continue; + } + if (expr instanceof AST_Seq + && (assign = expr.car) instanceof AST_Assign + && assign.operator == "=" + && (sym = assign.left) instanceof AST_Symbol + && vars.has(sym.name)) + { + var def = vars.get(sym.name); + if (def.value) break; + def.value = assign.right; + remove(defs, def); + defs.push(def); + self.body[i].body = expr.cdr; + continue; + } + } + break; + } + defs = make_node(AST_Var, self, { + definitions: defs + }); + hoisted.push(defs); + }; + } self.body = dirs.concat(hoisted, self.body); } return self; |