aboutsummaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/file_packager.py107
-rw-r--r--tools/find_bigfuncs.py4
-rw-r--r--tools/js-optimizer.js109
-rw-r--r--tools/js_optimizer.py4
-rw-r--r--tools/jsrun.py2
-rw-r--r--tools/response_file.py4
-rw-r--r--tools/shared.py3
-rwxr-xr-xtools/source-maps/sourcemapper.js43
-rw-r--r--tools/test-js-optimizer-asm-outline1-output.js295
-rw-r--r--tools/test-js-optimizer-asm-outline1.js48
-rw-r--r--tools/test-js-optimizer-asm-outline2-output.js790
11 files changed, 913 insertions, 496 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/find_bigfuncs.py b/tools/find_bigfuncs.py
index 6fdec3a9..79136343 100644
--- a/tools/find_bigfuncs.py
+++ b/tools/find_bigfuncs.py
@@ -1,5 +1,5 @@
'''
-Simple tool to find big functions in an .ll file.
+Simple tool to find big functions in a js or ll file
'''
import os, sys, re
@@ -11,7 +11,7 @@ curr = None
data = []
for line in open(filename):
i += 1
- if line.startswith('function '):
+ if line.startswith(('function ', 'define ')):
start = i
curr = line
elif line.startswith('}') and curr:
diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js
index ff6aee67..9a5104bf 100644
--- a/tools/js-optimizer.js
+++ b/tools/js-optimizer.js
@@ -801,7 +801,10 @@ function simplifyExpressions(ast) {
// HEAP[x >> 2]
// very often. We can in some cases do the shift on the variable itself when it is set,
// to greatly reduce the number of shift operations.
-// TODO: when shifting a variable, if there are other uses, keep an unshifted version too, to prevent slowdowns?
+// XXX this optimization is deprecated and currently invalid: does not handle overflows
+// or non-aligned (round numbers, x >> 2 is a multiple of 4). Both are ok to assume
+// for pointers (undefined behavior otherwise), but invalid in general, and we do
+// no sufficiently-well distinguish the cases.
function optimizeShiftsInternal(ast, conservative) {
var MAX_SHIFTS = 3;
traverseGeneratedFunctions(ast, function(fun) {
@@ -1233,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;
@@ -3001,7 +3004,7 @@ function outline(ast) {
// Try to flatten out code as much as possible, to make outlining more feasible.
function flatten(func, asmData) {
- var minSize = sizeToOutline;
+ var minSize = extraInfo.sizeToOutline/4;
var helperId = 0;
function getHelper() {
while (1) {
@@ -3023,58 +3026,90 @@ function outline(ast) {
if (ignore.indexOf(node) >= 0) continue;
var type = node[0];
if (measureSize(node) >= minSize) {
- if (type === 'if' && node[3]) {
+ if ((type === 'if' && node[3]) || type === 'switch') {
+ var isIf = type === 'if';
var reps = [];
var helper = getHelper();
// clear helper
reps.push(['stat', ['assign', true, ['name', helper], ['num', 1]]]); // 1 means continue in ifs
// gather parts
- var parts = [];
- var curr = node;
- while (1) {
- parts.push({ condition: curr[1], body: curr[2] });
- curr = curr[3];
- if (!curr) break;
- if (curr[0] != 'if') {
- parts.push({ condition: null, body: curr });
- break;
+ var parts;
+ if (isIf) {
+ parts = [];
+ var curr = node;
+ while (1) {
+ parts.push({ condition: curr[1], body: curr[2] });
+ curr = curr[3];
+ if (!curr) break;
+ if (curr[0] != 'if') {
+ parts.push({ condition: null, body: curr });
+ break;
+ }
}
+ } else { // switch
+ var switchVar = getHelper(); // switch var could be an expression
+ reps.push(['stat', ['assign', true, ['name', switchVar], node[1]]]);
+ parts = node[2].map(function(case_) {
+ return { condition: case_[0], body: case_[1] };
+ });
}
// chunkify. Each chunk is a chain of if-elses, with the new overhead just on entry and exit
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);
// generate flattened code
chunks.forEach(function(chunk) {
var pre = ['stat', ['assign', true, ['name', helper], ['num', 0]]];
- var chain = null, tail = null;
- chunk.forEach(function(part) {
- // add to chain
- var contents = makeIf(part.condition || ['num', 1], part.body[1]);
- if (chain) {
- tail[3] = contents;
- } else {
- chain = contents;
- ignore.push(contents);
+ if (isIf) {
+ var chain = null, tail = null;
+ chunk.forEach(function(part) {
+ // add to chain
+ var contents = makeIf(part.condition || ['num', 1], part.body[1]);
+ if (chain) {
+ tail[3] = contents;
+ } else {
+ chain = contents;
+ ignore.push(contents);
+ }
+ tail = contents;
+ });
+ // if none of the ifs were entered, in the final else note that we need to continue
+ tail[3] = ['block', [['stat', ['assign', true, ['name', helper], ['num', 1]]]]];
+ reps.push(makeIf(['name', helper], [pre, chain]));
+ } else { // switch
+ var hasDefault;
+ var s = makeSwitch(['binary', '|', ['name', switchVar], ['num', 0]], chunk.map(function(part) {
+ hasDefault = hasDefault || part.condition === null;
+ return [part.condition, part.body];
+ }));
+ // if no default, add one where we note that we need to continue
+ if (!hasDefault) {
+ s[2].push([null, [['block', [['stat', ['assign', true, ['name', helper], ['num', 1]]]]]]]);
}
- tail = contents;
- });
- // if none of the ifs were entered, in the final else note that we need to continue
- tail[3] = ['block', [['stat', ['assign', true, ['name', helper], ['num', 1]]]]];
- reps.push(makeIf(['name', helper], [pre, chain]));
+ ignore.push(s);
+ reps.push(makeIf(['name', helper], [pre, s]));
+ }
});
// replace code and update i
stats.splice.apply(stats, [i, 1].concat(reps));
@@ -3088,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
@@ -3107,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 };
@@ -3437,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
}
@@ -3475,6 +3513,9 @@ function outline(ast) {
}
}
}
+ function done() {
+ return asmData.splitCounter >= asmData.maxOutlinings || measureSize(func) <= extraInfo.sizeToOutline;
+ }
while (1) {
i--;
calcMinIndex(); // TODO: optimize
@@ -3530,7 +3571,7 @@ function outline(ast) {
if (ret.length > pre) {
// we outlined recursively, reset our state here
//printErr('successful outline in recursion ' + func[1] + ' due to recursive in level ' + level);
- if (measureSize(func) <= extraInfo.sizeToOutline) break;
+ if (done()) break;
end = i-1;
sizeSeen = 0;
canRestart = true;
@@ -3570,7 +3611,7 @@ function outline(ast) {
if (newFuncs.length) {
ret.push.apply(ret, newFuncs);
}
- if (measureSize(func) <= extraInfo.sizeToOutline) break;
+ if (done()) break;
sizeSeen = 0;
end = i-1;
canRestart = true;
@@ -3590,6 +3631,8 @@ function outline(ast) {
var funcs = ast[1];
+ var maxTotalFunctions = Infinity; // debugging tool
+
var more = true;
while (more) {
more = false;
@@ -3597,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/js_optimizer.py b/tools/js_optimizer.py
index acb87460..5d7dc562 100644
--- a/tools/js_optimizer.py
+++ b/tools/js_optimizer.py
@@ -224,6 +224,10 @@ EMSCRIPTEN_FUNCS();
total_size = len(js)
js = None
+ if 'last' in passes and len(funcs) > 0:
+ if max([len(func[1]) for func in funcs]) > 200000:
+ print >> sys.stderr, 'warning: Output contains some very large functions, consider using OUTLINING_LIMIT to break them up (see settings.js)'
+
# if we are making source maps, we want our debug numbering to start from the
# top of the file, so avoid breaking the JS into chunks
cores = 1 if source_map else int(os.environ.get('EMCC_CORES') or multiprocessing.cpu_count())
diff --git a/tools/jsrun.py b/tools/jsrun.py
index 27c55350..571e9cee 100644
--- a/tools/jsrun.py
+++ b/tools/jsrun.py
@@ -15,7 +15,7 @@ def timeout_run(proc, timeout, note='unnamed process', full_output=False):
def run_js(filename, engine=None, args=[], check_timeout=False, stdout=PIPE, stderr=None, cwd=None, full_output=False):
if type(engine) is not list:
engine = [engine]
- command = engine + [filename] + (['--'] if 'd8' in engine[0] else []) + args
+ command = engine + [filename] + (['--'] if 'd8' in engine[0] or 'jsc' in engine[0] else []) + args
return timeout_run(
Popen(
command,
diff --git a/tools/response_file.py b/tools/response_file.py
index 312cda73..f19cf8af 100644
--- a/tools/response_file.py
+++ b/tools/response_file.py
@@ -6,8 +6,8 @@ def create_response_file(args, directory):
(response_fd, response_filename) = tempfile.mkstemp(prefix='emscripten_', suffix='.rsp', dir=directory, text=True)
response_fd = os.fdopen(response_fd, "w")
#print >> sys.stderr, "Creating response file '%s'" % response_filename
- args = map(lambda p: p.replace(' ', '').replace('\\', '\\\\').replace('"', '\\"'), args)
- response_fd.write(' '.join(args))
+ args = map(lambda p: p.replace('\\', '\\\\').replace('"', '\\"'), args)
+ response_fd.write('"' + '" "'.join(args) + '"')
response_fd.close()
return response_filename
diff --git a/tools/shared.py b/tools/shared.py
index 917f548e..3ee5db23 100644
--- a/tools/shared.py
+++ b/tools/shared.py
@@ -290,7 +290,7 @@ def check_node_version():
# we re-check sanity when the settings are changed)
# We also re-check sanity and clear the cache when the version changes
-EMSCRIPTEN_VERSION = '1.5.5'
+EMSCRIPTEN_VERSION = '1.5.6'
def generate_sanity():
return EMSCRIPTEN_VERSION + '|' + get_llvm_target() + '|' + LLVM_ROOT
@@ -550,6 +550,7 @@ if USE_EMSDK:
# allows projects to override them)
EMSDK_OPTS = ['-nostdinc', '-Xclang', '-nobuiltininc', '-Xclang', '-nostdsysteminc',
'-Xclang', '-isystem' + path_from_root('system', 'local', 'include'),
+ '-Xclang', '-isystem' + path_from_root('system', 'include', 'compat'),
'-Xclang', '-isystem' + path_from_root('system', 'include', 'libcxx'),
'-Xclang', '-isystem' + path_from_root('system', 'include'),
'-Xclang', '-isystem' + path_from_root('system', 'include', 'emscripten'),
diff --git a/tools/source-maps/sourcemapper.js b/tools/source-maps/sourcemapper.js
index fa908900..06c9a227 100755
--- a/tools/source-maps/sourcemapper.js
+++ b/tools/source-maps/sourcemapper.js
@@ -16,6 +16,38 @@ function countLines(s) {
return count;
}
+// For a minor optimization, only do win32->unix normalization if we are actually on Windows,
+// which avoids redundantly scanning files if not needed.
+var isWindows = (process.platform === 'win32');
+
+var unixPathRe = new RegExp('\\\\', 'g');
+// Returns the given (possibly Windows) path p normalized to unix path separators '/'.
+function toUnixPath(p) {
+ if (isWindows) {
+ return p.replace(unixPathRe, '/');
+ } else {
+ return p;
+ }
+}
+
+var unixLineEndRe = new RegExp('\r\n', 'g');
+// Returns the given (possibly Windows) text data t normalized to unix line endings '\n'.
+function toUnixLineEnding(t) {
+ if (isWindows) {
+ return t.replace(unixLineEndRe, '\n');
+ } else {
+ return t;
+ }
+}
+
+// If path "p2" is a relative path, joins paths p1 and p2 to form "p1/p2". If p2 is an absolute path, "p2" is returned.
+function joinPath(p1, p2) {
+ if (p2[0] == '/' || (p2.length >= 3 && p2[1] == ':' && (p2[2] == '/' || p2[2] == '\\'))) // Is p2 an absolute path?
+ return p2;
+ else
+ return toUnixPath(path.join(p1, p2));
+}
+
/*
* Extracts the line (not block) comments from the generated function code and
* invokes commentHandler with (comment content, line number of comment). This
@@ -105,8 +137,7 @@ function generateMap(mappings, sourceRoot, mapFileBaseName, generatedLineOffset)
// avoid doing it unnecessarily
if (!(originalFileName in seenFiles)) {
seenFiles[originalFileName] = true;
- var rootedPath = originalFileName[0] === path.sep ?
- originalFileName : path.join(sourceRoot, originalFileName);
+ var rootedPath = joinPath(sourceRoot, originalFileName);
try {
generator.setSourceContent(originalFileName, fs.readFileSync(rootedPath, 'utf-8'));
} catch (e) {
@@ -144,15 +175,15 @@ if (require.main === module) {
} else {
var opts = parseArgs(process.argv.slice(2));
var fileName = opts._[0];
- var sourceRoot = opts.sourceRoot ? opts.sourceRoot : ".";
- var mapFileBaseName = opts.mapFileBaseName ? opts.mapFileBaseName : fileName;
+ var sourceRoot = opts.sourceRoot ? toUnixPath(opts.sourceRoot) : ".";
+ var mapFileBaseName = toUnixPath(opts.mapFileBaseName ? opts.mapFileBaseName : fileName);
var generatedLineOffset = opts.offset ? parseInt(opts.offset, 10) : 0;
- var generatedSource = fs.readFileSync(fileName, 'utf-8');
+ var generatedSource = toUnixLineEnding(fs.readFileSync(fileName, 'utf-8'));
var source = generatedSource;
var mappings = getMappings(generatedSource);
for (var i = 1, l = opts._.length; i < l; i ++) {
- var optimizedSource = fs.readFileSync(opts._[i], 'utf-8')
+ var optimizedSource = toUnixLineEnding(fs.readFileSync(opts._[i], 'utf-8'))
var optimizedMappings = getMappings(optimizedSource);
var newMappings = {};
// uglify processes the code between EMSCRIPTEN_START_FUNCS and
diff --git a/tools/test-js-optimizer-asm-outline1-output.js b/tools/test-js-optimizer-asm-outline1-output.js
index 904e56cf..895004d8 100644
--- a/tools/test-js-optimizer-asm-outline1-output.js
+++ b/tools/test-js-optimizer-asm-outline1-output.js
@@ -276,8 +276,29 @@ function vars_w_stack(x, y) {
function chain() {
var helper$0 = 0, sp = 0;
sp = STACKTOP;
- STACKTOP = STACKTOP + 240 | 0;
+ STACKTOP = STACKTOP + 464 | 0;
helper$0 = 1;
+ if (helper$0) {
+ helper$0 = 0;
+ if (x == 1) {
+ print(1);
+ } else {
+ helper$0 = 1;
+ }
+ }
+ if (helper$0) {
+ helper$0 = 0;
+ if (x == 2) {
+ print(2);
+ } else {
+ helper$0 = 1;
+ }
+ }
+ HEAP32[sp + 8 >> 2] = helper$0;
+ HEAP32[sp + 48 >> 2] = 0;
+ HEAP32[sp + 52 >> 2] = 0;
+ chain$4(sp);
+ helper$0 = HEAP32[sp + 8 >> 2] | 0;
HEAP32[sp + 8 >> 2] = helper$0;
HEAP32[sp + 40 >> 2] = 0;
HEAP32[sp + 44 >> 2] = 0;
@@ -288,6 +309,58 @@ function chain() {
HEAP32[sp + 36 >> 2] = 0;
chain$2(sp);
helper$0 = HEAP32[sp + 8 >> 2] | 0;
+ HEAP32[sp + 8 >> 2] = helper$0;
+ HEAP32[sp + 24 >> 2] = 0;
+ HEAP32[sp + 28 >> 2] = 0;
+ chain$1(sp);
+ helper$0 = HEAP32[sp + 8 >> 2] | 0;
+ HEAP32[sp + 8 >> 2] = helper$0;
+ HEAP32[sp + 16 >> 2] = 0;
+ HEAP32[sp + 20 >> 2] = 0;
+ chain$0(sp);
+ 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) {
@@ -500,22 +573,21 @@ function chain$0(sp) {
sp = sp | 0;
var helper$0 = 0;
helper$0 = HEAP32[sp + 8 >> 2] | 0;
- if (x == 7) {
- print(7);
- } else if (x == 8) {
- print(8);
- } else if (x == 9) {
- print(9);
- } else if (x == 10) {
- print(10);
- } else if (x == 11) {
- print(11);
- } else if (x == 12) {
- print(12);
- } else if (1) {
- print(99);
- } else {
- helper$0 = 1;
+ if (helper$0) {
+ helper$0 = 0;
+ if (x == 12) {
+ print(12);
+ } else {
+ helper$0 = 1;
+ }
+ }
+ if (helper$0) {
+ helper$0 = 0;
+ if (1) {
+ print(99);
+ } else {
+ helper$0 = 1;
+ }
}
HEAP32[sp + 8 >> 2] = helper$0;
}
@@ -523,20 +595,21 @@ function chain$1(sp) {
sp = sp | 0;
var helper$0 = 0;
helper$0 = HEAP32[sp + 8 >> 2] | 0;
- if (x == 1) {
- print(1);
- } else if (x == 2) {
- print(2);
- } else if (x == 3) {
- print(3);
- } else if (x == 4) {
- print(4);
- } else if (x == 5) {
- print(5);
- } else if (x == 6) {
- print(6);
- } else {
- helper$0 = 1;
+ if (helper$0) {
+ helper$0 = 0;
+ if (x == 10) {
+ print(10);
+ } else {
+ helper$0 = 1;
+ }
+ }
+ if (helper$0) {
+ helper$0 = 0;
+ if (x == 11) {
+ print(11);
+ } else {
+ helper$0 = 1;
+ }
}
HEAP32[sp + 8 >> 2] = helper$0;
}
@@ -546,11 +619,19 @@ function chain$2(sp) {
helper$0 = HEAP32[sp + 8 >> 2] | 0;
if (helper$0) {
helper$0 = 0;
- HEAP32[sp + 8 >> 2] = helper$0;
- HEAP32[sp + 16 >> 2] = 0;
- HEAP32[sp + 20 >> 2] = 0;
- chain$0(sp);
- helper$0 = HEAP32[sp + 8 >> 2] | 0;
+ if (x == 8) {
+ print(8);
+ } else {
+ helper$0 = 1;
+ }
+ }
+ if (helper$0) {
+ helper$0 = 0;
+ if (x == 9) {
+ print(9);
+ } else {
+ helper$0 = 1;
+ }
}
HEAP32[sp + 8 >> 2] = helper$0;
}
@@ -560,11 +641,143 @@ function chain$3(sp) {
helper$0 = HEAP32[sp + 8 >> 2] | 0;
if (helper$0) {
helper$0 = 0;
- HEAP32[sp + 8 >> 2] = helper$0;
- HEAP32[sp + 24 >> 2] = 0;
- HEAP32[sp + 28 >> 2] = 0;
- chain$1(sp);
- helper$0 = HEAP32[sp + 8 >> 2] | 0;
+ if (x == 6) {
+ print(6);
+ } else {
+ helper$0 = 1;
+ }
+ }
+ if (helper$0) {
+ helper$0 = 0;
+ if (x == 7) {
+ print(7);
+ } else {
+ helper$0 = 1;
+ }
+ }
+ HEAP32[sp + 8 >> 2] = helper$0;
+}
+function chain$4(sp) {
+ sp = sp | 0;
+ var helper$0 = 0;
+ helper$0 = HEAP32[sp + 8 >> 2] | 0;
+ if (helper$0) {
+ helper$0 = 0;
+ if (x == 3) {
+ print(3);
+ } else {
+ helper$0 = 1;
+ }
+ }
+ if (helper$0) {
+ helper$0 = 0;
+ if (x == 4) {
+ print(4);
+ } else {
+ helper$0 = 1;
+ }
+ }
+ if (helper$0) {
+ helper$0 = 0;
+ if (x == 5) {
+ print(5);
+ } else {
+ helper$0 = 1;
+ }
+ }
+ 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 }
diff --git a/tools/test-js-optimizer-asm-outline2-output.js b/tools/test-js-optimizer-asm-outline2-output.js
index 28feb6cb..2658fda0 100644
--- a/tools/test-js-optimizer-asm-outline2-output.js
+++ b/tools/test-js-optimizer-asm-outline2-output.js
@@ -23,7 +23,7 @@ function linear() {
}
function _free($mem) {
$mem = $mem | 0;
- var $5 = 0, $10 = 0, $16 = 0, $21 = 0, $25 = 0, $26 = 0, $psize_0 = 0, $p_0 = 0, $189 = 0, $194 = 0, sp = 0;
+ var $5 = 0, $10 = 0, $16 = 0, $21 = 0, $25 = 0, $26 = 0, $psize_0 = 0, $p_0 = 0, $189 = 0, $194 = 0, sp = 0, helper$0 = 0;
sp = STACKTOP;
if (($mem | 0) == 0) {
STACKTOP = sp;
@@ -39,59 +39,71 @@ function _free($mem) {
}
$16 = $mem + (($10 & -8) - 8) | 0;
L621 : do {
- if (($10 & 1 | 0) == 0) {
- $21 = HEAP32[($mem - 8 | 0) >> 2] | 0;
- if (($10 & 3 | 0) == 0) {
- return;
- }
- $25 = $mem + (-8 - $21 | 0) | 0;
- $26 = $21 + ($10 & -8) | 0;
- if (($mem + (-8 - $21 | 0) | 0) >>> 0 < $5 >>> 0) {
- _abort();
- }
- if (($25 | 0) == (HEAP32[25] | 0)) {
- if ((HEAP32[($mem + (($10 & -8) - 4) | 0) >> 2] & 3 | 0) != 3) {
- $p_0 = $25;
- $psize_0 = $26;
+ helper$0 = 1;
+ if (helper$0) {
+ helper$0 = 0;
+ if (($10 & 1 | 0) == 0) {
+ $21 = HEAP32[($mem - 8 | 0) >> 2] | 0;
+ if (($10 & 3 | 0) == 0) {
+ return;
+ }
+ $25 = $mem + (-8 - $21 | 0) | 0;
+ $26 = $21 + ($10 & -8) | 0;
+ if (($mem + (-8 - $2