in-place if_return
This commit is contained in:
parent
2de466331a
commit
0ff3c24ad5
115
lib/compress.js
115
lib/compress.js
|
|
@ -673,7 +673,7 @@ merge(Compressor.prototype, {
|
|||
eliminate_dead_code(statements, compressor);
|
||||
}
|
||||
if (compressor.option("if_return")) {
|
||||
statements = handle_if_return(statements, compressor);
|
||||
handle_if_return(statements, compressor);
|
||||
}
|
||||
if (compressor.sequences_limit > 0) {
|
||||
sequencesize(statements, compressor);
|
||||
|
|
@ -916,35 +916,34 @@ merge(Compressor.prototype, {
|
|||
var self = compressor.self();
|
||||
var multiple_if_returns = has_multiple_if_returns(statements);
|
||||
var in_lambda = self instanceof AST_Lambda;
|
||||
var ret = []; // Optimized statements, build from tail to front
|
||||
loop: for (var i = statements.length; --i >= 0;) {
|
||||
for (var i = statements.length; --i >= 0;) {
|
||||
var stat = statements[i];
|
||||
switch (true) {
|
||||
case (in_lambda && stat instanceof AST_Return && !stat.value && ret.length == 0):
|
||||
var next = statements[i + 1];
|
||||
|
||||
if (in_lambda && stat instanceof AST_Return && !stat.value && !next) {
|
||||
CHANGED = true;
|
||||
// note, ret.length is probably always zero
|
||||
// because we drop unreachable code before this
|
||||
// step. nevertheless, it's good to check.
|
||||
continue loop;
|
||||
case stat instanceof AST_If:
|
||||
statements.length--;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (stat instanceof AST_If) {
|
||||
var ab = aborts(stat.body);
|
||||
if (can_merge_flow(ab)) {
|
||||
if (ab.label) {
|
||||
remove(ab.label.thedef.references, ab);
|
||||
}
|
||||
CHANGED = true;
|
||||
var funs = extract_functions_from_statement_array(ret);
|
||||
var body = as_statement_array_with_return(stat.body, ab);
|
||||
stat = stat.clone();
|
||||
stat.condition = stat.condition.negate(compressor);
|
||||
var body = as_statement_array_with_return(stat.body, ab);
|
||||
stat.body = make_node(AST_BlockStatement, stat, {
|
||||
body: as_statement_array(stat.alternative).concat(ret)
|
||||
body: as_statement_array(stat.alternative).concat(extract_functions())
|
||||
});
|
||||
stat.alternative = make_node(AST_BlockStatement, stat, {
|
||||
body: body
|
||||
});
|
||||
ret = [ stat.transform(compressor) ].concat(funs);
|
||||
continue loop;
|
||||
statements[i] = stat.transform(compressor);
|
||||
continue;
|
||||
}
|
||||
|
||||
var ab = aborts(stat.alternative);
|
||||
|
|
@ -953,53 +952,54 @@ merge(Compressor.prototype, {
|
|||
remove(ab.label.thedef.references, ab);
|
||||
}
|
||||
CHANGED = true;
|
||||
var funs = extract_functions_from_statement_array(ret);
|
||||
stat = stat.clone();
|
||||
stat.body = make_node(AST_BlockStatement, stat.body, {
|
||||
body: as_statement_array(stat.body).concat(ret)
|
||||
body: as_statement_array(stat.body).concat(extract_functions())
|
||||
});
|
||||
var body = as_statement_array_with_return(stat.alternative, ab);
|
||||
stat.alternative = make_node(AST_BlockStatement, stat.alternative, {
|
||||
body: body
|
||||
});
|
||||
ret = [ stat.transform(compressor) ].concat(funs);
|
||||
continue loop;
|
||||
statements[i] = stat.transform(compressor);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (stat.body instanceof AST_Return) {
|
||||
if (stat instanceof AST_If && stat.body instanceof AST_Return) {
|
||||
var value = stat.body.value;
|
||||
//---
|
||||
// pretty silly case, but:
|
||||
// if (foo()) return; return; ==> foo(); return;
|
||||
if ((in_lambda && ret.length == 0 || ret[0] instanceof AST_Return && !ret[0].value)
|
||||
&& !value && !stat.alternative) {
|
||||
if (!value && !stat.alternative
|
||||
&& (in_lambda && !next || next instanceof AST_Return && !next.value)) {
|
||||
CHANGED = true;
|
||||
var cond = make_node(AST_SimpleStatement, stat.condition, {
|
||||
statements[i] = make_node(AST_SimpleStatement, stat.condition, {
|
||||
body: stat.condition
|
||||
});
|
||||
ret.unshift(cond);
|
||||
continue loop;
|
||||
continue;
|
||||
}
|
||||
//---
|
||||
// if (foo()) return x; return y; ==> return foo() ? x : y;
|
||||
if (ret[0] instanceof AST_Return && value && ret[0].value && !stat.alternative) {
|
||||
if (value && !stat.alternative && next instanceof AST_Return && next.value) {
|
||||
CHANGED = true;
|
||||
stat = stat.clone();
|
||||
stat.alternative = ret[0];
|
||||
ret[0] = stat.transform(compressor);
|
||||
continue loop;
|
||||
stat.alternative = next;
|
||||
statements[i] = stat.transform(compressor);
|
||||
statements.length = i + 1;
|
||||
continue;
|
||||
}
|
||||
//---
|
||||
// if (foo()) return x; [ return ; ] ==> return foo() ? x : undefined;
|
||||
if (multiple_if_returns && (ret.length == 0 || ret[0] instanceof AST_Return)
|
||||
&& value && !stat.alternative && in_lambda) {
|
||||
if (multiple_if_returns && in_lambda && value && !stat.alternative
|
||||
&& (!next || next instanceof AST_Return)) {
|
||||
CHANGED = true;
|
||||
stat = stat.clone();
|
||||
stat.alternative = ret[0] || make_node(AST_Return, stat, {
|
||||
stat.alternative = next || make_node(AST_Return, stat, {
|
||||
value: null
|
||||
});
|
||||
ret[0] = stat.transform(compressor);
|
||||
continue loop;
|
||||
statements[i] = stat.transform(compressor);
|
||||
statements.length = i + 1;
|
||||
continue;
|
||||
}
|
||||
//---
|
||||
// if (a) return b; if (c) return d; e; ==> return a ? b : c ? d : void e;
|
||||
|
|
@ -1007,27 +1007,18 @@ merge(Compressor.prototype, {
|
|||
// if sequences is not enabled, this can lead to an endless loop (issue #866).
|
||||
// however, with sequences on this helps producing slightly better output for
|
||||
// the example code.
|
||||
if (compressor.option("sequences")
|
||||
&& i > 0 && statements[i - 1] instanceof AST_If && statements[i - 1].body instanceof AST_Return
|
||||
&& ret.length == 1 && in_lambda && ret[0] instanceof AST_SimpleStatement
|
||||
&& !stat.alternative) {
|
||||
var prev = statements[i - 1];
|
||||
if (compressor.option("sequences") && in_lambda && !stat.alternative
|
||||
&& prev instanceof AST_If && prev.body instanceof AST_Return
|
||||
&& i + 2 == statements.length && next instanceof AST_SimpleStatement) {
|
||||
CHANGED = true;
|
||||
ret.push(make_node(AST_Return, ret[0], {
|
||||
statements.push(make_node(AST_Return, next, {
|
||||
value: null
|
||||
}).transform(compressor));
|
||||
ret.unshift(stat);
|
||||
continue loop;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
ret.unshift(stat);
|
||||
break;
|
||||
default:
|
||||
ret.unshift(stat);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
|
||||
function has_multiple_if_returns(statements) {
|
||||
var n = 0;
|
||||
|
|
@ -1052,6 +1043,18 @@ merge(Compressor.prototype, {
|
|||
|| ab instanceof AST_Break && lct instanceof AST_BlockStatement && self === lct;
|
||||
}
|
||||
|
||||
function extract_functions() {
|
||||
var tail = statements.slice(i + 1);
|
||||
statements.length = i + 1;
|
||||
return tail.filter(function(stat) {
|
||||
if (stat instanceof AST_Defun) {
|
||||
statements.push(stat);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
function as_statement_array_with_return(node, ab) {
|
||||
var body = as_statement_array(node).slice(0, -1);
|
||||
if (ab.value) {
|
||||
|
|
@ -1061,7 +1064,7 @@ merge(Compressor.prototype, {
|
|||
}
|
||||
return body;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function eliminate_dead_code(statements, compressor) {
|
||||
var has_quit;
|
||||
|
|
@ -1205,18 +1208,6 @@ merge(Compressor.prototype, {
|
|||
};
|
||||
}
|
||||
|
||||
function extract_functions_from_statement_array(statements) {
|
||||
var funs = [];
|
||||
for (var i = statements.length - 1; i >= 0; --i) {
|
||||
var stat = statements[i];
|
||||
if (stat instanceof AST_Defun) {
|
||||
statements.splice(i, 1);
|
||||
funs.unshift(stat);
|
||||
}
|
||||
}
|
||||
return funs;
|
||||
}
|
||||
|
||||
function extract_declarations_from_unreachable_code(compressor, stat, target) {
|
||||
if (!(stat instanceof AST_Defun)) {
|
||||
compressor.warn("Dropping unreachable code [{file}:{line},{col}]", stat.start);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user