summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/analyzer.js167
-rw-r--r--src/compiler.js22
-rw-r--r--src/intertyper.js9
-rw-r--r--src/jsifier.js163
-rw-r--r--src/library.js181
-rw-r--r--src/library_browser.js23
-rw-r--r--src/library_gc.js4
-rw-r--r--src/library_gl.js115
-rw-r--r--src/library_glut.js28
-rw-r--r--src/library_sdl.js10
-rw-r--r--src/long.js29
-rw-r--r--src/modules.js77
-rw-r--r--src/parseTools.js264
-rw-r--r--src/postamble.js4
-rw-r--r--src/preamble.js54
-rw-r--r--src/runtime.js86
-rw-r--r--src/settings.js7
-rw-r--r--src/utility.js6
18 files changed, 828 insertions, 421 deletions
diff --git a/src/analyzer.js b/src/analyzer.js
index 014579f4..0ad3e017 100644
--- a/src/analyzer.js
+++ b/src/analyzer.js
@@ -19,7 +19,7 @@ function recomputeLines(func) {
var BRANCH_INVOKE = set('branch', 'invoke');
var SIDE_EFFECT_CAUSERS = set('call', 'invoke', 'atomic');
-var UNUNFOLDABLE = set('value', 'type', 'phiparam');
+var UNUNFOLDABLE = set('value', 'structvalue', 'type', 'phiparam');
// Analyzer
@@ -120,12 +120,14 @@ function analyzer(data, sidePass) {
processItem: function(data) {
// Legalization
if (USE_TYPED_ARRAYS == 2) {
- function getLegalVars(base, bits) {
- assert(!isNumber(base));
+ function getLegalVars(base, bits, allowLegal) {
+ if (allowLegal && bits <= 32) return [{ ident: base, bits: bits }];
+ if (isNumber(base)) return getLegalLiterals(base, bits);
var ret = new Array(Math.ceil(bits/32));
var i = 0;
+ if (base == 'zeroinitializer' || base == 'undef') base = 0;
while (bits > 0) {
- ret[i] = { ident: base + '$' + i, bits: Math.min(32, bits) };
+ ret[i] = { ident: base ? base + '$' + i : '0', bits: Math.min(32, bits) };
bits -= 32;
i++;
}
@@ -142,6 +144,23 @@ function analyzer(data, sidePass) {
}
return ret;
}
+ function getLegalStructuralParts(value) {
+ return value.params.slice(0);
+ }
+ function getLegalParams(params, bits) {
+ return params.map(function(param) {
+ var value = param.value || param;
+ if (isNumber(value.ident)) {
+ return getLegalLiterals(value.ident, bits);
+ } else if (value.intertype == 'structvalue') {
+ return getLegalStructuralParts(value).map(function(part) {
+ return { ident: part.ident, bits: part.type.substr(1) };
+ });
+ } else {
+ return getLegalVars(value.ident, bits);
+ }
+ });
+ }
// Uses the right factor to multiply line numbers by so that they fit in between
// the line[i] and the line after it
function interpLines(lines, i, toAdd) {
@@ -191,6 +210,7 @@ function analyzer(data, sidePass) {
// Legalize lines in labels
var tempId = 0;
func.labels.forEach(function(label) {
+ if (dcheck('legalizer')) dprint('zz legalizing: \n' + dump(label.lines));
var i = 0, bits;
while (i < label.lines.length) {
var item = label.lines[i];
@@ -207,8 +227,12 @@ function analyzer(data, sidePass) {
if (isIllegalType(item.valueType) || isIllegalType(item.type)) {
isIllegal = true;
}
+ if ((item.intertype == 'load' || item.intertype == 'store') && isStructType(item.valueType)) {
+ isIllegal = true; // storing an entire structure is illegal
+ }
});
if (!isIllegal) {
+ //if (dcheck('legalizer')) dprint('no need to legalize \n' + dump(item));
i++;
continue;
}
@@ -222,10 +246,10 @@ function analyzer(data, sidePass) {
if (subItem != item && (!(subItem.intertype in UNUNFOLDABLE) ||
(subItem.intertype == 'value' && isNumber(subItem.ident) && isIllegalType(subItem.type)))) {
if (item.intertype == 'phi') {
- assert(subItem.intertype == 'value', 'We can only unfold illegal constants in phis');
+ assert(subItem.intertype == 'value' || subItem.intertype == 'structvalue', 'We can only unfold illegal constants in phis');
// we must handle this in the phi itself, if we unfold normally it will not be pushed back with the phi
} else {
- var tempIdent = '$$emscripten$temp$' + (tempId++);
+ var tempIdent = '$$etemp$' + (tempId++);
subItem.assignTo = tempIdent;
unfolded.unshift(subItem);
fixUnfolded(subItem);
@@ -234,7 +258,7 @@ function analyzer(data, sidePass) {
} else if (subItem.intertype == 'switch' && isIllegalType(subItem.type)) {
subItem.switchLabels.forEach(function(switchLabel) {
if (switchLabel.value[0] != '$') {
- var tempIdent = '$$emscripten$temp$' + (tempId++);
+ var tempIdent = '$$etemp$' + (tempId++);
unfolded.unshift({
assignTo: tempIdent,
intertype: 'value',
@@ -258,8 +282,7 @@ function analyzer(data, sidePass) {
case 'store': {
var toAdd = [];
bits = getBits(item.valueType);
- var elements;
- elements = getLegalVars(item.value.ident, bits);
+ var elements = getLegalParams([item.value], bits)[0];
var j = 0;
elements.forEach(function(element) {
var tempVar = '$st$' + i + '$' + j;
@@ -290,32 +313,43 @@ function analyzer(data, sidePass) {
i += removeAndAdd(label.lines, i, toAdd);
continue;
}
- // call, return: Return value is in an unlegalized array literal. Not fully optimal.
+ // call, return: Return the first 32 bits, the rest are in temp
case 'call': {
bits = getBits(value.type);
var elements = getLegalVars(item.assignTo, bits);
var toAdd = [value];
// legalize parameters
legalizeFunctionParameters(value.params);
- if (value.assignTo) {
+ if (value.assignTo && isIllegalType(item.type)) {
// legalize return value
- var j = 0;
- toAdd = toAdd.concat(elements.map(function(element) {
- return {
+ value.assignTo = elements[0].ident;
+ for (var j = 1; j < elements.length; j++) {
+ var element = elements[j];
+ toAdd.push({
intertype: 'value',
assignTo: element.ident,
- type: 'i' + bits,
- ident: value.assignTo + '[' + (j++) + ']'
- };
- }));
+ type: element.bits,
+ ident: 'tempRet' + (j - 1)
+ });
+ assert(j<10); // TODO: dynamically create more than 10 tempRet-s
+ }
}
i += removeAndAdd(label.lines, i, toAdd);
continue;
}
+ case 'landingpad': {
+ // not much to legalize
+ i++;
+ continue;
+ }
case 'return': {
bits = getBits(item.type);
var elements = getLegalVars(item.value.ident, bits);
- item.value.ident = '[' + elements.map(function(element) { return element.ident }).join(',') + ']';
+ item.value.ident = '(';
+ for (var j = 1; j < elements.length; j++) {
+ item.value.ident += 'tempRet' + (j-1) + '=' + elements[j].ident + ',';
+ }
+ item.value.ident += elements[0].ident + ')';
i++;
continue;
}
@@ -341,6 +375,21 @@ function analyzer(data, sidePass) {
i += removeAndAdd(label.lines, i, toAdd);
continue;
}
+ case 'structvalue': {
+ bits = getBits(value.type);
+ var elements = getLegalVars(item.assignTo, bits);
+ var toAdd = [];
+ for (var j = 0; j < item.params.length; j++) {
+ toAdd[j] = {
+ intertype: 'value',
+ assignTo: elements[j].ident,
+ type: 'i32',
+ ident: item.params[j].ident
+ };
+ }
+ i += removeAndAdd(label.lines, i, toAdd);
+ continue;
+ }
case 'load': {
bits = getBits(value.valueType);
var elements = getLegalVars(item.assignTo, bits);
@@ -382,13 +431,9 @@ function analyzer(data, sidePass) {
var toAdd = [];
var elements = getLegalVars(item.assignTo, bits);
var j = 0;
- var literalValues = {}; // special handling of literals - we cannot unfold them normally
- value.params.map(function(param) {
- if (isNumber(param.value.ident)) {
- literalValues[param.value.ident] = getLegalLiterals(param.value.ident, bits);
- }
- });
+ var values = getLegalParams(value.params, bits);
elements.forEach(function(element) {
+ var k = 0;
toAdd.push({
intertype: 'phi',
assignTo: element.ident,
@@ -399,7 +444,7 @@ function analyzer(data, sidePass) {
label: param.label,
value: {
intertype: 'value',
- ident: (param.value.ident in literalValues) ? literalValues[param.value.ident][j].ident : (param.value.ident + '$' + j),
+ ident: values[k++][j].ident,
type: 'i' + element.bits,
}
};
@@ -414,6 +459,62 @@ function analyzer(data, sidePass) {
i++;
continue; // special case, handled in makeComparison
}
+ case 'extractvalue': { // XXX we assume 32-bit alignment in extractvalue/insertvalue,
+ // but in theory they can run on packed structs too (see use getStructuralTypePartBits)
+ // potentially legalize the actual extracted value too if it is >32 bits, not just the extraction in general
+ var index = item.indexes[0][0].text;
+ var parts = getStructureTypeParts(item.type);
+ var indexedType = parts[index];
+ var targetBits = getBits(indexedType);
+ var sourceBits = getBits(item.type);
+ var elements = getLegalVars(item.assignTo, targetBits, true); // possibly illegal
+ var sourceElements = getLegalVars(item.ident, sourceBits); // definitely illegal
+ var toAdd = [];
+ var sourceIndex = 0;
+ for (var partIndex = 0; partIndex < parts.length; partIndex++) {
+ if (partIndex == index) {
+ for (var j = 0; j < elements.length; j++) {
+ toAdd.push({
+ intertype: 'value',
+ assignTo: elements[j].ident,
+ type: 'i' + elements[j].bits,
+ ident: sourceElements[sourceIndex+j].ident
+ });
+ }
+ break;
+ }
+ sourceIndex += getStructuralTypePartBits(parts[partIndex])/32;
+ }
+ i += removeAndAdd(label.lines, i, toAdd);
+ continue;
+ }
+ case 'insertvalue': {
+ var index = item.indexes[0][0].text; // the modified index
+ var parts = getStructureTypeParts(item.type);
+ var indexedType = parts[index];
+ var indexBits = getBits(indexedType);
+ var bits = getBits(item.type); // source and target
+ bits = getBits(value.type);
+ var toAdd = [];
+ var elements = getLegalVars(item.assignTo, bits);
+ var sourceElements = getLegalVars(item.ident, bits);
+ var indexElements = getLegalVars(item.value.ident, indexBits, true); // possibly legal
+ var sourceIndex = 0;
+ for (var partIndex = 0; partIndex < parts.length; partIndex++) {
+ var currNum = getStructuralTypePartBits(parts[partIndex])/32;
+ for (var j = 0; j < currNum; j++) {
+ toAdd.push({
+ intertype: 'value',
+ assignTo: elements[sourceIndex+j].ident,
+ type: 'i' + elements[sourceIndex+j].bits,
+ ident: partIndex == index ? indexElements[j].ident : sourceElements[sourceIndex+j].ident
+ });
+ }
+ sourceIndex += currNum;
+ }
+ i += removeAndAdd(label.lines, i, toAdd);
+ continue;
+ }
case 'bitcast': {
var inType = item.type2;
var outType = item.type;
@@ -477,17 +578,16 @@ function analyzer(data, sidePass) {
}
case 'select': {
sourceBits = targetBits = getBits(value.params[1].type);
- var otherElementsA = getLegalVars(value.params[1].ident, sourceBits);
- var otherElementsB = getLegalVars(value.params[2].ident, sourceBits);
+ var params = getLegalParams(value.params.slice(1), sourceBits);
processor = function(result, j) {
return {
intertype: 'mathop',
op: 'select',
- type: 'i' + otherElementsA[j].bits,
+ type: 'i' + params[0][j].bits,
params: [
value.params[0],
- { intertype: 'value', ident: otherElementsA[j].ident, type: 'i' + otherElementsA[j].bits },
- { intertype: 'value', ident: otherElementsB[j].ident, type: 'i' + otherElementsB[j].bits }
+ { intertype: 'value', ident: params[0][j].ident, type: 'i' + params[0][j].bits },
+ { intertype: 'value', ident: params[1][j].ident, type: 'i' + params[1][j].bits }
]
};
};
@@ -554,9 +654,10 @@ 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.bitshift64(' + sourceElements[0].ident + ', ' +
+ value.ident = 'Runtime' + (ASM_JS ? '_' : '.') + 'bitshift64(' + sourceElements[0].ident + ', ' +
sourceElements[1].ident + ',"' + value.op + '",' + value.params[1].ident + '$0);' +
- 'var ' + value.assignTo + '$0 = ' + value.assignTo + '[0], ' + value.assignTo + '$1 = ' + value.assignTo + '[1];';
+ 'var ' + value.assignTo + '$0 = ' + makeGetTempDouble(0) + ', ' + value.assignTo + '$1 = ' + makeGetTempDouble(1) + ';';
+ value.assignTo = null;
i++;
continue;
}
diff --git a/src/compiler.js b/src/compiler.js
index 3ce53b1e..7ca20c40 100644
--- a/src/compiler.js
+++ b/src/compiler.js
@@ -172,18 +172,24 @@ RUNTIME_DEBUG = LIBRARY_DEBUG || GL_DEBUG;
// Settings sanity checks
assert(!(USE_TYPED_ARRAYS === 2 && QUANTUM_SIZE !== 4), 'For USE_TYPED_ARRAYS == 2, must have normal QUANTUM_SIZE of 4');
+if (ASM_JS) {
+ assert(!ALLOW_MEMORY_GROWTH, 'Cannot grow asm.js heap');
+ assert((TOTAL_MEMORY&(TOTAL_MEMORY-1)) == 0, 'asm.js heap must be power of 2');
+}
// Output some info and warnings based on settings
-if (!MICRO_OPTS || !RELOOP || ASSERTIONS || CHECK_SIGNS || CHECK_OVERFLOWS || INIT_STACK || INIT_HEAP ||
- !SKIP_STACK_IN_SMALL || SAFE_HEAP || PGO || PROFILE || !DISABLE_EXCEPTION_CATCHING) {
- print('// Note: Some Emscripten settings will significantly limit the speed of the generated code.');
-} else {
- print('// Note: For maximum-speed code, see "Optimizing Code" on the Emscripten wiki, https://github.com/kripken/emscripten/wiki/Optimizing-Code');
-}
+if (phase == 'pre') {
+ if (!MICRO_OPTS || !RELOOP || ASSERTIONS || CHECK_SIGNS || CHECK_OVERFLOWS || INIT_STACK || INIT_HEAP ||
+ !SKIP_STACK_IN_SMALL || SAFE_HEAP || PGO || PROFILE || !DISABLE_EXCEPTION_CATCHING) {
+ print('// Note: Some Emscripten settings will significantly limit the speed of the generated code.');
+ } else {
+ print('// Note: For maximum-speed code, see "Optimizing Code" on the Emscripten wiki, https://github.com/kripken/emscripten/wiki/Optimizing-Code');
+ }
-if (DOUBLE_MODE || CORRECT_SIGNS || CORRECT_OVERFLOWS || CORRECT_ROUNDINGS) {
- print('// Note: Some Emscripten settings may limit the speed of the generated code.');
+ if (DOUBLE_MODE || CORRECT_SIGNS || CORRECT_OVERFLOWS || CORRECT_ROUNDINGS) {
+ print('// Note: Some Emscripten settings may limit the speed of the generated code.');
+ }
}
// Load compiler code
diff --git a/src/intertyper.js b/src/intertyper.js
index 1d18c3cf..2de6c6b9 100644
--- a/src/intertyper.js
+++ b/src/intertyper.js
@@ -125,6 +125,7 @@ function intertyper(data, sidePass, baseLineNums) {
// We need this early, to know basic function info - ident, params, varargs
ident: toNiceIdent(func.ident),
params: func.params,
+ returnType: func.returnType,
hasVarArgs: func.hasVarArgs,
lineNum: currFunctionLineNum,
lines: currFunctionLines
@@ -520,7 +521,12 @@ function intertyper(data, sidePass, baseLineNums) {
if (item.tokens[3].item) {
var subTokens = item.tokens[3].item.tokens;
splitTokenList(subTokens).forEach(function(segment) {
- ret.ctors.push(segment[1].tokens.slice(-1)[0].text);
+ var ctor = toNiceIdent(segment[1].tokens.slice(-1)[0].text);
+ ret.ctors.push(ctor);
+ if (ASM_JS) { // must export the global constructors from asm.js module, so mark as implemented and exported
+ Functions.implementedFunctions[ctor] = 'v';
+ EXPORTED_FUNCTIONS[ctor] = 1;
+ }
});
}
} else if (!external) {
@@ -741,6 +747,7 @@ function intertyper(data, sidePass, baseLineNums) {
}
var last = getTokenIndexByText(item.tokens, ';');
item.params = splitTokenList(item.tokens.slice(1, last)).map(parseLLVMSegment);
+ item.type = item.params[1].type;
this.forwardItem(item, 'Reintegrator');
}
});
diff --git a/src/jsifier.js b/src/jsifier.js
index 50703b90..9c3109ad 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -9,6 +9,8 @@ var STRUCT_LIST = set('struct', 'list');
var UNDERSCORE_OPENPARENS = set('_', '(');
var RELOOP_IGNORED_LASTS = set('return', 'unreachable', 'resume');
+var addedLibraryItems = {};
+
// JSifier
function JSify(data, functionsOnly, givenFunctions) {
var mainPass = !functionsOnly;
@@ -42,7 +44,9 @@ function JSify(data, functionsOnly, givenFunctions) {
var pre = processMacros(preprocess(read(preFile).replace('{{RUNTIME}}', getRuntime())));
print(pre);
- Functions.implementedFunctions = set(data.unparsedFunctions.map(function(func) { return func.ident }));
+ data.unparsedFunctions.forEach(function(func) {
+ Functions.implementedFunctions[func.ident] = Functions.getSignature(func.returnType, func.params.map(function(param) { return param.type }));
+ });
}
}
@@ -258,7 +262,7 @@ function JSify(data, functionsOnly, givenFunctions) {
var ret = [item];
if (item.ident == '_llvm_global_ctors') {
item.JS = '\n__ATINIT__ = __ATINIT__.concat([\n' +
- item.ctors.map(function(ctor) { return ' { func: ' + toNiceIdent(ctor) + ' }' }).join(',\n') +
+ item.ctors.map(function(ctor) { return ' { func: function() { ' + ctor + '() } }' }).join(',\n') +
'\n]);\n';
return ret;
} else {
@@ -273,12 +277,13 @@ function JSify(data, functionsOnly, givenFunctions) {
item.JS = makeGlobalDef(item.ident);
}
- if (item.external) {
+ if (item.external && !ASM_JS) { // ASM_JS considers externs to be globals
// Import external global variables from the library if available.
var shortident = item.ident.slice(1);
if (LibraryManager.library[shortident] &&
LibraryManager.library[shortident].length &&
!BUILD_AS_SHARED_LIB) {
+ if (addedLibraryItems[shortident]) return ret;
var val = LibraryManager.library[shortident];
var padding;
if (Runtime.isNumberType(item.type) || isPointerType(item.type)) {
@@ -302,7 +307,17 @@ function JSify(data, functionsOnly, givenFunctions) {
index = makeGlobalUse(item.ident); // index !== null indicates we are indexing this
allocator = 'ALLOC_NONE';
}
- constant = parseConst(item.value, item.type, item.ident);
+ if (item.external) {
+ assert(ASM_JS);
+ if (Runtime.isNumberType(item.type) || isPointerType(item.type)) {
+ constant = zeros(Runtime.getNativeFieldSize(item.type));
+ } else {
+ constant = makeEmptyStruct(item.type);
+ }
+ constant = JSON.stringify(constant);
+ } else {
+ constant = parseConst(item.value, item.type, item.ident);
+ }
if (typeof constant === 'string' && constant[0] != '[') {
constant = [constant]; // A single item. We may need a postset for it.
}
@@ -333,7 +348,7 @@ function JSify(data, functionsOnly, givenFunctions) {
}
js += '\n' + makePointer('[0]', null, allocator, ['void*'], index) + ';';
}
- if (EXPORT_ALL || (item.ident in EXPORTED_GLOBALS)) {
+ if (!ASM_JS && (EXPORT_ALL || (item.ident in EXPORTED_GLOBALS))) {
js += '\nModule["' + item.ident + '"] = ' + item.ident + ';';
}
if (BUILD_AS_SHARED_LIB == 2 && !item.private_) {
@@ -377,8 +392,6 @@ function JSify(data, functionsOnly, givenFunctions) {
}
});
- var addedLibraryItems = {};
-
// functionStub
substrate.addActor('FunctionStub', {
processItem: function(item) {
@@ -406,6 +419,7 @@ function JSify(data, functionsOnly, givenFunctions) {
deps.push(snippet);
snippet = '_' + snippet;
}
+ if (ASM_JS) Functions.libraryFunctions[ident] = 1;
} else if (typeof snippet === 'object') {
snippet = stringifyWithFunctions(snippet);
} else if (typeof snippet === 'function') {
@@ -420,6 +434,7 @@ function JSify(data, functionsOnly, givenFunctions) {
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; }';
}
+ if (ASM_JS) Functions.libraryFunctions[ident] = 1;
}
var postsetId = ident + '__postset';
@@ -519,8 +534,8 @@ function JSify(data, functionsOnly, givenFunctions) {
func.JS = '\n';
var paramIdents = func.params.map(function(param) {
- return (param.intertype == 'varargs') ? null : toNiceIdent(param.ident);
- }).filter(function(param) { return param != null; })
+ return toNiceIdent(param.ident);
+ });
if (CLOSURE_ANNOTATIONS) {
func.JS += '/**\n';
@@ -538,6 +553,34 @@ function JSify(data, functionsOnly, givenFunctions) {
func.JS += 'function ' + func.ident + '(' + paramIdents.join(', ') + ') {\n';
+ if (ASM_JS) {
+ // spell out argument types
+ func.params.forEach(function(param) {
+ func.JS += ' ' + param.ident + ' = ' + asmCoercion(param.ident, param.type) + ';\n';
+ });
+
+ // spell out local variables
+ var vars = values(func.variables).filter(function(v) { return v.origin != 'funcparam' });
+ if (vars.length > 0) {
+ var chunkSize = 8;
+ var chunks = [];
+ var i = 0;
+ while (i < vars.length) {
+ chunks.push(vars.slice(i, i+chunkSize));
+ i += chunkSize;
+ }
+ for (i = 0; i < chunks.length; i++) {
+ func.JS += ' var ' + chunks[i].map(function(v) {
+ if (v.type != 'i64') {
+ return v.ident + ' = ' + asmInitializer(v.type); //, func.variables[v.ident].impl);
+ } else {
+ return v.ident + '$0 = 0, ' + v.ident + '$1 = 1';
+ }
+ }).join(', ') + ';\n';
+ }
+ }
+ }
+
if (PROFILE) {
func.JS += ' if (PROFILING) { '
+ 'var __parentProfilingNode__ = PROFILING_NODE; PROFILING_NODE = PROFILING_NODE.children["' + func.ident + '"]; '
@@ -547,6 +590,21 @@ function JSify(data, functionsOnly, givenFunctions) {
+ '}\n';
}
+ if (true) { // TODO: optimize away when not needed
+ if (CLOSURE_ANNOTATIONS) func.JS += '/** @type {number} */';
+ func.JS += ' var label = 0;\n';
+ }
+
+ if (ASM_JS) {
+ var hasByVal = false;
+ func.params.forEach(function(param) {
+ hasByVal = hasByVal = hasByVal || param.byVal;
+ });
+ if (hasByVal) {
+ func.js += ' var tempParam = 0;\n';
+ }
+ }
+
// Prepare the stack, if we need one. If we have other stack allocations, force the stack to be set up.
func.JS += ' ' + RuntimeGenerator.stackEnter(func.initialStack, func.otherStackAllocations) + ';\n';
@@ -561,18 +619,13 @@ function JSify(data, functionsOnly, givenFunctions) {
if (param.byVal) {
var type = removePointing(param.type);
var typeInfo = Types.types[type];
- func.JS += ' var tempParam = ' + param.ident + '; ' + param.ident + ' = ' + RuntimeGenerator.stackAlloc(typeInfo.flatSize) + ';' +
+ func.JS += ' ' + (ASM_JS ? '' : 'var ') + 'tempParam = ' + param.ident + '; ' + param.ident + ' = ' + RuntimeGenerator.stackAlloc(typeInfo.flatSize) + ';' +
makeCopyValues(param.ident, 'tempParam', typeInfo.flatSize, 'null', null, param.byVal) + ';\n';
}
});
if (LABEL_DEBUG) func.JS += " Module.print(INDENT + ' Entering: " + func.ident + ": ' + Array.prototype.slice.call(arguments)); INDENT += ' ';\n";
- if (true) { // TODO: optimize away when not needed
- if (CLOSURE_ANNOTATIONS) func.JS += '/** @type {number} */';
- func.JS += ' var label;\n';
- }
-
// Walk function blocks and generate JS
function walkBlock(block, indent) {
if (!block) return '';
@@ -703,12 +756,12 @@ function JSify(data, functionsOnly, givenFunctions) {
if (PRINT_SPLIT_FILE_MARKER) {
func.JS += '\n//FUNCTION_END_MARKER_OF_SOURCE_FILE_' + associatedSourceFile + '\n';
}
-
- if (EXPORT_ALL || (func.ident in EXPORTED_FUNCTIONS)) {
+
+ if (!ASM_JS && (EXPORT_ALL || (func.ident in EXPORTED_FUNCTIONS))) {
func.JS += 'Module["' + func.ident + '"] = ' + func.ident + ';';
}
- if (INLINING_LIMIT && func.lines.length >= INLINING_LIMIT) {
+ if (!ASM_JS && INLINING_LIMIT && func.lines.length >= INLINING_LIMIT) {
func.JS += func.ident + '["X"]=1;';
}
@@ -754,8 +807,9 @@ function JSify(data, functionsOnly, givenFunctions) {
var valueJS = item.JS;
item.JS = '';
if (CLOSURE_ANNOTATIONS) item.JS += '/** @type {number} */ ';
- item.JS += (item.overrideSSA ? '' : 'var ') + toNiceIdent(item.assignTo);
-
+ if (!ASM_JS || item.intertype != 'alloca' || item.funcData.variables[item.assignTo].impl == VAR_EMULATED) { // asm only needs non-allocas
+ item.JS += ((ASM_JS || item.overrideSSA) ? '' : 'var ') + toNiceIdent(item.assignTo);
+ }
var value = parseNumerical(valueJS);
var impl = getVarImpl(item.funcData, item.assignTo);
switch (impl) {
@@ -785,7 +839,7 @@ function JSify(data, functionsOnly, givenFunctions) {
return substrate.addActor('Intertype:' + intertype, {
processItem: function(item) {
item.JS = func(item);
- if (!item.JS) throw "No JS generated for " + dump(item);
+ if (!item.JS) throw "No JS generated for " + dump((item.funcData=null,item));
if (item.assignTo) {
makeAssign(item);
if (!item.JS) throw "No assign JS generated for " + dump(item);
@@ -801,7 +855,7 @@ function JSify(data, functionsOnly, givenFunctions) {
return ';';
});
makeFuncLineActor('var', function(item) { // assigns into phis become simple vars
- return 'var ' + item.ident + ';';
+ return ASM_JS ? ';' : ('var ' + item.ident + ';');
});
makeFuncLineActor('store', function(item) {
var value = finalizeLLVMParameter(item.value);
@@ -895,7 +949,7 @@ function JSify(data, functionsOnly, givenFunctions) {
var labelSets = phiSets[label];
// FIXME: Many of the |var |s here are not needed, but without them we get slowdowns with closure compiler. TODO: remove this workaround.
if (labelSets.length == 1) {
- return 'var ' + labelSets[0].ident + ' = ' + labelSets[0].valueJS + ';';
+ return (ASM_JS ? '' : 'var ') + labelSets[0].ident + ' = ' + labelSets[0].valueJS + ';';
}
// TODO: eliminate unneeded sets (to undefined etc.)
var deps = {}; // for each ident we will set, which others it depends on
@@ -1031,33 +1085,36 @@ function JSify(data, functionsOnly, givenFunctions) {
}
ret += 'return';
if (item.value) {
- ret += ' ' + finalizeLLVMParameter(item.value);
+ ret += ' ' + asmCoercion(finalizeLLVMParameter(item.value), item.type);
}
return ret + ';';
});
makeFuncLineActor('resume', function(item) {
// If there is no current exception, set this one as it (during a resume, the current exception can be wiped out)
+ 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, item.ident + '.f0', 'void*') + ' } ' +
- 'throw ' + item.ident + '.f0;';
+ 'if (' + makeGetValue('_llvm_eh_exception.buf', 0, 'void*') + ' == 0) { ' + makeSetValue('_llvm_eh_exception.buf', 0, ptr, 'void*') + ' } ' +
+ 'throw ' + 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__ = false; return '
+ var ret = '(function() { try { __THREW__ = 0; return '
+ call_ + ' '
+ '} catch(e) { '
+ 'if (typeof e != "number") throw e; '
- + 'if (ABORT) throw e; __THREW__ = true; '
+ + '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 (isIllegalType(item.type)) {
- assert(item.type == 'i64', 'Can only handle i64 invoke among illegal invokes');
- ret += 'var ' + item.assignTo + '$0 = ' + item.assignTo + '[0], ' + item.assignTo + '$1 = ' + item.assignTo + '[1];';
+ if (USE_TYPED_ARRAYS == 2 && isIllegalType(item.type)) {
+ var bits = getBits(item.type);
+ for (var i = 0; i < bits/32; i++) {
+ ret += 'var ' + item.assignTo + '$' + i + ' = ' + (i == 0 ? item.assignTo : 'tempRet' + (i-1)) + ';'
+ }
}
item.assignTo = null;
}
@@ -1085,7 +1142,12 @@ function JSify(data, functionsOnly, givenFunctions) {
});
makeFuncLineActor('landingpad', function(item) {
var catchTypeArray = item.catchables.map(finalizeLLVMParameter).join(',');
- return '___cxa_find_matching_catch('+ makeGetValue('_llvm_eh_exception.buf', '0', 'void*') +',' + makeGetValue('_llvm_eh_exception.buf', QUANTUM_SIZE, 'void*') + ',[' + catchTypeArray +'])';
+ var ret = '___cxa_find_matching_catch('+ makeGetValue('_llvm_eh_exception.buf', '0', 'void*') +',' + makeGetValue('_llvm_eh_exception.buf', QUANTUM_SIZE, 'void*') + ',[' + catchTypeArray +'])';
+ if (USE_TYPED_ARRAYS == 2) {
+ ret = makeVarDef(item.assignTo) + '$0 = ' + ret + '; ' + item.assignTo + '$1 = tempRet0;';
+ item.assignTo = null;
+ }
+ return ret;
});
makeFuncLineActor('load', function(item) {
var value = finalizeLLVMParameter(item.pointer);
@@ -1160,6 +1222,7 @@ function JSify(data, functionsOnly, givenFunctions) {
var useJSArgs = (shortident + '__jsargs') in LibraryManager.library;
var hasVarArgs = isVarArgsFunctionType(type);
var normalArgs = (hasVarArgs && !useJSArgs) ? countNormalArgs(type) : -1;
+ var byPointer = getVarData(funcData, ident);
params.forEach(function(param, i) {
var val = finalizeParam(param);
@@ -1183,6 +1246,10 @@ 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]) });
+ }
+
varargs = varargs.map(function(vararg, i) {
if (ignoreFunctionIndexizing.indexOf(i) >= 0) return vararg;
return vararg === 0 ? 0 : indexizeFunctions(vararg, varargsTypes[i])
@@ -1225,11 +1292,23 @@ function JSify(data, functionsOnly, givenFunctions) {
return inline.apply(null, args); // Warning: inlining does not prevent recalculation of the arguments. They should be simple identifiers
}
- if (getVarData(funcData, ident)) {
- ident = 'FUNCTION_TABLE[' + ident + ']';
+ var returnType;
+ if (byPointer || ASM_JS) returnType = type.split(' ')[0];
+
+ if (byPointer) {
+ var sig = Functions.getSignature(returnType, argsTypes);
+ if (ASM_JS) {
+ assert(returnType.search(/\("'\[,/) == -1); // XXX need isFunctionType(type, out)
+ ident = '(' + ident + ')&{{{ FTM_' + sig + ' }}}'; // the function table mask is set in emscripten.py
+ }
+ ident = Functions.getTable(sig) + '[' + ident + ']';
}
- return ident + '(' + args.join(', ') + ')';
+ var ret = ident + '(' + args.join(', ') + ')';
+ if (ASM_JS && shortident in Functions.libraryFunctions) {
+ ret = asmCoercion(ret, returnType);
+ }
+ return ret;
}
makeFuncLineActor('getelementptr', function(item) { return finalizeLLVMFunctionCall(item) });
makeFuncLineActor('call', function(item) {
@@ -1284,8 +1363,9 @@ function JSify(data, functionsOnly, givenFunctions) {
if (phase == 'pre' && !Variables.generatedGlobalBase) {
Variables.generatedGlobalBase = true;
if (Variables.nextIndexedOffset > 0) {
- // Variables have been calculated, print out the base generation before we print them
- print('var GLOBAL_BASE = STATICTOP;\n');
+ // Variables have been calculated, get to base stuff before we print them
+ // GLOBAL_BASE is statically known to be equal to STACK_MAX and to TOTAL_STACK, assert on this
+ print('assert(STATICTOP == STACK_MAX); assert(STACK_MAX == TOTAL_STACK);\n');
print('STATICTOP += ' + Variables.nextIndexedOffset + ';\n');
print('assert(STATICTOP < TOTAL_MEMORY);\n');
}
@@ -1325,8 +1405,7 @@ function JSify(data, functionsOnly, givenFunctions) {
}
if (phase == 'pre' || phase == 'funcs') {
- // serialize out the data that later passes need
- PassManager.serialize(); // XXX for funcs pass, do not serialize it all. I think we just need which were indexized.
+ PassManager.serialize();
return;
}
@@ -1353,11 +1432,11 @@ function JSify(data, functionsOnly, givenFunctions) {
var postParts = processMacros(preprocess(read(postFile))).split('{{GLOBAL_VARS}}');
print(postParts[0]);
- print(Functions.generateIndexing()); // done last, as it may rely on aliases set in postsets
+ Functions.generateIndexing(); // done last, as it may rely on aliases set in postsets
// Load runtime-linked libraries
RUNTIME_LINKED_LIBS.forEach(function(lib) {
- print('eval(Module["read"]("' + lib + '"))(FUNCTION_TABLE.length, this);');
+ print('eval(Module["read"]("' + lib + '"))(' + Functions.getTable('x') + '.length, this);');
});
print(postParts[1]);
@@ -1369,6 +1448,8 @@ function JSify(data, functionsOnly, givenFunctions) {
return IGNORED_FUNCTIONS.indexOf(func.ident) < 0;
})) + '\n');
+ PassManager.serialize();
+
return null;
}
diff --git a/src/library.js b/src/library.js
index 1bdd840d..5bb414b0 100644
--- a/src/library.js
+++ b/src/library.js
@@ -20,10 +20,11 @@ LibraryManager.library = {
// File system base.
// ==========================================================================
- stdin: 0,
- stdout: 0,
- stderr: 0,
- _impure_ptr: 0,
+ // keep this low in memory, because we flatten arrays with them in them
+ stdin: 'allocate(1, "i32*", ALLOC_STACK)',
+ stdout: 'allocate(1, "i32*", ALLOC_STACK)',
+ stderr: 'allocate(1, "i32*", ALLOC_STACK)',
+ _impure_ptr: 'allocate(1, "i32*", ALLOC_STACK)',
$FS__deps: ['$ERRNO_CODES', '__setErrNo', 'stdin', 'stdout', 'stderr', '_impure_ptr'],
$FS__postset: '__ATINIT__.unshift({ func: function() { if (!Module["noFSInit"] && !FS.init.initialized) FS.init() } });' +
@@ -572,10 +573,10 @@ LibraryManager.library = {
eof: false,
ungotten: []
};
- // Allocate these on the stack (and never free, we are called from ATINIT or earlier), to keep their locations low
- _stdin = allocate([1], 'void*', ALLOC_STACK);
- _stdout = allocate([2], 'void*', ALLOC_STACK);
- _stderr = allocate([3], 'void*', ALLOC_STACK);
+ assert(Math.max(_stdin, _stdout, _stderr) < 128); // make sure these are low, we flatten arrays with these
+ {{{ makeSetValue('_stdin', 0, 1, 'void*') }}};
+ {{{ makeSetValue('_stdout', 0, 2, 'void*') }}};
+ {{{ makeSetValue('_stderr', 0, 3, 'void*') }}};
// Other system paths
FS.createPath('/', 'dev/shm/tmp', true, true); // temp files
@@ -591,9 +592,9 @@ LibraryManager.library = {
FS.checkStreams();
assert(FS.streams.length < 1024); // at this early stage, we should not have a large set of file descriptors - just a few
#endif
- __impure_ptr = allocate([ allocate(
+ allocate([ allocate(
{{{ Runtime.QUANTUM_SIZE === 4 ? '[0, 0, 0, 0, _stdin, 0, 0, 0, _stdout, 0, 0, 0, _stderr, 0, 0, 0]' : '[0, _stdin, _stdout, _stderr]' }}},
- 'void*', ALLOC_STATIC) ], 'void*', ALLOC_STATIC);
+ 'void*', ALLOC_STATIC) ], 'void*', ALLOC_NONE, __impure_ptr);
},
quit: function() {
@@ -3616,7 +3617,9 @@ LibraryManager.library = {
},
bsearch: function(key, base, num, size, compar) {
- var cmp = FUNCTION_TABLE[compar];
+ var cmp = function(x, y) {
+ return Runtime.dynCall('iii', compar, [x, y])
+ };
var left = 0;
var right = num;
var mid, test, addr;
@@ -3810,7 +3813,7 @@ LibraryManager.library = {
#if USE_TYPED_ARRAYS == 2
if (bits == 64) {
- ret = [{{{ splitI64('ret') }}}];
+ {{{ makeStructuralReturn(splitI64('ret')) }}};
}
#endif
@@ -3854,11 +3857,13 @@ LibraryManager.library = {
},
qsort__deps: ['memcpy'],
- qsort: function(base, num, size, comparator) {
+ qsort: function(base, num, size, cmp) {
if (num == 0 || size == 0) return;
// forward calls to the JavaScript sort method
// first, sort the items logically
- comparator = FUNCTION_TABLE[comparator];
+ var comparator = function(x, y) {
+ return Runtime.dynCall('iii', cmp, [x, y]);
+ }
var keys = [];
for (var i = 0; i < num; i++) keys.push(i);
keys.sort(function(a, b) {
@@ -3874,9 +3879,10 @@ LibraryManager.library = {
_free(temp);
},
- environ: null,
- __environ: null,
- __buildEnvironment__deps: ['environ', '__environ'],
+ environ: 'allocate(1, "i32*", ALLOC_STACK)',
+ __environ__deps: ['environ'],
+ __environ: '_environ',
+ __buildEnvironment__deps: ['__environ'],
__buildEnvironment: function(env) {
// WARNING: Arbitrary limit!
var MAX_ENV_VALUES = 64;
@@ -3885,7 +3891,8 @@ LibraryManager.library = {
// Statically allocate memory for the environment.
var poolPtr;
var envPtr;
- if (_environ === null) {
+ if (!___buildEnvironment.called) {
+ ___buildEnvironment.called = true;
// Set default values. Use string keys for Closure Compiler compatibility.
ENV['USER'] = 'root';
ENV['PATH'] = '/';
@@ -3898,9 +3905,7 @@ LibraryManager.library = {
envPtr = allocate(MAX_ENV_VALUES * {{{ Runtime.QUANTUM_SIZE }}},
'i8*', ALLOC_STATIC);
{{{ makeSetValue('envPtr', '0', 'poolPtr', 'i8*') }}}
- _environ = allocate([envPtr], 'i8**', ALLOC_STATIC);
- // Set up global variable alias.
- ___environ = _environ;
+ {{{ makeSetValue('_environ', 0, 'envPtr', 'i8*') }}};
} else {
envPtr = {{{ makeGetValue('_environ', '0', 'i8**') }}};
poolPtr = {{{ makeGetValue('envPtr', '0', 'i8*') }}};
@@ -4097,14 +4102,14 @@ LibraryManager.library = {
memcpy__inline: function (dest, src, num, align) {
var ret = '';
#if ASSERTIONS
- ret += "assert(" + num + " % 1 === 0, 'memcpy given ' + " + num + " + ' bytes to copy. Problem with quantum=1 corrections perhaps?');";
+ ret += "assert(" + num + " % 1 === 0);"; //, 'memcpy given ' + " + num + " + ' bytes to copy. Problem with quantum=1 corrections perhaps?');";
#endif
ret += makeCopyValues(dest, src, num, 'null', null, align);
return ret;
},
memcpy: function (dest, src, num, align) {
#if ASSERTIONS
- assert(num % 1 === 0, 'memcpy given ' + num + ' bytes to copy. Problem with quantum=1 corrections perhaps?');
+ assert(num % 1 === 0); //, 'memcpy given ' + num + ' bytes to copy. Problem with quantum=1 corrections perhaps?');
#endif
#if USE_TYPED_ARRAYS == 2
if (num >= {{{ SEEK_OPTIMAL_ALIGN_MIN }}} && src % 2 == dest % 2) {
@@ -4716,9 +4721,8 @@ LibraryManager.library = {
// ==========================================================================
llvm_va_start__inline: function(ptr) {
- // varargs - we received a pointer to the varargs as a final 'extra' parameter
- var data = 'arguments[' + Framework.currItem.funcData.ident + '.length]';
- return makeSetValue(ptr, 0, data, 'void*');
+ // varargs - we received a pointer to the varargs as a final 'extra' parameter called 'varrp'
+ return makeSetValue(ptr, 0, 'varrp', 'void*');
},
llvm_va_end: function() {},
@@ -4789,13 +4793,13 @@ LibraryManager.library = {
__cxa_throw: function(ptr, type, destructor) {
if (!___cxa_throw.initialized) {
try {
- {{{ makeSetValue('__ZTVN10__cxxabiv119__pointer_type_infoE', '0', '0', 'i32') }}}; // Workaround for libcxxabi integration bug
+ {{{ makeSetValue(makeGlobalUse('__ZTVN10__cxxabiv119__pointer_type_infoE'), '0', '0', 'i32') }}}; // Workaround for libcxxabi integration bug
} catch(e){}
try {
- {{{ makeSetValue('__ZTVN10__cxxabiv117__class_type_infoE', '0', '1', 'i32') }}}; // Workaround for libcxxabi integration bug
+ {{{ makeSetValue(makeGlobalUse('__ZTVN10__cxxabiv117__class_type_infoE'), '0', '1', 'i32') }}}; // Workaround for libcxxabi integration bug
} catch(e){}
try {
- {{{ makeSetValue('__ZTVN10__cxxabiv120__si_class_type_infoE', '0', '2', 'i32') }}}; // Workaround for libcxxabi integration bug
+ {{{ makeSetValue(makeGlobalUse('__ZTVN10__cxxabiv120__si_class_type_infoE'), '0', '2', 'i32') }}}; // Workaround for libcxxabi integration bug
} catch(e){}
___cxa_throw.initialized = true;
}
@@ -4844,14 +4848,18 @@ LibraryManager.library = {
return;
}
// Clear state flag.
- __THREW__ = false;
+#if ASM_JS
+ asm.setThrew(0);
+#else
+ __THREW__ = 0;
+#endif
// Clear type.
{{{ makeSetValue('_llvm_eh_exception.buf', QUANTUM_SIZE, '0', 'void*') }}}
// Call destructor if one is registered then clear it.
var ptr = {{{ makeGetValue('_llvm_eh_exception.buf', '0', 'void*') }}};
var destructor = {{{ makeGetValue('_llvm_eh_exception.buf', 2 * QUANTUM_SIZE, 'void*') }}};
if (destructor) {
- FUNCTION_TABLE[destructor](ptr);
+ Runtime.dynCall('vi', destructor, [ptr]);
{{{ makeSetValue('_llvm_eh_exception.buf', 2 * QUANTUM_SIZE, '0', 'i32') }}}
}
// Free ptr if it isn't null.
@@ -4889,20 +4897,20 @@ LibraryManager.library = {
__cxa_is_number_type: function(type) {
var isNumber = false;
- try { if (type == __ZTIi) isNumber = true } catch(e){}
- try { if (type == __ZTIj) isNumber = true } catch(e){}
- try { if (type == __ZTIl) isNumber = true } catch(e){}
- try { if (type == __ZTIm) isNumber = true } catch(e){}
- try { if (type == __ZTIx) isNumber = true } catch(e){}
- try { if (type == __ZTIy) isNumber = true } catch(e){}
- try { if (type == __ZTIf) isNumber = true } catch(e){}
- try { if (type == __ZTId) isNumber = true } catch(e){}
- try { if (type == __ZTIe) isNumber = true } catch(e){}
- try { if (type == __ZTIc) isNumber = true } catch(e){}
- try { if (type == __ZTIa) isNumber = true } catch(e){}
- try { if (type == __ZTIh) isNumber = true } catch(e){}
- try { if (type == __ZTIs) isNumber = true } catch(e){}
- try { if (type == __ZTIt) isNumber = true } catch(e){}
+ try { if (type == {{{ makeGlobalUse('__ZTIi') }}}) isNumber = true } catch(e){}
+ try { if (type == {{{ makeGlobalUse('__ZTIj') }}}) isNumber = true } catch(e){}
+ try { if (type == {{{ makeGlobalUse('__ZTIl') }}}) isNumber = true } catch(e){}
+ try { if (type == {{{ makeGlobalUse('__ZTIm') }}}) isNumber = true } catch(e){}
+ try { if (type == {{{ makeGlobalUse('__ZTIx') }}}) isNumber = true } catch(e){}
+ try { if (type == {{{ makeGlobalUse('__ZTIy') }}}) isNumber = true } catch(e){}
+ try { if (type == {{{ makeGlobalUse('__ZTIf') }}}) isNumber = true } catch(e){}
+ try { if (type == {{{ makeGlobalUse('__ZTId') }}}) isNumber = true } catch(e){}
+ try { if (type == {{{ makeGlobalUse('__ZTIe') }}}) isNumber = true } catch(e){}
+ try { if (type == {{{ makeGlobalUse('__ZTIc') }}}) isNumber = true } catch(e){}
+ try { if (type == {{{ makeGlobalUse('__ZTIa') }}}) isNumber = true } catch(e){}
+ try { if (type == {{{ makeGlobalUse('__ZTIh') }}}) isNumber = true } catch(e){}
+ try { if (type == {{{ makeGlobalUse('__ZTIs') }}}) isNumber = true } catch(e){}
+ try { if (type == {{{ makeGlobalUse('__ZTIt') }}}) isNumber = true } catch(e){}
return isNumber;
},
@@ -4933,12 +4941,12 @@ LibraryManager.library = {
// return the type of the catch block which should be called.
for (var i = 0; i < typeArray.length; i++) {
if (___cxa_does_inherit(typeArray[i], throwntype, thrown))
- return { f0:thrown, f1:typeArray[i] };
+ {{{ makeStructuralReturn(['thrown', 'typeArray[i]']) }}};
}
// Shouldn't happen unless we have bogus data in typeArray
// or encounter a type for which emscripten doesn't have suitable
// typeinfo defined. Best-efforts match just in case.
- return { f0:thrown, f1 :throwntype };
+ {{{ makeStructuralReturn(['thrown', 'throwntype']) }}};
},
// Recursively walks up the base types of 'possibilityType'
@@ -5004,73 +5012,51 @@ LibraryManager.library = {
llvm_uadd_with_overflow_i8: function(x, y) {
x = x & 0xff;
y = y & 0xff;
- return {
- f0: (x+y) & 0xff,
- f1: x+y > 255
- };
+ {{{ makeStructuralReturn(['(x+y) & 0xff', 'x+y > 255']) }}};
},
llvm_umul_with_overflow_i8: function(x, y) {
x = x & 0xff;
y = y & 0xff;
- return {
- f0: (x*y) & 0xff,
- f1: x*y > 255
- };
+ {{{ makeStructuralReturn(['(x*y) & 0xff', 'x*y > 255']) }}};
},
llvm_uadd_with_overflow_i16: function(x, y) {
x = x & 0xffff;
y = y & 0xffff;
- return {
- f0: (x+y) & 0xffff,
- f1: x+y > 65535
- };
+ {{{ makeStructuralReturn(['(x+y) & 0xffff', 'x+y > 65535']) }}};
},
llvm_umul_with_overflow_i16: function(x, y) {
x = x & 0xffff;
y = y & 0xffff;
- return {
- f0: (x*y) & 0xffff,
- f1: x*y > 65535
- };
+ {{{ makeStructuralReturn(['(x*y) & 0xffff', 'x*y > 65535']) }}};
},
llvm_uadd_with_overflow_i32: function(x, y) {
x = x>>>0;
y = y>>>0;
- return {
- f0: (x+y)>>>0,
- f1: x+y > 4294967295
- };
+ {{{ makeStructuralReturn(['(x+y)>>>0', 'x+y > 4294967295']) }}};
},
llvm_umul_with_overflow_i32: function(x, y) {
x = x>>>0;
y = y>>>0;
- return {
- f0: (x*y)>>>0,
- f1: x*y > 4294967295
- };
+ {{{ makeStructuralReturn(['(x*y)>>>0', 'x*y > 4294967295']) }}};
},
llvm_uadd_with_overflow_i64__deps: [function() { Types.preciseI64MathUsed = 1 }],
llvm_uadd_with_overflow_i64: function(xl, xh, yl, yh) {
i64Math.add(xl, xh, yl, yh);
- return {
- f0: i64Math.result,
- f1: 0 // XXX Need to hack support for this in long.js
- };
+ {{{ makeStructuralReturn(['HEAP32[tempDoublePtr>>2]', 'HEAP32[tempDoublePtr+4>>2]', '0']) }}};
+ // XXX Need to hack support for second param in long.js
},
llvm_umul_with_overflow_i64__deps: [function() { Types.preciseI64MathUsed = 1 }],
llvm_umul_with_overflow_i64: function(xl, xh, yl, yh) {
- i64Math.mul(xl, xh, yl, yh);
- return {
- f0: i64Math.result,
- f1: 0 // XXX Need to hack support for this in long.js
- };
+ i64Math.multiply(xl, xh, yl, yh);
+ {{{ makeStructuralReturn(['HEAP32[tempDoublePtr>>2]', 'HEAP32[tempDoublePtr+4>>2]', '0']) }}};
+ // XXX Need to hack support for second param in long.js
},
llvm_stacksave: function() {
@@ -5510,7 +5496,7 @@ LibraryManager.library = {
}
try {
- var lib_module = eval(lib_data)(FUNCTION_TABLE.length);
+ var lib_module = eval(lib_data)({{{ Functions.getTable('x') }}}.length);
} catch (e) {
#if ASSERTIONS
Module.printErr('Error in loading dynamic library: ' + e);
@@ -5583,9 +5569,9 @@ LibraryManager.library = {
} else {
var result = lib.module[symbol];
if (typeof result == 'function') {
- FUNCTION_TABLE.push(result);
- FUNCTION_TABLE.push(0);
- result = FUNCTION_TABLE.length - 2;
+ {{{ Functions.getTable('x') }}}.push(result);
+ {{{ Functions.getTable('x') }}}.push(0);
+ result = {{{ Functions.getTable('x') }}}.length - 2;
lib.cached_functions = result;
}
return result;
@@ -5653,11 +5639,11 @@ LibraryManager.library = {
'tm_gmtoff',
'tm_zone'], '%struct.tm'),
// Statically allocated time struct.
- __tm_current: 0,
+ __tm_current: 'allocate({{{ Runtime.QUANTUM_SIZE }}}*26, "i8", ALLOC_STACK)',
// Statically allocated timezone strings.
__tm_timezones: {},
// Statically allocated time strings.
- __tm_formatted: 0,
+ __tm_formatted: 'allocate({{{ Runtime.QUANTUM_SIZE }}}*26, "i8", ALLOC_STACK)',
mktime__deps: ['__tm_struct_layout', 'tzset'],
mktime: function(tmPtr) {
@@ -5680,7 +5666,6 @@ LibraryManager.library = {
gmtime__deps: ['malloc', '__tm_struct_layout', '__tm_current', 'gmtime_r'],
gmtime: function(time) {
- if (!___tm_current) ___tm_current = _malloc(___tm_struct_layout.__size__);
return _gmtime_r(time, ___tm_current);
},
@@ -5723,7 +5708,6 @@ LibraryManager.library = {
localtime__deps: ['malloc', '__tm_struct_layout', '__tm_current', 'localtime_r'],
localtime: function(time) {
- if (!___tm_current) ___tm_current = _malloc(___tm_struct_layout.__size__);
return _localtime_r(time, ___tm_current);
},
@@ -5759,7 +5743,6 @@ LibraryManager.library = {
asctime__deps: ['malloc', '__tm_formatted', 'asctime_r'],
asctime: function(tmPtr) {
- if (!___tm_formatted) ___tm_formatted = _malloc(26);
return _asctime_r(tmPtr, ___tm_formatted);
},
@@ -5794,18 +5777,17 @@ LibraryManager.library = {
// TODO: Initialize these to defaults on startup from system settings.
// Note: glibc has one fewer underscore for all of these. Also used in other related functions (timegm)
- _tzname: null,
- _daylight: null,
- _timezone: null,
+ _tzname: 'allocate({{{ 2*Runtime.QUANTUM_SIZE }}}, "i32*", ALLOC_STACK)',
+ _daylight: 'allocate(1, "i32*", ALLOC_STACK)',
+ _timezone: 'allocate(1, "i32*", ALLOC_STACK)',
tzset__deps: ['_tzname', '_daylight', '_timezone'],
tzset: function() {
// TODO: Use (malleable) environment variables instead of system settings.
- if (__tzname) return; // glibc does not need the double __
+ if (_tzset.called) return;
+ _tzset.called = true;
- __timezone = _malloc({{{ Runtime.QUANTUM_SIZE }}});
{{{ makeSetValue('__timezone', '0', '-(new Date()).getTimezoneOffset() * 60', 'i32') }}}
- __daylight = _malloc({{{ Runtime.QUANTUM_SIZE }}});
var winter = new Date(2000, 0, 1);
var summer = new Date(2000, 6, 1);
{{{ makeSetValue('__daylight', '0', 'Number(winter.getTimezoneOffset() != summer.getTimezoneOffset())', 'i32') }}}
@@ -5814,7 +5796,6 @@ LibraryManager.library = {
var summerName = 'GMT'; // XXX do not rely on browser timezone info, it is very unpredictable | summer.toString().match(/\(([A-Z]+)\)/)[1];
var winterNamePtr = allocate(intArrayFromString(winterName), 'i8', ALLOC_NORMAL);
var summerNamePtr = allocate(intArrayFromString(summerName), 'i8', ALLOC_NORMAL);
- __tzname = _malloc(2 * {{{ Runtime.QUANTUM_SIZE }}}); // glibc does not need the double __
{{{ makeSetValue('__tzname', '0', 'winterNamePtr', 'i32') }}}
{{{ makeSetValue('__tzname', Runtime.QUANTUM_SIZE, 'summerNamePtr', 'i32') }}}
},
@@ -6014,6 +5995,8 @@ LibraryManager.library = {
return 0;
},
+ freelocale: function(locale) {},
+
uselocale: function(locale) {
return 0;
},
@@ -6453,6 +6436,8 @@ LibraryManager.library = {
pthread_mutexattr_destroy: function() {},
pthread_mutex_lock: function() {},
pthread_mutex_unlock: function() {},
+ pthread_cond_init: function() {},
+ pthread_cond_destroy: function() {},
pthread_cond_broadcast: function() {},
pthread_self: function() {
//FIXME: assumes only a single thread
@@ -6486,7 +6471,7 @@ LibraryManager.library = {
pthread_once: function(ptr, func) {
if (!_pthread_once.seen) _pthread_once.seen = {};
if (ptr in _pthread_once.seen) return;
- FUNCTION_TABLE[func]();
+ Runtime.dynCall('v', func);
_pthread_once.seen[ptr] = 1;
},
@@ -6504,7 +6489,7 @@ LibraryManager.library = {
},
pthread_cleanup_push: function(routine, arg) {
- __ATEXIT__.push({ func: function() { FUNCTION_TABLE[routine](arg) } })
+ __ATEXIT__.push({ func: function() { Runtime.dynCall('vi', routine, [arg]) } })
_pthread_cleanup_push.level = __ATEXIT__.length;
},
diff --git a/src/library_browser.js b/src/library_browser.js
index 00ee158c..21bad254 100644
--- a/src/library_browser.js
+++ b/src/library_browser.js
@@ -377,10 +377,10 @@ mergeInto(LibraryManager.library, {
_file.substr(index +1),
_url, true, true,
function() {
- if (onload) FUNCTION_TABLE[onload](file);
+ if (onload) Runtime.dynCall('vi', onload, [file]);
},
function() {
- if (onerror) FUNCTION_TABLE[onerror](file);
+ if (onerror) Runtime.dynCall('vi', onerror, [file]);
}
);
},
@@ -395,10 +395,10 @@ mergeInto(LibraryManager.library, {
_file.substr(index +1),
new Uint8Array(data.object.contents), true, true,
function() {
- if (onload) FUNCTION_TABLE[onload](file);
+ if (onload) Runtime.dynCall('vi', onload, [file]);
},
function() {
- if (onerror) FUNCTION_TABLE[onerror](file);
+ if (onerror) Runtime.dynCall('vi', onerror, [file]);
},
true // don'tCreateFile - it's already there
);
@@ -417,10 +417,10 @@ mergeInto(LibraryManager.library, {
{{{ makeHEAPView('U8', 'data', 'data + size') }}},
true, true,
function() {
- if (onload) FUNCTION_TABLE[onload](arg, cname);
+ if (onload) Runtime.dynCall('vii', onload, [file, cname]);
},
function() {
- if (onerror) FUNCTION_TABLE[onerror](arg);
+ if (onerror) Runtime.dynCall('vi', onerror, [file]);
},
true // don'tCreateFile - it's already there
);
@@ -440,7 +440,6 @@ mergeInto(LibraryManager.library, {
emscripten_set_main_loop: function(func, fps, simulateInfiniteLoop) {
Module['noExitRuntime'] = true;
- var jsFunc = FUNCTION_TABLE[func];
Browser.mainLoop.runner = function() {
if (Browser.mainLoop.queue.length > 0) {
var start = Date.now();
@@ -473,7 +472,7 @@ mergeInto(LibraryManager.library, {
Module['preMainLoop']();
}
- jsFunc();
+ Runtime.dynCall('v', func);
if (Module['postMainLoop']) {
Module['postMainLoop']();
@@ -517,12 +516,16 @@ mergeInto(LibraryManager.library, {
},
_emscripten_push_main_loop_blocker: function(func, arg, name) {
- Browser.mainLoop.queue.push({ func: FUNCTION_TABLE[func], arg: arg, name: Pointer_stringify(name), counted: true });
+ Browser.mainLoop.queue.push({ func: function() {
+ Runtime.dynCall('vi', func, [arg]);
+ }, name: Pointer_stringify(name), counted: true });
Browser.mainLoop.updateStatus();
},
_emscripten_push_uncounted_main_loop_blocker: function(func, arg, name) {
- Browser.mainLoop.queue.push({ func: FUNCTION_TABLE[func], arg: arg, name: Pointer_stringify(name), counted: false });
+ Browser.mainLoop.queue.push({ func: function() {
+ Runtime.dynCall('vi', func, [arg]);
+ }, name: Pointer_stringify(name), counted: false });
Browser.mainLoop.updateStatus();
},
diff --git a/src/library_gc.js b/src/library_gc.js
index a06e2f01..fe4cbf63 100644
--- a/src/library_gc.js
+++ b/src/library_gc.js
@@ -1,5 +1,7 @@
if (GC_SUPPORT) {
+ EXPORTED_FUNCTIONS['_calloc'] = 1;
+
var LibraryGC = {
$GC__deps: ['sbrk'],
$GC: {
@@ -50,7 +52,7 @@ if (GC_SUPPORT) {
free: function(ptr) { // does not check if anything refers to it, this is a forced free
var finalizer = GC.finalizers[ptr];
if (finalizer) {
- Runtime.getFuncWrapper(finalizer)(ptr, GC.finalizerArgs[ptr]);
+ Runtime.getFuncWrapper(finalizer, 'vii')(ptr, GC.finalizerArgs[ptr]);
GC.finalizers[ptr] = 0;
}
_free(ptr);
diff --git a/src/library_gl.js b/src/library_gl.js
index 0f28a6a0..e9e93b93 100644
--- a/src/library_gl.js
+++ b/src/library_gl.js
@@ -1275,11 +1275,12 @@ var LibraryGL = {
getProcAddress: function(name) {
name = name.replace('EXT', '').replace('ARB', '');
// Do the translation carefully because of closure
+ var sig = '';
switch (name) {
- case 'glCreateShaderObject': case 'glCreateShader': func = _glCreateShader; break;
- case 'glCreateProgramObject': case 'glCreateProgram': func = _glCreateProgram; break;
- case 'glAttachObject': case 'glAttachShader': func = _glAttachShader; break;
- case 'glUseProgramObject': case 'glUseProgram': func = _glUseProgram; break;
+ case 'glCreateShaderObject': case 'glCreateShader': func = _glCreateShader; sig = 'ii'; break;
+ case 'glCreateProgramObject': case 'glCreateProgram': func = _glCreateProgram; sig = 'ii'; break;
+ case 'glAttachObject': case 'glAttachShader': func = _glAttachShader; sig = 'vi'; break;
+ case 'glUseProgramObject': case 'glUseProgram': func = _glUseProgram; sig = 'vi'; break;
case 'glDeleteObject': func = function(id) {
if (GL.programs[id]) {
_glDeleteProgram(id);
@@ -1288,7 +1289,7 @@ var LibraryGL = {
} else {
Module.printErr('WARNING: deleteObject received invalid id: ' + id);
}
- }; break;
+ }; sig = 'vi'; break;
case 'glGetObjectParameteriv': func = function(id, type, result) {
if (GL.programs[id]) {
if (type == 0x8B84) { // GL_OBJECT_INFO_LOG_LENGTH_ARB
@@ -1305,7 +1306,7 @@ var LibraryGL = {
} else {
Module.printErr('WARNING: getObjectParameteriv received invalid id: ' + id);
}
- }; break;
+ }; sig = 'viii'; break;
case 'glGetInfoLog': func = function(id, maxLength, length, infoLog) {
if (GL.programs[id]) {
_glGetProgramInfoLog(id, maxLength, length, infoLog);
@@ -1314,58 +1315,58 @@ var LibraryGL = {
} else {
Module.printErr('WARNING: getObjectParameteriv received invalid id: ' + id);
}
- }; break;
+ }; sig = 'viiii'; break;
case 'glBindProgram': func = function(type, id) {
assert(id == 0);
- }; break;
- case 'glDrawRangeElements': func = _glDrawRangeElements; break;
- case 'glShaderSource': func = _glShaderSource; break;
- case 'glCompileShader': func = _glCompileShader; break;
- case 'glLinkProgram': func = _glLinkProgram; break;
- case 'glGetUniformLocation': func = _glGetUniformLocation; break;
- case 'glUniform1f': func = _glUniform1f; break;
- case 'glUniform2f': func = _glUniform2f; break;
- case 'glUniform3f': func = _glUniform3f; break;
- case 'glUniform4f': func = _glUniform4f; break;
- case 'glUniform1fv': func = _glUniform1fv; break;
- case 'glUniform2fv': func = _glUniform2fv; break;
- case 'glUniform3fv': func = _glUniform3fv; break;
- case 'glUniform4fv': func = _glUniform4fv; break;
- case 'glUniform1i': func = _glUniform1i; break;
- case 'glUniform2i': func = _glUniform2i; break;
- case 'glUniform3i': func = _glUniform3i; break;
- case 'glUniform4i': func = _glUniform4i; break;
- case 'glUniform1iv': func = _glUniform1iv; break;
- case 'glUniform2iv': func = _glUniform2iv; break;
- case 'glUniform3iv': func = _glUniform3iv; break;
- case 'glUniform4iv': func = _glUniform4iv; break;
- case 'glBindAttribLocation': func = _glBindAttribLocation; break;
- case 'glGetActiveUniform': func = _glGetActiveUniform; break;
- case 'glGenBuffers': func = _glGenBuffers; break;
- case 'glBindBuffer': func = _glBindBuffer; break;
- case 'glBufferData': func = _glBufferData; break;
- case 'glBufferSubData': func = _glBufferSubData; break;
- case 'glDeleteBuffers': func = _glDeleteBuffers; break;
- case 'glActiveTexture': func = _glActiveTexture; break;
- case 'glClientActiveTexture': func = _glClientActiveTexture; break;
- case 'glGetProgramiv': func = _glGetProgramiv; break;
- case 'glEnableVertexAttribArray': func = _glEnableVertexAttribArray; break;
- case 'glDisableVertexAttribArray': func = _glDisableVertexAttribArray; break;
- case 'glVertexAttribPointer': func = _glVertexAttribPointer; break;
- case 'glBindRenderbuffer': func = _glBindRenderbuffer; break;
- case 'glDeleteRenderbuffers': func = _glDeleteRenderbuffers; break;
- case 'glGenRenderbuffers': func = _glGenRenderbuffers; break;
- case 'glCompressedTexImage2D': func = _glCompressedTexImage2D; break;
- case 'glCompressedTexSubImage2D': func = _glCompressedTexSubImage2D; break;
- case 'glBindFramebuffer': func = _glBindFramebuffer; break;
- case 'glGenFramebuffers': func = _glGenFramebuffers; break;
- case 'glDeleteFramebuffers': func = _glDeleteFramebuffers; break;
- case 'glFramebufferRenderbuffer': func = _glFramebufferRenderbuffer; break;
- case 'glFramebufferTexture2D': func = _glFramebufferTexture2D; break;
- case 'glGetFramebufferAttachmentParameteriv': func = _glGetFramebufferAttachmentParameteriv; break;
- case 'glIsFramebuffer': func = _glIsFramebuffer; break;
- case 'glCheckFramebufferStatus': func = _glCheckFramebufferStatus; break;
- case 'glRenderbufferStorage': func = _glRenderbufferStorage; break;
+ }; sig = 'vii'; break;
+ case 'glDrawRangeElements': func = _glDrawRangeElements; sig = 'viiiiii'; break;
+ case 'glShaderSource': func = _glShaderSource; sig = 'viiii'; break;
+ case 'glCompileShader': func = _glCompileShader; sig = 'vi'; break;
+ case 'glLinkProgram': func = _glLinkProgram; sig = 'vi'; break;
+ case 'glGetUniformLocation': func = _glGetUniformLocation; sig = 'iii'; break;
+ case 'glUniform1f': func = _glUniform1f; sig = 'vid'; break;
+ case 'glUniform2f': func = _glUniform2f; sig = 'vidd'; break;
+ case 'glUniform3f': func = _glUniform3f; sig = 'viddd'; break;
+ case 'glUniform4f': func = _glUniform4f; sig = 'vidddd'; break;
+ case 'glUniform1fv': func = _glUniform1fv; sig = 'viii'; break;
+ case 'glUniform2fv': func = _glUniform2fv; sig = 'viii'; break;
+ case 'glUniform3fv': func = _glUniform3fv; sig = 'viii'; break;
+ case 'glUniform4fv': func = _glUniform4fv; sig = 'viii'; break;
+ case 'glUniform1i': func = _glUniform1i; sig = 'vii'; break;
+ case 'glUniform2i': func = _glUniform2i; sig = 'viii'; break;
+ case 'glUniform3i': func = _glUniform3i; sig = 'viiii'; break;
+ case 'glUniform4i': func = _glUniform4i; sig = 'viiii'; break;
+ case 'glUniform1iv': func = _glUniform1iv; sig = 'viii'; break;
+ case 'glUniform2iv': func = _glUniform2iv; sig = 'viii'; break;
+ case 'glUniform3iv': func = _glUniform3iv; sig = 'viii'; break;
+ case 'glUniform4iv': func = _glUniform4iv; sig = 'viii'; break;
+ case 'glBindAttribLocation': func = _glBindAttribLocation; sig = 'viii'; break;
+ case 'glGetActiveUniform': func = _glGetActiveUniform; sig = 'viiiiiii'; break;
+ case 'glGenBuffers': func = _glGenBuffers; sig = 'iii'; break;
+ case 'glBindBuffer': func = _glBindBuffer; sig = 'vii'; break;
+ case 'glBufferData': func = _glBufferData; sig = 'viiii'; break;
+ case 'glBufferSubData': func = _glBufferSubData; sig = 'viiii'; break;
+ case 'glDeleteBuffers': func = _glDeleteBuffers; sig = 'vii'; break;
+ case 'glActiveTexture': func = _glActiveTexture; sig = 'vi'; break;
+ case 'glClientActiveTexture': func = _glClientActiveTexture; sig = 'vi'; break;
+ case 'glGetProgramiv': func = _glGetProgramiv; sig = 'viii'; break;
+ case 'glEnableVertexAttribArray': func = _glEnableVertexAttribArray; sig = 'vi'; break;
+ case 'glDisableVertexAttribArray': func = _glDisableVertexAttribArray; sig = 'vi'; break;
+ case 'glVertexAttribPointer': func = _glVertexAttribPointer; sig = 'viiiiii'; break;
+ case 'glBindRenderbuffer': func = _glBindRenderbuffer; sig = 'vii'; break;
+ case 'glDeleteRenderbuffers': func = _glDeleteRenderbuffers; sig = 'vii'; break;
+ case 'glGenRenderbuffers': func = _glGenRenderbuffers; sig = 'vii'; break;
+ case 'glCompressedTexImage2D': func = _glCompressedTexImage2D; sig = 'viiiiiiii'; break;
+ case 'glCompressedTexSubImage2D': func = _glCompressedTexSubImage2D; sig = 'viiiiiiiii'; break;
+ case 'glBindFramebuffer': func = _glBindFramebuffer; sig = 'vii'; break;
+ case 'glGenFramebuffers': func = _glGenFramebuffers; sig = 'vii'; break;
+ case 'glDeleteFramebuffers': func = _glDeleteFramebuffers; sig = 'vii'; break;
+ case 'glFramebufferRenderbuffer': func = _glFramebufferRenderbuffer; sig = 'viiii'; break;
+ case 'glFramebufferTexture2D': func = _glFramebufferTexture2D; sig = 'viiiii'; break;
+ case 'glGetFramebufferAttachmentParameteriv': func = _glGetFramebufferAttachmentParameteriv; sig = 'viiii'; break;
+ case 'glIsFramebuffer': func = _glIsFramebuffer; sig = 'ii'; break;
+ case 'glCheckFramebufferStatus': func = _glCheckFramebufferStatus; sig = 'ii'; break;
+ case 'glRenderbufferStorage': func = _glRenderbufferStorage; sig = 'viiii'; break;
default: {
Module.printErr('WARNING: getProcAddress failed for ' + name);
func = function() {
@@ -1374,7 +1375,7 @@ var LibraryGL = {
};
}
}
- return Runtime.addFunction(func);
+ return Runtime.addFunction(func, sig);
}
},
diff --git a/src/library_glut.js b/src/library_glut.js
index 6069b484..0994df34 100644
--- a/src/library_glut.js
+++ b/src/library_glut.js
@@ -54,11 +54,11 @@ var LibraryGLUT = {
if (GLUT.buttons == 0 && event.target == Module["canvas"] && GLUT.passiveMotionFunc) {
event.preventDefault();
GLUT.saveModifiers(event);
- FUNCTION_TABLE[GLUT.passiveMotionFunc](GLUT.lastX, GLUT.lastY);
+ Runtime.dynCall('vii', GLUT.passiveMotionFunc, [GLUT.lastX, GLUT.lastY]);
} else if (GLUT.buttons != 0 && GLUT.motionFunc) {
event.preventDefault();
GLUT.saveModifiers(event);
- FUNCTION_TABLE[GLUT.motionFunc](GLUT.lastX, GLUT.lastY);
+ Runtime.dynCall('vii', GLUT.motionFunc, [GLUT.lastX, GLUT.lastY]);
}
},
@@ -159,7 +159,7 @@ var LibraryGLUT = {
if( GLUT.specialFunc ) {
event.preventDefault();
GLUT.saveModifiers(event);
- FUNCTION_TABLE[GLUT.specialFunc](key, GLUT.lastX, GLUT.lastY);
+ Runtime.dynCall('viii', GLUT.specialFunc, [key, GLUT.lastX, GLUT.lastY]);
}
}
else
@@ -168,7 +168,7 @@ var LibraryGLUT = {
if( key !== null && GLUT.keyboardFunc ) {
event.preventDefault();
GLUT.saveModifiers(event);
- FUNCTION_TABLE[GLUT.keyboardFunc](key, GLUT.lastX, GLUT.lastY);
+ Runtime.dynCall('viii', GLUT.keyboardFunc, [key, GLUT.lastX, GLUT.lastY]);
}
}
}
@@ -181,7 +181,7 @@ var LibraryGLUT = {
if(GLUT.specialUpFunc) {
event.preventDefault ();
GLUT.saveModifiers(event);
- FUNCTION_TABLE[GLUT.specialUpFunc](key, GLUT.lastX, GLUT.lastY);
+ Runtime.dynCall('viii', GLUT.specialUpFunc, key, [GLUT.lastX, GLUT.lastY]);
}
}
else
@@ -190,7 +190,7 @@ var LibraryGLUT = {
if( key !== null && GLUT.keyboardUpFunc ) {
event.preventDefault ();
GLUT.saveModifiers(event);
- FUNCTION_TABLE[GLUT.keyboardUpFunc](key, GLUT.lastX, GLUT.lastY);
+ Runtime.dynCall('viii', GLUT.keyboardUpFunc, [key, GLUT.lastX, GLUT.lastY]);
}
}
}
@@ -206,7 +206,7 @@ var LibraryGLUT = {
} catch (e) {}
event.preventDefault();
GLUT.saveModifiers(event);
- FUNCTION_TABLE[GLUT.mouseFunc](event['button'], 0/*GLUT_DOWN*/, GLUT.lastX, GLUT.lastY);
+ Runtime.dynCall('viiii', GLUT.mouseFunc, [event['button'], 0/*GLUT_DOWN*/, GLUT.lastX, GLUT.lastY]);
}
},
@@ -217,7 +217,7 @@ var LibraryGLUT = {
if(GLUT.mouseFunc) {
event.preventDefault();
GLUT.saveModifiers(event);
- FUNCTION_TABLE[GLUT.mouseFunc](event['button'], 1/*GLUT_UP*/, GLUT.lastX, GLUT.lastY);
+ Runtime.dynCal('viiii', GLUT.mouseFunc, [event['button'], 1/*GLUT_UP*/, GLUT.lastX, GLUT.lastY]);
}
},
@@ -241,7 +241,7 @@ var LibraryGLUT = {
/* Can't call _glutReshapeWindow as that requests cancelling fullscreen. */
if (GLUT.reshapeFunc) {
// console.log("GLUT.reshapeFunc (from FS): " + width + ", " + height);
- FUNCTION_TABLE[GLUT.reshapeFunc](width, height);
+ Runtime.dynCall('vii', GLUT.reshapeFunc, [width, height]);
}
_glutPostRedisplay();
},
@@ -326,7 +326,7 @@ var LibraryGLUT = {
glutIdleFunc: function(func) {
var callback = function() {
if (GLUT.idleFunc) {
- FUNCTION_TABLE[GLUT.idleFunc]();
+ Runtime.dynCall('v', GLUT.idleFunc);
window.setTimeout(callback, 0);
}
}
@@ -336,7 +336,7 @@ var LibraryGLUT = {
},
glutTimerFunc: function(msec, func, value) {
- window.setTimeout(function() { FUNCTION_TABLE[func](value); }, msec);
+ window.setTimeout(function() { Runtime.dynCall('vi', func, [value]); }, msec);
},
glutDisplayFunc: function(func) {
@@ -388,7 +388,7 @@ var LibraryGLUT = {
Browser.setCanvasSize(width, height);
if (GLUT.reshapeFunc) {
// console.log("GLUT.reshapeFunc: " + width + ", " + height);
- FUNCTION_TABLE[GLUT.reshapeFunc](width, height);
+ Runtime.dynCall('vii', GLUT.reshapeFunc, [width, height]);
}
_glutPostRedisplay();
},
@@ -417,7 +417,9 @@ var LibraryGLUT = {
glutPostRedisplay: function() {
if (GLUT.displayFunc) {
- Browser.requestAnimationFrame(FUNCTION_TABLE[GLUT.displayFunc]);
+ Browser.requestAnimationFrame(function() {
+ Runtime.dynCall('vi', GLUT.displayFunc);
+ });
}
},
diff --git a/src/library_sdl.js b/src/library_sdl.js
index 0969f738..6f1ed32b 100644
--- a/src/library_sdl.js
+++ b/src/library_sdl.js
@@ -1116,7 +1116,7 @@ var LibrarySDL = {
SDL.audio.bufferSize = totalSamples*2; // hardcoded 16-bit audio
SDL.audio.buffer = _malloc(SDL.audio.bufferSize);
SDL.audio.caller = function() {
- FUNCTION_TABLE[SDL.audio.callback](SDL.audio.userdata, SDL.audio.buffer, SDL.audio.bufferSize);
+ Runtime.dynCall('viii', SDL.audio.callback, [SDL.audio.userdata, SDL.audio.buffer, SDL.audio.bufferSize]);
SDL.audio.pushAudio(SDL.audio.buffer, SDL.audio.bufferSize);
};
// Mozilla Audio API. TODO: Other audio APIs
@@ -1408,7 +1408,7 @@ var LibrarySDL = {
audio.pause();
SDL.music.audio = null;
if (SDL.hookMusicFinished) {
- FUNCTION_TABLE[SDL.hookMusicFinished]();
+ Runtime.dynCall('v', SDL.hookMusicFinished);
}
return 0;
},
@@ -1439,6 +1439,10 @@ var LibrarySDL = {
return id;
},
+ TTF_CloseFont: function(font) {
+ SDL.fonts[font] = null;
+ },
+
TTF_RenderText_Solid: function(font, text, color) {
// XXX the font and color are ignored
text = Pointer_stringify(text) || ' '; // if given an empty string, still return a valid surface
@@ -1551,7 +1555,7 @@ var LibrarySDL = {
SDL_AddTimer: function(interval, callback, param) {
return window.setTimeout(function() {
- FUNCTION_TABLE[callback](interval, param);
+ Runtime.dynCall('ii', callback, [interval, param]);
}, interval);
},
SDL_RemoveTimer: function(id) {
diff --git a/src/long.js b/src/long.js
index d5770e48..865540db 100644
--- a/src/long.js
+++ b/src/long.js
@@ -1530,27 +1530,26 @@ var i64Math = (function() { // Emscripten wrapper
// Emscripten wrapper
var Wrapper = {
- result: [0, 0], // return result stored here
add: function(xl, xh, yl, yh) {
var x = new goog.math.Long(xl, xh);
var y = new goog.math.Long(yl, yh);
var ret = x.add(y);
- Wrapper.result[0] = ret.low_;
- Wrapper.result[1] = ret.high_;
+ HEAP32[tempDoublePtr>>2] = ret.low_;
+ HEAP32[tempDoublePtr+4>>2] = ret.high_;
},
subtract: function(xl, xh, yl, yh) {
var x = new goog.math.Long(xl, xh);
var y = new goog.math.Long(yl, yh);
var ret = x.subtract(y);
- Wrapper.result[0] = ret.low_;
- Wrapper.result[1] = ret.high_;
+ HEAP32[tempDoublePtr>>2] = ret.low_;
+ HEAP32[tempDoublePtr+4>>2] = ret.high_;
},
multiply: function(xl, xh, yl, yh) {
var x = new goog.math.Long(xl, xh);
var y = new goog.math.Long(yl, yh);
var ret = x.multiply(y);
- Wrapper.result[0] = ret.low_;
- Wrapper.result[1] = ret.high_;
+ HEAP32[tempDoublePtr>>2] = ret.low_;
+ HEAP32[tempDoublePtr+4>>2] = ret.high_;
},
makeTwo32: function() {
Wrapper.two32 = new BigInteger();
@@ -1573,8 +1572,8 @@ var i64Math = (function() { // Emscripten wrapper
var x = new goog.math.Long(xl, xh);
var y = new goog.math.Long(yl, yh);
var ret = x.div(y);
- Wrapper.result[0] = ret.low_;
- Wrapper.result[1] = ret.high_;
+ HEAP32[tempDoublePtr>>2] = ret.low_;
+ HEAP32[tempDoublePtr+4>>2] = ret.high_;
} else {
// slow precise bignum division
var x = Wrapper.lh2bignum(xl >>> 0, xh >>> 0);
@@ -1584,8 +1583,8 @@ var i64Math = (function() { // Emscripten wrapper
var l = new BigInteger();
var h = new BigInteger();
z.divRemTo(Wrapper.two32, h, l);
- Wrapper.result[0] = parseInt(l.toString()) | 0;
- Wrapper.result[1] = parseInt(h.toString()) | 0;
+ HEAP32[tempDoublePtr>>2] = parseInt(l.toString()) | 0;
+ HEAP32[tempDoublePtr+4>>2] = parseInt(h.toString()) | 0;
}
},
modulo: function(xl, xh, yl, yh, unsigned) {
@@ -1594,8 +1593,8 @@ var i64Math = (function() { // Emscripten wrapper
var x = new goog.math.Long(xl, xh);
var y = new goog.math.Long(yl, yh);
var ret = x.modulo(y);
- Wrapper.result[0] = ret.low_;
- Wrapper.result[1] = ret.high_;
+ HEAP32[tempDoublePtr>>2] = ret.low_;
+ HEAP32[tempDoublePtr+4>>2] = ret.high_;
} else {
// slow precise bignum division
var x = Wrapper.lh2bignum(xl >>> 0, xh >>> 0);
@@ -1605,8 +1604,8 @@ var i64Math = (function() { // Emscripten wrapper
var l = new BigInteger();
var h = new BigInteger();
z.divRemTo(Wrapper.two32, h, l);
- Wrapper.result[0] = parseInt(l.toString()) | 0;
- Wrapper.result[1] = parseInt(h.toString()) | 0;
+ HEAP32[tempDoublePtr>>2] = parseInt(l.toString()) | 0;
+ HEAP32[tempDoublePtr+4>>2] = parseInt(h.toString()) | 0;
}
},
stringify: function(l, h, unsigned) {
diff --git a/src/modules.js b/src/modules.js
index fd0ec35e..5c1d6a1d 100644
--- a/src/modules.js
+++ b/src/modules.js
@@ -216,14 +216,26 @@ var Types = {
};
var Functions = {
- // All functions that will be implemented in this file
+ // All functions that will be implemented in this file. Maps id to signature
implementedFunctions: {},
+ libraryFunctions: {}, // functions added from the library
+ unimplementedFunctions: {}, // library etc. functions that we need to index, maps id to signature
indexedFunctions: {},
nextIndex: 2, // Start at a non-0 (even, see below) value
blockAddresses: {}, // maps functions to a map of block labels to label ids
+ getSignature: function(returnType, argTypes) {
+ var sig = returnType == 'void' ? 'v' : (isIntImplemented(returnType) ? 'i' : 'f');
+ for (var i = 0; i < argTypes.length; i++) {
+ var type = argTypes[i];
+ if (!type) break; // varargs
+ sig += isIntImplemented(type) ? (getBits(type) == 64 ? 'ii' : 'i') : 'f'; // legalized i64s will be i32s
+ }
+ return sig;
+ },
+
// Mark a function as needing indexing. Python will coordinate them all
getIndex: function(ident) {
if (phase != 'post') {
@@ -240,27 +252,53 @@ var Functions = {
}
},
+ getTable: function(sig) {
+ return ASM_JS ? 'FUNCTION_TABLE_' + sig : 'FUNCTION_TABLE';
+ },
+
// Generate code for function indexing
generateIndexing: function() {
- var vals = zeros(this.nextIndex);
+ var total = this.nextIndex;
+ if (ASM_JS) total = ceilPowerOfTwo(total); // must be power of 2 for mask
+ function emptyTable(sig) {
+ return zeros(total);
+ }
+ var tables = {};
+ 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
+ });
+ }
for (var ident in this.indexedFunctions) {
- vals[this.indexedFunctions[ident]] = ident;
+ var sig = ASM_JS ? Functions.implementedFunctions[ident] || Functions.unimplementedFunctions[ident] : 'x';
+ assert(sig, ident);
+ if (!tables[sig]) tables[sig] = emptyTable(sig); // TODO: make them compact
+ tables[sig][this.indexedFunctions[ident]] = ident;
}
// Resolve multi-level aliases all the way down
- for (var i = 0; i < vals.length; i++) {
- while (1) {
- var varData = Variables.globals[vals[i]];
- if (!(varData && varData.resolvedAlias)) break;
- vals[i] = vals[+varData.resolvedAlias || eval(varData.resolvedAlias)]; // might need to eval to turn (6) into 6
+ var generated = false;
+ for (var t in tables) {
+ generated = true;
+ var table = tables[t];
+ for (var i = 0; i < table.length; i++) {
+ while (1) {
+ var varData = Variables.globals[table[i]];
+ if (!(varData && varData.resolvedAlias)) break;
+ table[i] = table[+varData.resolvedAlias || eval(varData.resolvedAlias)]; // might need to eval to turn (6) into 6
+ }
+ }
+ var indices = table.toString().replace('"', '');
+ if (BUILD_AS_SHARED_LIB) {
+ // Shared libraries reuse the parent's function table.
+ tables[t] = Functions.getTable(t) + '.push.apply(' + Functions.getTable(t) + ', [' + indices + ']);\n';
+ } else {
+ tables[t] = 'var ' + Functions.getTable(t) + ' = [' + indices + '];\n';
}
}
- var indices = vals.toString().replace('"', '');
- if (BUILD_AS_SHARED_LIB) {
- // Shared libraries reuse the parent's function table.
- return 'FUNCTION_TABLE.push.apply(FUNCTION_TABLE, [' + indices + ']);';
- } else {
- return 'FUNCTION_TABLE = [' + indices + ']; Module["FUNCTION_TABLE"] = FUNCTION_TABLE;';
+ if (!generated && !ASM_JS) {
+ tables['x'] = 'var FUNCTION_TABLE = [0, 0];\n'; // default empty table
}
+ Functions.tables = tables;
}
};
@@ -311,16 +349,23 @@ var PassManager = {
print('\n//FORWARDED_DATA:' + JSON.stringify({
Types: Types,
Variables: Variables,
- Functions: Functions
+ Functions: Functions,
+ EXPORTED_FUNCTIONS: EXPORTED_FUNCTIONS // needed for asm.js global constructors (ctors)
}));
} else if (phase == 'funcs') {
print('\n//FORWARDED_DATA:' + JSON.stringify({
Types: { preciseI64MathUsed: Types.preciseI64MathUsed },
Functions: {
blockAddresses: Functions.blockAddresses,
- indexedFunctions: Functions.indexedFunctions
+ indexedFunctions: Functions.indexedFunctions,
+ implementedFunctions: ASM_JS ? Functions.implementedFunctions : [],
+ unimplementedFunctions: Functions.unimplementedFunctions,
}
}));
+ } else if (phase == 'post') {
+ print('\n//FORWARDED_DATA:' + JSON.stringify({
+ Functions: { tables: Functions.tables }
+ }));
}
},
load: function(json) {
diff --git a/src/parseTools.js b/src/parseTools.js
index b2093da3..1ef09f49 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -128,16 +128,48 @@ function isStructType(type) {
return type[0] == '%';
}
+function isStructuralType(type) {
+ return /^{ ?[^}]* ?}$/.test(type); // { i32, i8 } etc. - anonymous struct types
+}
+
+function getStructuralTypeParts(type) { // split { i32, i8 } etc. into parts
+ return type.replace(/[ {}]/g, '').split(',');
+}
+
+function getStructureTypeParts(type) {
+ if (isStructuralType(type)) {
+ return type.replace(/[ {}]/g, '').split(',');
+ } else {
+ var typeData = Types.types[type];
+ assert(typeData, type);
+ return typeData.fields;
+ }
+}
+
+function getStructuralTypePartBits(part) {
+ return Math.ceil((getBits(part) || 32)/32)*32; // simple 32-bit alignment. || 32 is for pointers
+}
+
function isIntImplemented(type) {
return type[0] == 'i' || isPointerType(type);
}
-// Note: works for iX types, not pointers (even though they are implemented as ints)
+// Note: works for iX types and structure types, not pointers (even though they are implemented as ints)
function getBits(type) {
- if (!type || type[0] != 'i') return 0;
- var left = type.substr(1);
- if (!isNumber(left)) return 0;
- return parseInt(left);
+ if (!type) return 0;
+ if (type[0] == 'i') {
+ var left = type.substr(1);
+ if (!isNumber(left)) return 0;
+ return parseInt(left);
+ }
+ if (isStructuralType(type)) {
+ return sum(getStructuralTypeParts(type).map(getStructuralTypePartBits));
+ }
+ if (isStructType(type)) {
+ var typeData = Types.types[type];
+ return typeData.flatSize*8;
+ }
+ return 0;
}
function isIllegalType(type) {
@@ -163,11 +195,13 @@ function isFunctionDef(token, out) {
var subtext = segment[0].text;
fail = fail || segment.length > 1 || !(isType(subtext) || subtext == '...');
});
- if (out) out.numArgs = segments.length;
+ if (out) {
+ out.segments = segments;
+ out.numArgs = segments.length;
+ }
return !fail;
}
-
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;
@@ -189,6 +223,7 @@ function isFunctionType(type, out) {
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);
}
@@ -310,7 +345,9 @@ function parseParamTokens(params) {
if (segment.length == 1) {
if (segment[0].text == '...') {
ret.push({
- intertype: 'varargs'
+ intertype: 'varargs',
+ type: 'i8*',
+ ident: 'varrp' // the conventional name we have for this
});
} else {
// Clang sometimes has a parameter with just a type,
@@ -360,25 +397,31 @@ var UNINDEXABLE_GLOBALS = set(
'_llvm_global_ctors' // special-cased
);
-function noticePtr(ptr) {
- if (!NAMED_GLOBALS && !LibraryManager.loaded) UNINDEXABLE_GLOBALS[ptr] = 1; // we cannot index globals referred to in the library, since they are used there by name
-}
-
function isIndexableGlobal(ident) {
if (!(ident in Variables.globals)) return false;
if (ident in UNINDEXABLE_GLOBALS) return false;
var data = Variables.globals[ident];
- return !data.alias && !data.external;
+ // in asm.js, externals are just globals
+ return !data.alias && (ASM_JS || !data.external);
}
function makeGlobalDef(ident) {
if (!NAMED_GLOBALS && isIndexableGlobal(ident)) return '';
- return 'var ' + ident + ';'; // TODO: add option for namespacing or offsetting to allow reducing the number of globals
+ return 'var ' + ident + ';';
}
function makeGlobalUse(ident) {
- if (!NAMED_GLOBALS && isIndexableGlobal(ident)) return '(' + getFastValue('GLOBAL_BASE', '+', Variables.indexedGlobals[ident]) + ')';
- return ident; // TODO: add option for namespacing or offsetting to allow reducing the number of globals
+ if (!NAMED_GLOBALS && isIndexableGlobal(ident)) {
+ var index = Variables.indexedGlobals[ident];
+ if (index === undefined) {
+ // we are accessing this before we index globals, likely from the library. mark as unindexable
+ UNINDEXABLE_GLOBALS[ident] = 1;
+ return ident;
+ }
+ // We know and assert on TOTAL_STACK being equal to GLOBAL_BASE
+ return (TOTAL_STACK + index).toString();
+ }
+ return ident;
}
function sortGlobals(globals) {
@@ -922,6 +965,12 @@ function checkSafeHeap() {
return SAFE_HEAP === 1 || checkSpecificSafeHeap();
}
+if (ASM_JS) {
+ var hexMemoryMask = '0x' + (TOTAL_MEMORY-1).toString(16);
+ var decMemoryMask = (TOTAL_MEMORY-1).toString();
+ var memoryMask = hexMemoryMask.length <= decMemoryMask.length ? hexMemoryMask : decMemoryMask;
+}
+
function getHeapOffset(offset, type) {
if (USE_TYPED_ARRAYS !== 2) {
return offset;
@@ -930,17 +979,44 @@ function getHeapOffset(offset, type) {
type = 'i32'; // XXX we emulate 64-bit values as 32
}
var shifts = Math.log(Runtime.getNativeTypeSize(type))/Math.LN2;
+ offset = '(' + offset + ')';
+ if (ASM_JS && phase == 'funcs') offset = '(' + offset + '&' + memoryMask + ')';
if (shifts != 0) {
- return '((' + offset + ')>>' + (shifts) + ')';
+ return '(' + offset + '>>' + shifts + ')';
} else {
- return '(' + offset + ')';
+ return offset;
}
}
}
+function makeVarDef(js) {
+ if (!ASM_JS) js = 'var ' + js;
+ return js;
+}
+
+function asmInitializer(type, impl) {
+ if (isIntImplemented(type)) {// || (impl && impl == 'VAR_EMULATED')) {
+ return '0';
+ } else {
+ return '+0';
+ }
+}
+
+function asmCoercion(value, type) {
+ if (!ASM_JS) return value;
+ if (isIntImplemented(type)) {
+ return '((' + value + ')|0)';
+ } else {
+ return '(+(' + value + '))';
+ }
+}
+
+function makeGetTempDouble(i) {
+ return makeGetValue('tempDoublePtr', Runtime.getNativeTypeSize('i32')*i, 'i32');
+}
+
// See makeSetValue
function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSafe) {
- noticePtr(ptr);
if (UNALIGNED_MEMORY) align = 1;
if (isStructType(type)) {
var typeData = Types.types[type];
@@ -952,9 +1028,9 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSa
}
if (DOUBLE_MODE == 1 && USE_TYPED_ARRAYS == 2 && type == 'double') {
- return '(tempDoubleI32[0]=' + makeGetValue(ptr, pos, 'i32', noNeedFirst, unsigned, ignore, align) + ',' +
- 'tempDoubleI32[1]=' + makeGetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'i32', noNeedFirst, unsigned, ignore, align) + ',' +
- 'tempDoubleF64[0])';
+ return '(HEAP32[tempDoublePtr>>2]=' + makeGetValue(ptr, pos, 'i32', noNeedFirst, unsigned, ignore, align) + ',' +
+ 'HEAP32[tempDoublePtr+4>>2]=' + makeGetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'i32', noNeedFirst, unsigned, ignore, align) + ',' +
+ 'HEAPF64[tempDoublePtr>>3])';
}
if (USE_TYPED_ARRAYS == 2 && align) {
@@ -977,9 +1053,9 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSa
}
} else {
if (type == 'float') {
- ret += 'copyTempFloat(' + getFastValue(ptr, '+', pos) + '),tempDoubleF32[0]';
+ ret += 'copyTempFloat(' + getFastValue(ptr, '+', pos) + '),HEAPF32[tempDoublePtr>>2]';
} else {
- ret += 'copyTempDouble(' + getFastValue(ptr, '+', pos) + '),tempDoubleF64[0]';
+ ret += 'copyTempDouble(' + getFastValue(ptr, '+', pos) + '),HEAP64[tempDoublePtr>>3]';
}
}
ret += ')';
@@ -993,14 +1069,24 @@ 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 {
- return makeGetSlabs(ptr, type, false, unsigned)[0] + '[' + getHeapOffset(offset, type) + ']';
+ var ret = makeGetSlabs(ptr, type, false, unsigned)[0] + '[' + getHeapOffset(offset, type) + ']';
+ if (ASM_JS && phase == 'funcs') {
+ ret = asmCoercion(ret, type);
+ }
+ return ret;
}
}
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');
- if (type && isFunctionType(type) && value[0] === '_') { // checking for _ differentiates from $ (local vars)
+ var out = {};
+ if (type && isFunctionType(type, out) && value[0] === '_') { // checking for _ differentiates from $ (local vars)
+ // add signature to library functions that we now know need indexing
+ if (!(value in Functions.implementedFunctions) && !(value in Functions.unimplementedFunctions)) {
+ Functions.unimplementedFunctions[value] = Functions.getSignature(out.returnType, out.segments ? out.segments.map(function(segment) { return segment[0].text }) : []);
+ }
+
if (BUILD_AS_SHARED_LIB) {
return '(FUNCTION_TABLE_OFFSET + ' + Functions.getIndex(value) + ')';
} else {
@@ -1021,7 +1107,6 @@ function indexizeFunctions(value, type) {
//! which means we should write to all slabs, ignore type differences if any on reads, etc.
//! @param noNeedFirst Whether to ignore the offset in the pointer itself.
function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe, sep, forcedAlign) {
- noticePtr(ptr);
if (UNALIGNED_MEMORY && !forcedAlign) align = 1;
sep = sep || ';';
if (isStructType(type)) {
@@ -1039,9 +1124,9 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe,
}
if (DOUBLE_MODE == 1 && USE_TYPED_ARRAYS == 2 && type == 'double') {
- return '(tempDoubleF64[0]=' + value + ',' +
- makeSetValue(ptr, pos, 'tempDoubleI32[0]', 'i32', noNeedFirst, ignore, align, noSafe, ',') + ',' +
- makeSetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'tempDoubleI32[1]', 'i32', noNeedFirst, ignore, align, noSafe, ',') + ')';
+ return '(HEAPF64[tempDoublePtr>>3]=' + value + ',' +
+ makeSetValue(ptr, pos, 'HEAP32[tempDoublePtr>>2]', 'i32', noNeedFirst, ignore, align, noSafe, ',') + ',' +
+ makeSetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'HEAP32[tempDoublePtr+4>>2]', 'i32', noNeedFirst, ignore, align, noSafe, ',') + ')';
} else if (USE_TYPED_ARRAYS == 2 && type == 'i64') {
return '(tempI64 = [' + splitI64(value) + '],' +
makeSetValue(ptr, pos, 'tempI64[0]', 'i32', noNeedFirst, ignore, align, noSafe, ',') + ',' +
@@ -1093,7 +1178,6 @@ var SEEK_OPTIMAL_ALIGN_MIN = 20;
var UNROLL_LOOP_MAX = 8;
function makeSetValues(ptr, pos, value, type, num, align) {
- noticePtr(ptr);
function unroll(type, num, jump, value$) {
jump = jump || 1;
value$ = value$ || value;
@@ -1125,7 +1209,7 @@ function makeSetValues(ptr, pos, value, type, num, align) {
[4, 2, 1].forEach(function(possibleAlign) {
if (num == 0) return;
if (align >= possibleAlign) {
- if (num <= UNROLL_LOOP_MAX*possibleAlign) {
+ if (num <= UNROLL_LOOP_MAX*possibleAlign || ASM_JS) { // XXX test asm performance
ret.push(unroll('i' + (possibleAlign*8), Math.floor(num/possibleAlign), possibleAlign, values[possibleAlign]));
} else {
ret.push('for (var $$dest = ' + getFastValue(ptr, '+', pos) + (possibleAlign > 1 ? '>>' + log2(possibleAlign) : '') + ', ' +
@@ -1143,8 +1227,6 @@ function makeSetValues(ptr, pos, value, type, num, align) {
var TYPED_ARRAY_SET_MIN = Infinity; // .set() as memcpy seems to just slow us down
function makeCopyValues(dest, src, num, type, modifier, align, sep) {
- noticePtr(dest);
- noticePtr(src);
sep = sep || ';';
function unroll(type, num, jump) {
jump = jump || 1;
@@ -1179,7 +1261,7 @@ function makeCopyValues(dest, src, num, type, modifier, align, sep) {
if (num == 0) return;
if (align >= possibleAlign) {
// If we can unroll the loop, do so. Also do so if we must unroll it (we do not create real loops when inlined)
- if (num <= UNROLL_LOOP_MAX*possibleAlign || sep == ',') {
+ if (num <= UNROLL_LOOP_MAX*possibleAlign || sep == ',' || ASM_JS) { // XXX test asm performance
ret.push(unroll('i' + (possibleAlign*8), Math.floor(num/possibleAlign), possibleAlign));
} else {
assert(sep == ';');
@@ -1509,8 +1591,35 @@ function handleOverflow(text, bits) {
}
}
-function makeLLVMStruct(values) { // TODO: Use this everywhere
- return '{ ' + values.map(function(value, i) { return 'f' + i + ': ' + value }).join(', ') + ' }'
+function makeLLVMStruct(values) {
+ if (USE_TYPED_ARRAYS == 2) {
+ return 'DEPRECATED' + (new Error().stack) + 'XXX';
+ } else {
+ return '{ ' + values.map(function(value, i) { return 'f' + i + ': ' + value }).join(', ') + ' }'
+ }
+}
+
+function makeStructuralReturn(values) {
+ if (USE_TYPED_ARRAYS == 2) {
+ var i = 0;
+ return 'return (' + values.slice(1).map(function(value) {
+ return ASM_JS ? 'asm.setTempRet' + (i++) + '(' + value + ')'
+ : 'tempRet' + (i++) + ' = ' + value;
+ }).concat([values[0]]).join(',') + ')';
+ } else {
+ var i = 0;
+ return 'return { ' + values.map(function(value) {
+ return 'f' + (i++) + ': ' + value;
+ }).join(', ') + ' }';
+ }
+}
+
+function makeStructuralAccess(ident, i) {
+ if (USE_TYPED_ARRAYS == 2) {
+ return ident + '$' + i;
+ } else {
+ return ident + '.f' + i;
+ }
}
// From parseLLVMSegment
@@ -1619,30 +1728,36 @@ function makeSignOp(value, type, op, force, ignore) {
function makeRounding(value, bits, signed, floatConversion) {
// TODO: handle roundings of i64s
assert(bits);
- // C rounds to 0 (-5.5 to -5, +5.5 to 5), while JS has no direct way to do that.
- if (bits <= 32 && signed) return '((' + value + ')&-1)'; // This is fast and even correct, for all cases. Note that it is the same
- // as |0, but &-1 hints to the js optimizer that this is a rounding correction
- // Do Math.floor, which is reasonably fast, if we either don't care, or if we can be sure
- // the value is non-negative
- if (!correctRoundings() || (!signed && !floatConversion)) return 'Math.floor(' + value + ')';
- // We are left with >32 bits signed, or a float conversion. Check and correct inline
- // Note that if converting a float, we may have the wrong sign at this point! But, we have
- // been rounded properly regardless, and we will be sign-corrected later when actually used, if
- // necessary.
- return makeInlineCalculation('VALUE >= 0 ? Math.floor(VALUE) : Math.ceil(VALUE)', value, 'tempBigIntR');
-/* refactored version - needs perf testing TODO
- if (bits <= 32) {
- if (signed) {
- return '((' + value + ')&-1)'; // &-1 (instead of |0) hints to the js optimizer that this is a rounding correction
- } else {
- return '((' + value + ')>>>0)';
+ if (!ASM_JS) {
+ // C rounds to 0 (-5.5 to -5, +5.5 to 5), while JS has no direct way to do that.
+ if (bits <= 32 && signed) return '((' + value + ')&-1)'; // This is fast and even correct, for all cases. Note that it is the same
+ // as |0, but &-1 hints to the js optimizer that this is a rounding correction
+ // Do Math.floor, which is reasonably fast, if we either don't care, or if we can be sure
+ // the value is non-negative
+ if (!correctRoundings() || (!signed && !floatConversion)) return 'Math.floor(' + value + ')';
+ // We are left with >32 bits signed, or a float conversion. Check and correct inline
+ // Note that if converting a float, we may have the wrong sign at this point! But, we have
+ // been rounded properly regardless, and we will be sign-corrected later when actually used, if
+ // necessary.
+ return makeInlineCalculation('VALUE >= 0 ? Math.floor(VALUE) : Math.ceil(VALUE)', value, 'tempBigIntR');
+ } else {
+ // asm.js mode, cleaner refactoring of this function as well. TODO: use in non-asm case, most of this
+ if (floatConversion && bits <= 32) {
+ return '(~~(' + value + '))'; // explicit float-to-int conversion
+ }
+
+ if (bits <= 32) {
+ if (signed) {
+ return '((' + value + ')&-1)'; // &-1 (instead of |0) hints to the js optimizer that this is a rounding correction
+ } else {
+ return '((' + value + ')>>>0)';
+ }
}
+ // Math.floor is reasonably fast if we don't care about corrections (and even correct if unsigned)
+ if (!correctRoundings() || !signed) return 'Math.floor(' + value + ')';
+ // We are left with >32 bits
+ return makeInlineCalculation('VALUE >= 0 ? Math.floor(VALUE) : Math.ceil(VALUE)', value, 'tempBigIntR');
}
- // Math.floor is reasonably fast if we don't care about corrections (and even correct if unsigned)
- if (!correctRoundings() || !signed) return 'Math.floor(' + value + ')';
- // We are left with >32 bits
- return makeInlineCalculation('VALUE >= 0 ? Math.floor(VALUE) : Math.ceil(VALUE)', value, 'tempBigIntR');
-*/
}
// fptoui and fptosi are not in these, because we need to be careful about what we do there. We can't
@@ -1716,8 +1831,8 @@ function processMathop(item) {
}
function i64PreciseOp(type, lastArg) {
Types.preciseI64MathUsed = true;
- return finish(['(i64Math.' + type + '(' + low1 + ',' + high1 + ',' + low2 + ',' + high2 +
- (lastArg ? ',' + lastArg : '') + '),i64Math.result[0])', 'i64Math.result[1]']);
+ return finish(['(i64Math' + (ASM_JS ? '_' : '.') + type + '(' + low1 + ',' + high1 + ',' + low2 + ',' + high2 +
+ (lastArg ? ',' + lastArg : '') + '),' + makeGetValue('tempDoublePtr', 0, 'i32') + ')', makeGetValue('tempDoublePtr', Runtime.getNativeTypeSize('i32'), 'i32')]);
}
switch (op) {
// basic integer ops
@@ -1734,7 +1849,8 @@ function processMathop(item) {
case 'ashr':
case 'lshr': {
if (!isNumber(idents[1])) {
- return 'Runtime.bitshift64(' + idents[0] + '[0], ' + idents[0] + '[1],"' + op + '",' + stripCorrections(idents[1]) + '[0]|0)';
+ return '(Runtime' + (ASM_JS ? '_' : '.') + 'bitshift64(' + idents[0] + '[0], ' + idents[0] + '[1],"' + op + '",' + stripCorrections(idents[1]) + '[0]|0),' +
+ '[' + makeGetTempDouble(0) + ',' + makeGetTempDouble(1) + '])';
}
bits = parseInt(idents[1]);
var ander = Math.pow(2, bits)-1;
@@ -1851,15 +1967,15 @@ function processMathop(item) {
var outType = item.type;
if (inType in Runtime.INT_TYPES && outType in Runtime.FLOAT_TYPES) {
if (legalizedI64s) {
- return '(tempDoubleI32[0]=' + idents[0] + '$0, tempDoubleI32[1]=' + idents[0] + '$1, tempDoubleF64[0])';
+ return '(HEAP32[tempDoublePtr>>2]=' + idents[0] + '$0, HEAP32[tempDoublePtr+4>>2]=' + idents[0] + '$1, HEAPF64[tempDoublePtr>>3])';
} else {
- return makeInlineCalculation('tempDoubleI32[0]=VALUE[0],tempDoubleI32[1]=VALUE[1],tempDoubleF64[0]', idents[0], 'tempI64');
+ return makeInlineCalculation('HEAP32[tempDoublePtr>>2]=VALUE[0],HEAP32[tempDoublePtr+4>>2]=VALUE[1],HEAPF64[tempDoublePtr>>>3]', idents[0], 'tempI64');
}
} else if (inType in Runtime.FLOAT_TYPES && outType in Runtime.INT_TYPES) {
if (legalizedI64s) {
- return 'tempDoubleF64[0]=' + idents[0] + '; ' + finish(['tempDoubleI32[0]','tempDoubleI32[1]']);
+ return 'HEAPF64[tempDoublePtr>>3]=' + idents[0] + '; ' + finish(['HEAP32[tempDoublePtr>>2]','HEAP32[tempDoublePtr+4>>2]']);
} else {
- return '(tempDoubleF64[0]=' + idents[0] + ',[tempDoubleI32[0],tempDoubleI32[1]])';
+ return '(HEAPF64[tempDoublePtr>>3]=' + idents[0] + ',[HEAP32[tempDoublePtr>>2],HEAP32[tempDoublePtr+4>>2]])';
}
} else {
throw 'Invalid USE_TYPED_ARRAYS == 2 bitcast: ' + dump(item) + ' : ' + item.params[0].type;
@@ -1877,8 +1993,16 @@ function processMathop(item) {
case 'mul': {
if (bits == 32 && PRECISE_I32_MUL) {
Types.preciseI64MathUsed = true;
- return '(i64Math.multiply(' + idents[0] + ',0,' + idents[1] + ',0),i64Math.result[0])';
+ return '(i64Math' + (ASM_JS ? '_' : '.') + 'multiply(' + idents[0] + ',0,' + idents[1] + ',0),' + makeGetValue('tempDoublePtr', 0, 'i32') + ')';
} else {
+ if (ASM_JS) {
+ // special-case: there is no integer multiply in asm, because there is no true integer
+ // multiply in JS. While we wait for Math.imul, do double multiply
+ if (USE_MATH_IMUL) {
+ return 'Math.imul(' + idents[0] + ',' + idents[1] + ')';
+ }
+ return '(~~(+' + idents[0] + ' * +' + idents[1] + '))';
+ }
return handleOverflow(getFastValue(idents[0], '*', idents[1], item.type), bits);
}
}
@@ -1927,7 +2051,7 @@ function processMathop(item) {
case 'fdiv': return getFastValue(idents[0], '/', idents[1], item.type);
case 'fmul': return getFastValue(idents[0], '*', idents[1], item.type);
case 'frem': return getFastValue(idents[0], '%', idents[1], item.type);
- case 'uitofp': case 'sitofp': return idents[0];
+ case 'uitofp': case 'sitofp': return asmCoercion(idents[0], 'double');
case 'fptoui': case 'fptosi': return makeRounding(idents[0], bitsLeft, op === 'fptosi', true);
// TODO: We sometimes generate false instead of 0, etc., in the *cmps. It seemed slightly faster before, but worth rechecking
@@ -1998,9 +2122,9 @@ function processMathop(item) {
(inType in Runtime.FLOAT_TYPES && outType in Runtime.INT_TYPES)) {
assert(USE_TYPED_ARRAYS == 2, 'Can only bitcast ints <-> floats with typed arrays mode 2');
if (inType in Runtime.INT_TYPES) {
- return '(tempDoubleI32[0] = ' + idents[0] + ',tempDoubleF32[0])';
+ return '(HEAP32[tempDoublePtr>>2] = ' + idents[0] + ',HEAPF32[tempDoublePtr>>2])';
} else {
- return '(tempDoubleF32[0] = ' + idents[0] + ',tempDoubleI32[0])';
+ return '(HEAPF32[tempDoublePtr>>2] = ' + idents[0] + ',HEAP32[tempDoublePtr>>2])';
}
}
return idents[0];
diff --git a/src/postamble.js b/src/postamble.js
index 144b5af9..83a4daa6 100644
--- a/src/postamble.js
+++ b/src/postamble.js
@@ -19,11 +19,11 @@ Module.callMain = function callMain(args) {
#if CATCH_EXIT_CODE
try {
- return _main(argc, argv, 0);
+ return Module['_main'](argc, argv, 0);
}
catch(e) { if (e.name == "ExitStatus") return e.status; throw e; }
#else
- return _main(argc, argv, 0);
+ return Module['_main'](argc, argv, 0);
#endif
}
diff --git a/src/preamble.js b/src/preamble.js
index 0917f977..e24c2957 100644
--- a/src/preamble.js
+++ b/src/preamble.js
@@ -275,7 +275,7 @@ Module['printProfiling'] = printProfiling;
// Runtime essentials
//========================================
-var __THREW__ = false; // Used in checking for thrown exceptions.
+var __THREW__ = 0; // Used in checking for thrown exceptions.
var setjmpId = 1; // Used in setjmp/longjmp
var setjmpLabels = {};
@@ -287,6 +287,7 @@ var undef = 0;
var tempValue, tempInt, tempBigInt, tempInt2, tempBigInt2, tempPair, tempBigIntI, tempBigIntR, tempBigIntS, tempBigIntP, tempBigIntD;
#if USE_TYPED_ARRAYS == 2
var tempI64, tempI64b;
+var tempRet0, tempRet1, tempRet2, tempRet3, tempRet4, tempRet5, tempRet6, tempRet7, tempRet8, tempRet9;
#endif
function abort(text) {
@@ -577,9 +578,6 @@ Module['Array_stringify'] = Array_stringify;
// Memory management
-var FUNCTION_TABLE; // XXX: In theory the indexes here can be equal to pointers to stacked or malloced memory. Such comparisons should
- // be false, but can turn out true. We should probably set the top bit to prevent such issues.
-
var PAGE_SIZE = 4096;
function alignMemoryPage(x) {
return ((x+4095)>>12)<<12;
@@ -699,47 +697,47 @@ Module['HEAPF64'] = HEAPF64;
#endif
STACK_ROOT = STACKTOP = Runtime.alignMemory(1);
-STACK_MAX = STACK_ROOT + TOTAL_STACK;
+STACK_MAX = TOTAL_STACK; // we lose a little stack here, but TOTAL_STACK is nice and round so use that as the max
#if USE_TYPED_ARRAYS == 2
-var tempDoublePtr = Runtime.alignMemory(STACK_MAX, 8);
-var tempDoubleI8 = HEAP8.subarray(tempDoublePtr);
-var tempDoubleI32 = HEAP32.subarray(tempDoublePtr >> 2);
-var tempDoubleF32 = HEAPF32.subarray(tempDoublePtr >> 2);
-var tempDoubleF64 = HEAPF64.subarray(tempDoublePtr >> 3);
+var tempDoublePtr = Runtime.alignMemory(allocate(12, 'i8', ALLOC_STACK), 8);
+assert(tempDoublePtr % 8 == 0);
function copyTempFloat(ptr) { // functions, because inlining this code is increases code size too much
- tempDoubleI8[0] = HEAP8[ptr];
- tempDoubleI8[1] = HEAP8[ptr+1];
- tempDoubleI8[2] = HEAP8[ptr+2];
- tempDoubleI8[3] = HEAP8[ptr+3];
+ HEAP8[tempDoublePtr] = HEAP8[ptr];
+ HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
+ HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
+ HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
}
function copyTempDouble(ptr) {
- tempDoubleI8[0] = HEAP8[ptr];
- tempDoubleI8[1] = HEAP8[ptr+1];
- tempDoubleI8[2] = HEAP8[ptr+2];
- tempDoubleI8[3] = HEAP8[ptr+3];
- tempDoubleI8[4] = HEAP8[ptr+4];
- tempDoubleI8[5] = HEAP8[ptr+5];
- tempDoubleI8[6] = HEAP8[ptr+6];
- tempDoubleI8[7] = HEAP8[ptr+7];
+ HEAP8[tempDoublePtr] = HEAP8[ptr];
+ HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
+ HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
+ HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
+ HEAP8[tempDoublePtr+4] = HEAP8[ptr+4];
+ HEAP8[tempDoublePtr+5] = HEAP8[ptr+5];
+ HEAP8[tempDoublePtr+6] = HEAP8[ptr+6];
+ HEAP8[tempDoublePtr+7] = HEAP8[ptr+7];
}
-STACK_MAX = tempDoublePtr + 8;
#endif
-STATICTOP = alignMemoryPage(STACK_MAX);
-
+STATICTOP = STACK_MAX;
assert(STATICTOP < TOTAL_MEMORY); // Stack must fit in TOTAL_MEMORY; allocations from here on may enlarge TOTAL_MEMORY
-var nullString = allocate(intArrayFromString('(null)'), 'i8', ALLOC_STATIC);
+var nullString = allocate(intArrayFromString('(null)'), 'i8', ALLOC_STACK);
function callRuntimeCallbacks(callbacks) {
while(callbacks.length > 0) {
var callback = callbacks.shift();
var func = callback.func;
if (typeof func === 'number') {
- func = FUNCTION_TABLE[func];
+ if (callback.arg === undefined) {
+ Runtime.dynCall('v', func);
+ } else {
+ Runtime.dynCall('vi', func, [callback.arg]);
+ }
+ } else {
+ func(callback.arg === undefined ? null : callback.arg);
}
- func(callback.arg === undefined ? null : callback.arg);
}
}
diff --git a/src/runtime.js b/src/runtime.js
index dd14e779..9d5e5e1f 100644
--- a/src/runtime.js
+++ b/src/runtime.js
@@ -13,7 +13,7 @@ var RuntimeGenerator = {
if (init) {
ret += sep + '_memset(' + type + 'TOP, 0, ' + size + ')';
}
- ret += sep + type + 'TOP += ' + size;
+ ret += sep + type + 'TOP = (' + type + 'TOP + ' + size + ')|0';
if ({{{ QUANTUM_SIZE }}} > 1 && !ignoreAlign) {
ret += sep + RuntimeGenerator.alignMemory(type + 'TOP', {{{ QUANTUM_SIZE }}});
}
@@ -23,27 +23,27 @@ var RuntimeGenerator = {
// An allocation that lives as long as the current function call
stackAlloc: function(size, sep) {
sep = sep || ';';
- if (USE_TYPED_ARRAYS === 2) 'STACKTOP += STACKTOP % ' + ({{{ QUANTUM_SIZE }}} - (isNumber(size) ? Math.min(size, {{{ QUANTUM_SIZE }}}) : {{{ QUANTUM_SIZE }}})) + sep;
+ if (USE_TYPED_ARRAYS === 2) 'STACKTOP = (STACKTOP + STACKTOP|0 % ' + ({{{ QUANTUM_SIZE }}} - (isNumber(size) ? Math.min(size, {{{ QUANTUM_SIZE }}}) : {{{ QUANTUM_SIZE }}})) + ')' + sep;
// The stack is always QUANTUM SIZE aligned, so we may not need to force alignment here
var ret = RuntimeGenerator.alloc(size, 'STACK', INIT_STACK, sep, USE_TYPED_ARRAYS != 2 || (isNumber(size) && parseInt(size) % {{{ QUANTUM_SIZE }}} == 0));
if (ASSERTIONS) {
- ret += sep + 'assert(STACKTOP < STACK_ROOT + STACK_MAX, "Ran out of stack")';
+ ret += sep + 'assert(STACKTOP|0 < STACK_MAX|0)';
}
return ret;
},
stackEnter: function(initial, force) {
if (initial === 0 && SKIP_STACK_IN_SMALL && !force) return '';
- var ret = 'var __stackBase__ = STACKTOP';
- if (initial > 0) ret += '; STACKTOP += ' + initial;
+ var ret = 'var __stackBase__ = ' + (ASM_JS ? '0; __stackBase__ = ' : '') + 'STACKTOP';
+ if (initial > 0) ret += '; STACKTOP = (STACKTOP + ' + initial + ')|0';
if (USE_TYPED_ARRAYS == 2) {
assert(initial % QUANTUM_SIZE == 0);
if (ASSERTIONS) {
- ret += '; assert(STACKTOP % {{{ QUANTUM_SIZE }}} == 0, "Stack is unaligned")';
+ ret += '; assert(STACKTOP|0 % {{{ QUANTUM_SIZE }}} == 0)';
}
}
if (ASSERTIONS) {
- ret += '; assert(STACKTOP < STACK_MAX, "Ran out of stack")';
+ ret += '; assert(STACKTOP < STACK_MAX)';
}
if (INIT_STACK) {
ret += '; _memset(__stackBase__, 0, ' + initial + ')';
@@ -124,36 +124,50 @@ var Runtime = {
// Mirrors processMathop's treatment of constants (which we optimize directly)
bitshift64: function(low, high, op, bits) {
+ var ret;
var ander = Math.pow(2, bits)-1;
if (bits < 32) {
switch (op) {
case 'shl':
- return [low << bits, (high << bits) | ((low&(ander << (32 - bits))) >>> (32 - bits))];
+ ret = [low << bits, (high << bits) | ((low&(ander << (32 - bits))) >>> (32 - bits))];
+ break;
case 'ashr':
- return [(((low >>> bits ) | ((high&ander) << (32 - bits))) >> 0) >>> 0, (high >> bits) >>> 0];
+ ret = [(((low >>> bits ) | ((high&ander) << (32 - bits))) >> 0) >>> 0, (high >> bits) >>> 0];
+ break;
case 'lshr':
- return [((low >>> bits) | ((high&ander) << (32 - bits))) >>> 0, high >>> bits];
+ ret = [((low >>> bits) | ((high&ander) << (32 - bits))) >>> 0, high >>> bits];
+ break;
}
} else if (bits == 32) {
switch (op) {
case 'shl':
- return [0, low];
+ ret = [0, low];
+ break;
case 'ashr':
- return [high, (high|0) < 0 ? ander : 0];
+ ret = [high, (high|0) < 0 ? ander : 0];
+ break;
case 'lshr':
- return [high, 0];
+ ret = [high, 0];
+ break;
}
} else { // bits > 32
switch (op) {
case 'shl':
- return [0, low << (bits - 32)];
+ ret = [0, low << (bits - 32)];
+ break;
case 'ashr':
- return [(high >> (bits - 32)) >>> 0, (high|0) < 0 ? ander : 0];
+ ret = [(high >> (bits - 32)) >>> 0, (high|0) < 0 ? ander : 0];
+ break;
case 'lshr':
- return [high >>> (bits - 32) , 0];
+ ret = [high >>> (bits - 32) , 0];
+ break;
}
}
- abort('unknown bitshift64 op: ' + [value, op, bits]);
+#if ASSERTIONS
+ assert(ret);
+#endif
+ HEAP32[tempDoublePtr>>2] = ret[0]; // cannot use utility functions since we are in runtime itself
+ HEAP32[tempDoublePtr+4>>2] = ret[1];
},
// Imprecise bitops utilities
@@ -311,10 +325,35 @@ var Runtime = {
return ret;
},
- addFunction: function(func) {
- var ret = FUNCTION_TABLE.length;
- FUNCTION_TABLE.push(func);
- FUNCTION_TABLE.push(0);
+ dynCall: function(sig, ptr, args) {
+ if (args && args.length) {
+#if ASSERTIONS
+ assert(args.length == sig.length-1);
+#endif
+#if ASM_JS
+ args.splice(0, 0, ptr);
+ return Module['dynCall_' + sig].apply(null, args);
+#else
+ return FUNCTION_TABLE[ptr].apply(null, args);
+#endif
+ } else {
+#if ASSERTIONS
+ assert(sig.length == 1);
+#endif
+#if ASM_JS
+ return Module['dynCall_' + sig].call(null, ptr);
+#else
+ return FUNCTION_TABLE[ptr]();
+#endif
+ }
+ },
+
+ addFunction: function(func, sig) {
+ assert(sig);
+ var table = FUNCTION_TABLE; // TODO: support asm
+ var ret = table.length;
+ table.push(func);
+ table.push(0);
return ret;
},
@@ -328,10 +367,11 @@ var Runtime = {
funcWrappers: {},
- getFuncWrapper: function(func) {
+ getFuncWrapper: function(func, sig) {
+ assert(sig);
if (!Runtime.funcWrappers[func]) {
Runtime.funcWrappers[func] = function() {
- FUNCTION_TABLE[func].apply(null, arguments);
+ Runtime.dynCall(sig, func, arguments);
};
}
return Runtime.funcWrappers[func];
diff --git a/src/settings.js b/src/settings.js
index 1d8805a8..af2e8082 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -43,7 +43,7 @@ var TOTAL_STACK = 5*1024*1024; // The total stack size. There is no way to enlar
// value must be large enough for the program's requirements. If
// assertions are on, we will assert on not exceeding this, otherwise,
// it will fail silently.
-var TOTAL_MEMORY = 10*1024*1024; // The total amount of memory to use. Using more memory than this will
+var TOTAL_MEMORY = 16777216; // The total amount of memory to use. Using more memory than this will
// cause us to expand the heap, which can be costly with typed arrays:
// we need to copy the old heap into a new one in that case.
var FAST_MEMORY = 2*1024*1024; // The amount of memory to initialize to 0. This ensures it will be
@@ -194,7 +194,7 @@ var PGO = 0; // Profile-guided optimization.
// All CORRECT_* options default to 1 with PGO builds.
// See https://github.com/kripken/emscripten/wiki/Optimizing-Code for more info
-var NAMED_GLOBALS = 1; // If 1, we use global variables for globals. Otherwise
+var NAMED_GLOBALS = 0; // If 1, we use global variables for globals. Otherwise
// they are referred to by a base plus an offset (called an indexed global),
// saving global variables but adding runtime overhead.
@@ -294,6 +294,9 @@ var HEADLESS = 0; // If 1, will include shim code that tries to 'fake' a browser
// very partial - it is hard to fake a whole browser! - so
// keep your expectations low for this to work.
+var ASM_JS = 0; // If 1, generate code in asm.js format
+var USE_MATH_IMUL = 0; // If 1, use Math.imul when useful
+
var NECESSARY_BLOCKADDRS = []; // List of (function, block) for all block addresses that are taken.
// Compiler debugging options
diff --git a/src/utility.js b/src/utility.js
index 84b50ce9..63582ae8 100644
--- a/src/utility.js
+++ b/src/utility.js
@@ -321,6 +321,12 @@ function isPowerOfTwo(x) {
return x > 0 && ((x & (x-1)) == 0);
}
+function ceilPowerOfTwo(x) {
+ var ret = 1;
+ while (ret < x) ret <<= 1;
+ return ret;
+}
+
function Benchmarker() {
var starts = {}, times = {}, counts = {};
this.start = function(id) {