aboutsummaryrefslogtreecommitdiff
path: root/tools/js-optimizer.js
diff options
context:
space:
mode:
authorRyan Kelly <ryan@rfk.id.au>2014-01-31 17:45:25 +1100
committerRyan Kelly <ryan@rfk.id.au>2014-02-02 08:50:09 +1100
commitfa4f4857166885f1dcfc3a85712473fb4711f08a (patch)
treee178962b9baeefc006e88a6003c7af65c333e158 /tools/js-optimizer.js
parent47288a40ac04bc7f4fe9734a3b6160735b58f1b2 (diff)
Simplify labelled-block handling so it works better with switch statements.
Diffstat (limited to 'tools/js-optimizer.js')
-rw-r--r--tools/js-optimizer.js58
1 files changed, 23 insertions, 35 deletions
diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js
index a3ed24d3..3dd4a23a 100644
--- a/tools/js-optimizer.js
+++ b/tools/js-optimizer.js
@@ -2145,11 +2145,11 @@ function registerizeHarder(ast) {
// For each block we store:
// * a single entry junction
// * a single exit junction
- // * any preconditions satisfied at entry to the block
// * a 'use' and 'kill' set of names for the block
// * full sequence of 'name' and 'assign' nodes in the block
// * whether each such node appears as part of a larger expression
// (and therefore cannot be safely eliminated)
+ // * set of labels that can be used to jump to this block
var junctions = [];
var blocks = [];
@@ -2205,7 +2205,7 @@ function registerizeHarder(ast) {
junctions[id].inblocks[nextBasicBlock.id] = 1;
blocks.push(nextBasicBlock);
}
- nextBasicBlock = { id: null, entry: null, exit: null, pre: {}, nodes: [], isexpr: [], use: {}, kill: {} };
+ nextBasicBlock = { id: null, entry: null, exit: null, labels: {}, nodes: [], isexpr: [], use: {}, kill: {} };
setJunction(id, force);
return id;
}
@@ -2285,29 +2285,10 @@ function registerizeHarder(ast) {
return node;
}
- function addPreCondTrue(node) {
- // Add pre-conditions implied by truth of the
- // given node to the current basic block.
- assert(nextBasicBlock.nodes.length === 0, 'cant add preconditions to an in-progress basic block')
- if (node[0] === 'binary' && node[1] === '==') {
- var lhs = lookThroughCasts(node[2]);
- var rhs = lookThroughCasts(node[3]);
- if (lhs[0] === 'name' && rhs[0] === 'num') {
- nextBasicBlock.pre[lhs[1]] = ['==', rhs[1]];
- }
- }
- }
-
- function addPreCondFalse(node) {
- // Add pre-conditions implied by falsehood of the
- // given node to the current basic block.
- assert(nextBasicBlock.nodes.length === 0, 'cant add preconditions to an in-progress basic block')
- if (node[0] === 'binary' && node[1] === '==') {
- var lhs = lookThroughCasts(node[2]);
- var rhs = lookThroughCasts(node[3]);
- if (lhs[0] === 'name' && rhs[0] === 'num') {
- nextBasicBlock.pre[lhs[1]] = ['!=', rhs[1]];
- }
+ function addBlockLabel(node) {
+ assert(nextBasicBlock.nodes.length === 0, 'cant add label to an in-progress basic block')
+ if (node[0] === 'num') {
+ nextBasicBlock.labels[node[1]] = 1;
}
}
@@ -2368,13 +2349,18 @@ function registerizeHarder(ast) {
isInExpr--;
var jEnter = markJunction();
var jExit = addJunction();
- addPreCondTrue(node[1]);
if (node[2]) {
+ // Detect and mark "if (label == N) { <labelled block> }".
+ if (node[1][0] === 'binary' && node[1][1] === '==') {
+ var lhs = lookThroughCasts(node[1][2]);
+ if (lhs[0] === 'name' && lhs[1] === 'label') {
+ addBlockLabel(lookThroughCasts(node[1][3]));
+ }
+ }
buildFlowGraph(node[2]);
}
joinJunction(jExit);
setJunction(jEnter);
- addPreCondFalse(node[1]);
if (node[3]) {
buildFlowGraph(node[3]);
}
@@ -2385,13 +2371,11 @@ function registerizeHarder(ast) {
buildFlowGraph(node[1]);
var jEnter = markJunction();
var jExit = addJunction();
- addPreCondTrue(node[1]);
if (node[2]) {
buildFlowGraph(node[2]);
}
joinJunction(jExit);
setJunction(jEnter);
- addPreCondFalse(node[1]);
if (node[3]) {
buildFlowGraph(node[3]);
}
@@ -2418,7 +2402,6 @@ function registerizeHarder(ast) {
isInExpr--;
joinJunction(jLoop);
pushActiveLabels(jCond, jExit);
- addPreCondTrue(node[1]);
buildFlowGraph(node[2]);
popActiveLabels();
joinJunction(jCond);
@@ -2495,6 +2478,7 @@ function registerizeHarder(ast) {
isInExpr++;
buildFlowGraph(node[1]);
isInExpr--;
+ var condition = lookThroughCasts(node[1]);
var jCheckExit = markJunction();
var jExit = addJunction();
pushActiveLabels(null, jExit);
@@ -2504,6 +2488,11 @@ function registerizeHarder(ast) {
// All case clauses are either 'default' or a numeric literal.
if (!node[2][i][0]) {
hasDefault = true;
+ } else {
+ // Detect switches dispatching to labelled blocks.
+ if (condition[0] === 'name' && condition[1] === 'label') {
+ addBlockLabel(lookThroughCasts(node[2][i][0]));
+ }
}
for (var j = 0; j < node[2][i][1].length; j++) {
buildFlowGraph(node[2][i][1][j]);
@@ -2629,18 +2618,17 @@ function registerizeHarder(ast) {
FINDLABELLEDBLOCKS:
for (var i = 0; i < blocks.length; i++) {
var block = blocks[i];
- // Does it have a specific label value as precondition?
- var labelCond = block.pre['label'];
- if (labelCond && labelCond[0] === '==') {
+ // Does it have any labels as preconditions to its entry?
+ for (var labelVal in block.labels) {
// If there are multiple blocks with the same label, all bets are off.
// This seems to happen sometimes for short blocks that end with a return.
// TODO: it should be safe to merge the duplicates if they're identical.
- if (labelCond[1] in labelledBlocks) {
+ if (labelVal in labelledBlocks) {
labelledBlocks = {};
labelledJumps = [];
break FINDLABELLEDBLOCKS;
}
- labelledBlocks[labelCond[1]] = block;
+ labelledBlocks[labelVal] = block;
}
// Does it assign a specific label value at exit?
if ('label' in block.kill) {