diff options
Diffstat (limited to 'src/modules.js')
-rw-r--r-- | src/modules.js | 133 |
1 files changed, 111 insertions, 22 deletions
diff --git a/src/modules.js b/src/modules.js index b31567be..e4093078 100644 --- a/src/modules.js +++ b/src/modules.js @@ -2,6 +2,8 @@ // Various namespace-like modules +var STACK_ALIGN = TARGET_X86 ? 4 : 8; + var LLVM = { LINKAGES: set('private', 'linker_private', 'linker_private_weak', 'linker_private_weak_def_auto', 'internal', 'available_externally', 'linkonce', 'common', 'weak', 'appending', 'extern_weak', 'linkonce_odr', @@ -13,8 +15,10 @@ var LLVM = { ACCESS_OPTIONS: set('volatile', 'atomic'), INVOKE_MODIFIERS: set('alignstack', 'alwaysinline', 'inlinehint', 'naked', 'noimplicitfloat', 'noinline', 'alwaysinline attribute.', 'noredzone', 'noreturn', 'nounwind', 'optsize', 'readnone', 'readonly', 'ssp', 'sspreq'), SHIFTS: set('ashr', 'lshr', 'shl'), - PHI_REACHERS: set('branch', 'switch', 'invoke'), + PHI_REACHERS: set('branch', 'switch', 'invoke', 'indirectbr'), EXTENDS: set('sext', 'zext'), + COMPS: set('icmp', 'fcmp'), + CONVERSIONS: set('inttoptr', 'ptrtoint', 'uitofp', 'sitofp', 'fptosi', 'fptoui'), INTRINSICS_32: set('_llvm_memcpy_p0i8_p0i8_i64', '_llvm_memmove_p0i8_p0i8_i64', '_llvm_memset_p0i8_i64'), // intrinsics that need args converted to i32 in USE_TYPED_ARRAYS == 2 }; LLVM.GLOBAL_MODIFIERS = set(keys(LLVM.LINKAGES).concat(['constant', 'global', 'hidden'])); @@ -88,6 +92,7 @@ var Debugging = { lines[i] = ';'; continue; } + if (line[0] == '!') skipLine = true; lines[i] = skipLine ? ';' : line; } @@ -177,7 +182,16 @@ var Variables = { globals: {}, indexedGlobals: {}, // for indexed globals, ident ==> index // Used in calculation of indexed globals - nextIndexedOffset: 0 + nextIndexedOffset: 0, + + resolveAliasToIdent: function(ident) { + while (1) { + var varData = Variables.globals[ident]; + if (!(varData && varData.targetIdent)) break; + ident = varData.targetIdent; // might need to eval to turn (6) into 6 + } + return ident; + }, }; var Types = { @@ -215,35 +229,46 @@ var Types = { preciseI64MathUsed: (PRECISE_I64_MATH == 2) }; +var firstTableIndex = (ASM_JS ? 2*RESERVED_FUNCTION_POINTERS : 0) + 2; + var Functions = { // All functions that will be implemented in this file. Maps id to signature implementedFunctions: {}, - libraryFunctions: {}, // functions added from the library + libraryFunctions: {}, // functions added from the library. value 2 means asmLibraryFunction unimplementedFunctions: {}, // library etc. functions that we need to index, maps id to signature indexedFunctions: {}, - nextIndex: 2, // Start at a non-0 (even, see below) value + nextIndex: firstTableIndex, // Start at a non-0 (even, see below) value + neededTables: set('v', 'vi', 'ii', 'iii'), // signatures that appeared (initialized with library stuff + // we always use), and we will need a function table for blockAddresses: {}, // maps functions to a map of block labels to label ids - getSignature: function(returnType, argTypes) { + getSignature: function(returnType, argTypes, hasVarArgs) { var sig = returnType == 'void' ? 'v' : (isIntImplemented(returnType) ? 'i' : 'f'); for (var i = 0; i < argTypes.length; i++) { var type = argTypes[i]; if (!type) break; // varargs sig += isIntImplemented(type) ? (getBits(type) == 64 ? 'ii' : 'i') : 'f'; // legalized i64s will be i32s } + if (hasVarArgs) sig += 'i'; return sig; }, // Mark a function as needing indexing. Python will coordinate them all - getIndex: function(ident) { + getIndex: function(ident, doNotCreate) { + if (doNotCreate && !(ident in this.indexedFunctions)) { + if (!Functions.getIndex.tentative) Functions.getIndex.tentative = {}; // only used by GL emulation; TODO: generalize when needed + Functions.getIndex.tentative[ident] = 0; + } if (phase != 'post' && singlePhase) { - this.indexedFunctions[ident] = 0; // tell python we need this indexized - return '{{{ FI_' + ident + ' }}}'; // something python will replace later + if (!doNotCreate) this.indexedFunctions[ident] = 0; // tell python we need this indexized + return "'{{ FI_" + toNiceIdent(ident) + " }}'"; // something python will replace later } else { + if (!singlePhase) return 'NO_INDEX'; // Should not index functions in post var ret = this.indexedFunctions[ident]; if (!ret) { + if (doNotCreate) return '0'; ret = this.nextIndex; this.nextIndex += 2; // Need to have indexes be even numbers, see |polymorph| test this.indexedFunctions[ident] = ret; @@ -258,41 +283,103 @@ var Functions = { // Generate code for function indexing generateIndexing: function() { - var total = this.nextIndex; - if (ASM_JS) total = ceilPowerOfTwo(total); // must be power of 2 for mask - function emptyTable(sig) { - return zeros(total); - } - var tables = {}; + var tables = { pre: '' }; if (ASM_JS) { - ['v', 'vi', 'ii', 'iii'].forEach(function(sig) { // add some default signatures that are used in the library - tables[sig] = emptyTable(sig); // TODO: make them compact + keys(Functions.neededTables).forEach(function(sig) { // add some default signatures that are used in the library + tables[sig] = zeros(firstTableIndex); }); } for (var ident in this.indexedFunctions) { - var sig = ASM_JS ? Functions.implementedFunctions[ident] || Functions.unimplementedFunctions[ident] : 'x'; + var sig = ASM_JS ? Functions.implementedFunctions[ident] || Functions.unimplementedFunctions[ident] || LibraryManager.library[ident.substr(1) + '__sig'] : 'x'; assert(sig, ident); - if (!tables[sig]) tables[sig] = emptyTable(sig); // TODO: make them compact - tables[sig][this.indexedFunctions[ident]] = ident; + if (!tables[sig]) tables[sig] = zeros(firstTableIndex); + var index = this.indexedFunctions[ident]; + for (var i = tables[sig].length; i < index; i++) { + tables[sig][i] = 0; // keep flat + } + tables[sig][index] = ident; } - // Resolve multi-level aliases all the way down var generated = false; + var wrapped = {}; + var maxTable = 0; for (var t in tables) { + if (t == 'pre') continue; generated = true; var table = tables[t]; for (var i = 0; i < table.length; i++) { + // Resolve multi-level aliases all the way down while (1) { var varData = Variables.globals[table[i]]; - if (!(varData && varData.resolvedAlias)) break; + if (!(varData && varData.resolvedAlias && varData.resolvedAlias.indexOf('FUNCTION_TABLE_OFFSET') < 0)) break; table[i] = table[+varData.resolvedAlias || eval(varData.resolvedAlias)]; // might need to eval to turn (6) into 6 } + // Resolve library aliases + if (table[i]) { + var libName = LibraryManager.getRootIdent(table[i].substr(1)); + if (libName && typeof libName == 'string') { + table[i] = (libName.indexOf('.') < 0 ? '_' : '') + libName; + } + } + if (ASM_JS) { + var curr = table[i]; + if (curr && curr != '0' && !Functions.implementedFunctions[curr]) { + curr = toNiceIdent(curr); // fix Math.* to Math_* + // This is a library function, we can't just put it in the function table, need a wrapper + if (!wrapped[curr]) { + var args = '', arg_coercions = '', call = curr + '(', retPre = '', retPost = ''; + if (t[0] != 'v') { + if (t[0] == 'i') { + retPre = 'return '; + retPost = '|0'; + } else { + retPre = 'return +'; + } + } + for (var j = 1; j < t.length; j++) { + args += (j > 1 ? ',' : '') + 'a' + j; + arg_coercions += 'a' + j + '=' + asmCoercion('a' + j, t[j] != 'i' ? 'float' : 'i32') + ';'; + call += (j > 1 ? ',' : '') + asmCoercion('a' + j, t[j] != 'i' ? 'float' : 'i32'); + } + call += ')'; + tables.pre += 'function ' + curr + '__wrapper(' + args + ') { ' + arg_coercions + ' ; ' + retPre + call + retPost + ' }\n'; + wrapped[curr] = 1; + } + table[i] = curr + '__wrapper'; + } + } + } + if (table.length > 20) { + // add some newlines in the table, for readability + var j = 10; + while (j+10 < table.length) { + table[j] += '\n'; + j += 10; + } } + maxTable = Math.max(maxTable, table.length); + } + if (ASM_JS) maxTable = ceilPowerOfTwo(maxTable); + for (var t in tables) { + if (t == 'pre') continue; + var table = tables[t]; + if (ASM_JS) { + // asm function table mask must be power of two + // if nonaliasing, then standardize function table size, to avoid aliasing pointers through the &M mask (in a small table using a big index) + var fullSize = ALIASING_FUNCTION_POINTERS ? ceilPowerOfTwo(table.length) : maxTable; + for (var i = table.length; i < fullSize; i++) { + table[i] = 0; + } + } + // finalize table var indices = table.toString().replace('"', ''); if (BUILD_AS_SHARED_LIB) { // Shared libraries reuse the parent's function table. tables[t] = Functions.getTable(t) + '.push.apply(' + Functions.getTable(t) + ', [' + indices + ']);\n'; } else { tables[t] = 'var ' + Functions.getTable(t) + ' = [' + indices + '];\n'; + if (SAFE_DYNCALLS) { + tables[t] += 'var FUNCTION_TABLE_NAMES = ' + JSON.stringify(table).replace(/\n/g, '').replace(/,0/g, ',0\n') + ';\n'; + } } } if (!generated && !ASM_JS) { @@ -304,12 +391,13 @@ var Functions = { var LibraryManager = { library: null, + structs: {}, loaded: false, load: function() { if (this.library) return; - var libraries = ['library.js', 'library_browser.js', 'library_sdl.js', 'library_gl.js', 'library_glut.js', 'library_xlib.js', 'library_egl.js', 'library_gc.js', 'library_jansson.js'].concat(additionalLibraries); + var libraries = ['library.js', 'library_browser.js', 'library_sdl.js', 'library_gl.js', 'library_glut.js', 'library_xlib.js', 'library_egl.js', 'library_gc.js', 'library_jansson.js', 'library_openal.js', 'library_glfw.js'].concat(additionalLibraries); for (var i = 0; i < libraries.length; i++) { eval(processMacros(preprocess(read(libraries[i])))); } @@ -360,6 +448,7 @@ var PassManager = { indexedFunctions: Functions.indexedFunctions, implementedFunctions: ASM_JS ? Functions.implementedFunctions : [], unimplementedFunctions: Functions.unimplementedFunctions, + neededTables: Functions.neededTables } })); } else if (phase == 'post') { |