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