diff options
Diffstat (limited to 'tools/js-optimizer.js')
-rw-r--r-- | tools/js-optimizer.js | 98 |
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) { |