aboutsummaryrefslogtreecommitdiff
path: root/src/jsifier.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/jsifier.js')
-rw-r--r--src/jsifier.js145
1 files changed, 107 insertions, 38 deletions
diff --git a/src/jsifier.js b/src/jsifier.js
index 50703b90..5e159ccf 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 {
@@ -279,6 +283,7 @@ function JSify(data, functionsOnly, givenFunctions) {
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)) {
@@ -333,7 +338,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 +382,6 @@ function JSify(data, functionsOnly, givenFunctions) {
}
});
- var addedLibraryItems = {};
-
// functionStub
substrate.addActor('FunctionStub', {
processItem: function(item) {
@@ -406,6 +409,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 +424,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 +524,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 +543,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 +580,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 +609,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 +746,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 +797,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 +829,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 +845,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 +939,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 +1075,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 +1132,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 +1212,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);
@@ -1182,7 +1235,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(indexizeFunctions(arg, argsTypes[i]), 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 +1281,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) {
@@ -1325,8 +1393,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 +1420,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 +1436,8 @@ function JSify(data, functionsOnly, givenFunctions) {
return IGNORED_FUNCTIONS.indexOf(func.ident) < 0;
})) + '\n');
+ PassManager.serialize();
+
return null;
}