diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/file_packager.py | 107 | ||||
-rw-r--r-- | tools/find_bigfuncs.py | 4 | ||||
-rw-r--r-- | tools/js-optimizer.js | 109 | ||||
-rw-r--r-- | tools/js_optimizer.py | 4 | ||||
-rw-r--r-- | tools/jsrun.py | 2 | ||||
-rw-r--r-- | tools/response_file.py | 4 | ||||
-rw-r--r-- | tools/shared.py | 3 | ||||
-rwxr-xr-x | tools/source-maps/sourcemapper.js | 43 | ||||
-rw-r--r-- | tools/test-js-optimizer-asm-outline1-output.js | 295 | ||||
-rw-r--r-- | tools/test-js-optimizer-asm-outline1.js | 48 | ||||
-rw-r--r-- | tools/test-js-optimizer-asm-outline2-output.js | 790 |
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 |