aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJez Ng <me@jezng.com>2013-06-26 01:25:13 -0700
committerJez Ng <me@jezng.com>2013-06-26 02:44:41 -0700
commite3a37fccf8a1c62388e998c8e31309f3bb834c27 (patch)
treec2edbf3b30675bfa8622d7a4954e041fad227a39
parent566447048806a59eb6e102fc364191ce292d7045 (diff)
Strict compare all the things!
-rw-r--r--tools/js-optimizer.js518
1 files changed, 259 insertions, 259 deletions
diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js
index 61d87c95..3943963a 100644
--- a/tools/js-optimizer.js
+++ b/tools/js-optimizer.js
@@ -103,7 +103,7 @@ function globalEval(x) {
eval.call(null, x);
}
-if (typeof load == 'undefined' && typeof read != 'undefined') {
+if (typeof load === 'undefined' && typeof read != 'undefined') {
this['load'] = function(f) {
globalEval(read(f));
};
@@ -194,7 +194,7 @@ function traverse(node, pre, post, stack) {
var result = pre(node, type, stack);
if (result === true) return true;
if (Array.isArray(result)) node = result; // Continue processing on this node
- if (stack && len == stack.length) stack.push(0);
+ if (stack && len === stack.length) stack.push(0);
}
if (result !== null) {
if (traverseChildren(node, traverse, pre, post, stack) === true) return true;
@@ -213,7 +213,7 @@ function traverse(node, pre, post, stack) {
function traverseGenerated(ast, pre, post, stack) {
assert(generatedFunctions);
traverse(ast, function(node) {
- if (node[0] == 'defun') {
+ if (node[0] === 'defun') {
traverse(node, pre, post, stack);
return null;
}
@@ -222,13 +222,13 @@ function traverseGenerated(ast, pre, post, stack) {
function traverseGeneratedFunctions(ast, callback) {
assert(generatedFunctions);
- if (ast[0] == 'toplevel') {
+ if (ast[0] === 'toplevel') {
var stats = ast[1];
for (var i = 0; i < stats.length; i++) {
var curr = stats[i];
- if (curr[0] == 'defun') callback(curr);
+ if (curr[0] === 'defun') callback(curr);
}
- } else if (ast[0] == 'defun') {
+ } else if (ast[0] === 'defun') {
callback(ast);
}
}
@@ -238,7 +238,7 @@ function traverseWithVariables(ast, callback) {
traverse(ast, function(node, type, stack) {
if (type in FUNCTION) {
stack.push({ type: 'function', vars: node[2] });
- } else if (type == 'var') {
+ } else if (type === 'var') {
// Find our function, add our vars
var func = stack[stack.length-1];
if (func) {
@@ -246,12 +246,12 @@ function traverseWithVariables(ast, callback) {
}
}
}, function(node, type, stack) {
- if (type == 'toplevel' || type in FUNCTION) {
+ if (type === 'toplevel' || type in FUNCTION) {
// We know all of the variables that are seen here, proceed to do relevant replacements
var allVars = stack.map(function(item) { return item ? item.vars : [] }).reduce(concatenator, []); // FIXME dictionary for speed?
traverse(node, function(node2, type2, stack2) {
// Be careful not to look into our inner functions. They have already been processed.
- if (sum(stack2) > 1 || (type == 'toplevel' && sum(stack2) == 1)) return;
+ if (sum(stack2) > 1 || (type === 'toplevel' && sum(stack2) === 1)) return;
if (type2 in FUNCTION) stack2.push(1);
return callback(node2, type2, allVars);
}, null, []);
@@ -264,7 +264,7 @@ function emptyNode() { // XXX do we need to create new nodes here? can't we reus
}
function isEmptyNode(node) {
- return node.length == 2 && node[0] == 'toplevel' && node[1].length == 0;
+ return node.length === 2 && node[0] === 'toplevel' && node[1].length === 0;
}
// Passes
@@ -286,7 +286,7 @@ function unGlobalize(ast) {
throw 'this is deprecated!'; // and does not work with parallel compilation
- assert(ast[0] == 'toplevel');
+ assert(ast[0] === 'toplevel');
var values = {};
// Find global renamings of the relevant values
ast[1].forEach(function(node, i) {
@@ -307,7 +307,7 @@ function unGlobalize(ast) {
ast[1][i][1][j] = emptyNode();
var assigned = false;
traverseWithVariables(ast, function(node, type, allVars) {
- if (type == 'assign' && node[2][0] == 'name' && node[2][1] == ident) assigned = true;
+ if (type === 'assign' && node[2][0] === 'name' && node[2][1] === ident) assigned = true;
});
ast[1][i][1][j] = [ident, value];
if (!assigned) {
@@ -317,12 +317,12 @@ function unGlobalize(ast) {
return true;
});
- if (node[1].length == 0) {
+ if (node[1].length === 0) {
ast[1][i] = emptyNode();
}
});
traverseWithVariables(ast, function(node, type, allVars) {
- if (type == 'name') {
+ if (type === 'name') {
var ident = node[1];
if (ident in values && allVars.indexOf(ident) < 0) {
return copy(values[ident]);
@@ -345,9 +345,9 @@ function unGlobalize(ast) {
// is now explicit.
function removeAssignsToUndefined(ast) {
traverse(ast, function(node, type) {
- if (type == 'assign' && jsonCompare(node[3], ['unary-prefix', 'void', ['num', 0]])) {
+ if (type === 'assign' && jsonCompare(node[3], ['unary-prefix', 'void', ['num', 0]])) {
return emptyNode();
- } else if (type == 'var') {
+ } else if (type === 'var') {
node[1] = node[1].map(function(varItem, j) {
var ident = varItem[0];
var value = varItem[1];
@@ -361,10 +361,10 @@ function removeAssignsToUndefined(ast) {
while (modified) {
modified = false;
traverse(ast, function(node, type) {
- if (type == 'assign' && jsonCompare(node[3], emptyNode())) {
+ if (type === 'assign' && jsonCompare(node[3], emptyNode())) {
modified = true;
return emptyNode();
- } else if (type == 'var') {
+ } else if (type === 'var') {
node[1] = node[1].map(function(varItem, j) {
var ident = varItem[0];
var value = varItem[1];
@@ -382,19 +382,19 @@ function removeAssignsToUndefined(ast) {
// are actually necessary. It's easy to clean those up now.
function removeUnneededLabelSettings(ast) {
traverse(ast, function(node, type) {
- if (type == 'defun') { // all of our compiled code is in defun nodes
+ if (type === 'defun') { // all of our compiled code is in defun nodes
// Find all checks
var checked = {};
traverse(node, function(node, type) {
- if (type == 'binary' && node[1] == '==' && node[2][0] == 'name' && node[2][1] == 'label') {
- assert(node[3][0] == 'num');
+ if (type === 'binary' && node[1] === '==' && node[2][0] === 'name' && node[2][1] === 'label') {
+ assert(node[3][0] === 'num');
checked[node[3][1]] = 1;
}
});
// Remove unneeded sets
traverse(node, function(node, type) {
- if (type == 'assign' && node[2][0] == 'name' && node[2][1] == 'label') {
- assert(node[3][0] == 'num');
+ if (type === 'assign' && node[2][0] === 'name' && node[2][1] === 'label') {
+ assert(node[3][0] === 'num');
if (!(node[3][1] in checked)) return emptyNode();
}
});
@@ -410,13 +410,13 @@ function simplifyExpressionsPre(ast) {
// Look for (x&A)<<B>>B and replace it with X&A if possible.
function simplifySignExtends(ast) {
traverse(ast, function(node, type) {
- if (type == 'binary' && node[1] == '>>' && node[3][0] == 'num' &&
- node[2][0] == 'binary' && node[2][1] == '<<' && node[2][3][0] == 'num' && node[3][1] == node[2][3][1]) {
+ if (type === 'binary' && node[1] === '>>' && node[3][0] === 'num' &&
+ node[2][0] === 'binary' && node[2][1] === '<<' && node[2][3][0] === 'num' && node[3][1] === node[2][3][1]) {
var innerNode = node[2][2];
var shifts = node[3][1];
- if (innerNode[0] == 'binary' && innerNode[1] == '&' && innerNode[3][0] == 'num') {
+ if (innerNode[0] === 'binary' && innerNode[1] === '&' && innerNode[3][0] === 'num') {
var mask = innerNode[3][1];
- if (mask << shifts >> shifts == mask) {
+ if (mask << shifts >> shifts === mask) {
return innerNode;
}
}
@@ -446,8 +446,8 @@ function simplifyExpressionsPre(ast) {
while (rerun) {
rerun = false;
traverse(ast, function process(node, type, stack) {
- if (type == 'binary' && node[1] == '|') {
- if (node[2][0] == 'num' && node[3][0] == 'num') {
+ if (type === 'binary' && node[1] === '|') {
+ if (node[2][0] === 'num' && node[3][0] === 'num') {
node[2][1] |= node[3][1];
return node[2];
}
@@ -469,9 +469,9 @@ function simplifyExpressionsPre(ast) {
for (var i = stack.length-1; i >= 0; i--) {
if (stack[i] >= 1) {
if (asm) {
- if (stack[stack.length-1] < 2 && node[2][0] == 'call') break; // we can only remove multiple |0s on these
+ if (stack[stack.length-1] < 2 && node[2][0] === 'call') break; // we can only remove multiple |0s on these
if (stack[stack.length-1] < 1 && (node[2][0] in COERCION_REQUIRING_OPS ||
- (node[2][0] == 'binary' && node[2][1] in COERCION_REQUIRING_BINARIES))) break; // we can remove |0 or >>2
+ (node[2][0] === 'binary' && node[2][1] in COERCION_REQUIRING_BINARIES))) break; // we can remove |0 or >>2
}
// we will replace ourselves with the non-zero side. Recursively process that node.
var result = jsonCompare(node[2], ZERO) ? node[3] : node[2], other;
@@ -482,15 +482,15 @@ function simplifyExpressionsPre(ast) {
}
rerun = true;
return process(result, result[0], stack);
- } else if (stack[i] == -1) {
+ } else if (stack[i] === -1) {
break; // Too bad, we can't
}
}
stack.push(2); // From here on up, no need for this kind of correction, it's done at the top
// (Add this at the end, so it is only added if we did not remove it)
- } else if (type == 'binary' && node[1] in USEFUL_BINARY_OPS) {
+ } else if (type === 'binary' && node[1] in USEFUL_BINARY_OPS) {
stack.push(1);
- } else if ((type == 'binary' && node[1] in SAFE_BINARY_OPS) || type == 'num' || type == 'name') {
+ } else if ((type === 'binary' && node[1] in SAFE_BINARY_OPS) || type === 'num' || type === 'name') {
stack.push(0); // This node is safe in that it does not interfere with this optimization
} else {
stack.push(-1); // This node is dangerous! Give up if you see this before you see '1'
@@ -506,7 +506,7 @@ function simplifyExpressionsPre(ast) {
var heapBits, heapUnsigned;
function parseHeap(name) {
if (name.substr(0, 4) != 'HEAP') return false;
- heapUnsigned = name[4] == 'U';
+ heapUnsigned = name[4] === 'U';
heapBits = parseInt(name.substr(heapUnsigned ? 5 : 4));
return true;
}
@@ -514,21 +514,21 @@ function simplifyExpressionsPre(ast) {
var hasTempDoublePtr = false, rerunOrZeroPass = false;
traverse(ast, function(node, type) {
- if (type == 'name') {
- if (node[1] == 'tempDoublePtr') hasTempDoublePtr = true;
- } else if (type == 'binary' && node[1] == '&' && node[3][0] == 'num') {
- if (node[2][0] == 'num') return ['num', node[2][1] & node[3][1]];
+ if (type === 'name') {
+ if (node[1] === 'tempDoublePtr') hasTempDoublePtr = true;
+ } else if (type === 'binary' && node[1] === '&' && node[3][0] === 'num') {
+ if (node[2][0] === 'num') return ['num', node[2][1] & node[3][1]];
var input = node[2];
var amount = node[3][1];
- if (input[0] == 'binary' && input[1] == '&' && input[3][0] == 'num') {
+ if (input[0] === 'binary' && input[1] === '&' && input[3][0] === 'num') {
// Collapse X & 255 & 1
node[3][1] = amount & input[3][1];
node[2] = input[2];
- } else if (input[0] == 'sub' && input[1][0] == 'name') {
+ } else if (input[0] === 'sub' && input[1][0] === 'name') {
// HEAP8[..] & 255 => HEAPU8[..]
var name = input[1][1];
if (parseHeap(name)) {
- if (amount == Math.pow(2, heapBits)-1) {
+ if (amount === Math.pow(2, heapBits)-1) {
if (!heapUnsigned) {
input[1][1] = 'HEAPU' + heapBits; // make unsigned
}
@@ -542,14 +542,14 @@ function simplifyExpressionsPre(ast) {
}
}
}
- } else if (type == 'binary' && node[1] == '>>' && node[3][0] == 'num' &&
- node[2][0] == 'binary' && node[2][1] == '<<' && node[2][3][0] == 'num' &&
- node[2][2][0] == 'sub' && node[2][2][1][0] == 'name') {
+ } else if (type === 'binary' && node[1] === '>>' && node[3][0] === 'num' &&
+ 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
var amount = node[3][1];
var name = node[2][2][1][1];
- if (amount == node[2][3][1] && parseHeap(name)) {
- if (heapBits == 32 - amount) {
+ if (amount === node[2][3][1] && parseHeap(name)) {
+ if (heapBits === 32 - amount) {
node[2][2][1][1] = 'HEAP' + heapBits;
node[1] = '|';
node[2] = node[2][2];
@@ -558,29 +558,29 @@ function simplifyExpressionsPre(ast) {
return node;
}
}
- } else if (type == 'assign') {
+ } else if (type === 'assign') {
// optimizations for assigning into HEAP32 specifically
- if (node[1] === true && node[2][0] == 'sub' && node[2][1][0] == 'name' && node[2][1][1] == 'HEAP32') {
+ if (node[1] === true && node[2][0] === 'sub' && node[2][1][0] === 'name' && node[2][1][1] === 'HEAP32') {
// HEAP32[..] = x | 0 does not need the | 0 (unless it is a mandatory |0 of a call)
- if (node[3][0] == 'binary' && node[3][1] == '|') {
- if (node[3][2][0] == 'num' && node[3][2][1] == 0 && node[3][3][0] != 'call') {
+ if (node[3][0] === 'binary' && node[3][1] === '|') {
+ if (node[3][2][0] === 'num' && node[3][2][1] === 0 && node[3][3][0] != 'call') {
node[3] = node[3][3];
- } else if (node[3][3][0] == 'num' && node[3][3][1] == 0 && node[3][2][0] != 'call') {
+ } else if (node[3][3][0] === 'num' && node[3][3][1] === 0 && node[3][2][0] != 'call') {
node[3] = node[3][2];
}
}
}
var value = node[3];
- if (value[0] == 'binary' && value[1] == '|') {
+ if (value[0] === 'binary' && value[1] === '|') {
// canonicalize order of |0 to end
- if (value[2][0] == 'num' && value[2][1] == 0) {
+ if (value[2][0] === 'num' && value[2][1] === 0) {
var temp = value[2];
value[2] = value[3];
value[3] = temp;
}
// if a seq ends in an |0, remove an external |0
// note that it is only safe to do this in assigns, like we are doing here (return (x, y|0); is not valid)
- if (value[2][0] == 'seq' && value[2][2][0] == 'binary' && value[2][2][1] in USEFUL_BINARY_OPS) {
+ if (value[2][0] === 'seq' && value[2][2][0] === 'binary' && value[2][2][1] in USEFUL_BINARY_OPS) {
node[3] = value[2];
}
}
@@ -592,27 +592,27 @@ function simplifyExpressionsPre(ast) {
if (asm) {
if (hasTempDoublePtr) {
traverse(ast, function(node, type) {
- if (type == 'assign') {
- if (node[1] === true && node[2][0] == 'sub' && node[2][1][0] == 'name' && node[2][1][1] == 'HEAP32') {
+ if (type === 'assign') {
+ if (node[1] === true && node[2][0] === 'sub' && node[2][1][0] === 'name' && node[2][1][1] === 'HEAP32') {
// remove bitcasts that are now obviously pointless, e.g.
// HEAP32[$45 >> 2] = HEAPF32[tempDoublePtr >> 2] = ($14 < $28 ? $14 : $28) - $42, HEAP32[tempDoublePtr >> 2] | 0;
var value = node[3];
- if (value[0] == 'seq' && value[1][0] == 'assign' && value[1][2][0] == 'sub' && value[1][2][1][0] == 'name' && value[1][2][1][1] == 'HEAPF32' &&
- value[1][2][2][0] == 'binary' && value[1][2][2][2][0] == 'name' && value[1][2][2][2][1] == 'tempDoublePtr') {
+ if (value[0] === 'seq' && value[1][0] === 'assign' && value[1][2][0] === 'sub' && value[1][2][1][0] === 'name' && value[1][2][1][1] === 'HEAPF32' &&
+ value[1][2][2][0] === 'binary' && value[1][2][2][2][0] === 'name' && value[1][2][2][2][1] === 'tempDoublePtr') {
// transform to HEAPF32[$45 >> 2] = ($14 < $28 ? $14 : $28) - $42;
node[2][1][1] = 'HEAPF32';
node[3] = value[1][3];
}
}
- } else if (type == 'seq') {
+ } else if (type === 'seq') {
// (HEAP32[tempDoublePtr >> 2] = HEAP32[$37 >> 2], +HEAPF32[tempDoublePtr >> 2])
// ==>
// +HEAPF32[$37 >> 2]
- if (node[0] == 'seq' && node[1][0] == 'assign' && node[1][2][0] == 'sub' && node[1][2][1][0] == 'name' &&
- (node[1][2][1][1] == 'HEAP32' || node[1][2][1][1] == 'HEAPF32') &&
- node[1][2][2][0] == 'binary' && node[1][2][2][2][0] == 'name' && node[1][2][2][2][1] == 'tempDoublePtr' &&
- node[1][3][0] == 'sub' && node[1][3][1][0] == 'name' && (node[1][3][1][1] == 'HEAP32' || node[1][3][1][1] == 'HEAPF32')) {
- if (node[1][2][1][1] == 'HEAP32') {
+ if (node[0] === 'seq' && node[1][0] === 'assign' && node[1][2][0] === 'sub' && node[1][2][1][0] === 'name' &&
+ (node[1][2][1][1] === 'HEAP32' || node[1][2][1][1] === 'HEAPF32') &&
+ node[1][2][2][0] === 'binary' && node[1][2][2][2][0] === 'name' && node[1][2][2][2][1] === 'tempDoublePtr' &&
+ node[1][3][0] === 'sub' && node[1][3][1][0] === 'name' && (node[1][3][1][1] === 'HEAP32' || node[1][3][1][1] === 'HEAPF32')) {
+ if (node[1][2][1][1] === 'HEAP32') {
node[1][3][1][1] = 'HEAPF32';
return ['unary-prefix', '+', node[1][3]];
} else {
@@ -627,11 +627,11 @@ function simplifyExpressionsPre(ast) {
// the other heap type, then eliminate the bitcast
var bitcastVars = {};
traverse(ast, function(node, type) {
- if (type == 'assign' && node[1] === true && node[2][0] == 'name') {
+ if (type === 'assign' && node[1] === true && node[2][0] === 'name') {
var value = node[3];
- if (value[0] == 'seq' && value[1][0] == 'assign' && value[1][2][0] == 'sub' && value[1][2][1][0] == 'name' &&
- (value[1][2][1][1] == 'HEAP32' || value[1][2][1][1] == 'HEAPF32') &&
- value[1][2][2][0] == 'binary' && value[1][2][2][2][0] == 'name' && value[1][2][2][2][1] == 'tempDoublePtr') {
+ if (value[0] === 'seq' && value[1][0] === 'assign' && value[1][2][0] === 'sub' && value[1][2][1][0] === 'name' &&
+ (value[1][2][1][1] === 'HEAP32' || value[1][2][1][1] === 'HEAPF32') &&
+ value[1][2][2][0] === 'binary' && value[1][2][2][2][0] === 'name' && value[1][2][2][2][1] === 'tempDoublePtr') {
var name = node[2][1];
if (!bitcastVars[name]) bitcastVars[name] = {
define_HEAP32: 0, define_HEAPF32: 0, use_HEAP32: 0, use_HEAPF32: 0, bad: false, namings: 0, defines: [], uses: []
@@ -642,15 +642,15 @@ function simplifyExpressionsPre(ast) {
}
});
traverse(ast, function(node, type) {
- if (type == 'name' && bitcastVars[node[1]]) {
+ if (type === 'name' && bitcastVars[node[1]]) {
bitcastVars[node[1]].namings++;
- } else if (type == 'assign' && node[1] === true) {
+ } else if (type === 'assign' && node[1] === true) {
var value = node[3];
- if (value[0] == 'name') {
+ if (value[0] === 'name') {
var name = value[1];
if (bitcastVars[name]) {
var target = node[2];
- if (target[0] == 'sub' && target[1][0] == 'name' && (target[1][1] == 'HEAP32' || target[1][1] == 'HEAPF32')) {
+ if (target[0] === 'sub' && target[1][0] === 'name' && (target[1][1] === 'HEAP32' || target[1][1] === 'HEAPF32')) {
bitcastVars[name]['use_' + target[1][1]]++;
bitcastVars[name].uses.push(node);
}
@@ -662,14 +662,14 @@ function simplifyExpressionsPre(ast) {
for (var v in bitcastVars) {
var info = bitcastVars[v];
// good variables define only one type, use only one type, have definitions and uses, and define as a different type than they use
- if (info.define_HEAP32*info.define_HEAPF32 == 0 && info.use_HEAP32*info.use_HEAPF32 == 0 &&
+ if (info.define_HEAP32*info.define_HEAPF32 === 0 && info.use_HEAP32*info.use_HEAPF32 === 0 &&
info.define_HEAP32+info.define_HEAPF32 > 0 && info.use_HEAP32+info.use_HEAPF32 > 0 &&
- info.define_HEAP32*info.use_HEAP32 == 0 && info.define_HEAPF32*info.use_HEAPF32 == 0 &&
- v in asmData.vars && info.namings == info.define_HEAP32+info.define_HEAPF32+info.use_HEAP32+info.use_HEAPF32) {
+ info.define_HEAP32*info.use_HEAP32 === 0 && info.define_HEAPF32*info.use_HEAPF32 === 0 &&
+ v in asmData.vars && info.namings === info.define_HEAP32+info.define_HEAPF32+info.use_HEAP32+info.use_HEAPF32) {
var correct = info.use_HEAP32 ? 'HEAPF32' : 'HEAP32';
info.defines.forEach(function(define) {
define[3] = define[3][1][3];
- if (correct == 'HEAP32') {
+ if (correct === 'HEAP32') {
define[3] = ['binary', '|', define[3], ['num', 0]];
} else {
define[3] = ['unary-prefix', '+', define[3]];
@@ -687,7 +687,7 @@ function simplifyExpressionsPre(ast) {
// optimize num >> num, in asm we need this here since we do not run optimizeShifts
traverse(ast, function(node, type) {
- if (type == 'binary' && node[1] == '>>' && node[2][0] == 'num' && node[3][0] == 'num') {
+ if (type === 'binary' && node[1] === '>>' && node[2][0] === 'num' && node[3][0] === 'num') {
node[0] = 'num';
node[1] = node[2][1] >> node[3][1];
node.length = 2;
@@ -703,15 +703,15 @@ function simplifyExpressionsPre(ast) {
while (rerun) {
rerun = false;
traverse(ast, function(node, type) {
- if (type == 'binary' && node[1] === '+') {
- if (node[2][0] == 'num' && node[3][0] == 'num') {
+ if (type === 'binary' && node[1] === '+') {
+ if (node[2][0] === 'num' && node[3][0] === 'num') {
rerun = true;
return ['num', node[2][1] + node[3][1]];
}
for (var i = 2; i <= 3; i++) {
var ii = 5-i;
for (var j = 2; j <= 3; j++) {
- if (node[i][0] == 'num' && node[ii][0] == 'binary' && node[ii][1] === '+' && node[ii][j][0] == 'num') {
+ if (node[i][0] === 'num' && node[ii][0] === 'binary' && node[ii][1] === '+' && node[ii][j][0] === 'num') {
rerun = true;
node[ii][j][1] += node[i][1];
return node[ii];
@@ -723,15 +723,15 @@ function simplifyExpressionsPre(ast) {
}
}
- // if (x == 0) can be if (!x), etc.
+ // if (x === 0) can be if (!x), etc.
function simplifyZeroComp(ast) {
traverse(ast, function(node, type) {
var binary;
- if (type == 'if' && (binary = node[1])[0] == 'binary') {
- if ((binary[1] == '!=' || binary[1] == '!==') && binary[3][0] == 'num' && binary[3][1] == 0) {
+ if (type === 'if' && (binary = node[1])[0] === 'binary') {
+ if ((binary[1] === '!=' || binary[1] === '!==') && binary[3][0] === 'num' && binary[3][1] === 0) {
node[1] = binary[2];
return node;
- } else if ((binary[1] == '==' || binary[1] == '===') && binary[3][0] == 'num' && binary[3][1] == 0) {
+ } else if ((binary[1] === '==' || binary[1] === '===') && binary[3][0] === 'num' && binary[3][1] === 0) {
node[1] = ['unary-prefix', '!', binary[2]];
return node;
}
@@ -743,7 +743,7 @@ function simplifyExpressionsPre(ast) {
// Add final returns when necessary
var returnType = null;
traverse(fun, function(node, type) {
- if (type == 'return' && node[1]) {
+ if (type === 'return' && node[1]) {
returnType = detectAsmCoercion(node[1]);
}
});
@@ -753,7 +753,7 @@ function simplifyExpressionsPre(ast) {
var last = stats[stats.length-1];
if (last[0] != 'return') {
var returnValue = ['num', 0];
- if (returnType == ASM_DOUBLE) returnValue = ['unary-prefix', '+', returnValue];
+ if (returnType === ASM_DOUBLE) returnValue = ['unary-prefix', '+', returnValue];
stats.push(['return', returnValue]);
}
}
@@ -803,11 +803,11 @@ function optimizeShiftsInternal(ast, conservative) {
// vars
// XXX if var has >>=, ignore it here? That means a previous pass already optimized it
var hasSwitch = traverse(fun, function(node, type) {
- if (type == 'var') {
+ if (type === 'var') {
node[1].forEach(function(arg) {
newVar(arg[0], false, arg[1]);
});
- } else if (type == 'switch') {
+ } else if (type === 'switch') {
// The relooper can't always optimize functions, and we currently don't work with
// switch statements when optimizing shifts. Bail.
return true;
@@ -820,25 +820,25 @@ function optimizeShiftsInternal(ast, conservative) {
// optimize for code size, not speed.
traverse(fun, function(node, type, stack) {
stack.push(node);
- if (type == 'name' && vars[node[1]] && stack[stack.length-2][0] != 'assign') {
+ if (type === 'name' && vars[node[1]] && stack[stack.length-2][0] != 'assign') {
vars[node[1]].uses++;
- } else if (type == 'assign' && node[2][0] == 'name' && vars[node[2][1]]) {
+ } else if (type === 'assign' && node[2][0] === 'name' && vars[node[2][1]]) {
vars[node[2][1]].defs++;
}
}, null, []);
// First, break up elements inside a shift. This lets us see clearly what to do next.
traverse(fun, function(node, type) {
- if (type == 'binary' && node[1] == '>>' && node[3][0] == 'num') {
+ if (type === 'binary' && node[1] === '>>' && node[3][0] === 'num') {
var shifts = node[3][1];
if (shifts <= MAX_SHIFTS) {
// Push the >> inside the value elements
function addShift(subNode) {
- if (subNode[0] == 'binary' && subNode[1] === '+') {
+ if (subNode[0] === 'binary' && subNode[1] === '+') {
subNode[2] = addShift(subNode[2]);
subNode[3] = addShift(subNode[3]);
return subNode;
}
- if (subNode[0] == 'name' && !subNode[2]) { // names are returned with a shift, but we also note their being shifted
+ if (subNode[0] === 'name' && !subNode[2]) { // names are returned with a shift, but we also note their being shifted
var name = subNode[1];
if (vars[name]) {
vars[name].timesShifted[shifts]++;
@@ -852,7 +852,7 @@ function optimizeShiftsInternal(ast, conservative) {
}
});
traverse(fun, function(node, type) {
- if (node[0] == 'name' && node[2]) {
+ if (node[0] === 'name' && node[2]) {
return node.slice(0, 2); // clean up our notes
}
});
@@ -861,7 +861,7 @@ function optimizeShiftsInternal(ast, conservative) {
for (var name in vars) {
var data = vars[name];
var totalTimesShifted = sum(data.timesShifted);
- if (totalTimesShifted == 0) {
+ if (totalTimesShifted === 0) {
continue;
}
if (totalTimesShifted != Math.max.apply(null, data.timesShifted)) {
@@ -871,7 +871,7 @@ function optimizeShiftsInternal(ast, conservative) {
if (funFinished[name]) continue;
// We have one shift size (and possible unshifted uses). Consider replacing this variable with a shifted clone. If
// the estimated benefit is >0, we will do it
- if (data.defs == 1) {
+ if (data.defs === 1) {
data.benefit = totalTimesShifted - 2*(data.defs + (data.param ? 1 : 0));
}
if (conservative) data.benefit = 0;
@@ -887,7 +887,7 @@ function optimizeShiftsInternal(ast, conservative) {
//printErr(JSON.stringify(vars));
function cleanNotes() { // We need to mark 'name' nodes as 'processed' in some passes here; this cleans the notes up
traverse(fun, function(node, type) {
- if (node[0] == 'name' && node[2]) {
+ if (node[0] === 'name' && node[2]) {
return node.slice(0, 2);
}
});
@@ -909,7 +909,7 @@ function optimizeShiftsInternal(ast, conservative) {
}
traverse(fun, function(node, type, stack) { // add shift to assignments
stack.push(node);
- if (node[0] == 'assign' && node[1] === true && node[2][0] == 'name' && needsShift(node[2][1]) && !node[2][2]) {
+ if (node[0] === 'assign' && node[1] === true && node[2][0] === 'name' && needsShift(node[2][1]) && !node[2][2]) {
var name = node[2][1];
var data = vars[name];
var parent = stack[stack.length-3];
@@ -917,7 +917,7 @@ function optimizeShiftsInternal(ast, conservative) {
assert(statements, 'Invalid parent for assign-shift: ' + dump(parent));
var i = statements.indexOf(stack[stack.length-2]);
statements.splice(i+1, 0, ['stat', ['assign', true, ['name', name + '$s' + data.primaryShift], ['binary', '>>', ['name', name, true], ['num', data.primaryShift]]]]);
- } else if (node[0] == 'var') {
+ } else if (node[0] === 'var') {
var args = node[1];
for (var i = 0; i < args.length; i++) {
var arg = args[i];
@@ -933,14 +933,14 @@ function optimizeShiftsInternal(ast, conservative) {
cleanNotes();
traverse(fun, function(node, type, stack) { // replace shifted name with new variable
stack.push(node);
- if (node[0] == 'binary' && node[1] == '>>' && node[2][0] == 'name' && needsShift(node[2][1]) && node[3][0] == 'num') {
+ if (node[0] === 'binary' && node[1] === '>>' && node[2][0] === 'name' && needsShift(node[2][1]) && node[3][0] === 'num') {
var name = node[2][1];
var data = vars[name];
var parent = stack[stack.length-2];
// Don't modify in |x$sN = x >> 2|, in normal assigns and in var assigns
- if (parent[0] == 'assign' && parent[2][0] == 'name' && parent[2][1] == name + '$s' + data.primaryShift) return;
- if (parent[0] == name + '$s' + data.primaryShift) return;
- if (node[3][1] == data.primaryShift) {
+ if (parent[0] === 'assign' && parent[2][0] === 'name' && parent[2][1] === name + '$s' + data.primaryShift) return;
+ if (parent[0] === name + '$s' + data.primaryShift) return;
+ if (node[3][1] === data.primaryShift) {
return ['name', name + '$s' + data.primaryShift];
}
}
@@ -951,8 +951,8 @@ function optimizeShiftsInternal(ast, conservative) {
while (more) { // combine shifts in the same direction as an optimization
more = false;
traverse(fun, function(node, type) {
- if (node[0] == 'binary' && node[1] in SIMPLE_SHIFTS && node[2][0] == 'binary' && node[2][1] == node[1] &&
- node[3][0] == 'num' && node[2][3][0] == 'num') { // do not turn a << b << c into a << b + c; while logically identical, it is slower
+ if (node[0] === 'binary' && node[1] in SIMPLE_SHIFTS && node[2][0] === 'binary' && node[2][1] === node[1] &&
+ node[3][0] === 'num' && node[2][3][0] === 'num') { // do not turn a << b << c into a << b + c; while logically identical, it is slower
more = true;
return ['binary', node[1], node[2][2], ['num', node[3][1] + node[2][3][1]]];
}
@@ -961,32 +961,32 @@ function optimizeShiftsInternal(ast, conservative) {
// Before recombining, do some additional optimizations
traverse(fun, function(node, type) {
// Apply constant shifts onto constants
- if (type == 'binary' && node[1] == '>>' && node[2][0] == 'num' && node[3][0] == 'num' && node[3][1] <= MAX_SHIFTS) {
+ if (type === 'binary' && node[1] === '>>' && node[2][0] === 'num' && node[3][0] === 'num' && node[3][1] <= MAX_SHIFTS) {
var subNode = node[2];
var shifts = node[3][1];
var result = subNode[1] / Math.pow(2, shifts);
- if (result % 1 == 0) {
+ if (result % 1 === 0) {
subNode[1] = result;
return subNode;
}
}
// Optimize the case of ($a*80)>>2 into ($a*20)|0
- if (type == 'binary' && node[1] in SIMPLE_SHIFTS &&
- node[2][0] == 'binary' && node[2][1] == '*') {
+ if (type === 'binary' && node[1] in SIMPLE_SHIFTS &&
+ node[2][0] === 'binary' && node[2][1] === '*') {
var mulNode = node[2];
- if (mulNode[2][0] == 'num') {
+ if (mulNode[2][0] === 'num') {
var temp = mulNode[2];
mulNode[2] = mulNode[3];
mulNode[3] = temp;
}
- if (mulNode[3][0] == 'num') {
- if (node[1] == '<<') {
+ if (mulNode[3][0] === 'num') {
+ if (node[1] === '<<') {
mulNode[3][1] *= Math.pow(2, node[3][1]);
node[1] = '|';
node[3][1] = 0;
return node;
} else {
- if (mulNode[3][1] % Math.pow(2, node[3][1]) == 0) {
+ if (mulNode[3][1] % Math.pow(2, node[3][1]) === 0) {
mulNode[3][1] /= Math.pow(2, node[3][1]);
node[1] = '|';
node[3][1] = 0;
@@ -997,8 +997,8 @@ function optimizeShiftsInternal(ast, conservative) {
}
/* XXX - theoretically useful optimization(s), but commented out as not helpful in practice
// Transform (x << 2) >> 2 into x & mask or something even simpler
- if (type == 'binary' && node[1] == '>>' && node[3][0] == 'num' &&
- node[2][0] == 'binary' && node[2][1] == '<<' && node[2][3][0] == 'num' && node[3][1] == node[2][3][1]) {
+ if (type === 'binary' && node[1] === '>>' && node[3][0] === 'num' &&
+ node[2][0] === 'binary' && node[2][1] === '<<' && node[2][3][0] === 'num' && node[3][1] === node[2][3][1]) {
var subNode = node[2];
var shifts = node[3][1];
var mask = ((0xffffffff << shifts) >>> shifts) | 0;
@@ -1011,11 +1011,11 @@ function optimizeShiftsInternal(ast, conservative) {
// Re-combine remaining shifts, to undo the breaking up we did before. may require reordering inside +'s
traverse(fun, function(node, type, stack) {
stack.push(node);
- if (type == 'binary' && node[1] === '+' && (stack[stack.length-2][0] != 'binary' || stack[stack.length-2][1] !== '+')) {
+ if (type === 'binary' && node[1] === '+' && (stack[stack.length-2][0] != 'binary' || stack[stack.length-2][1] !== '+')) {
// 'Flatten' added items
var addedItems = [];
function flatten(node) {
- if (node[0] == 'binary' && node[1] === '+') {
+ if (node[0] === 'binary' && node[1] === '+') {
flatten(node[2]);
flatten(node[3]);
} else {
@@ -1028,15 +1028,15 @@ function optimizeShiftsInternal(ast, conservative) {
function originalOrderKey(item) {
return -originalOrder.indexOf(item);
}
- if (node[0] == 'binary' && node[1] in SIMPLE_SHIFTS) {
- if (node[3][0] == 'num' && node[3][1] <= MAX_SHIFTS) return 2*node[3][1] + (node[1] == '>>' ? 100 : 0); // 0-106
- return (node[1] == '>>' ? 20000 : 10000) + originalOrderKey(node);
+ if (node[0] === 'binary' && node[1] in SIMPLE_SHIFTS) {
+ if (node[3][0] === 'num' && node[3][1] <= MAX_SHIFTS) return 2*node[3][1] + (node[1] === '>>' ? 100 : 0); // 0-106
+ return (node[1] === '>>' ? 20000 : 10000) + originalOrderKey(node);
}
- if (node[0] == 'num') return -20000 + node[1];
+ if (node[0] === 'num') return -20000 + node[1];
return -10000 + originalOrderKey(node); // Don't modify the original order if we don't modify anything
}
for (var i = 0; i < addedItems.length; i++) {
- if (addedItems[i][0] == 'string') return; // this node is not relevant for us
+ if (addedItems[i][0] === 'string') return; // this node is not relevant for us
}
addedItems.sort(function(node1, node2) {
return key(node1) - key(node2);
@@ -1045,7 +1045,7 @@ function optimizeShiftsInternal(ast, conservative) {
var i = 0;
while (i < addedItems.length-1) { // re-combine inside addedItems
var k = key(addedItems[i]), k1 = key(addedItems[i+1]);
- if (k == k1 && k >= 0 && k1 <= 106) {
+ if (k === k1 && k >= 0 && k1 <= 106) {
addedItems[i] = ['binary', addedItems[i][1], ['binary', '+', addedItems[i][2], addedItems[i+1][2]], addedItems[i][3]];
addedItems.splice(i+1, 1);
} else {
@@ -1054,7 +1054,7 @@ function optimizeShiftsInternal(ast, conservative) {
}
var num = 0;
for (i = 0; i < addedItems.length; i++) { // combine all numbers into one
- if (addedItems[i][0] == 'num') {
+ if (addedItems[i][0] === 'num') {
num += addedItems[i][1];
addedItems.splice(i, 1);
i--;
@@ -1066,7 +1066,7 @@ function optimizeShiftsInternal(ast, conservative) {
// so it might take more space, but normally at most one more digit).
var added = false;
for (i = 0; i < addedItems.length; i++) {
- if (addedItems[i][0] == 'binary' && addedItems[i][1] == '>>' && addedItems[i][3][0] == 'num' && addedItems[i][3][1] <= MAX_SHIFTS) {
+ if (addedItems[i][0] === 'binary' && addedItems[i][1] === '>>' && addedItems[i][3][0] === 'num' && addedItems[i][3][1] <= MAX_SHIFTS) {
addedItems[i] = ['binary', '>>', ['binary', '+', addedItems[i][2], ['num', num << addedItems[i][3][1]]], addedItems[i][3]];
added = true;
}
@@ -1103,8 +1103,8 @@ function optimizeShiftsAggressive(ast) {
// if (!(x < 5))
// or such. Simplifying these saves space and time.
function simplifyNotCompsDirect(node) {
- if (node[0] == 'unary-prefix' && node[1] == '!') {
- if (node[2][0] == 'binary') {
+ if (node[0] === 'unary-prefix' && node[1] === '!') {
+ if (node[2][0] === 'binary') {
switch(node[2][1]) {
case '<': return ['binary', '>=', node[2][2], node[2][3]];
case '>': return ['binary', '<=', node[2][2], node[2][3]];
@@ -1115,7 +1115,7 @@ function simplifyNotCompsDirect(node) {
case '===': return ['binary', '!==', node[2][2], node[2][3]];
case '!==': return ['binary', '===', node[2][2], node[2][3]];
}
- } else if (node[2][0] == 'unary-prefix' && node[2][1] == '!') {
+ } e