aboutsummaryrefslogtreecommitdiff
path: root/src/jsifier.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/jsifier.js')
-rw-r--r--src/jsifier.js1222
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)
- }
- }