diff options
author | Alon Zakai <alonzakai@gmail.com> | 2013-01-24 12:02:42 -0800 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2013-01-24 12:02:42 -0800 |
commit | 64c779641a2a9587613cc65ad7251890f18e25c3 (patch) | |
tree | 87344a57db509e92b3196e5a4291a8c3bd8c2449 | |
parent | 4e09482e006eda934527e1707036d74245d8dd91 (diff) | |
parent | 03e2e6c321d28e3df3b37a2c0bed3ba9d04e52b3 (diff) |
Merge branch 'incoming'
40 files changed, 1429 insertions, 399 deletions
@@ -45,3 +45,6 @@ a license to everyone to use it as detailed in LICENSE.) * Alan Kligman <alan.kligman@gmail.com> (copyright owned by Mozilla Foundation) * Anthony Liot <wolfviking0@yahoo.com> * Michael Riss <Michael.Riss@gmx.de> +* Jasper St. Pierre <jstpierre@mecheye.net> +* Manuel Schölling <manuel.schoelling@gmx.de> + diff --git a/README.markdown b/README.markdown index dadbf3a4..81a95141 100644 --- a/README.markdown +++ b/README.markdown @@ -1,4 +1,6 @@ + + Emscripten ========== diff --git a/cmake/Platform/Emscripten.cmake b/cmake/Platform/Emscripten.cmake index 532e5d99..4b9c6572 100644 --- a/cmake/Platform/Emscripten.cmake +++ b/cmake/Platform/Emscripten.cmake @@ -42,3 +42,20 @@ set(CMAKE_C_ARCHIVE_CREATE "${CMAKE_C_COMPILER} -o <TARGET> -emit-llvm <LINK_FLA # Set a global EMSCRIPTEN variable that can be used in client CMakeLists.txt to detect when building using Emscripten. # There seems to be some kind of bug with CMake, so you might need to define this manually on the command line with "-DEMSCRIPTEN=1". set(EMSCRIPTEN 1) + +set(CMAKE_C_FLAGS_RELEASE "-DNDEBUG" CACHE STRING "Emscripten-overridden CMAKE_C_FLAGS_RELEASE") +set(CMAKE_C_FLAGS_MINSIZEREL "-DNDEBUG" CACHE STRING "Emscripten-overridden CMAKE_C_FLAGS_MINSIZEREL") +set(CMAKE_C_FLAGS_RELWITHDEBINFO "" CACHE STRING "Emscripten-overridden CMAKE_C_FLAGS_RELWITHDEBINFO") +set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG" CACHE STRING "Emscripten-overridden CMAKE_CXX_FLAGS_RELEASE") +set(CMAKE_CXX_FLAGS_MINSIZEREL "-DNDEBUG" CACHE STRING "Emscripten-overridden CMAKE_CXX_FLAGS_MINSIZEREL") +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "" CACHE STRING "Emscripten-overridden CMAKE_CXX_FLAGS_RELWITHDEBINFO") + +set(CMAKE_EXE_LINKER_FLAGS_RELEASE "-O2" CACHE STRING "Emscripten-overridden CMAKE_EXE_LINKER_FLAGS_RELEASE") +set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "-O2" CACHE STRING "Emscripten-overridden CMAKE_EXE_LINKER_FLAGS_MINSIZEREL") +set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "-O2" CACHE STRING "Emscripten-overridden CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO") +set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "-O2" CACHE STRING "Emscripten-overridden CMAKE_SHARED_LINKER_FLAGS_RELEASE") +set(CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL "-O2" CACHE STRING "Emscripten-overridden CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL") +set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "-O2" CACHE STRING "Emscripten-overridden CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO") +set(CMAKE_MODULE_LINKER_FLAGS_RELEASE "-O2" CACHE STRING "Emscripten-overridden CMAKE_MODULE_LINKER_FLAGS_RELEASE") +set(CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL "-O2" CACHE STRING "Emscripten-overridden CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL") +set(CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO "-O2" CACHE STRING "Emscripten-overridden CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO") @@ -1186,15 +1186,7 @@ try: if DEBUG: save_intermediate('transformed') if shared.Settings.ASM_JS: # XXX temporary wrapping for testing purposes - print >> sys.stderr, 'emcc: ASM_JS mode is highly experimental, and will not work on most codebases yet. It is NOT recommended that you try this yet.' # XXX TODO: 0.0 instead of +0 for local var defs - unwrapped = open(final).read() - final += '.asmwrap.js' - open(final, 'w').write(''' -(function() { // prevent new Function from seeing the global scope -%s -}).apply(null, arguments); -''' % unwrapped) - if DEBUG: save_intermediate('asmwrap') + print >> sys.stderr, 'emcc: ASM_JS mode is highly experimental, and will not work on most codebases yet. It is NOT recommended that you try this yet.' # It is useful to run several js optimizer passes together, to save on unneeded unparsing/reparsing js_optimizer_queue = [] diff --git a/emscripten.py b/emscripten.py index 2662e40a..68fb4aee 100755 --- a/emscripten.py +++ b/emscripten.py @@ -248,6 +248,11 @@ def emscript(infile, settings, outfile, libraries=[]): for key, value in curr_forwarded_json['Functions']['unimplementedFunctions'].iteritems(): forwarded_json['Functions']['unimplementedFunctions'][key] = value + if settings.get('ASM_JS'): + parts = pre.split('// ASM_LIBRARY FUNCTIONS\n') + if len(parts) > 1: + pre = parts[0] + outputs.append([parts[1]]) funcs_js = ''.join([output[0] for output in outputs]) outputs = None @@ -265,7 +270,7 @@ def emscript(infile, settings, outfile, libraries=[]): indexing = forwarded_json['Functions']['indexedFunctions'] def indexize(js): - return re.sub(r'{{{ FI_([\w\d_$]+) }}}', lambda m: str(indexing[m.groups(0)[0]]), js) + return re.sub(r"'{{ FI_([\w\d_$]+) }}'", lambda m: str(indexing.get(m.groups(0)[0]) or 0), js) blockaddrs = forwarded_json['Functions']['blockAddresses'] def blockaddrsize(js): @@ -295,23 +300,34 @@ def emscript(infile, settings, outfile, libraries=[]): simple = os.environ.get('EMCC_SIMPLE_ASM') class Counter: i = 0 + pre_tables = last_forwarded_json['Functions']['tables']['pre'] + del last_forwarded_json['Functions']['tables']['pre'] + + # Find function table calls without function tables generated for them + for use in set(re.findall(r'{{{ FTM_[\w\d_$]+ }}}', funcs_js)): + sig = use[8:len(use)-4] + if sig not in last_forwarded_json['Functions']['tables']: + if DEBUG: print >> sys.stderr, 'add empty function table', sig + last_forwarded_json['Functions']['tables'][sig] = 'var FUNCTION_TABLE_' + sig + ' = [0,0];\n' + def make_table(sig, raw): i = Counter.i Counter.i += 1 bad = 'b' + str(i) params = ','.join(['p%d' % p for p in range(len(sig)-1)]) - coercions = ';'.join(['p%d = %sp%d%s' % (p, '+' if sig[p+1] == 'd' else '', p, '' if sig[p+1] == 'd' else '|0') for p in range(len(sig)-1)]) + ';' - ret = '' if sig[0] == 'v' else ('return %s0' % ('+' if sig[0] == 'd' else '')) - return 'function %s(%s) { %s abort(%d); %s };\n' % (bad, params, coercions, i, ret) + raw.replace('[0,', '[' + bad + ',').replace(',0,', ',' + bad + ',').replace(',0,', ',' + bad + ',').replace(',0]', ',' + bad + ']').replace(',0]', ',' + bad + ']') - function_tables_defs = '\n'.join([make_table(sig, raw) for sig, raw in last_forwarded_json['Functions']['tables'].iteritems()]) - - maths = ['Runtime.bitshift64', 'Math.floor', 'Math.min', 'Math.abs', 'Math.sqrt', 'Math.pow', 'Math.cos', 'Math.sin', 'Math.tan', 'Math.acos', 'Math.asin', 'Math.atan', 'Math.atan2', 'Math.exp', 'Math.log', 'Math.ceil'] + coercions = ';'.join(['p%d = %sp%d%s' % (p, '+' if sig[p+1] != 'i' else '', p, '' if sig[p+1] != 'i' else '|0') for p in range(len(sig)-1)]) + ';' + ret = '' if sig[0] == 'v' else ('return %s0' % ('+' if sig[0] != 'i' else '')) + return ('function %s(%s) { %s abort(%d); %s };' % (bad, params, coercions, i, ret), raw.replace('[0,', '[' + bad + ',').replace(',0,', ',' + bad + ',').replace(',0,', ',' + bad + ',').replace(',0]', ',' + bad + ']').replace(',0]', ',' + bad + ']')) + infos = [make_table(sig, raw) for sig, raw in last_forwarded_json['Functions']['tables'].iteritems()] + function_tables_defs = '\n'.join([info[0] for info in infos] + [info[1] for info in infos]) + maths = ['Math.' + func for func in ['floor', 'abs', 'sqrt', 'pow', 'cos', 'sin', 'tan', 'acos', 'asin', 'atan', 'atan2', 'exp', 'log', 'ceil']] if settings['USE_MATH_IMUL']: maths += ['Math.imul'] - asm_setup = '\n'.join(['var %s = %s;' % (f.replace('.', '_'), f) for f in maths]) - fundamentals = ['buffer', 'Int8Array', 'Int16Array', 'Int32Array', 'Uint8Array', 'Uint16Array', 'Uint32Array', 'Float32Array', 'Float64Array'] - basic_funcs = ['abort', 'assert', 'asmPrintInt', 'asmPrintFloat'] + [m.replace('.', '_') for m in maths] + fundamentals = ['Math', 'Int8Array', 'Int16Array', 'Int32Array', 'Uint8Array', 'Uint16Array', 'Uint32Array', 'Float32Array', 'Float64Array'] + math_envs = ['Runtime.bitshift64', 'Math.min'] # TODO: move min to maths + asm_setup = '\n'.join(['var %s = %s;' % (f.replace('.', '_'), f) for f in math_envs]) + basic_funcs = ['abort', 'assert', 'asmPrintInt', 'asmPrintFloat'] + [m.replace('.', '_') for m in math_envs] basic_vars = ['STACKTOP', 'STACK_MAX', 'tempDoublePtr', 'ABORT'] basic_float_vars = ['NaN', 'Infinity'] if forwarded_json['Types']['preciseI64MathUsed']: @@ -325,18 +341,25 @@ var i64Math_modulo = function(a, b, c, d, e) { i64Math.modulo(a, b, c, d, e) }; ''' asm_runtime_funcs = ['stackAlloc', 'stackSave', 'stackRestore', 'setThrew'] + ['setTempRet%d' % i for i in range(10)] # function tables + def asm_coerce(value, sig): + if sig == 'v': return value + return ('+' if sig != 'i' else '') + value + ('|0' if sig == 'i' else '') + function_tables = ['dynCall_' + table for table in last_forwarded_json['Functions']['tables']] function_tables_impls = [] for sig in last_forwarded_json['Functions']['tables'].iterkeys(): args = ','.join(['a' + str(i) for i in range(1, len(sig))]) - arg_coercions = ' '.join(['a' + str(i) + '=' + ('+' if sig[i] == 'd' else '') + 'a' + str(i) + ('|0' if sig[i] == 'i' else '') + ';' for i in range(1, len(sig))]) + arg_coercions = ' '.join(['a' + str(i) + '=' + asm_coerce('a' + str(i), sig[i]) + ';' for i in range(1, len(sig))]) + coerced_args = ','.join([asm_coerce('a' + str(i), sig[i]) for i in range(1, len(sig))]) + ret = ('return ' if sig[0] != 'v' else '') + asm_coerce('FUNCTION_TABLE_%s[index&{{{ FTM_%s }}}](%s)' % (sig, sig, coerced_args), sig[0]) function_tables_impls.append(''' function dynCall_%s(index%s%s) { index = index|0; %s - %sFUNCTION_TABLE_%s[index&{{{ FTM_%s }}}](%s); + %s; } -''' % (sig, ',' if len(sig) > 1 else '', args, arg_coercions, 'return ' if sig[0] != 'v' else '', sig, sig, args)) +''' % (sig, ',' if len(sig) > 1 else '', args, arg_coercions, ret)) + # calculate exports exported_implemented_functions = list(exported_implemented_functions) exports = [] @@ -356,11 +379,13 @@ var i64Math_modulo = function(a, b, c, d, e) { i64Math.modulo(a, b, c, d, e) }; global_funcs = ['_' + x for x in forwarded_json['Functions']['libraryFunctions'].keys()] def math_fix(g): return g if not g.startswith('Math_') else g.split('_')[1]; - asm_global_funcs = ''.join([' var ' + g + '=env.' + math_fix(g) + ';\n' for g in basic_funcs + global_funcs]) + asm_global_funcs = ''.join([' var ' + g.replace('.', '_') + '=global.' + g + ';\n' for g in maths]) + \ + ''.join([' var ' + g + '=env.' + math_fix(g) + ';\n' for g in basic_funcs + global_funcs]) asm_global_vars = ''.join([' var ' + g + '=env.' + g + '|0;\n' for g in basic_vars + global_vars]) + \ ''.join([' var ' + g + '=+env.' + g + ';\n' for g in basic_float_vars]) # sent data - sending = '{ ' + ', '.join([math_fix(s) + ': ' + s for s in fundamentals + basic_funcs + global_funcs + basic_vars + basic_float_vars + global_vars]) + ' }' + the_global = '{ ' + ', '.join([math_fix(s) + ': ' + s for s in fundamentals]) + ' }' + sending = '{ ' + ', '.join([math_fix(s) + ': ' + s for s in basic_funcs + global_funcs + basic_vars + basic_float_vars + global_vars]) + ' }' # received if not simple: receiving = ';\n'.join(['var ' + s + ' = Module["' + s + '"] = asm.' + s for s in exported_implemented_functions + function_tables]) @@ -375,20 +400,20 @@ function asmPrintInt(x) { function asmPrintFloat(x) { Module.print('float ' + x);// + ' ' + new Error().stack); } -var asmPre = (function(env, buffer) { +var asm = (function(global, env, buffer) { 'use asm'; - var HEAP8 = new env.Int8Array(buffer); - var HEAP16 = new env.Int16Array(buffer); - var HEAP32 = new env.Int32Array(buffer); - var HEAPU8 = new env.Uint8Array(buffer); - var HEAPU16 = new env.Uint16Array(buffer); - var HEAPU32 = new env.Uint32Array(buffer); - var HEAPF32 = new env.Float32Array(buffer); - var HEAPF64 = new env.Float64Array(buffer); + var HEAP8 = new global.Int8Array(buffer); + var HEAP16 = new global.Int16Array(buffer); + var HEAP32 = new global.Int32Array(buffer); + var HEAPU8 = new global.Uint8Array(buffer); + var HEAPU16 = new global.Uint16Array(buffer); + var HEAPU32 = new global.Uint32Array(buffer); + var HEAPF32 = new global.Float32Array(buffer); + var HEAPF64 = new global.Float64Array(buffer); ''' % (asm_setup,) + '\n' + asm_global_vars + ''' var __THREW__ = 0; var undef = 0; - var tempInt = 0, tempBigInt = 0, tempValue = 0; + var tempInt = 0, tempBigInt = 0, tempBigIntP = 0, tempBigIntS = 0, tempBigIntR = 0.0, tempBigIntI = 0, tempBigIntD = 0, tempValue = 0, tempDouble = 0.0; ''' + ''.join([''' var tempRet%d = 0;''' % i for i in range(10)]) + '\n' + asm_global_funcs + ''' function stackAlloc(size) { @@ -420,18 +445,12 @@ var asmPre = (function(env, buffer) { %s return %s; -}); -if (asmPre.toSource) { // works in sm but not v8, so we get full coverage between those two - asmPre = asmPre.toSource(); - asmPre = asmPre.substr(25, asmPre.length-28); - asmPre = new Function('env', 'buffer', asmPre); -} -var asm = asmPre(%s, buffer); // pass through Function to prevent seeing outside scope +})(%s, %s, buffer); %s; Runtime.stackAlloc = function(size) { return asm.stackAlloc(size) }; Runtime.stackSave = function() { return asm.stackSave() }; Runtime.stackRestore = function(top) { asm.stackRestore(top) }; -''' % (function_tables_defs.replace('\n', '\n ') + '\n' + '\n'.join(function_tables_impls), exports, sending, receiving) +''' % (pre_tables + '\n'.join(function_tables_impls) + '\n' + function_tables_defs.replace('\n', '\n '), exports, the_global, sending, receiving) # Set function table masks def function_table_maskize(js): @@ -442,9 +461,6 @@ Runtime.stackRestore = function(top) { asm.stackRestore(top) }; default = sig def fix(m): sig = m.groups(0)[0] - if not sig in masks: - print >> sys.stderr, 'warning: function table use without functions for it!', sig - return masks[default] # TODO: generate empty function tables for this case, even though it would fail at runtime if used return masks[sig] return re.sub(r'{{{ FTM_([\w\d_$]+) }}}', lambda m: fix(m), js) # masks[m.groups(0)[0]] funcs_js = function_table_maskize(funcs_js) diff --git a/src/analyzer.js b/src/analyzer.js index 229bda9f..60ef5ba8 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -635,7 +635,7 @@ function analyzer(data, sidePass) { break; } case 'add': case 'sub': case 'sdiv': case 'udiv': case 'mul': case 'urem': case 'srem': - case 'uitofp': case 'sitofp': { + case 'uitofp': case 'sitofp': case 'fptosi': case 'fptoui': { // We cannot do these in parallel chunks of 32-bit operations. We will handle these in processMathop i++; continue; diff --git a/src/compiler.js b/src/compiler.js index 118ca83a..25c306cf 100644 --- a/src/compiler.js +++ b/src/compiler.js @@ -168,6 +168,7 @@ if (PGO) { // by default, correct everything during PGO EXPORTED_FUNCTIONS = set(EXPORTED_FUNCTIONS); EXPORTED_GLOBALS = set(EXPORTED_GLOBALS); +EXCEPTION_CATCHING_WHITELIST = set(EXCEPTION_CATCHING_WHITELIST); RUNTIME_DEBUG = LIBRARY_DEBUG || GL_DEBUG; diff --git a/src/determinstic.js b/src/determinstic.js new file mode 100644 index 00000000..7bf1143c --- /dev/null +++ b/src/determinstic.js @@ -0,0 +1,16 @@ + +var MAGIC = 0; +Math.random = function() { + MAGIC = Math.pow(MAGIC + 1.8912, 3) % 1; + return MAGIC + 10; +}; +var TIME = 0; +Date.now = function() { + TIME += 0.05; + return TIME; +}; +performance.now = function() { + TIME += 0.05; + return TIME; +}; + diff --git a/src/experimental/functypeopt.diff b/src/experimental/functypeopt.diff new file mode 100644 index 00000000..6e2fa396 --- /dev/null +++ b/src/experimental/functypeopt.diff @@ -0,0 +1,113 @@ +diff --git a/src/parseTools.js b/src/parseTools.js +index 9786460..fb4be9f 100644 +--- a/src/parseTools.js ++++ b/src/parseTools.js +@@ -205,26 +205,57 @@ function isFunctionDef(token, out) { + function isPossiblyFunctionType(type) { + // A quick but unreliable way to see if something is a function type. Yes is just 'maybe', no is definite. + var len = type.length; +- return type[len-2] == ')' && type[len-1] == '*'; ++ return type[len-2] == ')' && type[len-1] == '*' && type.indexOf('(') > 0; + } + + function isFunctionType(type, out) { + if (!isPossiblyFunctionType(type)) return false; + type = type.replace(/"[^"]+"/g, '".."'); +- var parts; + // hackish, but quick splitting of function def parts. this must be fast as it happens a lot +- if (type[0] != '[') { +- parts = type.split(' '); +- } else { +- var index = type.search(']'); +- index += type.substr(index).search(' '); +- parts = [type.substr(0, index), type.substr(index+1)]; +- } ++ var parts = type.split(' '); + if (pointingLevels(type) !== 1) return false; + var text = removeAllPointing(parts.slice(1).join(' ')); + if (!text) return false; +- if (out) out.returnType = parts[0]; +- return isType(parts[0]) && isFunctionDef({ text: text, item: tokenize(text.substr(1, text.length-2), true) }, out); ++ if (!isType(parts[0])) return false; ++ var level = 0; ++ var chunks = []; ++ var currStart = 0; ++ for (var i = 0; i < type.length; i++) { ++ var curr = type[i]; ++ if (curr == '(') { ++ level++; ++ if (level == 1) { ++ chunks.push(type.substring(currStart, i)); ++ currStart = i+1; ++ } ++ } else if (curr == ')') { ++ level--; ++ if (level == 0) { ++ curr = type.substring(currStart, i); ++ if (curr == '') curr = '$'; // make sure inside of () stays valid ++ chunks.push(curr); ++ currStart = i+1; ++ } ++ } ++ } ++//printErr('pre chunks ' + JSON.stringify(chunks)); ++ chunks = chunks.map(function(chunk) { return chunk.replace(/ /g, '') }) ++ .filter(function(chunk) { return chunk.length > 0 }) ++ .map(function(chunk) { return chunk.replace(/\$/g, ' ') }); ++//printErr('post chunks ' + JSON.stringify(chunks)); ++ switch (chunks.length) { ++ case 2: { // e.g. void (i32,i32) ++ if (out) out.returnType = chunks[0]; // TODO: add cache, with this as the value ++ return isFunctionDef({ text: '(' + chunks[1] + ')', item: tokenize(chunks[1], true) }, out); ++ } ++ case 4: { // e.g. void (i32)* (i32, i32) (i.e., returns void (i32)*!) ++ if (chunks[2] != '*') return false; ++ if (out) out.returnType = chunks[0] + ' ' + chunks[1]; ++ return isFunctionDef({ text: '(' + chunks[1] + ')', item: tokenize(chunks[1], true) }) && ++ isFunctionDef({ text: '(' + chunks[2] + ')', item: tokenize(chunks[2], true) }, out); ++ } ++ } ++ return false; + } + + var isTypeCache = {}; // quite hot, optimize as much as possible +diff --git a/tests/runner.py b/tests/runner.py +index 842daca..312541f 100755 +--- a/tests/runner.py ++++ b/tests/runner.py +@@ -2860,6 +2860,35 @@ Exiting setjmp function, level: 0, prev_jmp: -1 + ''' + self.do_run(src, 'fn2(-5) = 5, fn(10) = 3.16') + ++ def test_funcptrfunc(self): ++ src = r''' ++ #include <stdio.h> ++ ++/* ++define internal fastcc void ()* @sqlite3OsDlSym(%struct.sqlite3_vfs* %pVfs, i8* %pHdle, i8* %zSym) nounwind { ++ %1 = getelementptr inbounds %struct.sqlite3_vfs* %pVfs, i32 0, i32 12 ++ %2 = load void ()* (%struct.sqlite3_vfs*, i8*, i8*)** %1, align 4 ++ %3 = tail call void ()* (%struct.sqlite3_vfs*, i8*, i8*)* %2(%struct.sqlite3_vfs* %pVfs, i8* %pHdle, i8* %zSym) nounwind ++ ret void ()* %3 ++} ++*/ ++ ++ typedef void (*funcptr)(int, int); ++ typedef funcptr (*funcptrfunc)(int); ++ ++ funcptr __attribute__ ((noinline)) getIt(int x) { ++ return (funcptr)x; ++ } ++ ++ int main(int argc, char **argv) ++ { ++ funcptrfunc fpf = argc < 100 ? getIt : NULL; ++ printf("*%p*\n", fpf(argc)); ++ return 0; ++ } ++ ''' ++ self.do_run(src, '*0x1*') ++ + def test_emptyclass(self): + if self.emcc_args is None: return self.skip('requires emcc') + src = ''' diff --git a/src/intertyper.js b/src/intertyper.js index 00d504f5..c1a98354 100644 --- a/src/intertyper.js +++ b/src/intertyper.js @@ -725,7 +725,7 @@ function intertyper(data, sidePass, baseLineNums) { substrate.addActor('Invoke', { processItem: function(item) { var result = makeCall.call(this, item, 'invoke'); - if (DISABLE_EXCEPTION_CATCHING) { + if (DISABLE_EXCEPTION_CATCHING == 1) { result.item.intertype = 'call'; result.ret.push({ intertype: 'branch', @@ -834,15 +834,17 @@ function intertyper(data, sidePass, baseLineNums) { item.params[i-1] = parseLLVMSegment(segments[i-1]); } } + var setParamTypes = true; if (item.op === 'select') { assert(item.params[1].type === item.params[2].type); item.type = item.params[1].type; - } else if (item.op === 'inttoptr' || item.op === 'ptrtoint') { + } else if (item.op in LLVM.CONVERSIONS) { item.type = item.params[1].type; + setParamTypes = false; } else { item.type = item.params[0].type; } - if (item.op != 'ptrtoint') { + if (setParamTypes) { for (var i = 0; i < 4; i++) { if (item.params[i]) item.params[i].type = item.type; // All params have the same type, normally } diff --git a/src/jsifier.js b/src/jsifier.js index 5fbea5ba..84a9b5f7 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -10,6 +10,7 @@ var UNDERSCORE_OPENPARENS = set('_', '('); var RELOOP_IGNORED_LASTS = set('return', 'unreachable', 'resume'); var addedLibraryItems = {}; +var asmLibraryFunctions = []; // JSifier function JSify(data, functionsOnly, givenFunctions) { @@ -76,7 +77,7 @@ function JSify(data, functionsOnly, givenFunctions) { assert(!BUILD_AS_SHARED_LIB, 'Cannot have both INCLUDE_FULL_LIBRARY and BUILD_AS_SHARED_LIB set.') libFuncsToInclude = []; for (var key in LibraryManager.library) { - if (!key.match(/__(deps|postset|inline)$/)) { + if (!key.match(/__(deps|postset|inline|asm|sig)$/)) { libFuncsToInclude.push(key); } } @@ -292,7 +293,7 @@ function JSify(data, functionsOnly, givenFunctions) { padding = makeEmptyStruct(item.type); } var padded = val.concat(padding.slice(val.length)); - var js = item.ident + '=' + makePointer(JSON.stringify(padded), null, allocator, item.type, index) + ';' + var js = item.ident + '=' + makePointer(padded, null, allocator, item.type, index) + ';' if (LibraryManager.library[shortident + '__postset']) { js += '\n' + LibraryManager.library[shortident + '__postset']; } @@ -332,7 +333,6 @@ function JSify(data, functionsOnly, givenFunctions) { constant[i] = '0'; } }); - constant = '[' + constant.join(', ') + ']'; } // NOTE: This is the only place that could potentially create static // allocations in a shared library. @@ -346,7 +346,7 @@ function JSify(data, functionsOnly, givenFunctions) { if (index !== null) { index = getFastValue(index, '+', Runtime.alignMemory(calcAllocatedSize(Variables.globals[item.ident].type))); } - js += '\n' + makePointer('[0]', null, allocator, ['void*'], index) + ';'; + js += '\n' + makePointer([0], null, allocator, ['void*'], index) + ';'; } if (!ASM_JS && (EXPORT_ALL || (item.ident in EXPORTED_GLOBALS))) { js += '\nModule["' + item.ident + '"] = ' + item.ident + ';'; @@ -440,8 +440,8 @@ function JSify(data, functionsOnly, givenFunctions) { // name the function; overwrite if it's already named snippet = snippet.replace(/function(?:\s+([^(]+))?\s*\(/, 'function _' + ident + '('); if (LIBRARY_DEBUG) { - snippet = snippet.replace('{', '{ var ret = (function() { if (Runtime.debug) Module.print("[library call:' + ident + ': " + Array.prototype.slice.call(arguments).map(Runtime.prettyPrint) + "]"); '); - snippet = snippet.substr(0, snippet.length-1) + '}).apply(this, arguments); if (Runtime.debug && typeof ret !== "undefined") Module.print(" [ return:" + Runtime.prettyPrint(ret)); return ret; }'; + snippet = snippet.replace('{', '{ var ret = (function() { if (Runtime.debug) Module.printErr("[library call:' + ident + ': " + Array.prototype.slice.call(arguments).map(Runtime.prettyPrint) + "]"); '); + snippet = snippet.substr(0, snippet.length-1) + '}).apply(this, arguments); if (Runtime.debug && typeof ret !== "undefined") Module.printErr(" [ return:" + Runtime.prettyPrint(ret)); return ret; \n}'; } if (ASM_JS) Functions.libraryFunctions[ident] = 1; } @@ -477,13 +477,25 @@ function JSify(data, functionsOnly, givenFunctions) { } else { ident = '_' + ident; } - var text = (deps ? '\n' + deps.map(addFromLibrary).filter(function(x) { return x != '' }).join('\n') : ''); + var depsText = (deps ? '\n' + deps.map(addFromLibrary).filter(function(x) { return x != '' }).join('\n') : ''); // redirected idents just need a var, but no value assigned to them - it would be unused - text += isFunction ? snippet : ('var ' + ident + (redirectedIdent ? '' : '=' + snippet) + ';'); - if (EXPORT_ALL || (ident in EXPORTED_FUNCTIONS)) { - text += '\nModule["' + ident + '"] = ' + ident + ';'; + var contentText = isFunction ? snippet : ('var ' + ident + (redirectedIdent ? '' : '=' + snippet) + ';'); + if (ASM_JS) { + var sig = LibraryManager.library[ident.substr(1) + '__sig']; + if (isFunction && sig && LibraryManager.library[ident.substr(1) + '__asm']) { + // asm library function, add it as generated code alongside the generated code + Functions.implementedFunctions[ident] = sig; + asmLibraryFunctions.push(contentText); + contentText = ' '; + EXPORTED_FUNCTIONS[ident] = 1; + delete Functions.libraryFunctions[ident.substr(1)]; + } + } else { + if (EXPORT_ALL || (ident in EXPORTED_FUNCTIONS)) { + contentText += '\nModule["' + ident + '"] = ' + ident + ';'; + } } - return text; + return depsText + contentText; } var ret = [item]; @@ -606,10 +618,11 @@ function JSify(data, functionsOnly, givenFunctions) { } for (i = 0; i < chunks.length; i++) { func.JS += ' var ' + chunks[i].map(function(v) { - if (!isIllegalType(v.type) || v.ident.indexOf('$', 1) > 0) { // not illegal, or a broken up illegal - return v.ident + ' = ' + asmInitializer(v.type); //, func.variables[v.ident].impl); + var type = getImplementationType(v); + if (!isIllegalType(type) || v.ident.indexOf('$', 1) > 0) { // not illegal, or a broken up illegal + return v.ident + ' = ' + asmInitializer(type); //, func.variables[v.ident].impl); } else { - return range(Math.ceil(getBits(v.type)/32)).map(function(i) { + return range(Math.ceil(getBits(type)/32)).map(function(i) { return v.ident + '$' + i + '= 0'; }).join(','); } @@ -722,12 +735,13 @@ function JSify(data, functionsOnly, givenFunctions) { if (func.setjmpTable) { ret += 'try { '; } - ret += 'switch(label) {\n'; + ret += 'switch(' + asmCoercion('label', 'i32') + ') {\n'; ret += block.labels.map(function(label) { return indent + ' case ' + getLabelId(label.ident) + ': ' + (SHOW_LABELS ? '// ' + getOriginalLabelId(label.ident) : '') + '\n' + getLabelLines(label, indent + ' '); - |