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 /src | |
parent | 4e09482e006eda934527e1707036d74245d8dd91 (diff) | |
parent | 03e2e6c321d28e3df3b37a2c0bed3ba9d04e52b3 (diff) |
Merge branch 'incoming'
Diffstat (limited to 'src')
-rw-r--r-- | src/analyzer.js | 2 | ||||
-rw-r--r-- | src/compiler.js | 1 | ||||
-rw-r--r-- | src/determinstic.js | 16 | ||||
-rw-r--r-- | src/experimental/functypeopt.diff | 113 | ||||
-rw-r--r-- | src/intertyper.js | 8 | ||||
-rw-r--r-- | src/jsifier.js | 112 | ||||
-rw-r--r-- | src/library.js | 88 | ||||
-rw-r--r-- | src/library_browser.js | 12 | ||||
-rw-r--r-- | src/library_gl.js | 384 | ||||
-rw-r--r-- | src/library_sdl.js | 21 | ||||
-rw-r--r-- | src/modules.js | 49 | ||||
-rw-r--r-- | src/parseTools.js | 187 | ||||
-rw-r--r-- | src/preamble.js | 32 | ||||
-rw-r--r-- | src/runtime.js | 7 | ||||
-rw-r--r-- | src/settings.js | 8 | ||||
-rw-r--r-- | src/shell.js | 2 | ||||
-rw-r--r-- | src/utility.js | 6 |
17 files changed, 769 insertions, 279 deletions
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 + ' '); - }).join('\n'); - ret += '\n' + indent + ' default: assert(0, "bad label: " + label);\n' + indent + '}'; + }).join('\n') + '\n'; + if (ASSERTIONS) ret += indent + ' default: assert(0, "bad label: " + label);\n'; + ret += indent + '}\n'; if (func.setjmpTable) { ret += ' } catch(e) { if (!e.longjmp || !(e.id in mySetjmpIds)) throw(e); setjmpTable[setjmpLabels[e.id]](e.value) }'; } @@ -785,10 +799,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'; @@ -1092,7 +1106,7 @@ function JSify(data, functionsOnly, givenFunctions) { var value; if (useIfs) { value = targetLabels[targetLabel].map(function(value) { - return makeComparison(signedIdent, makeSignOp(value, item.type, 're'), item.type) + return makeComparison(signedIdent, '==', makeSignOp(value, item.type, 're'), item.type) }).join(' | '); ret += 'if (' + value + ') {\n'; } else { @@ -1142,8 +1156,10 @@ function JSify(data, functionsOnly, givenFunctions) { + "INDENT = INDENT.substr(0, INDENT.length-2);\n"; } ret += 'return'; - if (item.value) { - ret += ' ' + asmCoercion(finalizeLLVMParameter(item.value), item.type); + var value = item.value ? finalizeLLVMParameter(item.value) : null; + if (!value && item.funcData.returnType != 'void') value = '0'; // no-value returns must become value returns if function returns + if (value) { + ret += ' ' + asmCoercion(value, item.type); } return ret + ';'; }); @@ -1152,20 +1168,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*') + ' } ' + - makeThrow('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)) { @@ -1242,7 +1267,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 (' + makeComparison('ibr', '==', targetLabel, 'i32') + ') { ' + getPhiSetsForLabel(phiSets, targetLabel) + ' }\n'; + } + return js + makeBranch('ibr', item.currLabelId, true); }); makeFuncLineActor('alloca', function(item) { if (typeof item.allocatedIndex === 'number') { @@ -1365,10 +1395,12 @@ function JSify(data, functionsOnly, givenFunctions) { } var returnType; - if (byPointer || ASM_JS) returnType = type.split(' ')[0]; + if (byPointer || ASM_JS) { + returnType = getReturnType(type); + } if (byPointer) { - var sig = Functions.getSignature(returnType, argsTypes); + var sig = Functions.getSignature(returnType, argsTypes, hasVarArgs); if (ASM_JS) { assert(returnType.search(/\("'\[,/) == -1); // XXX need isFunctionType(type, out) callIdent = '(' + callIdent + ')&{{{ FTM_' + sig + ' }}}'; // the function table mask is set in emscripten.py @@ -1477,6 +1509,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 b70aadbc..74ebdc07 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 @@ -810,6 +810,8 @@ LibraryManager.library = { return 0; }, + utimes: function() { throw 'utimes not implemented' }, + // ========================================================================== // libgen.h // ========================================================================== @@ -1038,6 +1040,8 @@ LibraryManager.library = { return _chmod(allocate(pathArray, 'i8', ALLOC_STACK), mode); } }, + lchmod: function() { throw 'TODO: lchmod' }, + umask__deps: ['$FS'], umask: function(newMask) { // mode_t umask(mode_t cmask); @@ -2515,7 +2519,7 @@ LibraryManager.library = { var curr = 0; var buffer = []; // Read characters according to the format. floats are trickier, they may be in an unfloat state in the middle, then be a valid float later - if (type == 'f') { + if (type == 'f' || type == 'e' || type == 'g' || type == 'E') { var last = 0; next = get(); while (next > 0) { @@ -2569,6 +2573,10 @@ LibraryManager.library = { {{{ makeSetValue('argPtr', 0, 'parseInt(text, 16)', 'i32') }}} break; case 'f': + case 'e': + case 'g': + case 'E': + // fallthrough intended if (long_) { {{{ makeSetValue('argPtr', 0, 'parseFloat(text)', 'double') }}} } else { @@ -2607,6 +2615,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; @@ -2933,7 +2942,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--) { @@ -3496,6 +3505,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') }}}; } @@ -3525,10 +3540,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', @@ -3613,7 +3633,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(){}, @@ -4209,6 +4229,8 @@ LibraryManager.library = { } }, + wmemcpy: function() { throw 'wmemcpy not implemented' }, + llvm_memcpy_i32: 'memcpy', llvm_memcpy_i64: 'memcpy', llvm_memcpy_p0i8_p0i8_i32: 'memcpy', @@ -4234,6 +4256,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); }, @@ -4268,8 +4292,18 @@ LibraryManager.library = { llvm_memset_p0i8_i32: 'memset', llvm_memset_p0i8_i64: 'memset', + wmemset: function() { throw 'wmemset not implemented' }, + + strlen__sig: 'ii', + strlen__asm: true, 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. @@ -4277,6 +4311,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) { @@ -4493,17 +4534,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); @@ -5069,6 +5111,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. @@ -5910,6 +5954,9 @@ LibraryManager.library = { return 0; }, + setitimer: function() { throw 'setitimer not implemented yet' }, + getitimer: function() { throw 'getitimer not implemented yet' }, + // ========================================================================== // sys/time.h // ========================================================================== @@ -6078,6 +6125,8 @@ LibraryManager.library = { }, killpg: 'kill', + siginterrupt: function() { throw 'siginterrupt not implemented' }, + // ========================================================================== // sys/wait.h // ========================================================================== @@ -6125,6 +6174,8 @@ LibraryManager.library = { return me.ret; }, + __locale_mb_cur_max: function() { throw '__locale_mb_cur_max not implemented' }, + // ========================================================================== // langinfo.h // ========================================================================== @@ -6305,6 +6356,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 // ========================================================================== @@ -6548,6 +6603,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; @@ -7108,6 +7164,22 @@ LibraryManager.library = { return ret; }, + // pty.h + + openpty: function() { throw 'openpty: TODO' }, + forkpty: function() { throw 'forkpty: TODO' }, + + // grp.h + + initgroups: function() { throw 'initgroups: TODO' }, + + // pwd.h + + getpwnam: function() { throw 'getpwnam: TODO' }, + setpwent: function() { throw 'setpwent: TODO' }, + getpwent: function() { throw 'getpwent: TODO' }, + endpwent: function() { throw 'endpwent: TODO' }, + // ========================================================================== // emscripten.h // ========================================================================== diff --git a/src/library_browser.js b/src/library_browser.js index 13275702..0bc6d130 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -389,10 +389,10 @@ mergeInto(LibraryManager.library, { Browser.asyncLoad(Pointer_stringify(url), function(byteArray) { var buffer = _malloc(byteArray.length); HEAPU8.set(byteArray, buffer); - FUNCTION_TABLE[onload](arg, buffer, byteArray.length); + Runtime.dynCall('viii', onload, [arg, buffer, byteArray.length]); _free(buffer); }, function() { - if (onerror) FUNCTION_TABLE[onerror](arg); + if (onerror) Runtime.dynCall('vi', onerror, [arg]); }, true /* no need for run dependency, this is async but will not do any prepare etc. step */ ); }, @@ -411,21 +411,21 @@ mergeInto(LibraryManager.library, { http.onload = function(e) { if (http.status == 200) { FS.createDataFile( _file.substr(0, index), _file.substr(index + 1), new Uint8Array(http.response), true, true); - if (onload) FUNCTION_TABLE[onload](arg, file); + if (onload) Runtime.dynCall('vii', onload, [arg, file]); } else { - if (onerror) FUNCTION_TABLE[onerror](arg, http.status); + if (onerror) Runtime.dynCall('vii', onerror, [arg, http.status]); } }; // ERROR http.onerror = function(e) { - if (onerror) FUNCTION_TABLE[onerror](arg, http.status); + if (onerror) Runtime.dynCall('vii', onerror, [arg, http.status]); }; // PROGRESS http.onprogress = function(e) { var percentComplete = (e.position / e.totalSize)*100; - if (onprogress) FUNCTION_TABLE[onprogress](arg, percentComplete); + if (onprogress) Runtime.dynCall('vii', onprogress, [arg, percentComplete]); }; // Useful because the browser can limit the number of redirection diff --git a/src/library_gl.js b/src/library_gl.js index 2a6ec92f..c153a181 100644 --- a/src/library_gl.js +++ b/src/library_gl.js @@ -364,6 +364,7 @@ var LibraryGL = { } }, + glCompressedTexImage2D__sig: 'viiiiiiii', glCompressedTexImage2D: function(target, level, internalFormat, width, height, border, imageSize, data) { assert(GL.compressionExt); if (data) { @@ -374,6 +375,7 @@ var LibraryGL = { Module.ctx['compressedTexImage2D'](target, level, internalFormat, width, height, border, data); }, + glCompressedTexSubImage2D__sig: 'viiiiiiiii', glCompressedTexSubImage2D: function(target, level, xoffset, yoffset, width, height, format, imageSize, data) { assert(GL.compressionExt); if (data) { @@ -429,6 +431,7 @@ var LibraryGL = { return Module.ctx.isTexture(fb); }, + glGenBuffers__sig: 'vii', glGenBuffers: function(n, buffers) { for (var i = 0; i < n; i++) { var id = GL.getNewId(GL.buffers); @@ -437,6 +440,7 @@ var LibraryGL = { } }, + glDeleteBuffers__sig: 'vii', glDeleteBuffers: function(n, buffers) { for (var i = 0; i < n; i++) { var id = {{{ makeGetValue('buffers', 'i*4', 'i32') }}}; @@ -449,10 +453,12 @@ var LibraryGL = { {{{ makeSetValue('data', '0', 'Module.ctx.getBufferParameter(target, value)', 'i32') }}}; }, + glBufferData__sig: 'viiii', glBufferData: function(target, size, data, usage) { |