diff options
Diffstat (limited to 'src/jsifier.js')
-rw-r--r-- | src/jsifier.js | 1222 |
1 files changed, 578 insertions, 644 deletions
diff --git a/src/jsifier.js b/src/jsifier.js index 1f53b1a2..96cb8d9a 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -22,6 +22,8 @@ var functionStubSigs = {}; function JSify(data, functionsOnly, givenFunctions) { var mainPass = !functionsOnly; + var itemsDict = { type: [], GlobalVariableStub: [], functionStub: [], function: [], GlobalVariable: [], GlobalVariablePostSet: [] }; + if (mainPass) { var shellFile = SHELL_FILE ? SHELL_FILE : (BUILD_AS_SHARED_LIB || SIDE_MODULE ? 'shell_sharedlib.js' : 'shell.js'); @@ -58,17 +60,6 @@ function JSify(data, functionsOnly, givenFunctions) { } } - // Does simple 'macro' substitution, using Django-like syntax, - // {{{ code }}} will be replaced with |eval(code)|. - function processMacros(text) { - return text.replace(/{{{[^}]+}}}/g, function(str) { - str = str.substr(3, str.length-6); - return eval(str).toString(); - }); - } - - var substrate = new Substrate('JSifyer'); - if (mainPass) { // Handle unparsed types TODO: Batch them analyzer(intertyper(data.unparsedTypess[0].lines, true), true); @@ -138,21 +129,6 @@ function JSify(data, functionsOnly, givenFunctions) { // Actors - // type - // FIXME: This is no longer used, we do not actually need to JSify on types. TODO: Remove this and related code - substrate.addActor('Type', { - processItem: function(item) { - var type = Types.types[item.name_]; - var niceName = toNiceIdent(item.name_); - // We might export all of Types.types, cleaner that way, but do not want slowdowns in accessing flatteners - item.JS = 'var ' + niceName + '___SIZE = ' + Types.types[item.name_].flatSize + '; // ' + item.name_ + '\n'; - if (type.needsFlattening && !type.flatFactor) { - item.JS += 'var ' + niceName + '___FLATTENER = ' + JSON.stringify(Types.types[item.name_].flatIndexes) + ';'; - } - return [item]; - } - }); - function makeEmptyStruct(type) { var ret = []; var typeData = Types.types[type]; @@ -255,146 +231,144 @@ function JSify(data, functionsOnly, givenFunctions) { } // globalVariable - substrate.addActor('GlobalVariable', { - processItem: function(item) { - function needsPostSet(value) { - if (typeof value !== 'string') return false; - return value[0] in UNDERSCORE_OPENPARENS || value.substr(0, 14) === 'CHECK_OVERFLOW' - || value.substr(0, 6) === 'GLOBAL'; - } - - item.intertype = 'GlobalVariableStub'; - assert(!item.lines); // FIXME remove this, after we are sure it isn't needed - var ret = [item]; - if (item.ident == '_llvm_global_ctors') { - item.JS = '\n/* global initializers */ __ATINIT__.push(' + - item.ctors.map(function(ctor) { return '{ func: function() { ' + ctor + '() } }' }).join(',') + - ');\n'; - return ret; - } + function globalVariableHandler(item) { + function needsPostSet(value) { + if (typeof value !== 'string') return false; + return value[0] in UNDERSCORE_OPENPARENS || value.substr(0, 14) === 'CHECK_OVERFLOW' + || value.substr(0, 6) === 'GLOBAL'; + } + + item.intertype = 'GlobalVariableStub'; + itemsDict.GlobalVariableStub.push(item); + assert(!item.lines); // FIXME remove this, after we are sure it isn't needed + if (item.ident == '_llvm_global_ctors') { + item.JS = '\n/* global initializers */ __ATINIT__.push(' + + item.ctors.map(function(ctor) { return '{ func: function() { ' + ctor + '() } }' }).join(',') + + ');\n'; + return; + } - var constant = null; - var allocator = (BUILD_AS_SHARED_LIB && !item.external) ? 'ALLOC_NORMAL' : 'ALLOC_STATIC'; - var index = null; - if (item.external && BUILD_AS_SHARED_LIB) { - // External variables in shared libraries should not be declared as - // they would shadow similarly-named globals in the parent. - item.JS = ''; - } else { - item.JS = makeGlobalDef(item.ident); - } + var constant = null; + var allocator = (BUILD_AS_SHARED_LIB && !item.external) ? 'ALLOC_NORMAL' : 'ALLOC_STATIC'; + var index = null; + if (item.external && BUILD_AS_SHARED_LIB) { + // External variables in shared libraries should not be declared as + // they would shadow similarly-named globals in the parent. + item.JS = ''; + } else { + item.JS = makeGlobalDef(item.ident); + } - if (!NAMED_GLOBALS && isIndexableGlobal(item.ident)) { - index = makeGlobalUse(item.ident); // index !== null indicates we are indexing this - allocator = 'ALLOC_NONE'; - } + if (!NAMED_GLOBALS && isIndexableGlobal(item.ident)) { + index = makeGlobalUse(item.ident); // index !== null indicates we are indexing this + allocator = 'ALLOC_NONE'; + } - Variables.globals[item.ident].named = item.named; + Variables.globals[item.ident].named = item.named; - if (ASM_JS && (MAIN_MODULE || SIDE_MODULE) && !item.private_ && !NAMED_GLOBALS && isIndexableGlobal(item.ident)) { - // We need this to be named (and it normally would not be), so that it can be linked to and used from other modules - Variables.globals[item.ident].linkable = 1; - } + if (ASM_JS && (MAIN_MODULE || SIDE_MODULE) && !item.private_ && !NAMED_GLOBALS && isIndexableGlobal(item.ident)) { + // We need this to be named (and it normally would not be), so that it can be linked to and used from other modules + Variables.globals[item.ident].linkable = 1; + } - if (isBSS(item)) { - var length = calcAllocatedSize(item.type); - length = Runtime.alignMemory(length); + if (isBSS(item)) { + var length = calcAllocatedSize(item.type); + length = Runtime.alignMemory(length); - // If using indexed globals, go ahead and early out (no need to explicitly - // initialize). - if (!NAMED_GLOBALS) { - return ret; - } - // If using named globals, we can at least shorten the call to allocate by - // passing an integer representing the size of memory to alloc instead of - // an array of 0s of size length. - else { - constant = length; + // If using indexed globals, go ahead and early out (no need to explicitly + // initialize). + if (!NAMED_GLOBALS) { + return; + } + // If using named globals, we can at least shorten the call to allocate by + // passing an integer representing the size of memory to alloc instead of + // an array of 0s of size length. + else { + constant = length; + } + } else { + if (item.external) { + if (Runtime.isNumberType(item.type) || isPointerType(item.type)) { + constant = zeros(Runtime.getNativeFieldSize(item.type)); + } else { + constant = makeEmptyStruct(item.type); } } else { - if (item.external) { - if (Runtime.isNumberType(item.type) || isPointerType(item.type)) { - constant = zeros(Runtime.getNativeFieldSize(item.type)); - } else { - constant = makeEmptyStruct(item.type); - } - } else { - constant = parseConst(item.value, item.type, item.ident); + constant = parseConst(item.value, item.type, item.ident); + } + assert(typeof constant === 'object');//, [typeof constant, JSON.stringify(constant), item.external]); + + // This is a flattened object. We need to find its idents, so they can be assigned to later + var structTypes = null; + constant.forEach(function(value, i) { + if (needsPostSet(value)) { // ident, or expression containing an ident + if (!structTypes) structTypes = generateStructTypes(item.type); + itemsDict.GlobalVariablePostSet.push({ + intertype: 'GlobalVariablePostSet', + JS: makeSetValue(makeGlobalUse(item.ident), i, value, structTypes[i], false, true) + ';' // ignore=true, since e.g. rtti and statics cause lots of safe_heap errors + }); + constant[i] = '0'; } - assert(typeof constant === 'object');//, [typeof constant, JSON.stringify(constant), item.external]); - - // This is a flattened object. We need to find its idents, so they can be assigned to later - var structTypes = null; - constant.forEach(function(value, i) { - if (needsPostSet(value)) { // ident, or expression containing an ident - if (!structTypes) structTypes = generateStructTypes(item.type); - ret.push({ - intertype: 'GlobalVariablePostSet', - JS: makeSetValue(makeGlobalUse(item.ident), i, value, structTypes[i], false, true) + ';' // ignore=true, since e.g. rtti and statics cause lots of safe_heap errors - }); - constant[i] = '0'; - } - }); + }); - if (item.external) { - // External variables in shared libraries should not be declared as - // they would shadow similarly-named globals in the parent, so do nothing here. - if (BUILD_AS_SHARED_LIB) return ret; - if (SIDE_MODULE) return []; - // Library items need us to emit something, but everything else requires nothing. - if (!LibraryManager.library[item.ident.slice(1)]) return ret; + if (item.external) { + // External variables in shared libraries should not be declared as + // they would shadow similarly-named globals in the parent, so do nothing here. + if (BUILD_AS_SHARED_LIB) return; + if (SIDE_MODULE) { + itemsDict.GlobalVariableStub.pop(); // remove this item + return; } + // Library items need us to emit something, but everything else requires nothing. + if (!LibraryManager.library[item.ident.slice(1)]) return; + } - // ensure alignment - constant = constant.concat(zeros(Runtime.alignMemory(constant.length) - constant.length)); + // ensure alignment + constant = constant.concat(zeros(Runtime.alignMemory(constant.length) - constant.length)); - // Special case: class vtables. We make sure they are null-terminated, to allow easy runtime operations - if (item.ident.substr(0, 5) == '__ZTV') { - constant = constant.concat(zeros(Runtime.alignMemory(QUANTUM_SIZE))); - } + // Special case: class vtables. We make sure they are null-terminated, to allow easy runtime operations + if (item.ident.substr(0, 5) == '__ZTV') { + constant = constant.concat(zeros(Runtime.alignMemory(QUANTUM_SIZE))); } + } - // NOTE: This is the only place that could potentially create static - // allocations in a shared library. - constant = makePointer(constant, null, allocator, item.type, index); + // NOTE: This is the only place that could potentially create static + // allocations in a shared library. + constant = makePointer(constant, null, allocator, item.type, index); - var js = (index !== null ? '' : item.ident + '=') + constant; - if (js) js += ';'; + var js = (index !== null ? '' : item.ident + '=') + constant; + if (js) js += ';'; - if (!ASM_JS && NAMED_GLOBALS && (EXPORT_ALL || (item.ident in EXPORTED_GLOBALS))) { - js += '\nModule["' + item.ident + '"] = ' + item.ident + ';'; - } - if (BUILD_AS_SHARED_LIB == 2 && !item.private_) { - // TODO: make the assert conditional on ASSERTIONS - js += 'if (globalScope) { assert(!globalScope["' + item.ident + '"]); globalScope["' + item.ident + '"] = ' + item.ident + ' }'; - } - if (item.external && !NAMED_GLOBALS) { - js = 'var ' + item.ident + ' = ' + js; // force an explicit naming, even if unnamed globals, for asm forwarding - } - return ret.concat({ - intertype: 'GlobalVariable', - JS: js, - }); + if (!ASM_JS && NAMED_GLOBALS && (EXPORT_ALL || (item.ident in EXPORTED_GLOBALS))) { + js += '\nModule["' + item.ident + '"] = ' + item.ident + ';'; } - }); + if (BUILD_AS_SHARED_LIB == 2 && !item.private_) { + // TODO: make the assert conditional on ASSERTIONS + js += 'if (globalScope) { assert(!globalScope["' + item.ident + '"]); globalScope["' + item.ident + '"] = ' + item.ident + ' }'; + } + if (item.external && !NAMED_GLOBALS) { + js = 'var ' + item.ident + ' = ' + js; // force an explicit naming, even if unnamed globals, for asm forwarding + } + itemsDict.GlobalVariableStub.push({ + intertype: 'GlobalVariable', + JS: js, + }); + } // alias - substrate.addActor('Alias', { - processItem: function(item) { - item.intertype = 'GlobalVariableStub'; - var ret = [item]; - item.JS = 'var ' + item.ident + ';'; - // Set the actual value in a postset, since it may be a global variable. We also order by dependencies there - Variables.globals[item.ident].targetIdent = item.value.ident; - var value = Variables.globals[item.ident].resolvedAlias = finalizeLLVMParameter(item.value); - if ((MAIN_MODULE || SIDE_MODULE) && isFunctionType(item.type)) { - var target = item.value.ident; - if (!Functions.aliases[target]) Functions.aliases[target] = []; - Functions.aliases[target].push(item.ident); - } - return ret; + function aliasHandler(item) { + item.intertype = 'GlobalVariableStub'; + itemsDict.GlobalVariableStub.push(item); + item.JS = 'var ' + item.ident + ';'; + // Set the actual value in a postset, since it may be a global variable. We also order by dependencies there + Variables.globals[item.ident].targetIdent = item.value.ident; + var value = Variables.globals[item.ident].resolvedAlias = finalizeLLVMParameter(item.value); + if ((MAIN_MODULE || SIDE_MODULE) && isFunctionType(item.type)) { + var target = item.value.ident; + if (!Functions.aliases[target]) Functions.aliases[target] = []; + Functions.aliases[target].push(item.ident); } - }); + } function processLibraryFunction(snippet, ident) { snippet = snippet.toString(); @@ -411,147 +385,163 @@ function JSify(data, functionsOnly, givenFunctions) { } // functionStub - substrate.addActor('FunctionStub', { - processItem: function(item) { - // note the signature - if (item.returnType && item.params) { - functionStubSigs[item.ident] = Functions.getSignature(item.returnType.text, item.params.map(function(arg) { return arg.type }), false); - } - - function addFromLibrary(ident) { - if (ident in addedLibraryItems) return ''; - addedLibraryItems[ident] = true; - - // dependencies can be JS functions, which we just run - if (typeof ident == 'function') return ident(); - - // Don't replace implemented functions with library ones (which can happen when we add dependencies). - // Note: We don't return the dependencies here. Be careful not to end up where this matters - if (('_' + ident) in Functions.implementedFunctions) return ''; - - var snippet = LibraryManager.library[ident]; - var redirectedIdent = null; - var deps = LibraryManager.library[ident + '__deps'] || []; - var isFunction = false; - - if (typeof snippet === 'string') { - var target = LibraryManager.library[snippet]; - if (target) { - // Redirection for aliases. We include the parent, and at runtime make ourselves equal to it. - // This avoid having duplicate functions with identical content. - redirectedIdent = snippet; - deps.push(snippet); - snippet = '_' + snippet; - } - // In asm, we need to know about library functions. If there is a target, though, then no - // need to consider this a library function - we will call directly to it anyhow - if (ASM_JS && !redirectedIdent && (typeof target == 'function' || /Math\.\w+/.exec(snippet))) { - Functions.libraryFunctions[ident] = 1; - } - } else if (typeof snippet === 'object') { - snippet = stringifyWithFunctions(snippet); - } else if (typeof snippet === 'function') { - isFunction = true; - snippet = processLibraryFunction(snippet, ident); - if (ASM_JS) Functions.libraryFunctions[ident] = 1; + function functionStubHandler(item) { + // note the signature + if (item.returnType && item.params) { + functionStubSigs[item.ident] = Functions.getSignature(item.returnType.text, item.params.map(function(arg) { return arg.type }), false); + } + + function addFromLibrary(ident) { + if (ident in addedLibraryItems) return ''; + addedLibraryItems[ident] = true; + + // dependencies can be JS functions, which we just run + if (typeof ident == 'function') return ident(); + + // Don't replace implemented functions with library ones (which can happen when we add dependencies). + // Note: We don't return the dependencies here. Be careful not to end up where this matters + if (('_' + ident) in Functions.implementedFunctions) return ''; + + var snippet = LibraryManager.library[ident]; + var redirectedIdent = null; + var deps = LibraryManager.library[ident + '__deps'] || []; + var isFunction = false; + + if (typeof snippet === 'string') { + var target = LibraryManager.library[snippet]; + if (target) { + // Redirection for aliases. We include the parent, and at runtime make ourselves equal to it. + // This avoid having duplicate functions with identical content. + redirectedIdent = snippet; + deps.push(snippet); + snippet = '_' + snippet; } - - var postsetId = ident + '__postset'; - var postset = LibraryManager.library[postsetId]; - if (postset && !addedLibraryItems[postsetId] && !SIDE_MODULE) { - addedLibraryItems[postsetId] = true; - ret.push({ - intertype: 'GlobalVariablePostSet', - JS: postset - }); + // In asm, we need to know about library functions. If there is a target, though, then no + // need to consider this a library function - we will call directly to it anyhow + if (ASM_JS && !redirectedIdent && (typeof target == 'function' || /Math\.\w+/.exec(snippet))) { + Functions.libraryFunctions[ident] = 1; } + } else if (typeof snippet === 'object') { + snippet = stringifyWithFunctions(snippet); + } else if (typeof snippet === 'function') { + isFunction = true; + snippet = processLibraryFunction(snippet, ident); + if (ASM_JS) Functions.libraryFunctions[ident] = 1; + } + + var postsetId = ident + '__postset'; + var postset = LibraryManager.library[postsetId]; + if (postset && !addedLibraryItems[postsetId] && !SIDE_MODULE) { + addedLibraryItems[postsetId] = true; + itemsDict.GlobalVariablePostSet.push({ + intertype: 'GlobalVariablePostSet', + JS: postset + }); + } - if (redirectedIdent) { - deps = deps.concat(LibraryManager.library[redirectedIdent + '__deps'] || []); - } - if (ASM_JS) { - // In asm, dependencies implemented in C might be needed by JS library functions. - // We don't know yet if they are implemented in C or not. To be safe, export such - // special cases. - [LIBRARY_DEPS_TO_AUTOEXPORT].forEach(function(special) { - deps.forEach(function(dep) { - if (dep == special && !EXPORTED_FUNCTIONS[dep]) { - EXPORTED_FUNCTIONS[dep] = 1; - } - }); + if (redirectedIdent) { + deps = deps.concat(LibraryManager.library[redirectedIdent + '__deps'] || []); + } + if (ASM_JS) { + // In asm, dependencies implemented in C might be needed by JS library functions. + // We don't know yet if they are implemented in C or not. To be safe, export such + // special cases. + [LIBRARY_DEPS_TO_AUTOEXPORT].forEach(function(special) { + deps.forEach(function(dep) { + if (dep == special && !EXPORTED_FUNCTIONS[dep]) { + EXPORTED_FUNCTIONS[dep] = 1; + } }); + }); + } + // $ident's are special, we do not prefix them with a '_'. + if (ident[0] === '$') { + ident = ident.substr(1); + } else { + ident = '_' + ident; + } + if (VERBOSE) printErr('adding ' + ident + ' and deps ' + deps); + var depsText = (deps ? '\n' + deps.map(addFromLibrary).filter(function(x) { return x != '' }).join('\n') : ''); + var contentText = isFunction ? snippet : ('var ' + ident + '=' + snippet + ';'); + if (ASM_JS) { + var sig = LibraryManager.library[ident.substr(1) + '__sig']; + if (isFunction && sig && LibraryManager.library[ident.substr(1) + '__asm']) { + // asm library function, add it as generated code alongside the generated code + Functions.implementedFunctions[ident] = sig; + asmLibraryFunctions.push(contentText); + contentText = ' '; + EXPORTED_FUNCTIONS[ident] = 1; + Functions.libraryFunctions[ident.substr(1)] = 2; } - // $ident's are special, we do not prefix them with a '_'. - if (ident[0] === '$') { - ident = ident.substr(1); - } else { - ident = '_' + ident; - } - if (VERBOSE) printErr('adding ' + ident + ' and deps ' + deps); - var depsText = (deps ? '\n' + deps.map(addFromLibrary).filter(function(x) { return x != '' }).join('\n') : ''); - var contentText = isFunction ? snippet : ('var ' + ident + '=' + snippet + ';'); - if (ASM_JS) { - var sig = LibraryManager.library[ident.substr(1) + '__sig']; - if (isFunction && sig && LibraryManager.library[ident.substr(1) + '__asm']) { - // asm library function, add it as generated code alongside the generated code - Functions.implementedFunctions[ident] = sig; - asmLibraryFunctions.push(contentText); - contentText = ' '; - EXPORTED_FUNCTIONS[ident] = 1; - Functions.libraryFunctions[ident.substr(1)] = 2; - } - } - if (SIDE_MODULE) return ';'; // we import into the side module js library stuff from the outside parent - if ((!ASM_JS || phase == 'pre') && - (EXPORT_ALL || (ident in EXPORTED_FUNCTIONS))) { - contentText += '\nModule["' + ident + '"] = ' + ident + ';'; - } - return depsText + contentText; } + if (SIDE_MODULE) return ';'; // we import into the side module js library stuff from the outside parent + if ((!ASM_JS || phase == 'pre') && + (EXPORT_ALL || (ident in EXPORTED_FUNCTIONS))) { + contentText += '\nModule["' + ident + '"] = ' + ident + ';'; + } + return depsText + contentText; + } - var ret = [item]; - if (IGNORED_FUNCTIONS.indexOf(item.ident) >= 0) return null; - var shortident = item.ident.substr(1); - if (BUILD_AS_SHARED_LIB) { - // Shared libraries reuse the runtime of their parents. - item.JS = ''; - } else { - // If this is not linkable, anything not in the library is definitely missing - var cancel = false; - if (!LINKABLE && !LibraryManager.library.hasOwnProperty(shortident) && !LibraryManager.library.hasOwnProperty(shortident + '__inline')) { - if (ERROR_ON_UNDEFINED_SYMBOLS) error('unresolved symbol: ' + shortident); - if (VERBOSE || WARN_ON_UNDEFINED_SYMBOLS) printErr('warning: unresolved symbol: ' + shortident); - if (ASM_JS || item.ident in DEAD_FUNCTIONS) { - // emit a stub that will fail during runtime. this allows asm validation to succeed. - LibraryManager.library[shortident] = new Function("Module['printErr']('missing function: " + shortident + "'); abort(-1);"); - } else { - cancel = true; // emit nothing, not even var X = undefined; - } + itemsDict.functionStub.push(item); + if (IGNORED_FUNCTIONS.indexOf(item.ident) >= 0) return; + var shortident = item.ident.substr(1); + if (BUILD_AS_SHARED_LIB) { + // Shared libraries reuse the runtime of their parents. + item.JS = ''; + } else { + // If this is not linkable, anything not in the library is definitely missing + var cancel = false; + if (!LINKABLE && !LibraryManager.library.hasOwnProperty(shortident) && !LibraryManager.library.hasOwnProperty(shortident + '__inline')) { + if (ERROR_ON_UNDEFINED_SYMBOLS) error('unresolved symbol: ' + shortident); + if (VERBOSE || WARN_ON_UNDEFINED_SYMBOLS) printErr('warning: unresolved symbol: ' + shortident); + if (ASM_JS || item.ident in DEAD_FUNCTIONS) { + // emit a stub that will fail during runtime. this allows asm validation to succeed. + LibraryManager.library[shortident] = new Function("Module['printErr']('missing function: " + shortident + "'); abort(-1);"); + } else { + cancel = true; // emit nothing, not even var X = undefined; } - item.JS = cancel ? ';' : addFromLibrary(shortident); } - return ret; + item.JS = cancel ? ';' : addFromLibrary(shortident); } - }); + } // function splitter - substrate.addActor('FunctionSplitter', { - processItem: function(item) { - var ret = [item]; - item.splitItems = 0; - item.labels.forEach(function(label) { - label.lines.forEach(function(line) { - line.func = item.ident; - line.funcData = item; // TODO: remove all these, access it globally - line.parentLabel = label.ident; - ret.push(line); - item.splitItems ++; - }); - }); - - this.forwardItems(ret, 'FuncLineTriager'); - } - }); + function functionSplitter(item) { + item.lines.forEach(function(line) { + Framework.currItem = line; + line.funcData = item; // TODO: remove all these, access it globally + switch (line.intertype) { + case 'value': line.JS = valueHandler(line); break; + case 'noop': line.JS = noopHandler(line); break; + case 'var': line.JS = varHandler(line); break; + case 'store': line.JS = storeHandler(line); break; + case 'deleted': line.JS = deletedHandler(line); break; + case 'branch': line.JS = branchHandler(line); break; + case 'switch': line.JS = switchHandler(line); break; + case 'return': line.JS = returnHandler(line); break; + case 'resume': line.JS = resumeHandler(line); break; + case 'invoke': line.JS = invokeHandler(line); break; + case 'atomic': line.JS = atomicHandler(line); break; + case 'landingpad': line.JS = landingpadHandler(line); break; + case 'load': line.JS = loadHandler(line); break; + case 'extractvalue': line.JS = extractvalueHandler(line); break; + case 'insertvalue': line.JS = insertvalueHandler(line); break; + case 'indirectbr': line.JS = indirectbrHandler(line); break; + case 'alloca': line.JS = allocaHandler(line); break; + case 'va_arg': line.JS = va_argHandler(line); break; + case 'mathop': line.JS = mathopHandler(line); break; + case 'bitcast': line.JS = bitcastHandler(line); break; + case 'getelementptr': line.JS = getelementptrHandler(line); break; + case 'call': line.JS = callHandler(line); break; + case 'unreachable': line.JS = unreachableHandler(line); break; + default: throw 'what is this line? ' + dump(line); + } + assert(line.JS); + if (line.assignTo) makeAssign(line); + Framework.currItem = null; + }); + functionReconstructor(item); + } // function for filtering functions for label debugging if (LABEL_FUNCTION_FILTERS.length > 0) { @@ -567,322 +557,297 @@ function JSify(data, functionsOnly, givenFunctions) { } // function reconstructor & post-JS optimizer - substrate.addActor('FunctionReconstructor', { - funcs: {}, - seen: {}, - processItem: function(item) { - if (this.seen[item.__uid__]) return null; - if (item.intertype == 'function') { - this.funcs[item.ident] = item; - item.relines = {}; - this.seen[item.__uid__] = true; - return null; - } - var line = item; - var func = this.funcs[line.func]; - if (!func) return null; - - // Re-insert our line - this.seen[item.__uid__] = true; - var label = func.labels.filter(function(label) { return label.ident == line.parentLabel })[0]; - label.lines = label.lines.map(function(line2) { - return (line2.lineNum !== line.lineNum) ? line2 : line; - }); - func.splitItems --; - // OLD delete line.funcData; // clean up - if (func.splitItems > 0) return null; + function functionReconstructor(func) { + // We have this function all reconstructed, go and finalize it's JS! - // We have this function all reconstructed, go and finalize it's JS! + if (IGNORED_FUNCTIONS.indexOf(func.ident) >= 0) return null; - if (IGNORED_FUNCTIONS.indexOf(func.ident) >= 0) return null; + func.JS = '\n'; - func.JS = '\n'; + var paramIdents = func.params.map(function(param) { + return toNiceIdent(param.ident); + }); - var paramIdents = func.params.map(function(param) { - return toNiceIdent(param.ident); + if (CLOSURE_ANNOTATIONS) { + func.JS += '/**\n'; + paramIdents.forEach(function(param) { + func.JS += ' * @param {number} ' + param + '\n'; }); + func.JS += ' * @return {number}\n' + func.JS += ' */\n'; + } - if (CLOSURE_ANNOTATIONS) { - func.JS += '/**\n'; - paramIdents.forEach(function(param) { - func.JS += ' * @param {number} ' + param + '\n'; - }); - func.JS += ' * @return {number}\n' - func.JS += ' */\n'; - } - - if (PRINT_SPLIT_FILE_MARKER) { - func.JS += '\n//FUNCTION_BEGIN_MARKER\n' - var associatedSourceFile = "NO_SOURCE"; - } - - if (DLOPEN_SUPPORT) Functions.getIndex(func.ident); + if (PRINT_SPLIT_FILE_MARKER) { + func.JS += '\n//FUNCTION_BEGIN_MARKER\n' + var associatedSourceFile = "NO_SOURCE"; + } + + if (DLOPEN_SUPPORT) Functions.getIndex(func.ident); - func.JS += 'function ' + func.ident + '(' + paramIdents.join(', ') + ') {\n'; + func.JS += 'function ' + func.ident + '(' + paramIdents.join(', ') + ') {\n'; - if (PGO) { - func.JS += INDENTATION + 'PGOMonitor.called["' + func.ident + '"] = 1;\n'; - } + if (PGO) { + func.JS += INDENTATION + 'PGOMonitor.called["' + func.ident + '"] = 1;\n'; + } - if (ASM_JS) { - // spell out argument types - func.params.forEach(function(param) { - func.JS += INDENTATION + param.ident + ' = ' + asmCoercion(param.ident, param.type) + ';\n'; - }); + if (ASM_JS) { + // spell out argument types + func.params.forEach(function(param) { + func.JS += INDENTATION + 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 += INDENTATION + 'var ' + chunks[i].map(function(v) { - var type = getImplementationType(v); - if (!isIllegalType(type) || v.ident.indexOf('$', 1) > 0) { // not illegal, or a broken up illegal - return v.ident + ' = ' + asmInitializer(type); //, func.variables[v.ident].impl); - } else { - return range(Math.ceil(getBits(type)/32)).map(function(i) { - return v.ident + '$' + i + '= 0'; - }).join(','); - } - }).join(', ') + ';\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 += INDENTATION + 'var ' + chunks[i].map(function(v) { + var type = getImplementationType(v); + if (!isIllegalType(type) || v.ident.indexOf('$', 1) > 0) { // not illegal, or a broken up illegal + return v.ident + ' = ' + asmInitializer(type); //, func.variables[v.ident].impl); + } else { + return range(Math.ceil(getBits(type)/32)).map(function(i) { + return v.ident + '$' + i + '= 0'; + }).join(','); + } + }).join(', ') + ';\n'; } } + } - if (true) { // TODO: optimize away when not needed - if (CLOSURE_ANNOTATIONS) func.JS += '/** @type {number} */'; - func.JS += INDENTATION + 'var label = 0;\n'; - } + if (true) { // TODO: optimize away when not needed + if (CLOSURE_ANNOTATIONS) func.JS += '/** @type {number} */'; + func.JS += INDENTATION + 'var label = 0;\n'; + } - if (ASM_JS) { - var hasByVal = false; - func.params.forEach(function(param) { - hasByVal = hasByVal || param.byVal; - }); - if (hasByVal) { - func.JS += INDENTATION + 'var tempParam = 0;\n'; - } + if (ASM_JS) { + var hasByVal = false; + func.params.forEach(function(param) { + hasByVal = hasByVal || param.byVal; + }); + if (hasByVal) { + func.JS += INDENTATION + 'var tempParam = 0;\n'; } + } + + if (func.hasVarArgsCall) { + func.JS += INDENTATION + 'var tempVarArgs = 0;\n'; + } + + // Prepare the stack, if we need one. If we have other stack allocations, force the stack to be set up. + func.JS += INDENTATION + RuntimeGenerator.stackEnter(func.initialStack, func.otherStackAllocations) + ';\n'; - if (func.hasVarArgsCall) { - func.JS += INDENTATION + 'var tempVarArgs = 0;\n'; + // Make copies of by-value params + // XXX It is not clear we actually need this. While without this we fail, it does look like + // Clang normally does the copy itself, in the calling function. We only need this code + // when Clang optimizes the code and passes the original, not the copy, to the other + // function. But Clang still copies, the copy is just unused! Need to figure out if that + // is caused by our running just some optimizations (the safe ones), or if its a bug + // in Clang, or a bug in our understanding of the IR. + func.params.forEach(function(param) { + if (param.byVal) { + var type = removePointing(param.type); + var typeInfo = Types.types[type]; + func.JS += INDENTATION + (ASM_JS ? '' : 'var ') + 'tempParam = ' + param.ident + '; ' + param.ident + ' = ' + RuntimeGenerator.stackAlloc(typeInfo.flatSize) + ';' + + makeCopyValues(param.ident, 'tempParam', typeInfo.flatSize, 'null', null, param.byVal) + ';\n'; } + }); - // Prepare the stack, if we need one. If we have other stack allocations, force the stack to be set up. - func.JS += INDENTATION + RuntimeGenerator.stackEnter(func.initialStack, func.otherStackAllocations) + ';\n'; + if (LABEL_DEBUG && functionNameFilterTest(func.ident)) func.JS += " Module.print(INDENT + ' Entering: " + func.ident + ": ' + Array.prototype.slice.call(arguments)); INDENT += ' ';\n"; - // Make copies of by-value params - // XXX It is not clear we actually need this. While without this we fail, it does look like - // Clang normally does the copy itself, in the calling function. We only need this code - // when Clang optimizes the code and passes the original, not the copy, to the other - // function. But Clang still copies, the copy is just unused! Need to figure out if that - // is caused by our running just some optimizations (the safe ones), or if its a bug - // in Clang, or a bug in our understanding of the IR. - func.params.forEach(function(param) { - if (param.byVal) { - var type = removePointing(param.type); - var typeInfo = Types.types[type]; - func.JS += INDENTATION + (ASM_JS ? '' : 'var ') + 'tempParam = ' + param.ident + '; ' + param.ident + ' = ' + RuntimeGenerator.stackAlloc(typeInfo.flatSize) + ';' + - makeCopyValues(param.ident, 'tempParam', typeInfo.flatSize, 'null', null, param.byVal) + ';\n'; + // Walk function blocks and generate JS + function walkBlock(block, indent) { + if (!block) return ''; + dprint('relooping', 'walking block: ' + block.type + ',' + block.entries + ' : ' + block.labels.length); + function getLabelLines(label, indent, relooping) { + if (!label) return ''; + var ret = ''; + if ((LABEL_DEBUG >= 2) && functionNameFilterTest(func.ident)) { + ret += indent + "Module.print(INDENT + '" + func.ident + ":" + label.ident + "');\n"; } - }); - - if (LABEL_DEBUG && functionNameFilterTest(func.ident)) func.JS += " Module.print(INDENT + ' Entering: " + func.ident + ": ' + Array.prototype.slice.call(arguments)); INDENT += ' ';\n"; - - // Walk function blocks and generate JS - function walkBlock(block, indent) { - if (!block) return ''; - dprint('relooping', 'walking block: ' + block.type + ',' + block.entries + ' : ' + block.labels.length); - function getLabelLines(label, indent, relooping) { - if (!label) return ''; - var ret = ''; - if ((LABEL_DEBUG >= 2) && functionNameFilterTest(func.ident)) { - ret += indent + "Module.print(INDENT + '" + func.ident + ":" + label.ident + "');\n"; - } - if (EXECUTION_TIMEOUT > 0) { - ret += indent + 'if (Date.now() - START_TIME >= ' + (EXECUTION_TIMEOUT*1000) + ') throw "Timed out!" + (new Error().stack);\n'; - } - - if (PRINT_SPLIT_FILE_MARKER && Debugging.on && Debugging.getAssociatedSourceFile(line.lineNum)) { - // Overwrite the associated source file for every line. The last line should contain the source file associated to - // the return value/address of outer most block (the marked function). - associatedSourceFile = Debugging.getAssociatedSourceFile(line.lineNum); - } - - // for special labels we care about (for phi), mark that we visited them - var i = 0; - return ret + label.lines.map(function(line) { - var JS = line.JS; - if (relooping && i == label.lines.length-1) { - if (line.intertype == 'branch' || line.intertype == 'switch') { - JS = ''; // just branching operations - done in the relooper, so nothing need be done here - } else if (line.intertype == 'invoke') { - JS = line.reloopingJS; // invokes have code that is not rendered in the relooper (the call inside a try-catch) - } - } |