aboutsummaryrefslogtreecommitdiff
path: root/tools/js-optimizer.js
diff options
context:
space:
mode:
Diffstat (limited to 'tools/js-optimizer.js')
-rw-r--r--tools/js-optimizer.js77
1 files changed, 67 insertions, 10 deletions
diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js
index 5601f65c..32ed1cce 100644
--- a/tools/js-optimizer.js
+++ b/tools/js-optimizer.js
@@ -493,6 +493,7 @@ function simplifyExpressionsPre(ast) {
node[2][0] == 'binary' && node[2][1] == '<<' && node[2][3][0] == 'num' &&
node[2][2][0] == 'sub' && node[2][2][1][0] == 'name') {
// collapse HEAPU?8[..] << 24 >> 24 etc. into HEAP8[..] | 0
+ // TODO: run this before | 0 | 0 removal, because we generate | 0
var amount = node[3][1];
var name = node[2][2][1][1];
if (amount == node[2][3][1] && parseHeap(name)) {
@@ -1391,7 +1392,12 @@ function normalizeAsm(func) {
var name = v[0];
var value = v[1];
if (!(name in data.vars)) {
- data.vars[name] = detectAsmCoercion(value);
+ if (value[0] != 'name') {
+ data.vars[name] = detectAsmCoercion(value); // detect by coercion
+ } else {
+ var origin = value[1];
+ data.vars[name] = data.vars[origin] || ASM_INT; // detect by origin variable, or assume int for non-locals
+ }
}
}
unVarify(node[1], node);
@@ -1781,6 +1787,7 @@ function eliminate(ast, memSafe) {
if (asm) var asmData = normalizeAsm(func);
//printErr('eliminate in ' + func[1]);
+
// First, find the potentially eliminatable functions: that have one definition and one use
var definitions = {};
var uses = {};
@@ -1796,6 +1803,7 @@ function eliminate(ast, memSafe) {
}
}
// examine body and note locals
+ var hasSwitch = false;
traverse(func, function(node, type) {
if (type === 'var') {
var node1 = node[1];
@@ -1827,31 +1835,79 @@ function eliminate(ast, memSafe) {
uses[name]--; // because the name node will show up by itself in the previous case
}
}
+ } else if (type == 'switch') {
+ hasSwitch = true;
}
});
+
+ // we cannot eliminate variables if there is a switch
+ if (traverse(func, function(node, type) {
+ if (type == 'switch') return true;
+ })) {
+ if (asm) denormalizeAsm(func, asmData);
+ return;
+ }
+
var potentials = {}; // local variables with 1 definition and 1 use
var sideEffectFree = {}; // whether a local variable has no side effects in its definition
- for (var name in locals) {
+
+ function unprocessVariable(name) {
+ if (name in potentials) delete potentials[name];
+ if (name in varsToRemove) delete varsToRemove[name];
+ if (name in sideEffectFree) delete sideEffectFree[name];
+ if (name in varsToTryToRemove) delete varsToTryToRemove[name];
+ }
+ function processVariable(name) {
if (definitions[name] == 1 && uses[name] == 1) {
potentials[name] = 1;
} else if (uses[name] == 0 && (!definitions[name] || definitions[name] <= 1)) { // no uses, no def or 1 def (cannot operate on phis, and the llvm optimizer will remove unneeded phis anyhow)
var hasSideEffects = false;
- if (values[name]) {
- traverse(values[name], function(node, type) {
- if (!(type in NODES_WITHOUT_ELIMINATION_SIDE_EFFECTS)) {
- hasSideEffects = true; // cannot remove this unused variable, constructing it has side effects
- return true;
- }
- });
+ var value = values[name];
+ if (value) {
+ // TODO: merge with other side effect code
+ // First, pattern-match
+ // (HEAP32[((tempDoublePtr)>>2)]=((HEAP32[(($_sroa_0_0__idx1)>>2)])|0),HEAP32[(((tempDoublePtr)+(4))>>2)]=((HEAP32[((($_sroa_0_0__idx1)+(4))>>2)])|0),(+(HEAPF64[(tempDoublePtr)>>3])))
+ // which has no side effects and is the special form of converting double to i64.
+ if (!(value[0] == 'seq' && value[1][0] == 'assign' && value[1][2][0] == 'sub' && value[1][2][2][0] == 'binary' && value[1][2][2][1] == '>>' &&
+ value[1][2][2][2][0] == 'name' && value[1][2][2][2][1] == 'tempDoublePtr')) {
+ // If not that, then traverse and scan normally.
+ traverse(value, function(node, type) {
+ if (!(type in NODES_WITHOUT_ELIMINATION_SIDE_EFFECTS)) {
+ hasSideEffects = true; // cannot remove this unused variable, constructing it has side effects
+ return true;
+ }
+ });
+ }
}
if (!hasSideEffects) {
varsToRemove[name] = !definitions[name] ? 2 : 1; // remove it normally
sideEffectFree[name] = true;
+ // Each time we remove a variable with 0 uses, if its value has no
+ // side effects and vanishes too, then we can remove a use from variables
+ // appearing in it, and possibly eliminate again
+ if (value) {
+ traverse(value, function(node, type) {
+ if (type == 'name') {
+ var name = node[1];
+ node[1] = ''; // we can remove this - it will never be shown, and should not be left to confuse us as we traverse
+ if (name in locals) {
+ uses[name]--; // cannot be infinite recursion since we descend an energy function
+ assert(uses[name] >= 0);
+ unprocessVariable(name);
+ processVariable(name);
+ }
+ }
+ });
+ }
} else {
varsToTryToRemove[name] = 1; // try to remove it later during scanning
}
}
}
+ for (var name in locals) {
+ processVariable(name);
+ }
+
//printErr('defs: ' + JSON.stringify(definitions));
//printErr('uses: ' + JSON.stringify(uses));
//printErr('values: ' + JSON.stringify(values));
@@ -2352,7 +2408,8 @@ var passes = {
compress: function() { compress = true },
noPrintMetadata: function() { printMetadata = false },
asm: function() { asm = true },
- last: function() { last = true }
+ last: function() { last = true },
+ closure: function(){} // handled in python
};
// Main