aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMihai Bazon <mihai@bazon.net>2012-12-05 12:30:25 +0200
committerMihai Bazon <mihai@bazon.net>2012-12-05 12:30:25 +0200
commit320c110b331be9c6cb20f4db1d63aaaa98eef739 (patch)
treeabe45dd2081e319e66a6079ee963fd913fe36909
parentdbe33bbfc53badf7135d0aa93b7cdac708175629 (diff)
downloadtracifyjs-320c110b331be9c6cb20f4db1d63aaaa98eef739.tar.gz
tracifyjs-320c110b331be9c6cb20f4db1d63aaaa98eef739.zip
When hoisting variables, try to merge in assignments that follow.
-rw-r--r--lib/compress.js89
-rw-r--r--lib/scope.js11
-rw-r--r--lib/utils.js8
3 files changed, 79 insertions, 29 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;
diff --git a/lib/scope.js b/lib/scope.js
index dc637cc5..758b61f7 100644
--- a/lib/scope.js
+++ b/lib/scope.js
@@ -110,9 +110,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(){
labels.del(l.name);
return true; // no descend again
}
- if (node instanceof AST_SymbolDeclaration) {
- node.init_scope_vars();
- }
if (node instanceof AST_Symbol) {
node.scope = scope;
}
@@ -128,8 +125,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(){
// scope. Don't like this fix but seems we can't do any
// better. IE: please die. Please!
(node.scope = scope.parent_scope).def_function(node);
-
- node.init.push(tw.parent());
}
else if (node instanceof AST_SymbolDefun) {
// Careful here, the scope where this should be defined is
@@ -138,14 +133,12 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(){
// instanceof AST_Scope) but we get to the symbol a bit
// later.
(node.scope = scope.parent_scope).def_function(node);
- node.init.push(tw.parent());
}
else if (node instanceof AST_SymbolVar
|| node instanceof AST_SymbolConst) {
var def = scope.def_variable(node);
def.constant = node instanceof AST_SymbolConst;
def = tw.parent();
- if (def.value) node.init.push(def);
}
else if (node instanceof AST_SymbolCatch) {
// XXX: this is wrong according to ECMA-262 (12.4). the
@@ -246,10 +239,6 @@ AST_SymbolRef.DEFMETHOD("reference", function() {
this.frame = this.scope.nesting - def.scope.nesting;
});
-AST_SymbolDeclaration.DEFMETHOD("init_scope_vars", function(){
- this.init = [];
-});
-
AST_Label.DEFMETHOD("init_scope_vars", function(){
this.references = [];
});
diff --git a/lib/utils.js b/lib/utils.js
index 15eed9ba..c95b9824 100644
--- a/lib/utils.js
+++ b/lib/utils.js
@@ -255,6 +255,14 @@ Dictionary.prototype = {
this._values["$" + key] = val;
return this;
},
+ add: function(key, val) {
+ if (this.has(key)) {
+ this.get(key).push(val);
+ } else {
+ this.set(key, [ val ]);
+ }
+ return this;
+ },
get: function(key) { return this._values["$" + key] },
del: function(key) {
if (this.has(key)) {