diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/analyzer.js | 15 | ||||
-rw-r--r-- | src/compiler.js | 1 | ||||
-rw-r--r-- | src/intertyper.js | 10 | ||||
-rw-r--r-- | src/jsifier.js | 103 | ||||
-rw-r--r-- | src/library.js | 65 | ||||
-rw-r--r-- | src/library_gl.js | 4 | ||||
-rw-r--r-- | src/modules.js | 24 | ||||
-rw-r--r-- | src/parseTools.js | 185 | ||||
-rw-r--r-- | src/preamble.js | 24 | ||||
-rw-r--r-- | src/runtime.js | 23 | ||||
-rw-r--r-- | src/settings.js | 8 |
11 files changed, 328 insertions, 134 deletions
diff --git a/src/analyzer.js b/src/analyzer.js index 8146c75c..60ef5ba8 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -617,8 +617,8 @@ function analyzer(data, sidePass) { for (var i = 0; i < targetElements.length; i++) { if (i > 0) { switch(value.variant) { - case 'eq': ident += '&&'; break; - case 'ne': ident += '||'; break; + case 'eq': ident += '&'; break; + case 'ne': ident += '|'; break; default: throw 'unhandleable illegal icmp: ' + value.variant; } } @@ -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; @@ -654,9 +654,12 @@ function analyzer(data, sidePass) { // We can't statically legalize this, do the operation at runtime TODO: optimize assert(sourceBits == 64, 'TODO: handle nonconstant shifts on != 64 bits'); value.intertype = 'value'; - value.ident = 'Runtime' + (ASM_JS ? '_' : '.') + 'bitshift64(' + sourceElements[0].ident + ', ' + - sourceElements[1].ident + ',"' + value.op + '",' + value.params[1].ident + '$0);' + - 'var ' + value.assignTo + '$0 = ' + makeGetTempDouble(0, 'i32') + ', ' + value.assignTo + '$1 = ' + makeGetTempDouble(1, 'i32') + ';'; + value.ident = 'Runtime' + (ASM_JS ? '_' : '.') + 'bitshift64(' + + asmCoercion(sourceElements[0].ident, 'i32') + ',' + + asmCoercion(sourceElements[1].ident, 'i32') + ',' + + Runtime['BITSHIFT64_' + value.op.toUpperCase()] + ',' + + asmCoercion(value.params[1].ident + '$0', 'i32') + ');' + + 'var ' + value.assignTo + '$0 = ' + makeGetTempDouble(0, 'i32') + ', ' + value.assignTo + '$1 = ' + makeGetTempDouble(1, 'i32') + ';'; value.assignTo = null; 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/intertyper.js b/src/intertyper.js index 5bca9236..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 } @@ -851,6 +853,8 @@ function intertyper(data, sidePass, baseLineNums) { item.type = item.params[1].ident; item.params[0].type = item.params[1].type; // TODO: also remove 2nd param? + } else if (item.op in LLVM.COMPS) { + item.type = 'i1'; } if (USE_TYPED_ARRAYS == 2) { // Some specific corrections, since 'i64' is special diff --git a/src/jsifier.js b/src/jsifier.js index 44d9cc53..08b6d4f6 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)$/)) { 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 + ';'; @@ -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 asmSig = LibraryManager.library[ident.substr(1) + '__asm']; + if (isFunction && asmSig) { + // asm library function, add it as generated code alongside the generated code + Functions.implementedFunctions[ident] = asmSig; + 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,12 @@ function JSify(data, functionsOnly, givenFunctions) { } for (i = 0; i < chunks.length; i++) { func.JS += ' var ' + chunks[i].map(function(v) { - if (v.type != 'i64') { + 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); } else { - return v.ident + '$0 = 0, ' + v.ident + '$1 = 1'; + return range(Math.ceil(getBits(v.type)/32)).map(function(i) { + return v.ident + '$' + i + '= 0'; + }).join(','); } }).join(', ') + ';\n'; } @@ -720,12 +734,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 + ' '); }).join('\n'); - ret += '\n' + indent + ' default: assert(0, "bad label: " + label);\n' + indent + '}'; + if (ASSERTIONS) ret += '\n' + indent + ' default: assert(0, "bad label: " + label);\n'; + ret += indent + '}'; if (func.setjmpTable) { ret += ' } catch(e) { if (!e.longjmp || !(e.id in mySetjmpIds)) throw(e); setjmpTable[setjmpLabels[e.id]](e.value) }'; } @@ -783,10 +798,10 @@ function JSify(data, functionsOnly, givenFunctions) { func.JS += walkBlock(func.block, ' '); // Finalize function if (LABEL_DEBUG && functionNameFilterTest(func.ident)) func.JS += " INDENT = INDENT.substr(0, INDENT.length-2);\n"; - // Add an unneeded return, needed for strict mode to not throw warnings in some cases. - // If we are not relooping, then switches make it unimportant to have this (and, we lack hasReturn anyhow) - if (RELOOP && func.lines.length > 0 && func.labels.filter(function(label) { return label.hasReturn }).length > 0) { - func.JS += ' return' + (func.returnType !== 'void' ? ' null' : '') + ';\n'; + // Ensure a return in a function with a type that returns, even if it lacks a return (e.g., if it aborts()) + if (RELOOP && func.lines.length > 0 && func.returnType != 'void') { + var returns = func.labels.filter(function(label) { return label.lines[label.lines.length-1].intertype == 'return' }).length; + if (returns == 0) func.JS += ' return ' + asmCoercion('0', func.returnType); } func.JS += '}\n'; @@ -1091,7 +1106,7 @@ function JSify(data, functionsOnly, givenFunctions) { if (useIfs) { value = targetLabels[targetLabel].map(function(value) { return makeComparison(signedIdent, makeSignOp(value, item.type, 're'), item.type) - }).join(' || '); + }).join(' | '); ret += 'if (' + value + ') {\n'; } else { value = targetLabels[targetLabel].map(function(value) { @@ -1150,20 +1165,29 @@ function JSify(data, functionsOnly, givenFunctions) { var ptr = makeStructuralAccess(item.ident, 0); return (EXCEPTION_DEBUG ? 'Module.print("Resuming exception");' : '') + 'if (' + makeGetValue('_llvm_eh_exception.buf', 0, 'void*') + ' == 0) { ' + makeSetValue('_llvm_eh_exception.buf', 0, ptr, 'void*') + ' } ' + - 'throw ' + ptr + ';'; + makeThrow(ptr) + ';'; }); makeFuncLineActor('invoke', function(item) { // Wrapping in a function lets us easily return values if we are // in an assignment var phiSets = calcPhiSets(item); var call_ = makeFunctionCall(item.ident, item.params, item.funcData, item.type); - var ret = '(function() { try { __THREW__ = 0; return ' - + call_ + ' ' - + '} catch(e) { ' - + 'if (typeof e != "number") throw e; ' - + 'if (ABORT) throw e; __THREW__ = 1; ' - + (EXCEPTION_DEBUG ? 'Module.print("Exception: " + e + ", currently at: " + (new Error().stack)); ' : '') - + 'return null } })();'; + + var ret; + + if (DISABLE_EXCEPTION_CATCHING == 2 && !(item.funcData.ident in EXCEPTION_CATCHING_WHITELIST)) { + ret = call_ + ';'; + } else { + ret = '(function() { try { __THREW__ = 0; return ' + + call_ + ' ' + + '} catch(e) { ' + + 'if (typeof e != "number") throw e; ' + + 'if (ABORT) throw e; __THREW__ = 1; ' + + (EXCEPTION_DEBUG ? 'Module.print("Exception: " + e + ", currently at: " + (new Error().stack)); ' : '') + + 'return null } })();'; + } + + if (item.assignTo) { ret = 'var ' + item.assignTo + ' = ' + ret; if (USE_TYPED_ARRAYS == 2 && isIllegalType(item.type)) { @@ -1191,7 +1215,7 @@ function JSify(data, functionsOnly, givenFunctions) { case 'xchg': return '(tempValue=' + makeGetValue(param1, 0, type) + ',' + makeSetValue(param1, 0, param2, type, null, null, null, null, ',') + ',tempValue)'; case 'cmpxchg': { var param3 = finalizeLLVMParameter(item.params[2]); - return '(tempValue=' + makeGetValue(param1, 0, type) + ',(' + makeGetValue(param1, 0, type) + '==' + param2 + ' && (' + makeSetValue(param1, 0, param3, type, null, null, null, null, ',') + ')),tempValue)'; + return '(tempValue=' + makeGetValue(param1, 0, type) + ',(' + makeGetValue(param1, 0, type) + '==' + param2 + ' ? ' + makeSetValue(param1, 0, param3, type, null, null, null, null, ',') + ' : 0),tempValue)'; } default: throw 'unhandled atomic op: ' + item.op; } @@ -1240,7 +1264,12 @@ function JSify(data, functionsOnly, givenFunctions) { return ret + item.ident + '.f' + item.indexes[0][0].text + ' = ' + finalizeLLVMParameter(item.value) + ', ' + item.ident + ')'; }); makeFuncLineActor('indirectbr', function(item) { - return makeBranch(finalizeLLVMParameter(item.value), item.currLabelId, true); + var phiSets = calcPhiSets(item); + var js = 'var ibr = ' + finalizeLLVMParameter(item.value) + ';\n'; + for (var targetLabel in phiSets) { + js += 'if (ibr == ' + targetLabel + ') { ' + getPhiSetsForLabel(phiSets, targetLabel) + ' }\n'; + } + return js + makeBranch('ibr', item.currLabelId, true); }); makeFuncLineActor('alloca', function(item) { if (typeof item.allocatedIndex === 'number') { @@ -1311,8 +1340,12 @@ function JSify(data, functionsOnly, givenFunctions) { }); args = args.map(function(arg, i) { return indexizeFunctions(arg, argsTypes[i]) }); - if (ASM_JS && shortident in Functions.libraryFunctions) { - args = args.map(function(arg, i) { return asmCoercion(arg, argsTypes[i]) }); + if (ASM_JS) { + if (shortident in Functions.libraryFunctions) { + args = args.map(function(arg, i) { return asmCoercion(arg, argsTypes[i]) }); + } else { + args = args.map(function(arg, i) { return asmEnsureFloat(arg, argsTypes[i]) }); + } } varargs = varargs.map(function(vararg, i) { @@ -1471,6 +1504,16 @@ function JSify(data, functionsOnly, givenFunctions) { generated.forEach(function(item) { print(indentify(item.JS || '', 2)); }); legalizedI64s = legalizedI64sDefault; + + if (asmLibraryFunctions.length > 0) { + print('// ASM_LIBRARY FUNCTIONS'); + function fix(f) { // fix indenting to not confuse js optimizer + f = f.substr(f.indexOf('f')); // remove initial spaces before 'function' + f = f.substr(0, f.lastIndexOf('\n')+1); // remove spaces and last } + return f + '}'; // add unindented } to match function + } + print(asmLibraryFunctions.map(fix).join('\n')); + } } else { if (singlePhase) { assert(data.unparsedGlobalss[0].lines.length == 0, dump([phase, data.unparsedGlobalss])); diff --git a/src/library.js b/src/library.js index 3b229dfa..9268edd5 100644 --- a/src/library.js +++ b/src/library.js @@ -52,7 +52,7 @@ LibraryManager.library = { streams: [null], #if ASSERTIONS checkStreams: function() { - for (var i in FS.streams) assert(i >= 0 && i < FS.streams.length); // no keys not in dense span + for (var i in FS.streams) if (FS.streams.hasOwnProperty(i)) assert(i >= 0 && i < FS.streams.length); // no keys not in dense span for (var i = 0; i < FS.streams.length; i++) assert(typeof FS.streams[i] == 'object'); // no non-null holes in dense span }, #endif @@ -2611,6 +2611,7 @@ LibraryManager.library = { // format: A pointer to the format string. // varargs: A pointer to the start of the arguments list. // Returns the resulting string string as a character array. + _formatString__deps: ['strlen'], _formatString: function(format, varargs) { var textIndex = format; var argIndex = 0; @@ -2937,7 +2938,7 @@ LibraryManager.library = { } else if (next == 's'.charCodeAt(0)) { // String. var arg = getNextArg('i8*') || nullString; - var argLength = String_len(arg); + var argLength = _strlen(arg); if (precisionSet) argLength = Math.min(argLength, precision); if (!flagLeftAlign) { while (argLength < width--) { @@ -3500,6 +3501,12 @@ LibraryManager.library = { var result = __formatString(format, varargs); var limit = (n === undefined) ? result.length : Math.min(result.length, Math.max(n - 1, 0)); + if (s < 0) { + s = -s; + var buf = _malloc(limit+1); + {{{ makeSetValue('s', '0', 'buf', 'i8*') }}}; + s = buf; + } for (var i = 0; i < limit; i++) { {{{ makeSetValue('s', 'i', 'result[i]', 'i8') }}}; } @@ -3529,10 +3536,15 @@ LibraryManager.library = { // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html return _snprintf(s, undefined, format, varargs); }, + asprintf__deps: ['sprintf'], + asprintf: function(s, format, varargs) { + return _sprintf(-s, format, varargs); + }, vfprintf: 'fprintf', vsnprintf: 'snprintf', vprintf: 'printf', vsprintf: 'sprintf', + vasprintf: 'asprintf', vscanf: 'scanf', vfscanf: 'fscanf', vsscanf: 'sscanf', @@ -3617,7 +3629,7 @@ LibraryManager.library = { * implementation (replaced by dlmalloc normally) so * not an issue. */ - ptr = Runtime.staticAlloc(bytes + 8); + var ptr = Runtime.staticAlloc(bytes + 8); return (ptr+8) & 0xFFFFFFF8; }, free: function(){}, @@ -4213,6 +4225,8 @@ LibraryManager.library = { } }, + wmemcpy: function() { throw 'wmemcpy not implemented' }, + llvm_memcpy_i32: 'memcpy', llvm_memcpy_i64: 'memcpy', llvm_memcpy_p0i8_p0i8_i32: 'memcpy', @@ -4238,6 +4252,8 @@ LibraryManager.library = { llvm_memmove_p0i8_p0i8_i32: 'memmove', llvm_memmove_p0i8_p0i8_i64: 'memmove', + wmemmove: function() { throw 'wmemmove not implemented' }, + memset__inline: function(ptr, value, num, align) { return makeSetValues(ptr, 0, value, 'null', num, align); }, @@ -4272,8 +4288,17 @@ LibraryManager.library = { llvm_memset_p0i8_i32: 'memset', llvm_memset_p0i8_i64: 'memset', + wmemset: function() { throw 'wmemset not implemented' }, + + strlen__asm: 'ii', strlen: function(ptr) { - return String_len(ptr); + ptr = ptr|0; + var curr = 0; + curr = ptr; + while ({{{ makeGetValueAsm('curr', '0', 'i8') }}}|0 != 0) { + curr = (curr + 1)|0; + } + return (curr - ptr)|0; }, // TODO: Implement when we have real unicode support. @@ -4281,6 +4306,13 @@ LibraryManager.library = { return 1; }, + wcslen: function() { throw 'wcslen not implemented' }, + mbrlen: function() { throw 'mbrlen not implemented' }, + mbsrtowcs: function() { throw 'mbsrtowcs not implemented' }, + wcsnrtombs: function() { throw 'wcsnrtombs not implemented' }, + mbsnrtowcs: function() { throw 'mbsnrtowcs not implemented' }, + mbrtowc: function() { throw 'mbrtowc not implemented' }, + strspn: function(pstr, pset) { var str = pstr, set, strcurr, setcurr; while (1) { @@ -4497,17 +4529,18 @@ LibraryManager.library = { }, rindex: 'strrchr', + strdup__deps: ['strlen'], strdup: function(ptr) { - var len = String_len(ptr); + var len = _strlen(ptr); var newStr = _malloc(len + 1); {{{ makeCopyValues('newStr', 'ptr', 'len', 'null', null, 1) }}}; {{{ makeSetValue('newStr', 'len', '0', 'i8') }}}; return newStr; }, - strndup__deps: ['strdup'], + strndup__deps: ['strdup', 'strlen'], strndup: function(ptr, size) { - var len = String_len(ptr); + var len = _strlen(ptr); if (size >= len) { return _strdup(ptr); @@ -4898,12 +4931,12 @@ LibraryManager.library = { } else { __ZSt18uncaught_exceptionv.uncaught_exception++; } - throw ptr; + {{{ makeThrow('ptr') }}}; }, __cxa_rethrow__deps: ['llvm_eh_exception', '__cxa_end_catch'], __cxa_rethrow: function() { ___cxa_end_catch.rethrown = true; - throw {{{ makeGetValue('_llvm_eh_exception.buf', '0', 'void*') }}}; + {{{ makeThrow(makeGetValue('_llvm_eh_exception.buf', '0', 'void*')) }}}; }, llvm_eh_exception__postset: '_llvm_eh_exception.buf = allocate(12, "void*", ALLOC_STATIC);', llvm_eh_exception: function() { @@ -4966,11 +4999,10 @@ LibraryManager.library = { }, _Unwind_Resume_or_Rethrow: function(ptr) { - throw ptr; + {{{ makeThrow('ptr') }}}; }, - _Unwind_RaiseException__deps: ['llvm_eh_exception', '__cxa_find_matching_catch'], _Unwind_RaiseException: function(ptr) { - throw ptr; + {{{ makeThrow('ptr') }}}; }, _Unwind_DeleteException: function(ptr) {}, @@ -5074,6 +5106,8 @@ LibraryManager.library = { _ZNSt9exceptionD2Ev: function(){}, // XXX a dependency of dlmalloc, but not actually needed if libcxx is not anyhow included + _ZNSt9type_infoD2Ev: function(){}, + // RTTI hacks for exception handling, defining type_infos for common types. // The values are dummies. We simply use the addresses of these statically // allocated variables as unique identifiers. @@ -6130,6 +6164,8 @@ LibraryManager.library = { return me.ret; }, + __locale_mb_cur_max: function() { throw '__locale_mb_cur_max not implemented' }, + // ========================================================================== // langinfo.h // ========================================================================== @@ -6310,6 +6346,10 @@ LibraryManager.library = { return me.ret; }, + _Z7catopenPKci: function() { throw 'catopen not implemented' }, + _Z7catgetsP8_nl_catdiiPKc: function() { throw 'catgets not implemented' }, + _Z8catcloseP8_nl_catd: function() { throw 'catclose not implemented' }, + // ========================================================================== // errno.h // ========================================================================== @@ -6553,6 +6593,7 @@ LibraryManager.library = { pthread_cond_init: function() {}, pthread_cond_destroy: function() {}, pthread_cond_broadcast: function() {}, + pthread_cond_wait: function() {}, pthread_self: function() { //FIXME: assumes only a single thread return 0; diff --git a/src/library_gl.js b/src/library_gl.js index 267a6185..2a6ec92f 100644 --- a/src/library_gl.js +++ b/src/library_gl.js @@ -2462,6 +2462,10 @@ var LibraryGL = { {{{ makeSetValue('objZ', '0', 'result[2]', 'double') }}}; return 1 /* GL_TRUE */; + }, + + gluOrtho2D: function(left, right, bottom, top) { + _glOrtho(left, right, bottom, top, -1, 1); } }; diff --git a/src/modules.js b/src/modules.js index b5a30866..a08d6f1a 100644 --- a/src/modules.js +++ b/src/modules.js @@ -13,8 +13,10 @@ var LLVM = { ACCESS_OPTIONS: set('volatile', 'atomic'), INVOKE_MODIFIERS: set('alignstack', 'alwaysinline', 'inlinehint', 'naked', 'noimplicitfloat', 'noinline', 'alwaysinline attribute.', 'noredzone', 'noreturn', 'nounwind', 'optsize', 'readnone', 'readonly', 'ssp', 'sspreq'), SHIFTS: set('ashr', 'lshr', 'shl'), - PHI_REACHERS: set('branch', 'switch', 'invoke'), + PHI_REACHERS: set('branch', 'switch', 'invoke', 'indirectbr'), EXTENDS: set('sext', 'zext'), + COMPS: set('icmp', 'fcmp'), + CONVERSIONS: set('inttoptr', 'ptrtoint', 'uitofp', 'sitofp', 'fptosi', 'fptoui'), INTRINSICS_32: set('_llvm_memcpy_p0i8_p0i8_i64', '_llvm_memmove_p0i8_p0i8_i64', '_llvm_memset_p0i8_i64'), // intrinsics that need args converted to i32 in USE_TYPED_ARRAYS == 2 }; LLVM.GLOBAL_MODIFIERS = set(keys(LLVM.LINKAGES).concat(['constant', 'global', 'hidden'])); @@ -263,7 +265,7 @@ var Functions = { function emptyTable(sig) { return zeros(total); } - var tables = {}; + var tables = { pre: '' }; if (ASM_JS) { ['v', 'vi', 'ii', 'iii'].forEach(function(sig) { // add some default signatures that are used in the library tables[sig] = emptyTable(sig); // TODO: make them compact @@ -276,7 +278,9 @@ var Functions = { tables[sig][this.indexedFunctions[ident]] = ident; } var generated = false; + var wrapped = {}; for (var t in tables) { + if (t == 'pre') continue; generated = true; var table = tables[t]; for (var i = 0; i < table.length; i++) { @@ -293,6 +297,22 @@ var Functions = { table[i] = (libName.indexOf('.') < 0 ? '_' : '') + libName; } } + var curr = table[i]; + if (curr && Functions.unimplementedFunctions[table[i]]) { + // This is a library function, we can't just put it in the function table, need a wrapper + if (!wrapped[curr]) { + var args = '', arg_coercions = '', call = curr + '(', ret = t[0] == 'v' ? '' : ('return ' + (t[0] == 'f' ? '+0' : '0')); + for (var i = 1; i < t.length; i++) { + args += (i > 1 ? ',' : '') + 'a' + i; + arg_coercions += 'a' + i + '=' + asmCoercion('a' + i, t[i] == 'f' ? 'float' : 'i32') + ';'; + call += (i > 1 ? ',' : '') + asmCoercion('a' + i, t[i] == 'f' ? 'float' : 'i32'); + } + call += ')'; + tables.pre += 'function ' + curr + '__wrapper(' + args + ') { ' + arg_coercions + ' ; ' + call + ' ; ' + ret + ' }\n'; + wrapped[curr] = 1; + } + table[i] = curr + '__wrapper'; + } } var indices = table.toString().replace('"', ''); if (BUILD_AS_SHARED_LIB) { diff --git a/src/parseTools.js b/src/parseTools.js index 32bf70e9..5f8797b0 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -974,7 +974,7 @@ if (ASM_JS) { var memoryMask = hexMemoryMask.length <= decMemoryMask.length ? hexMemoryMask : decMemoryMask; } -function getHeapOffset(offset, type) { +function getHeapOffset(offset, type, forceAsm) { if (USE_TYPED_ARRAYS !== 2) { return offset; } else { @@ -983,7 +983,7 @@ function getHeapOffset(offset, type) { } var shifts = Math.log(Runtime.getNativeTypeSize(type))/Math.LN2; offset = '(' + offset + ')'; - if (ASM_JS && phase == 'funcs') offset = '(' + offset + '&' + memoryMask + ')'; + if (ASM_JS && (phase == 'funcs' || forceAsm)) offset = '(' + offset + '&' + memoryMask + ')'; if (shifts != 0) { return '(' + offset + '>>' + shifts + ')'; } else { @@ -1019,14 +1019,18 @@ function asmCoercion(value, type, signedness) { if (type == 'void') { return value; } else if (type in Runtime.FLOAT_TYPES) { - if (signedness) { - if (signedness == 'u') { - value = '(' + value + ')>>>0'; - } else { - value = '(' + value + ')|0'; + if (isNumber(value)) { + return asmEnsureFloat(value, type); + } else { + if (signedness) { + if (signedness == 'u') { + value = '(' + value + ')>>>0'; + } else { + value = '(' + value + ')|0'; + } } + return '(+(' + value + '))'; } - return '(+(' + value + '))'; } else { return '((' + value + ')|0)'; } @@ -1041,7 +1045,7 @@ function asmMultiplyI32(a, b) { return '(~~(+((' + a + ')|0) * +((' + b + ')|0)))'; } -function makeGetTempDouble(i, type) { // get an aliased part of the tempDouble temporary storage +function makeGetTempDouble(i, type, forSet) { // get an aliased part of the tempDouble temporary storage // Cannot use makeGetValue because it uses us // this is a unique case where we *can* use HEAPF64 var slab = type == 'double' ? 'HEAPF64' : makeGetSlabs(null, type)[0]; @@ -1053,11 +1057,17 @@ function makeGetTempDouble(i, type) { // get an aliased part of the tempDouble t } else { offset = getHeapOffset(ptr, type); } - return slab + '[' + offset + ']'; + var ret = slab + '[' + offset + ']'; + if (!forSet) ret = asmCoercion(ret, type); + return ret; +} + +function makeSetTempDouble(i, type, value) { + return makeGetTempDouble(i, type, true) + '=' + asmEnsureFloat(value, type); } // See makeSetValue -function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSafe) { +function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSafe, forceAsm) { if (UNALIGNED_MEMORY) align = 1; if (isStructType(type)) { var typeData = Types.types[type]; @@ -1069,8 +1079,8 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSa } if (DOUBLE_MODE == 1 && USE_TYPED_ARRAYS == 2 && type == 'double') { - return '(' + makeGetTempDouble(0, 'i32') + '=' + makeGetValue(ptr, pos, 'i32', noNeedFirst, unsigned, ignore, align) + ',' + - makeGetTempDouble(1, 'i32') + '=' + makeGetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'i32', noNeedFirst, unsigned, ignore, align) + ',' + + return '(' + makeSetTempDouble(0, 'i32', makeGetValue(ptr, pos, 'i32', noNeedFirst, unsigned, ignore, align)) + ',' + + makeSetTempDouble(1, 'i32', makeGetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'i32', noNeedFirst, unsigned, ignore, align)) + ',' + makeGetTempDouble(0, 'double') + ')'; } @@ -1110,7 +1120,7 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSa if (type[0] === '#') type = type.substr(1); return 'SAFE_HEAP_LOAD(' + offset + ', ' + type + ', ' + (!!unsigned+0) + ', ' + ((!checkSafeHeap() || ignore)|0) + ')'; } else { - var ret = makeGetSlabs(ptr, type, false, unsigned)[0] + '[' + getHeapOffset(offset, type) + ']'; + var ret = makeGetSlabs(ptr, type, false, unsigned)[0] + '[' + getHeapOffset(offset, type, forceAsm) + ']'; if (ASM_JS && phase == 'funcs') { ret = asmCoercion(ret, type); } @@ -1118,6 +1128,10 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSa } } +function makeGetValueAsm(ptr, pos, type) { + return makeGetValue(ptr, pos, type, null, null, null, null, null, true); +} + function indexizeFunctions(value, type) { assert((type && type !== '?') || (typeof value === 'string' && value.substr(0, 6) === 'CHECK_'), 'No type given for function indexizing'); assert(value !== type, 'Type set to value'); @@ -1165,7 +1179,7 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe, } if (DOUBLE_MODE == 1 && USE_TYPED_ARRAYS == 2 && type == 'double') { - return '(' + makeGetTempDouble(0, 'double') + '=' + value + ',' + + return '(' + makeSetTempDouble(0, 'double', value) + ',' + makeSetValue(ptr, pos, makeGetTempDouble(0, 'i32'), 'i32', noNeedFirst, ignore, align, noSafe, ',') + ',' + makeSetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), makeGetTempDouble(1, 'i32'), 'i32', noNeedFirst, ignore, align, noSafe, ',') + ')'; } else if (USE_TYPED_ARRAYS == 2 && type == 'i64') { @@ -1191,7 +1205,7 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe, ret += 'tempBigInt=' + value + sep; for (var i = 0; i < bytes; i++) { ret += makeSetValue(ptr, getFastValue(pos, '+', i), 'tempBigInt&0xff', 'i8', noNeedFirst, ignore, 1); - if (i < bytes-1) ret += sep + 'tempBigInt>>=8' + sep; + if (i < bytes-1) ret += sep + 'tempBigInt = tempBigInt>>8' + sep; } } } else { @@ -1236,7 +1250,7 @@ function makeSetValues(ptr, pos, value, type, num, align) { // If we don't know how to handle this at compile-time, or handling it is best done in a large amount of code, call memset // TODO: optimize the case of numeric num but non-numeric value if (!isNumber(num) || !isNumber(value) || (align < 4 && parseInt(num) >= SEEK_OPTIMAL_ALIGN_MIN)) { - return '_memset(' + getFastValue(ptr, '+', pos) + ', ' + value + ', ' + num + ', ' + align + ')'; + return '_memset(' + asmCoercion(getFastValue(ptr, '+', pos), 'i32') + ', ' + asmCoercion(value, 'i32') + ', ' + asmCoercion(num, 'i32') + ', ' + align + ')'; } num = parseInt(num); value = parseInt(value); @@ -1426,8 +1440,18 @@ var IHEAP_FHEAP = set('IHEAP', 'IHEAPU', 'FHEAP'); function makePointer(slab, pos, allocator, type, ptr) { assert(type, 'makePointer requires type info'); - if (slab.substr(0, 4) === 'HEAP' || (USE_TYPED_ARRAYS == 1 && slab in IHEAP_FHEAP)) return pos; + if (typeof slab == 'string' && (slab.substr(0, 4) === 'HEAP' || (USE_TYPED_ARRAYS == 1 && slab in IHEAP_FHEAP))) return pos; var types = generateStructTypes(type); + if (typeof slab == 'object') { + for (var i = 0; i < slab.length; i++) { + var curr = slab[i]; + if (isNumber(curr)) { + slab[i] = parseFloat(curr); // fix "5" to 5 etc. + } else if (curr == 'undef') { + slab[i] = 0; + } + } + } // compress type info and data if possible var de; try { @@ -1435,25 +1459,68 @@ function makePointer(slab, pos, allocator, type, ptr) { // note that we cannot always eval the slab, e.g., if it contains ident,0,0 etc. In that case, no compression TODO: ensure we get arrays here, not str var evaled = typeof slab === 'string' ? eval(slab) : slab; de = dedup(evaled); - if (de.length === 1 && de[0] === 0) { + if (de.length === 1 && de[0] == 0) { slab = types.length; - if (USE_TYPED_ARRAYS == 2) { - types = ['i8']; // if data is zeros, we don't need type info - } } // TODO: if not all zeros, at least filter out items with type === 0. requires cleverness to know how to skip at runtime though. also // be careful of structure padding } catch(e){} - de = dedup(types); - if (de.length === 1) { - types = de[0]; - } else if (de.length === 2 && typeof slab === 'number') { - // If slab is all zeros, we can compress types even if we have i32,0,0,0,i32,0,0,0 etc. - we do not need the zeros - de = de.filter(function(x) { return x !== 0 }); + if (USE_TYPED_ARRAYS != 2) { + de = dedup(types); if (de.length === 1) { types = de[0]; + } else if (de.length === 2 && typeof slab === 'number') { + // If slab is all zeros, we can compress types even if we have i32,0,0,0,i32,0,0,0 etc. - we do not need the zeros + de = de.filter(function(x) { |