remove __label__ settings in hoisted blocks and if we are sure the label setting is unimportant because the next code after us is not a check for the label

This commit is contained in:
Alon Zakai 2012-01-01 21:00:34 -08:00
Родитель b724d8ba0b
Коммит a914110dac
3 изменённых файлов: 196 добавлений и 71 удалений

Просмотреть файл

@ -667,36 +667,44 @@ function optimizeShiftsAggressive(ast) {
optimizeShiftsInternal(ast, false);
}
function simplifyExpressionsPost(ast) {
// We often have branchings that are simplified so one end vanishes, and
// we then get
// if (!(x < 5))
// or such. Simplifying these saves space and time.
function simplifyNotComps(ast) {
traverse(ast, function(node, type) {
if (type == 'unary-prefix' && node[1] == '!' && node[2][0] == 'binary') {
if (node[2][1] == '<') {
return ['binary', '>=', node[2][2], node[2][3]];
} else if (node[2][1] == '>') {
return ['binary', '<=', node[2][2], node[2][3]];
} else if (node[2][1] == '==') {
return ['binary', '!=', node[2][2], node[2][3]];
} else if (node[2][1] == '!=') {
return ['binary', '==', node[2][2], node[2][3]];
} else if (node[2][1] == '===') {
return ['binary', '!==', node[2][2], node[2][3]];
} else if (node[2][1] == '!==') {
return ['binary', '===', node[2][2], node[2][3]];
}
// We often have branchings that are simplified so one end vanishes, and
// we then get
// if (!(x < 5))
// or such. Simplifying these saves space and time.
function simplifyNotComps(ast) {
traverse(ast, function(node, type) {
if (type == 'unary-prefix' && node[1] == '!' && node[2][0] == 'binary') {
if (node[2][1] == '<') {
return ['binary', '>=', node[2][2], node[2][3]];
} else if (node[2][1] == '>') {
return ['binary', '<=', node[2][2], node[2][3]];
} else if (node[2][1] == '==') {
return ['binary', '!=', node[2][2], node[2][3]];
} else if (node[2][1] == '!=') {
return ['binary', '==', node[2][2], node[2][3]];
} else if (node[2][1] == '===') {
return ['binary', '!==', node[2][2], node[2][3]];
} else if (node[2][1] == '!==') {
return ['binary', '===', node[2][2], node[2][3]];
}
});
}
// Go
}
});
}
function simplifyExpressionsPost(ast) {
simplifyNotComps(ast);
}
function hasSideEffects(node) { // this is 99% incomplete and wrong! It just works on __label__ == X and number literals
if (node[0] == 'num') return false;
if (node[0] == 'binary' && (node[1] == '==' || node[1] == '!=') && node[2][0] == 'name' &&
node[3][0] == 'num') {
return false;
} else {
return true;
}
}
// Clear out empty ifs and blocks, and redundant blocks/stats and so forth
function vacuum(ast) {
function isEmpty(node) {
@ -729,18 +737,9 @@ function vacuum(ast) {
}
var type = node[0];
if (type == 'defun' && isGenerated(node[1])) {
simplifyNotComps(node);
traverse(node, function(node, type) {
if (type == 'if') {
if (((node[2][0] == 'block' && (!node[2][1] || node[2][1].length == 0)) ||
jsonCompare(node[2], emptyNode())) && !node[3]) {
more = true;
return emptyNode();
} else if (node[3] && isEmpty(node[3])) {
more = true;
node[3] = null;
return node;
}
} else if (type == 'block' && node[1] && node[1].length == 1 && node[1][0][0] == 'block') {
if (type == 'block' && node[1] && node[1].length == 1 && node[1][0][0] == 'block') {
more = true;
return node[1][0];
} else if (type == 'stat' && node[1][0] == 'block') {
@ -762,9 +761,25 @@ function vacuum(ast) {
} else if (type == 'label' && jsonCompare(node[2], emptyNode())) {
more = true;
return emptyNode();
} else if (type == 'if' && isEmpty(node[3])) { // empty else clauses
node[3] = null;
return node;
} else if (type == 'if') {
var empty2 = isEmpty(node[2]), empty3 = isEmpty(node[3]), has3 = node.length == 4;
if (!empty2 && empty3 && has3) { // empty else clauses
more = true;
return node.slice(0, 3);
} else if (empty2 && !empty3) { // empty if blocks
more = true;
return ['if', ['unary-prefix', '!', node[1]], node[3]];
} else if (empty2 && empty3) {
more = true;
if (hasSideEffects(node[1])) {
return ['stat', node[1]];
} else {
return emptyNode();
}
}
} else if (type == 'do' && isEmpty(node[2]) && !hasSideEffects(node[1])) {
more = true;
return emptyNode();
}
});
}
@ -772,6 +787,16 @@ function vacuum(ast) {
}
}
function getStatements(node) {
if (node[0] == 'defun') {
return node[3];
} else if (node[0] == 'block') {
return node[1];
} else {
return null;
}
}
// Multiple blocks from the relooper are, in general, implemented by
// if (__label__ == x) { } else if ..
// and branching into them by
@ -781,12 +806,7 @@ function hoistMultiples(ast) {
ast[1].forEach(function(node, i) {
if (!(node[0] == 'defun' && isGenerated(node[1]))) return;
traverse(node, function(node, type) {
var statements = null;
if (type == 'defun') {
statements = node[3];
} else if (type == 'block') {
statements = node[1];
}
var statements = getStatements(node);
if (!statements) return;
var modified = false;
for (var i = 0; i < statements.length-1; i++) {
@ -833,11 +853,11 @@ function hoistMultiples(ast) {
if (!found && preType == 'assign' && preNode[2][0] == 'name' && preNode[2][1] == '__label__') {
assert(preNode[3][0] == 'num');
if (preNode[3][1] == labelNum) {
// That's it! Hoist away
// That's it! Hoist away. We can also throw away the __label__ setting as its goal has already been achieved
found = true;
modifiedI = true;
postInner[2] = ['block', []];
return ['block', [preNode].concat(labelBlock[1])];
return labelBlock;
}
}
});
@ -850,6 +870,45 @@ function hoistMultiples(ast) {
}
if (modified) return node;
});
// After hoisting in this function, it is safe to remove { __label__ = x; } blocks, because
// if they were leading to the next code right after them, they would be hoisted, and if they
// are going to some other place entirely, they would break or continue. The only risky
// situation is if the code after us is a multiple, in which case we might be checking for
// this label inside it (or in a later multiple, even)
function tryEliminate(node) {
if (node[0] == 'if') {
if (tryEliminate(node[2])) node[2] = emptyNode();
if (node[3] && tryEliminate(node[3])) node[3] = emptyNode();
} else {
if (node[0] == 'block' && node[1] && node[1].length == 1) {
var subNode = node[1][0];
if (subNode[0] == 'stat' && subNode[1][0] == 'assign' && subNode[1][2][0] == 'name' &&
subNode[1][2][1] == '__label__' && subNode[1][3][0] == 'num') {
return true;
}
}
}
return false;
}
function getActualStatement(node) { // find the actual active statement, ignoring a label and one-time do loop
if (node[0] == 'label') node = node[2];
if (node[0] == 'do') node = node[2];
if (node[0] == 'block' && node[1].length == 1) node = node[1][0];
return node;
}
vacuum([0, [node]]);
traverse(node, function(node, type) {
var statements = getStatements(node);
if (!statements) return;
for (var i = 0; i < statements.length-1; i++) {
var curr = getActualStatement(statements[i]);
var next = statements[i+1];
if (curr[0] == 'if' && next[0] != 'if' && next[0] != 'label' && next[0] != 'do' && next[0] != 'while') {
tryEliminate(curr);
}
}
});
});
vacuum(ast);

Просмотреть файл

@ -99,62 +99,80 @@ function maths() {
}
function hoisting() {
if ($i < $N) {
__label__ = 2;
callOther();
}
pause(1);
$for_body3$$for_end$5 : do {
if ($i < $N) {
__label__ = 2;
while (true) {
break $for_body3$$for_end$5;
}
callOther();
} else {
__label__ = 3;
}
} while (0);
pause(2);
do {
if ($i < $N) {
__label__ = 2;
if (callOther()) break;
} else {
__label__ = 3;
}
} while (0);
pause(3);
if ($i < $N) {
__label__ = 2;
callOther();
} else {
__label__ = 3;
}
pause(4);
if ($i < $N) {
__label__ = 2;
callOther();
} else {
__label__ = 3;
somethingElse();
}
pause(5);
if ($i < $N) {
__label__ = 2;
} else {
__label__ = 3;
somethingElse();
}
if (__label__ == 55) {
callOther();
}
pause(6);
if ($i < $N) {
__label__ = 2;
} else {
__label__ = 3;
if ($i >= $N) {
somethingElse();
}
pause(7);
while (1) {
if ($i < $N) {
somethingElse();
} else {
__label__ = 3;
break;
}
if ($i < $N) {
somethingElse();
}
nothing();
}
pause(8);
var $cmp95 = $69 == -1;
do {
if ($cmp95) {
if (!$cmp103) {
__label__ = 38;
break;
}
if (!$cmp106) {
__label__ = 38;
break;
}
__label__ = 39;
break;
} else {
__label__ = 38;
}
} while (0);
if (__label__ == 38) {
var $79 = $_pr6;
}
}
var FS = {
absolutePath: (function(relative, base) {
@ -184,7 +202,6 @@ function demangle($cmp) {
if ($cmp) {
__label__ = 3;
} else {
__label__ = 1;
if (something()) {
__label__ = 3;
break;
@ -200,10 +217,7 @@ function demangle($cmp) {
function lua() {
while (1) {
do {
if ($14) {
__label__ = 3;
} else {
__label__ = 4;
if (!$14) {
var $17 = $i;
var $18 = $3;
var $19 = $18 + ($17 << 2) | 0;
@ -218,12 +232,15 @@ function lua() {
pause();
if ($1435 == 0) {
__label__ = 176;
} else if ($1435 == 1) {} else {
cheez();
} else if ($1435 != 1) {
__label__ = 180;
cheez();
}
pause();
if ($1435 == 0) {
__label__ = 176;
cheez();
}
}
function moreLabels() {

Просмотреть файл

@ -106,7 +106,6 @@ function hoisting() {
if (__label__ == 2) {
callOther();
}
// ok /*
pause(1);
if ($i < $N) {
__label__ = 2;
@ -170,6 +169,53 @@ function hoisting() {
if (__label__ == 3) {
somethingElse();
}
pause(7);
free: while (1) {
if ($i < $N) {
__label__ = 2;
} else {
__label__ = 3; // this cannot be removed!
break;
}
if (__label__ == 2) {
somethingElse();
}
if ($i < $N) {
__label__ = 2;
} else {
__label__ = 3; // this can be removed!
}
if (__label__ == 2) {
somethingElse();
}
nothing();
}
pause(8);
var $cmp95 = $69 == -1;
if ($cmp95) {
__label__ = 35;
} else {
__label__ = 38;
}
$if_then96$$if_end110thread_pre_split$48 : do {
if (__label__ == 35) {
if (!$cmp103) {
__label__ = 38;
break $if_then96$$if_end110thread_pre_split$48;
}
if (!$cmp106) {
__label__ = 38;
break $if_then96$$if_end110thread_pre_split$48;
}
__label__ = 39;
break $if_then96$$if_end110thread_pre_split$48;
}
} while (0);
$if_end110$$if_end110thread_pre_split$52 : do {
if (__label__ == 38) {
var $79 = $_pr6;
}
} while (0);
}
var FS = {
absolutePath: function(relative, base) { // Don't touch this!
@ -243,12 +289,15 @@ function lua() {
pause();
if ($1435 == 0) {
__label__ = 176;
cheez();
} else if ($1435 == 1) {} else {
__label__ = 180;
cheez();
}
pause();
if ($1435 == 0) {
__label__ = 176;
cheez();
} else if ($1435 == 1) {}
}
function moreLabels() {