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.js98
1 files changed, 77 insertions, 21 deletions
diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js
index 532dc7fc..c772f667 100644
--- a/tools/js-optimizer.js
+++ b/tools/js-optimizer.js
@@ -144,7 +144,7 @@ var FALSE_NODE = ['unary-prefix', '!', ['num', 1]];
var GENERATED_FUNCTIONS_MARKER = '// EMSCRIPTEN_GENERATED_FUNCTIONS';
var generatedFunctions = false; // whether we have received only generated functions
-var minifierInfo = null;
+var extraInfo = null;
function srcToAst(src) {
return uglify.parser.parse(src, false, debug);
@@ -1638,7 +1638,7 @@ function denormalizeAsm(func, data) {
// Very simple 'registerization', coalescing of variables into a smaller number,
// as part of minification. Globals-level minification began in a previous pass,
-// we receive minifierInfo which tells us how to rename globals. (Only in asm.js.)
+// we receive extraInfo which tells us how to rename globals. (Only in asm.js.)
//
// We do not optimize when there are switches, so this pass only makes sense with
// relooping.
@@ -1680,7 +1680,7 @@ function registerize(ast) {
}
});
vacuum(fun);
- if (minifierInfo) {
+ if (extraInfo) {
assert(asm);
var usedGlobals = {};
var nextLocal = 0;
@@ -1688,7 +1688,7 @@ function registerize(ast) {
traverse(fun, function(node, type) {
if (type === 'name') {
var name = node[1];
- var minified = minifierInfo.globals[name];
+ var minified = extraInfo.globals[name];
if (minified) {
assert(!localVars[name], name); // locals must not shadow globals, or else we don't know which is which
if (localVars[minified]) {
@@ -1721,8 +1721,8 @@ function registerize(ast) {
}
}
});
- assert(fun[1] in minifierInfo.globals, fun[1]);
- fun[1] = minifierInfo.globals[fun[1]];
+ assert(fun[1] in extraInfo.globals, fun[1]);
+ fun[1] = extraInfo.globals[fun[1]];
assert(fun[1]);
var nextRegName = 0;
}
@@ -1730,14 +1730,14 @@ function registerize(ast) {
function getNewRegName(num, name) {
if (!asm) return 'r' + num;
var type = asmData.vars[name];
- if (!minifierInfo) {
+ if (!extraInfo) {
var ret = (type ? 'd' : 'i') + num;
regTypes[ret] = type;
return ret;
}
// find the next free minified name that is not used by a global that shows up in this function
- while (nextRegName < minifierInfo.names.length) {
- var ret = minifierInfo.names[nextRegName++];
+ while (nextRegName < extraInfo.names.length) {
+ var ret = extraInfo.names[nextRegName++];
if (!usedGlobals[ret]) {
regTypes[ret] = type;
return ret;
@@ -2540,13 +2540,13 @@ function eliminate(ast, memSafe) {
var ifTrue = last[2];
var ifFalse = last[3];
var flip = false;
- if (ifFalse[1][0][0] === 'break') { // canonicalize break in the if
+ if (ifFalse[1][0] && ifFalse[1][0][0] === 'break') { // canonicalize break in the if
var temp = ifFalse;
ifFalse = ifTrue;
ifTrue = temp;
flip = true;
}
- if (ifTrue[1][0][0] === 'break') {
+ if (ifTrue[1][0] && ifTrue[1][0][0] === 'break') {
var assigns = ifFalse[1];
var loopers = [], helpers = [];
for (var i = 0; i < assigns.length; i++) {
@@ -2696,16 +2696,16 @@ function minifyGlobals(ast) {
var vars = node[1];
for (var i = 0; i < vars.length; i++) {
var name = vars[i][0];
- assert(next < minifierInfo.names.length);
- vars[i][0] = minified[name] = minifierInfo.names[next++];
+ assert(next < extraInfo.names.length);
+ vars[i][0] = minified[name] = extraInfo.names[next++];
}
}
});
// add all globals in function chunks, i.e. not here but passed to us
- for (var i = 0; i < minifierInfo.globals.length; i++) {
- name = minifierInfo.globals[i];
- assert(next < minifierInfo.names.length);
- minified[name] = minifierInfo.names[next++];
+ for (var i = 0; i < extraInfo.globals.length; i++) {
+ name = extraInfo.globals[i];
+ assert(next < extraInfo.names.length);
+ minified[name] = extraInfo.names[next++];
}
// apply minification
traverse(ast, function(node, type) {
@@ -2716,9 +2716,64 @@ function minifyGlobals(ast) {
}
}
});
- suffix = '// MINIFY_INFO:' + JSON.stringify(minified);
+ suffix = '// EXTRA_INFO:' + JSON.stringify(minified);
}
+// Relocation pass for a shared module (for the functions part of the module)
+//
+// 1. Replace function names with alternate names as defined (to avoid colliding with
+// names in the main module we are being linked to)
+// 2. Hardcode function table offsets from F_BASE+x to const+x if x is a variable, or
+// the constant sum of the base + offset
+// 3. Hardcode heap offsets from H_BASE as well
+function relocate(ast) {
+ assert(asm); // we also assume we are normalized
+
+ var replacements = extraInfo.replacements;
+ var fBase = extraInfo.fBase;
+ var hBase = extraInfo.hBase;
+
+ traverse(ast, function(node, type) {
+ switch(type) {
+ case 'name': case 'defun': {
+ var rep = replacements[node[1]];
+ if (rep) node[1] = rep;
+ break;
+ }
+ case 'binary': {
+ if (node[1] == '+' && node[2][0] == 'name') {
+ var base = null;
+ if (node[2][1] == 'F_BASE') {
+ base = fBase;
+ } else if (node[2][1] == 'H_BASE') {
+ base = hBase;
+ }
+ if (base) {
+ var other = node[3];
+ if (other[0] == 'num') {
+ other[1] += base;
+ return other;
+ } else {
+ node[2] = ['num', base];
+ }
+ }
+ }
+ break;
+ }
+ case 'var': {
+ var vars = node[1];
+ for (var i = 0; i < vars.length; i++) {
+ var name = vars[i][0];
+ assert(!(name in replacements)); // cannot shadow functions we are replacing TODO: fix that
+ }
+ break;
+ }
+ }
+ });
+}
+
+// Last pass utilities
+
// Change +5 to DOT$ZERO(5). We then textually change 5 to 5.0 (uglify's ast cannot differentiate between 5 and 5.0 directly)
function prepDotZero(ast) {
traverse(ast, function(node, type) {
@@ -2783,6 +2838,7 @@ var passes = {
eliminate: eliminate,
eliminateMemSafe: eliminateMemSafe,
minifyGlobals: minifyGlobals,
+ relocate: relocate,
minifyWhitespace: function() { minifyWhitespace = true },
noPrintMetadata: function() { printMetadata = false },
asm: function() { asm = true },
@@ -2805,9 +2861,9 @@ var src = read(arguments_[0]);
var ast = srcToAst(src);
//printErr(JSON.stringify(ast)); throw 1;
generatedFunctions = src.indexOf(GENERATED_FUNCTIONS_MARKER) >= 0;
-var minifierInfoStart = src.indexOf('// MINIFY_INFO:')
-if (minifierInfoStart > 0) minifierInfo = JSON.parse(src.substr(minifierInfoStart + 15));
-//printErr(JSON.stringify(minifierInfo));
+var extraInfoStart = src.indexOf('// EXTRA_INFO:')
+if (extraInfoStart > 0) extraInfo = JSON.parse(src.substr(extraInfoStart + 14));
+//printErr(JSON.stringify(extraInfo));
arguments_.slice(1).forEach(function(arg) {