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.js34
1 files changed, 29 insertions, 5 deletions
diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js
index 9efca25f..161ed59c 100644
--- a/tools/js-optimizer.js
+++ b/tools/js-optimizer.js
@@ -271,6 +271,16 @@ function isEmptyNode(node) {
return node.length === 2 && node[0] === 'toplevel' && node[1].length === 0;
}
+function clearEmptyNodes(list) {
+ for (var i = 0; i < list.length;) {
+ if (isEmptyNode(list[i]) || (list[i][0] === 'stat' && isEmptyNode(list[i][1]))) {
+ list.splice(i, 1);
+ } else {
+ i++;
+ }
+ }
+}
+
// Passes
// Dump the AST. Useful for debugging. For example,
@@ -2134,14 +2144,11 @@ function registerize(ast) {
// In memSafe mode, we are more careful and assume functions can replace HEAP and FUNCTION_TABLE, which
// can happen in ALLOW_MEMORY_GROWTH mode
-var ELIMINATION_SAFE_NODES = set('var', 'assign', 'call', 'if', 'toplevel', 'do', 'return', 'label', 'switch'); // do is checked carefully, however
+var ELIMINATION_SAFE_NODES = set('var', 'assign', 'call', 'if', 'toplevel', 'do', 'return', 'label', 'switch', 'binary', 'unary-prefix'); // do is checked carefully, however
var IGNORABLE_ELIMINATOR_SCAN_NODES = set('num', 'toplevel', 'string', 'break', 'continue', 'dot'); // dot can only be STRING_TABLE.*
var ABORTING_ELIMINATOR_SCAN_NODES = set('new', 'object', 'function', 'defun', 'for', 'while', 'array', 'throw'); // we could handle some of these, TODO, but nontrivial (e.g. for while, the condition is hit multiple times after the body)
function isTempDoublePtrAccess(node) { // these are used in bitcasts; they are not really affecting memory, and should cause no invalidation
- // XXX note that we assume they have no effect. this is only true due to the compiler emitting (write, read)
- // using the comma operator, so they are not split up. Otherwise, we would need to invalidate
- // tempDoublePtr when it is used, so write; read; write; read; would not become write; write; read; read;
assert(node[0] === 'sub');
return (node[2][0] === 'name' && node[2][1] === 'tempDoublePtr') ||
(node[2][0] === 'binary' && ((node[2][2][0] === 'name' && node[2][2][1] === 'tempDoublePtr') ||
@@ -2427,7 +2434,12 @@ function eliminate(ast, memSafe) {
if (allowTracking) track(name, node[3], node);
}
} else if (target[0] === 'sub') {
- if (!isTempDoublePtrAccess(target) && !memoryInvalidated) {
+ if (isTempDoublePtrAccess(target)) {
+ if (!globalsInvalidated) {
+ invalidateGlobals();
+ globalsInvalidated = true;
+ }
+ } else if (!memoryInvalidated) {
invalidateMemory();
memoryInvalidated = true;
}
@@ -2687,6 +2699,7 @@ function eliminate(ast, memSafe) {
}
if (ifTrue[1][0] && ifTrue[1][0][0] === 'break') {
var assigns = ifFalse[1];
+ clearEmptyNodes(assigns);
var loopers = [], helpers = [];
for (var i = 0; i < assigns.length; i++) {
if (assigns[i][0] === 'stat' && assigns[i][1][0] === 'assign') {
@@ -3112,6 +3125,17 @@ function outline(ast) {
parts = [];
var curr = node;
while (1) {
+ if (!curr[3]) {
+ // we normally expect ..if (cond) { .. } else [if (nextCond) {] (in [] is what we hope to see)
+ // but are now seeing ..if (cond) { .. } with no else. This might be
+ // ..if (cond) if (nextCond) {
+ // which vacuum can generate from if (cond) {} else if (nextCond), making it
+ // if (!cond) if (nextCond)
+ // so we undo that, in hopes of making it more flattenable
+ curr[3] = curr[2];
+ curr[2] = ['block', []];
+ curr[1] = simplifyNotCompsDirect(['unary-prefix', '!', curr[1]]);
+ }
parts.push({ condition: curr[1], body: curr[2] });
curr = curr[3];
if (!curr) break;