aboutsummaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/file_packager.py107
-rw-r--r--tools/js-optimizer.js23
-rw-r--r--tools/test-js-optimizer-asm-outline1-output.js136
-rw-r--r--tools/test-js-optimizer-asm-outline1.js48
4 files changed, 256 insertions, 58 deletions
diff --git a/tools/file_packager.py b/tools/file_packager.py
index 33ccebad..bb62e905 100644
--- a/tools/file_packager.py
+++ b/tools/file_packager.py
@@ -329,13 +329,55 @@ if has_preloaded:
# Data requests - for getting a block of data out of the big archive - have a similar API to XHRs
code += '''
- function DataRequest() {}
+ function DataRequest(start, end, crunched, audio) {
+ this.start = start;
+ this.end = end;
+ this.crunched = crunched;
+ this.audio = audio;
+ }
DataRequest.prototype = {
requests: {},
open: function(mode, name) {
+ this.name = name;
this.requests[name] = this;
+ Module['addRunDependency']('fp ' + this.name);
+ },
+ send: function() {},
+ onload: function() {
+ var data = this.byteArray.subarray(this.start, this.end);
+ var size = this.end - this.start;
+ var ptr = Module['_malloc'](size); // XXX leaked if a preload plugin replaces with new data
+ Module['HEAPU8'].set(data, ptr);
+ var arrayBuffer = Module['HEAPU8'].subarray(ptr, ptr + size);
+ assert(arrayBuffer, 'Loading file ' + name + ' failed');
+ var byteArray = !arrayBuffer.subarray ? new Uint8Array(arrayBuffer) : arrayBuffer;
+
+ if (this.crunched) {
+ var ddsHeader = byteArray.subarray(0, 128);
+ var that = this;
+ requestDecrunch(this.name, byteArray.subarray(128), function(ddsData) {
+ byteArray = new Uint8Array(ddsHeader.length + ddsData.length);
+ byteArray.set(ddsHeader, 0);
+ byteArray.set(ddsData, 128);
+ that.finish(byteArray);
+ });
+ } else {
+ this.finish(byteArray);
+ }
+ },
+ finish: function(byteArray) {
+ var that = this;
+ Module['FS_createPreloadedFile'](PATH.dirname(this.name), PATH.basename(this.name), byteArray, true, true, function() {
+ Module['removeRunDependency']('fp ' + that.name);
+ }, function() {
+ if (that.audio) {
+ Module['removeRunDependency']('fp ' + that.name); // workaround for chromium bug 124926 (still no audio with this, but at least we don't hang)
+ } else {
+ Runtime.warn('Preloading file ' + that.name + ' failed');
+ }
+ });
+ this.requests[this.name] = null;
},
- send: function() {}
};
'''
@@ -364,66 +406,23 @@ for file_ in data_files:
# Preload
varname = 'filePreload%d' % counter
counter += 1
- dds = crunch and filename.endswith(CRUNCH_INPUT_SUFFIX)
-
- prepare = ''
- finish = "Module['removeRunDependency']('fp %s');\n" % filename
-
- if dds:
- # decompress crunch format into dds
- prepare = '''
- var ddsHeader = byteArray.subarray(0, %(dds_header_size)d);
- requestDecrunch('%(filename)s', byteArray.subarray(%(dds_header_size)d), function(ddsData) {
- byteArray = new Uint8Array(ddsHeader.length + ddsData.length);
- byteArray.set(ddsHeader, 0);
- byteArray.set(ddsData, %(dds_header_size)d);
-''' % { 'filename': filename, 'dds_header_size': DDS_HEADER_SIZE }
-
- finish += '''
- });
-'''
-
- code += '''
- var %(varname)s = new %(request)s();
- %(varname)s.open('GET', '%(filename)s', true);
- %(varname)s.responseType = 'arraybuffer';
- %(varname)s.onload = function() {
- var arrayBuffer = %(varname)s.response;
- assert(arrayBuffer, 'Loading file %(filename)s failed.');
- var byteArray = !arrayBuffer.subarray ? new Uint8Array(arrayBuffer) : arrayBuffer;
- %(prepare)s
- Module['FS_createPreloadedFile']('%(dirname)s', '%(basename)s', byteArray, true, true, function() {
- %(finish)s
- }%(fail)s);
- };
- Module['addRunDependency']('fp %(filename)s');
- %(varname)s.send(null);
+ code += ''' new DataRequest(%(start)d, %(end)d, %(crunched)s, %(audio)s).open('GET', '%(filename)s');
''' % {
- 'request': 'DataRequest', # In the past we also supported XHRs here
- 'varname': varname,
- 'filename': filename,
- 'dirname': dirname,
- 'basename': basename,
- 'prepare': prepare,
- 'finish': finish,
- 'fail': '' if filename[-4:] not in AUDIO_SUFFIXES else ''', function() { Module['removeRunDependency']('fp %s') }''' % filename # workaround for chromium bug 124926 (still no audio with this, but at least we don't hang)
- }
+ 'filename': file_['dstpath'],
+ 'start': file_['data_start'],
+ 'end': file_['data_end'],
+ 'crunched': '1' if crunch and filename.endswith(CRUNCH_INPUT_SUFFIX) else '0',
+ 'audio': '1' if filename[-4:] in AUDIO_SUFFIXES else '0',
+ }
else:
assert 0
if has_preloaded:
# Get the big archive and split it up
- use_data = ''
+ use_data = ' DataRequest.prototype.byteArray = byteArray;\n'
for file_ in data_files:
if file_['mode'] == 'preload':
- use_data += '''
- curr = DataRequest.prototype.requests['%s'];
- var data = byteArray.subarray(%d, %d);
- var ptr = Module['_malloc'](%d);
- Module['HEAPU8'].set(data, ptr);
- curr.response = Module['HEAPU8'].subarray(ptr, ptr + %d);
- curr.onload();
- ''' % (file_['dstpath'], file_['data_start'], file_['data_end'], file_['data_end'] - file_['data_start'], file_['data_end'] - file_['data_start'])
+ use_data += ' DataRequest.prototype.requests["%s"].onload();\n' % (file_['dstpath'])
use_data += " Module['removeRunDependency']('datafile_%s');\n" % data_target
if Compression.on:
diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js
index a673e019..9a5104bf 100644
--- a/tools/js-optimizer.js
+++ b/tools/js-optimizer.js
@@ -1236,7 +1236,7 @@ function vacuum(ast) {
}
} break;
case 'label': {
- if (node[2][0] === 'toplevel' && (!node[2][1] || node[2][1].length === 0)) {
+ if (node[2] && node[2][0] === 'toplevel' && (!node[2][1] || node[2][1].length === 0)) {
return emptyNode();
}
} break;
@@ -3057,16 +3057,24 @@ function outline(ast) {
var chunks = [];
var currSize = 0;
var currChunk = [];
+ var force = false; // when we hit a case X: that falls through, we force inclusion of everything until a full case
parts.forEach(function(part) {
var size = (part.condition ? measureSize(part.condition) : 0) + measureSize(part.body) + 5; // add constant for overhead of extra code
assert(size > 0);
- if (size + currSize >= minSize && currSize) {
+ if (size + currSize >= minSize && currSize && !force) {
chunks.push(currChunk);
currChunk = [];
currSize = 0;
}
currChunk.push(part);
currSize += size;
+ if (!isIf) {
+ var last = part.body;
+ last = last[stats.length-1];
+ if (last && last[0] === 'block') last = last[1][last[1].length-1];
+ if (last && last[0] === 'stat') last = last[1];
+ force = !last || last[0] !== 'break';
+ }
});
assert(currSize);
chunks.push(currChunk);
@@ -3115,6 +3123,8 @@ function outline(ast) {
});
}
+ var maxTotalOutlinings = Infinity; // debugging tool
+
// Prepares information for spilling of local variables
function analyzeFunction(func, asmData) {
var stack = []; // list of variables, each gets 8 bytes
@@ -3134,7 +3144,7 @@ function outline(ast) {
// The control variables are zeroed out when calling an outlined function, and after using
// the value after they return.
var size = measureSize(func);
- asmData.maxOutlinings = Math.round(3*size/extraInfo.sizeToOutline);
+ asmData.maxOutlinings = Math.min(Math.round(3*size/extraInfo.sizeToOutline), maxTotalOutlinings);
asmData.intendedPieces = Math.ceil(size/extraInfo.sizeToOutline);
asmData.totalStackSize = stackSize + (stack.length + 2*asmData.maxOutlinings)*8;
asmData.controlStackPos = function(i) { return stackSize + (stack.length + i)*8 };
@@ -3464,6 +3474,7 @@ function outline(ast) {
asmData.splitCounter--;
return [];
}
+ maxTotalOutlinings--;
for (var v in owned) {
if (v != 'sp') delete asmData.vars[v]; // parent does not need these anymore
}
@@ -3620,6 +3631,8 @@ function outline(ast) {
var funcs = ast[1];
+ var maxTotalFunctions = Infinity; // debugging tool
+
var more = true;
while (more) {
more = false;
@@ -3627,9 +3640,11 @@ function outline(ast) {
var newFuncs = [];
funcs.forEach(function(func) {
+ vacuum(func); // clear out empty nodes that affect code size
var asmData = normalizeAsm(func);
var size = measureSize(func);
- if (size >= extraInfo.sizeToOutline) {
+ if (size >= extraInfo.sizeToOutline && maxTotalFunctions > 0) {
+ maxTotalFunctions--;
aggressiveVariableElimination(func, asmData);
flatten(func, asmData);
analyzeFunction(func, asmData);
diff --git a/tools/test-js-optimizer-asm-outline1-output.js b/tools/test-js-optimizer-asm-outline1-output.js
index d8ea9446..895004d8 100644
--- a/tools/test-js-optimizer-asm-outline1-output.js
+++ b/tools/test-js-optimizer-asm-outline1-output.js
@@ -321,6 +321,48 @@ function chain() {
helper$0 = HEAP32[sp + 8 >> 2] | 0;
STACKTOP = sp;
}
+function switchh() {
+ var helper$0 = 0, helper$1 = 0, sp = 0;
+ sp = STACKTOP;
+ STACKTOP = STACKTOP + 296 | 0;
+ helper$0 = 1;
+ helper$1 = x;
+ if (helper$0) {
+ helper$0 = 0;
+ switch (helper$1 | 0) {
+ case 0:
+ {
+ f(0);
+ g();
+ break;
+ }
+ default:
+ {
+ helper$0 = 1;
+ }
+ }
+ }
+ HEAP32[sp + 8 >> 2] = helper$0;
+ HEAP32[sp + 16 >> 2] = helper$1;
+ HEAP32[sp + 40 >> 2] = 0;
+ HEAP32[sp + 44 >> 2] = 0;
+ switchh$2(sp);
+ helper$0 = HEAP32[sp + 8 >> 2] | 0;
+ HEAP32[sp + 8 >> 2] = helper$0;
+ HEAP32[sp + 16 >> 2] = helper$1;
+ HEAP32[sp + 32 >> 2] = 0;
+ HEAP32[sp + 36 >> 2] = 0;
+ switchh$1(sp);
+ helper$0 = HEAP32[sp + 8 >> 2] | 0;
+ if (helper$0) {
+ helper$0 = 0;
+ HEAP32[sp + 16 >> 2] = helper$1;
+ HEAP32[sp + 24 >> 2] = 0;
+ HEAP32[sp + 28 >> 2] = 0;
+ switchh$0(sp);
+ }
+ STACKTOP = sp;
+}
function lin$0(sp) {
sp = sp | 0;
c(14);
@@ -645,4 +687,98 @@ function chain$4(sp) {
}
HEAP32[sp + 8 >> 2] = helper$0;
}
+function switchh$0(sp) {
+ sp = sp | 0;
+ var helper$1 = 0;
+ helper$1 = HEAP32[sp + 16 >> 2] | 0;
+ switch (helper$1 | 0) {
+ case 4:
+ {
+ f(4);
+ g();
+ }
+ case 5:
+ {
+ f(5);
+ g();
+ }
+ case 6:
+ {
+ f(6);
+ g();
+ }
+ default:
+ {
+ print(9);
+ }
+ }
+}
+function switchh$1(sp) {
+ sp = sp | 0;
+ var helper$0 = 0, helper$1 = 0;
+ helper$0 = HEAP32[sp + 8 >> 2] | 0;
+ helper$1 = HEAP32[sp + 16 >> 2] | 0;
+ if (helper$0) {
+ helper$0 = 0;
+ switch (helper$1 | 0) {
+ case 21:
+ case 22:
+ case 23:
+ case 24:
+ case 25:
+ case 26:
+ case 27:
+ case 28:
+ case 29:
+ case 3:
+ {
+ f(3);
+ g();
+ break;
+ }
+ default:
+ {
+ helper$0 = 1;
+ }
+ }
+ }
+ HEAP32[sp + 8 >> 2] = helper$0;
+}
+function switchh$2(sp) {
+ sp = sp | 0;
+ var helper$0 = 0, helper$1 = 0;
+ helper$0 = HEAP32[sp + 8 >> 2] | 0;
+ helper$1 = HEAP32[sp + 16 >> 2] | 0;
+ if (helper$0) {
+ helper$0 = 0;
+ switch (helper$1 | 0) {
+ case 1:
+ {
+ f(1);
+ g();
+ break;
+ }
+ default:
+ {
+ helper$0 = 1;
+ }
+ }
+ }
+ if (helper$0) {
+ helper$0 = 0;
+ switch (helper$1 | 0) {
+ case 2:
+ {
+ f(2);
+ g();
+ break;
+ }
+ default:
+ {
+ helper$0 = 1;
+ }
+ }
+ }
+ HEAP32[sp + 8 >> 2] = helper$0;
+}
diff --git a/tools/test-js-optimizer-asm-outline1.js b/tools/test-js-optimizer-asm-outline1.js
index 311cb206..3c454182 100644
--- a/tools/test-js-optimizer-asm-outline1.js
+++ b/tools/test-js-optimizer-asm-outline1.js
@@ -259,5 +259,53 @@ function chain() {
print(99);
}
}
+function switchh() {
+ switch (x) {
+ case 0: {
+ f(0);
+ g();
+ break;
+ }
+ case 1: {
+ f(1);
+ g();
+ break;
+ }
+ case 2: {
+ f(2);
+ g();
+ break;
+ }
+ case 21: // gotta keem em unseparated
+ case 22:
+ case 23:
+ case 24:
+ case 25:
+ case 26:
+ case 27:
+ case 28:
+ case 29:
+ case 3: { // these too
+ f(3);
+ g();
+ break;
+ }
+ case 4: {
+ f(4);
+ g();
+ }
+ case 5: {
+ f(5);
+ g();
+ }
+ case 6: {
+ f(6);
+ g();
+ }
+ default: {
+ print(9);
+ }
+ }
+}
// EMSCRIPTEN_GENERATED_FUNCTIONS
// EXTRA_INFO: { "sizeToOutline": 30, "allowCostlyOutlines": 1 }