more AST_If optimizations

This commit is contained in:
Mihai Bazon
2012-09-12 16:10:03 +03:00
parent 2b1e4628e0
commit a132841fb9
2 changed files with 85 additions and 15 deletions

View File

@@ -122,17 +122,17 @@ function Compressor(options, false_by_default) {
}; };
function SQUEEZE(nodetype, squeeze) { function SQUEEZE(nodetype, squeeze) {
nodetype.DEFMETHOD("squeeze", function(compressor){ nodetype.DEFMETHOD("squeeze", function(compressor, block, index){
compressor.push_node(this); compressor.push_node(this);
var new_node = squeeze(this, compressor); var new_node = squeeze(this, compressor, block, index);
compressor.pop_node(); compressor.pop_node();
return new_node !== undefined ? new_node : this; return new_node !== undefined ? new_node : this;
}); });
}; };
function do_list(array, compressor, splice_blocks) { function do_list(array, compressor, splice_blocks) {
return MAP(array, function(node){ return MAP(array, function(node, i){
node = node.squeeze(compressor); node = node.squeeze(compressor, array, i);
if (splice_blocks) { if (splice_blocks) {
if (node instanceof AST_BlockStatement) { if (node instanceof AST_BlockStatement) {
return MAP.splice(eliminate_spurious_blocks(node.body)); return MAP.splice(eliminate_spurious_blocks(node.body));
@@ -222,7 +222,8 @@ function Compressor(options, false_by_default) {
} }
else if (i == last else if (i == last
&& cur instanceof AST_Exit && cur.value && cur instanceof AST_Exit && cur.value
&& a.length == 1 && prev instanceof AST_SimpleStatement) { && a.length > 0
&& prev instanceof AST_SimpleStatement) {
// it only makes sense to do this transformation // it only makes sense to do this transformation
// if the AST gets to a single statement. // if the AST gets to a single statement.
var seq = make_node(AST_Seq, prev, { var seq = make_node(AST_Seq, prev, {
@@ -230,7 +231,9 @@ function Compressor(options, false_by_default) {
second: cur.value second: cur.value
}); });
cur.value = seq; cur.value = seq;
return [ cur ]; a.pop();
a.push(cur);
return a;
} }
else { else {
a.push(cur); a.push(cur);
@@ -459,7 +462,9 @@ function Compressor(options, false_by_default) {
return basic_negation(this); return basic_negation(this);
}); });
})(function(node, func){ })(function(node, func){
node.DEFMETHOD("negate", func); node.DEFMETHOD("negate", function(compressor){
return func.call(this, compressor).optimize(compressor);
});
}); });
// determine if expression has side effects // determine if expression has side effects
@@ -494,6 +499,15 @@ function Compressor(options, false_by_default) {
node.DEFMETHOD("has_side_effects", func); node.DEFMETHOD("has_side_effects", func);
}); });
// tell me if a statement aborts
(function(def){
def(AST_StatementBase, function(){ return null });
def(AST_Jump, function(){ return this });
def(AST_BlockStatement, function(){ return this.body[this.body.length - 1].aborts() });
})(function(node, func){
node.DEFMETHOD("aborts", func);
});
/* -----[ node squeezers ]----- */ /* -----[ node squeezers ]----- */
SQUEEZE(AST_Debugger, function(self, compressor){ SQUEEZE(AST_Debugger, function(self, compressor){
@@ -516,9 +530,13 @@ function Compressor(options, false_by_default) {
SQUEEZE(AST_BlockStatement, function(self, compressor){ SQUEEZE(AST_BlockStatement, function(self, compressor){
self = self.clone(); self = self.clone();
self.body = tighten_body(self.body, compressor); self.body = tighten_body(self.body, compressor);
if (self.body.length == 1) return self.optimize(compressor);
return self.body[0]; });
return self;
AST_BlockStatement.DEFMETHOD("optimize", function(compressor){
if (this.body.length == 1)
return this.body[0];
return this;
}); });
SQUEEZE(AST_Block, function(self, compressor){ SQUEEZE(AST_Block, function(self, compressor){
@@ -705,16 +723,16 @@ function Compressor(options, false_by_default) {
return self; return self;
}); });
SQUEEZE(AST_If, function(self, compressor){ SQUEEZE(AST_If, function(self, compressor, block, index){
self = self.clone(); self = self.clone();
self.condition = self.condition.squeeze(compressor); self.condition = self.condition.squeeze(compressor);
self.body = self.body.squeeze(compressor); self.body = self.body.squeeze(compressor);
if (self.alternative) if (self.alternative)
self.alternative = self.alternative.squeeze(compressor); self.alternative = self.alternative.squeeze(compressor);
return self.optimize(compressor); return self.optimize(compressor, block, index);
}); });
AST_If.DEFMETHOD("optimize", function(compressor){ AST_If.DEFMETHOD("optimize", function(compressor, block, index){
var self = this; var self = this;
if (!compressor.option("conditionals")) return self; if (!compressor.option("conditionals")) return self;
// if condition can be statically determined, warn and drop // if condition can be statically determined, warn and drop
@@ -809,6 +827,49 @@ function Compressor(options, false_by_default) {
}).optimize(compressor) }).optimize(compressor)
}); });
} }
if (self.body instanceof AST_Return
&& !self.body.value
&& !self.alternative
&& index < block.length - 1) {
if (compressor.parent() instanceof AST_Lambda) {
var rest = tighten_body(block.slice(index + 1), compressor);
var cond = negated_is_best ? negated : self.condition.negate(compressor);
while (rest[0] instanceof AST_If && rest[0].body instanceof AST_Return && !rest[0].alternative) {
cond = make_node(AST_Binary, rest[0], {
operator: "&&",
left: cond,
right: rest[0].condition.negate(compressor)
});
rest.shift();
}
return MAP.last(make_node(AST_If, self, {
condition: cond,
body: make_node(AST_BlockStatement, block[index + 1], {
body: rest
}).optimize(compressor)
}).optimize(compressor));
}
}
if (self.body instanceof AST_If
&& !self.body.alternative
&& !self.alternative) {
self.condition = make_node(AST_Binary, self.condition, {
operator: "&&",
left: self.condition,
right: self.body.condition
});
self.body = self.body.body;
}
var abort = self.body.aborts();
if (abort) {
if (self.alternative) {
var alt = self.alternative;
self.alternative = null;
return make_node(AST_BlockStatement, self, {
body: [ self, alt ]
}).optimize(compressor);
}
}
return self; return self;
}); });

