aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/analyzer.js2
-rw-r--r--src/compiler.js1
-rw-r--r--src/determinstic.js16
-rw-r--r--src/experimental/functypeopt.diff113
-rw-r--r--src/intertyper.js8
-rw-r--r--src/jsifier.js112
-rw-r--r--src/library.js88
-rw-r--r--src/library_browser.js12
-rw-r--r--src/library_gl.js384
-rw-r--r--src/library_sdl.js21
-rw-r--r--src/modules.js49
-rw-r--r--src/parseTools.js187
-rw-r--r--src/preamble.js32
-rw-r--r--src/runtime.js7
-rw-r--r--src/settings.js8
-rw-r--r--src/shell.js2
-rw-r--r--src/utility.js6
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) {
Module.ctx.bufferData(target, HEAPU8.subarray(data, data+size), usage);
},
+ glBufferSubData__sig: 'viiii',
glBufferSubData: function(target, offset, size, data) {
Module.ctx.bufferSubData(target, offset, HEAPU8.subarray(data, data+size));
},
@@ -465,6 +471,7 @@ var LibraryGL = {
return Module.ctx.isBuffer(fb);
},
+ glGenRenderbuffers__sig: 'vii',
glGenRenderbuffers: function(n, renderbuffers) {
for (var i = 0; i < n; i++) {
var id = GL.getNewId(GL.renderbuffers);
@@ -473,6 +480,7 @@ var LibraryGL = {
}
},
+ glDeleteRenderbuffers__sig: 'vii',
glDeleteRenderbuffers: function(n, renderbuffers) {
for (var i = 0; i < n; i++) {
var id = {{{ makeGetValue('renderbuffers', 'i*4', 'i32') }}};
@@ -481,6 +489,7 @@ var LibraryGL = {
}
},
+ glBindRenderbuffer__sig: 'vii',
glBindRenderbuffer: function(target, renderbuffer) {
Module.ctx.bindRenderbuffer(target, renderbuffer ? GL.renderbuffers[renderbuffer] : null);
},