aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/analyzer.js15
-rw-r--r--src/compiler.js1
-rw-r--r--src/intertyper.js10
-rw-r--r--src/jsifier.js103
-rw-r--r--src/library.js65
-rw-r--r--src/library_gl.js4
-rw-r--r--src/modules.js24
-rw-r--r--src/parseTools.js185
-rw-r--r--src/preamble.js24
-rw-r--r--src/runtime.js23
-rw-r--r--src/settings.js8
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) {