diff options
Diffstat (limited to 'src/jsifier.js')
-rw-r--r-- | src/jsifier.js | 145 |
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; } |