View File

@@ -113,6 +113,8 @@ var MAP = (function(){
var ret = [], top = [], i; var ret = [], top = [], i;
function doit() { function doit() {
var val = f.call(o, a[i], i); var val = f.call(o, a[i], i);
var is_last = val instanceof Last;
if (is_last) val = val.v;
if (val instanceof AtTop) { if (val instanceof AtTop) {
val = val.v; val = val.v;
if (val instanceof Splice) { if (val instanceof Splice) {
@@ -128,16 +130,23 @@ var MAP = (function(){
ret.push(val); ret.push(val);
} }
} }
return is_last;
}; };
if (a instanceof Array) for (i = 0; i < a.length; ++i) doit(); if (a instanceof Array) {
else for (i in a) if (HOP(a, i)) doit(); for (i = 0; i < a.length; ++i) if (doit()) break;
}
else {
for (i in a) if (HOP(a, i)) if (doit()) break;
}
return top.concat(ret); return top.concat(ret);
}; };
MAP.at_top = function(val) { return new AtTop(val) }; MAP.at_top = function(val) { return new AtTop(val) };
MAP.splice = function(val) { return new Splice(val) }; MAP.splice = function(val) { return new Splice(val) };
MAP.last = function(val) { return new Last(val) };
var skip = MAP.skip = {}; var skip = MAP.skip = {};
function AtTop(val) { this.v = val }; function AtTop(val) { this.v = val };
function Splice(val) { this.v = val }; function Splice(val) { this.v = val };
function Last(val) { this.v = val };
return MAP; return MAP;
})(); })();