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.js43
1 files changed, 36 insertions, 7 deletions
diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js
index d1f164d4..ee067a19 100644
--- a/tools/js-optimizer.js
+++ b/tools/js-optimizer.js
@@ -120,6 +120,7 @@ var FUNCTION = set('defun', 'function');
var LOOP = set('do', 'while', 'for');
var LOOP_FLOW = set('break', 'continue');
var ASSIGN_OR_ALTER = set('assign', 'unary-postfix', 'unary-prefix');
+var CONTROL_FLOW = set('do', 'while', 'for', 'if', 'switch');
var NULL_NODE = ['name', 'null'];
var UNDEFINED_NODE = ['unary-prefix', 'void', ['num', 0]];
@@ -1169,26 +1170,54 @@ function registerize(ast) {
}
});
vacuum(fun);
- // Find the # of uses of each variable
+ // Find the # of uses of each variable.
+ // While doing so, check if all a variable's uses are dominated in a simple
+ // way by a simple assign, if so, then we can assign its register to it
+ // just for its definition to its last use, and not to the entire toplevel loop,
+ // we call such variables "optimizable"
var varUses = {};
- var varAssigns = {};
+ var level = 1;
+ var levelDominations = {};
+ var varLevels = {};
+ var possibles = {};
+ var unoptimizables = {};
traverse(fun, function(node, type) {
if (type == 'name') {
var name = node[1];
if (localVars[name]) {
if (!varUses[name]) varUses[name] = 0;
varUses[name]++;
+ if (possibles[name] && !varLevels[name]) unoptimizables[name] = 1; // used outside of simple domination
}
- } else if (type in ASSIGN_OR_ALTER) {
+ } else if (type == 'assign' && typeof node[1] != 'string') {
if (node[2] && node[2][0] == 'name') {
var name = node[2][1];
- if (localVars[name]) {
- if (!varAssigns[name]) varAssigns[name] = 0;
- varAssigns[name]++;
+ // if local and not yet used, this might be optimizable if we dominate
+ // all other uses
+ if (localVars[name] && !varUses[name] && !varLevels[name]) {
+ possibles[name] = 1;
+ varLevels[name] = level;
+ if (!levelDominations[level]) levelDominations[level] = {};
+ levelDominations[level][name] = 1;
}
}
+ } else if (type in CONTROL_FLOW) {
+ level++;
+ }
+ }, function(node, type) {
+ if (type in CONTROL_FLOW) {
+ // Invalidate all dominating on this level, further users make it unoptimizable
+ for (var name in levelDominations[level]) {
+ varLevels[name] = 0;
+ }
+ levelDominations[level] = null;
+ level--;
}
});
+ var optimizables = {};
+ for (var possible in possibles) {
+ if (!unoptimizables[possible]) optimizables[possible] = 1;
+ }
// Go through the function's code, assigning 'registers'.
// The only tricky bit is to keep variables locked on a register through loops,
// since they can potentially be returned to. We use a simple approach of
@@ -1217,7 +1246,7 @@ function registerize(ast) {
varUses[name]--;
assert(varUses[name] >= 0);
if (varUses[name] == 0) {
- if (loops == 0) {
+ if (loops == 0 || optimizables[name]) {
// free register
freeRegs.push(reg);
} else {