generate separate type-specific function tables

This commit is contained in:
Alon Zakai 2012-11-24 23:06:44 +01:00
Родитель ff39897223
Коммит 26e9eba5aa
9 изменённых файлов: 141 добавлений и 96 удалений

Просмотреть файл

@ -236,6 +236,8 @@ def emscript(infile, settings, outfile, libraries=[]):
if settings.get('ASM_JS'):
for key in curr_forwarded_json['Functions']['implementedFunctions'].iterkeys():
if key in all_exported_functions: exported_implemented_functions.add(key)
for key, value in curr_forwarded_json['Functions']['libraryFunctions'].iteritems():
forwarded_json['Functions']['libraryFunctions'][key] = value
funcs_js = ''.join([output[0] for output in outputs])
@ -247,7 +249,7 @@ def emscript(infile, settings, outfile, libraries=[]):
exports = '{ ' + ', '.join(exports) + ' }'
# caculate globals
global_vars = forwarded_json['Variables']['globals'].keys()
global_funcs = ['_' + x for x in forwarded_json['Functions']['libraryFunctions']]
global_funcs = ['_' + x for x in forwarded_json['Functions']['libraryFunctions'].keys()]
asm_globals = ''.join([' var ' + g + '=env.' + g + ';\n' for g in global_vars + global_funcs])
# sent data
basics = ['buffer', 'Int8Array', 'Int16Array', 'Int32Array', 'Uint8Array', 'Uint16Array', 'Uint32Array', 'Float32Array', 'Float64Array']
@ -311,6 +313,7 @@ for (var _export in asm) Module[_export] = asm[_export];
open(post_file, 'w').write('\n') # no input, just processing of forwarded data
out = shared.run_js(compiler, shared.COMPILER_ENGINE, [settings_file, post_file, 'post', forwarded_file] + libraries, stdout=subprocess.PIPE, cwd=path_from_root('src'))
#if DEBUG: outfile.write('// post\n')
outfile.write(indexize(out))
if DEBUG: print >> sys.stderr, ' emscript: phase 3 took %s seconds' % (time.time() - t)

Просмотреть файл

@ -125,6 +125,7 @@ function intertyper(data, sidePass, baseLineNums) {
// We need this early, to know basic function info - ident, params, varargs
ident: toNiceIdent(func.ident),
params: func.params,
returnType: func.returnType,
hasVarArgs: func.hasVarArgs,
lineNum: currFunctionLineNum,
lines: currFunctionLines

Просмотреть файл

@ -42,7 +42,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 }));
});
}
}
@ -420,7 +422,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.push(ident);
if (ASM_JS) Functions.libraryFunctions[ident] = 1;
}
var postsetId = ident + '__postset';
@ -1159,6 +1161,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);
@ -1224,8 +1227,8 @@ 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 + ']';
if (byPointer) {
ident = 'FUNCTION_TABLE_' + Functions.getSignature(type, argsTypes) + '[' + ident + ']';
}
return ident + '(' + args.join(', ') + ')';
@ -1324,8 +1327,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;
}
@ -1352,7 +1354,7 @@ 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) {
@ -1368,6 +1370,8 @@ function JSify(data, functionsOnly, givenFunctions) {
return IGNORED_FUNCTIONS.indexOf(func.ident) < 0;
})) + '\n');
PassManager.serialize();
return null;
}

Просмотреть файл

@ -1275,11 +1275,12 @@ var LibraryGL = {
getProcAddress: function(name) {
name = name.replace('EXT', '').replace('ARB', '');
// Do the translation carefully because of closure
var sig = '';
switch (name) {
case 'glCreateShaderObject': case 'glCreateShader': func = _glCreateShader; break;
case 'glCreateProgramObject': case 'glCreateProgram': func = _glCreateProgram; break;
case 'glAttachObject': case 'glAttachShader': func = _glAttachShader; break;
case 'glUseProgramObject': case 'glUseProgram': func = _glUseProgram; break;
case 'glCreateShaderObject': case 'glCreateShader': func = _glCreateShader; sig = 'ii'; break;
case 'glCreateProgramObject': case 'glCreateProgram': func = _glCreateProgram; sig = 'ii'; break;
case 'glAttachObject': case 'glAttachShader': func = _glAttachShader; sig = 'vi'; break;
case 'glUseProgramObject': case 'glUseProgram': func = _glUseProgram; sig = 'vi'; break;
case 'glDeleteObject': func = function(id) {
if (GL.programs[id]) {
_glDeleteProgram(id);
@ -1288,7 +1289,7 @@ var LibraryGL = {
} else {
Module.printErr('WARNING: deleteObject received invalid id: ' + id);
}
}; break;
}; sig = 'vi'; break;
case 'glGetObjectParameteriv': func = function(id, type, result) {
if (GL.programs[id]) {
if (type == 0x8B84) { // GL_OBJECT_INFO_LOG_LENGTH_ARB
@ -1305,7 +1306,7 @@ var LibraryGL = {
} else {
Module.printErr('WARNING: getObjectParameteriv received invalid id: ' + id);
}
}; break;
}; sig = 'viii'; break;
case 'glGetInfoLog': func = function(id, maxLength, length, infoLog) {
if (GL.programs[id]) {
_glGetProgramInfoLog(id, maxLength, length, infoLog);
@ -1314,58 +1315,58 @@ var LibraryGL = {
} else {
Module.printErr('WARNING: getObjectParameteriv received invalid id: ' + id);
}
}; break;
}; sig = 'viiii'; break;
case 'glBindProgram': func = function(type, id) {
assert(id == 0);
}; break;
case 'glDrawRangeElements': func = _glDrawRangeElements; break;
case 'glShaderSource': func = _glShaderSource; break;
case 'glCompileShader': func = _glCompileShader; break;
case 'glLinkProgram': func = _glLinkProgram; break;
case 'glGetUniformLocation': func = _glGetUniformLocation; break;
case 'glUniform1f': func = _glUniform1f; break;
case 'glUniform2f': func = _glUniform2f; break;
case 'glUniform3f': func = _glUniform3f; break;
case 'glUniform4f': func = _glUniform4f; break;
case 'glUniform1fv': func = _glUniform1fv; break;
case 'glUniform2fv': func = _glUniform2fv; break;
case 'glUniform3fv': func = _glUniform3fv; break;
case 'glUniform4fv': func = _glUniform4fv; break;
case 'glUniform1i': func = _glUniform1i; break;
case 'glUniform2i': func = _glUniform2i; break;
case 'glUniform3i': func = _glUniform3i; break;
case 'glUniform4i': func = _glUniform4i; break;
case 'glUniform1iv': func = _glUniform1iv; break;
case 'glUniform2iv': func = _glUniform2iv; break;
case 'glUniform3iv': func = _glUniform3iv; break;
case 'glUniform4iv': func = _glUniform4iv; break;
case 'glBindAttribLocation': func = _glBindAttribLocation; break;
case 'glGetActiveUniform': func = _glGetActiveUniform; break;
case 'glGenBuffers': func = _glGenBuffers; break;
case 'glBindBuffer': func = _glBindBuffer; break;
case 'glBufferData': func = _glBufferData; break;
case 'glBufferSubData': func = _glBufferSubData; break;
case 'glDeleteBuffers': func = _glDeleteBuffers; break;
case 'glActiveTexture': func = _glActiveTexture; break;
case 'glClientActiveTexture': func = _glClientActiveTexture; break;
case 'glGetProgramiv': func = _glGetProgramiv; break;
case 'glEnableVertexAttribArray': func = _glEnableVertexAttribArray; break;
case 'glDisableVertexAttribArray': func = _glDisableVertexAttribArray; break;
case 'glVertexAttribPointer': func = _glVertexAttribPointer; break;
case 'glBindRenderbuffer': func = _glBindRenderbuffer; break;
case 'glDeleteRenderbuffers': func = _glDeleteRenderbuffers; break;
case 'glGenRenderbuffers': func = _glGenRenderbuffers; break;
case 'glCompressedTexImage2D': func = _glCompressedTexImage2D; break;
case 'glCompressedTexSubImage2D': func = _glCompressedTexSubImage2D; break;
case 'glBindFramebuffer': func = _glBindFramebuffer; break;
case 'glGenFramebuffers': func = _glGenFramebuffers; break;
case 'glDeleteFramebuffers': func = _glDeleteFramebuffers; break;
case 'glFramebufferRenderbuffer': func = _glFramebufferRenderbuffer; break;
case 'glFramebufferTexture2D': func = _glFramebufferTexture2D; break;
case 'glGetFramebufferAttachmentParameteriv': func = _glGetFramebufferAttachmentParameteriv; break;
case 'glIsFramebuffer': func = _glIsFramebuffer; break;
case 'glCheckFramebufferStatus': func = _glCheckFramebufferStatus; break;
case 'glRenderbufferStorage': func = _glRenderbufferStorage; break;
}; sig = 'vii'; break;
case 'glDrawRangeElements': func = _glDrawRangeElements; sig = 'viiiiii'; break;
case 'glShaderSource': func = _glShaderSource; sig = 'viiii'; break;
case 'glCompileShader': func = _glCompileShader; sig = 'vi'; break;
case 'glLinkProgram': func = _glLinkProgram; sig = 'vi'; break;
case 'glGetUniformLocation': func = _glGetUniformLocation; sig = 'iii'; break;
case 'glUniform1f': func = _glUniform1f; sig = 'vid'; break;
case 'glUniform2f': func = _glUniform2f; sig = 'vidd'; break;
case 'glUniform3f': func = _glUniform3f; sig = 'viddd'; break;
case 'glUniform4f': func = _glUniform4f; sig = 'vidddd'; break;
case 'glUniform1fv': func = _glUniform1fv; sig = 'viii'; break;
case 'glUniform2fv': func = _glUniform2fv; sig = 'viii'; break;
case 'glUniform3fv': func = _glUniform3fv; sig = 'viii'; break;
case 'glUniform4fv': func = _glUniform4fv; sig = 'viii'; break;
case 'glUniform1i': func = _glUniform1i; sig = 'vii'; break;
case 'glUniform2i': func = _glUniform2i; sig = 'viii'; break;
case 'glUniform3i': func = _glUniform3i; sig = 'viiii'; break;
case 'glUniform4i': func = _glUniform4i; sig = 'viiii'; break;
case 'glUniform1iv': func = _glUniform1iv; sig = 'viii'; break;
case 'glUniform2iv': func = _glUniform2iv; sig = 'viii'; break;
case 'glUniform3iv': func = _glUniform3iv; sig = 'viii'; break;
case 'glUniform4iv': func = _glUniform4iv; sig = 'viii'; break;
case 'glBindAttribLocation': func = _glBindAttribLocation; sig = 'viii'; break;
case 'glGetActiveUniform': func = _glGetActiveUniform; sig = 'viiiiiii'; break;
case 'glGenBuffers': func = _glGenBuffers; sig = 'iii'; break;
case 'glBindBuffer': func = _glBindBuffer; sig = 'vii'; break;
case 'glBufferData': func = _glBufferData; sig = 'viiii'; break;
case 'glBufferSubData': func = _glBufferSubData; sig = 'viiii'; break;
case 'glDeleteBuffers': func = _glDeleteBuffers; sig = 'vii'; break;
case 'glActiveTexture': func = _glActiveTexture; sig = 'vi'; break;
case 'glClientActiveTexture': func = _glClientActiveTexture; sig = 'vi'; break;
case 'glGetProgramiv': func = _glGetProgramiv; sig = 'viii'; break;
case 'glEnableVertexAttribArray': func = _glEnableVertexAttribArray; sig = 'vi'; break;
case 'glDisableVertexAttribArray': func = _glDisableVertexAttribArray; sig = 'vi'; break;
case 'glVertexAttribPointer': func = _glVertexAttribPointer; sig = 'viiiiii'; break;
case 'glBindRenderbuffer': func = _glBindRenderbuffer; sig = 'vii'; break;
case 'glDeleteRenderbuffers': func = _glDeleteRenderbuffers; sig = 'vii'; break;
case 'glGenRenderbuffers': func = _glGenRenderbuffers; sig = 'vii'; break;
case 'glCompressedTexImage2D': func = _glCompressedTexImage2D; sig = 'viiiiiiii'; break;
case 'glCompressedTexSubImage2D': func = _glCompressedTexSubImage2D; sig = 'viiiiiiiii'; break;
case 'glBindFramebuffer': func = _glBindFramebuffer; sig = 'vii'; break;
case 'glGenFramebuffers': func = _glGenFramebuffers; sig = 'vii'; break;
case 'glDeleteFramebuffers': func = _glDeleteFramebuffers; sig = 'vii'; break;
case 'glFramebufferRenderbuffer': func = _glFramebufferRenderbuffer; sig = 'viiii'; break;
case 'glFramebufferTexture2D': func = _glFramebufferTexture2D; sig = 'viiiii'; break;
case 'glGetFramebufferAttachmentParameteriv': func = _glGetFramebufferAttachmentParameteriv; sig = 'viiii'; break;
case 'glIsFramebuffer': func = _glIsFramebuffer; sig = 'ii'; break;
case 'glCheckFramebufferStatus': func = _glCheckFramebufferStatus; sig = 'ii'; break;
case 'glRenderbufferStorage': func = _glRenderbufferStorage; sig = 'viiii'; break;
default: {
Module.printErr('WARNING: getProcAddress failed for ' + name);
func = function() {
@ -1374,7 +1375,7 @@ var LibraryGL = {
};
}
}
return Runtime.addFunction(func);
return Runtime.addFunction(func, sig);
}
},

Просмотреть файл

@ -216,15 +216,23 @@ var Types = {
};
var Functions = {
// All functions that will be implemented in this file
// 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. Maps id to 1, or to a signature if we need indexing
indexedFunctions: {},
nextIndex: 2, // Start at a non-0 (even, see below) value
blockAddresses: {}, // maps functions to a map of block labels to label ids
getSignature: function(returnType, argTypes) {
var sig = returnType == 'void' ? 'v' : (isIntImplemented(returnType) ? 'i' : 'f');
for (var i = 0; i < argTypes.length; i++) {
sig += isIntImplemented(argTypes[i]) ? 'i' : 'f';
}
return sig;
},
// Mark a function as needing indexing. Python will coordinate them all
getIndex: function(ident) {
if (phase != 'post') {
@ -243,25 +251,33 @@ var Functions = {
// Generate code for function indexing
generateIndexing: function() {
var vals = zeros(this.nextIndex);
var tables = {};
for (var ident in this.indexedFunctions) {
vals[this.indexedFunctions[ident]] = ident;
var sig = Functions.implementedFunctions[ident] || Functions.libraryFunctions[ident];
assert(sig);
if (!tables[sig]) tables[sig] = zeros(this.nextIndex); // TODO: make them compact
tables[sig][this.indexedFunctions[ident]] = ident;
}
// Resolve multi-level aliases all the way down
for (var i = 0; i < vals.length; i++) {
while (1) {
var varData = Variables.globals[vals[i]];
if (!(varData && varData.resolvedAlias)) break;
vals[i] = vals[+varData.resolvedAlias || eval(varData.resolvedAlias)]; // might need to eval to turn (6) into 6
var ret = '';
for (var t in tables) {
var table = tables[t];
for (var i = 0; i < table.length; i++) {
while (1) {
var varData = Variables.globals[table[i]];
if (!(varData && varData.resolvedAlias)) break;
table[i] = table[+varData.resolvedAlias || eval(varData.resolvedAlias)]; // might need to eval to turn (6) into 6
}
}
var indices = table.toString().replace('"', '');
if (BUILD_AS_SHARED_LIB) {
// Shared libraries reuse the parent's function table.
ret += 'FUNCTION_TABLE.push.apply(FUNCTION_TABLE_' + t + ', [' + indices + ']);\n';
} else {
ret += 'FUNCTION_TABLE_' + t + ' = [' + indices + '];\nModule["FUNCTION_TABLE_' + t + '"] = FUNCTION_TABLE_' + t + ';\n';
}
}
var indices = vals.toString().replace('"', '');
if (BUILD_AS_SHARED_LIB) {
// Shared libraries reuse the parent's function table.
return 'FUNCTION_TABLE.push.apply(FUNCTION_TABLE, [' + indices + ']);';
} else {
return 'FUNCTION_TABLE = [' + indices + ']; Module["FUNCTION_TABLE"] = FUNCTION_TABLE;';
}
Functions.tables = ret;
}
};
@ -320,9 +336,15 @@ var PassManager = {
Functions: {
blockAddresses: Functions.blockAddresses,
indexedFunctions: Functions.indexedFunctions,
implementedFunctions: ASM_JS ? Functions.implementedFunctions : []
implementedFunctions: ASM_JS ? Functions.implementedFunctions : [],
libraryFunctions: ASM_JS ? Functions.libraryFunctions : {},
}
}));
} else if (phase == 'post') {
printErr('forward post!');
print('\n//FORWARDED_DATA:' + JSON.stringify({
Functions: { tables: Functions.tables }
}));
}
},
load: function(json) {

Просмотреть файл

@ -163,11 +163,13 @@ function isFunctionDef(token, out) {
var subtext = segment[0].text;
fail = fail || segment.length > 1 || !(isType(subtext) || subtext == '...');
});
if (out) out.numArgs = segments.length;
if (out) {
out.segments = segments;
out.numArgs = segments.length;
}
return !fail;
}
function isPossiblyFunctionType(type) {
// A quick but unreliable way to see if something is a function type. Yes is just 'maybe', no is definite.
var len = type.length;
@ -189,6 +191,7 @@ function isFunctionType(type, out) {
if (pointingLevels(type) !== 1) return false;
var text = removeAllPointing(parts.slice(1).join(' '));
if (!text) return false;
if (out) out.returnType = parts[0];
return isType(parts[0]) && isFunctionDef({ text: text, item: tokenize(text.substr(1, text.length-2), true) }, out);
}
@ -1000,7 +1003,13 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSa
function indexizeFunctions(value, type) {
assert((type && type !== '?') || (typeof value === 'string' && value.substr(0, 6) === 'CHECK_'), 'No type given for function indexizing');
assert(value !== type, 'Type set to value');
if (type && isFunctionType(type) && value[0] === '_') { // checking for _ differentiates from $ (local vars)
var out = {};
if (type && isFunctionType(type, out) && value[0] === '_') { // checking for _ differentiates from $ (local vars)
// add signature to library functions that we now know need indexing
if (!(value in Functions.implementedFunctions) && !(value in Functions.libraryFunctions)) {
Functions.libraryFunctions[value] = Functions.getSignature(out.returnType, out.segments ? out.segments.map(function(segment) { return segment[0].text }) : []);
}
if (BUILD_AS_SHARED_LIB) {
return '(FUNCTION_TABLE_OFFSET + ' + Functions.getIndex(value) + ')';
} else {

Просмотреть файл

@ -575,9 +575,6 @@ Module['Array_stringify'] = Array_stringify;
// Memory management
var FUNCTION_TABLE; // XXX: In theory the indexes here can be equal to pointers to stacked or malloced memory. Such comparisons should
// be false, but can turn out true. We should probably set the top bit to prevent such issues.
var PAGE_SIZE = 4096;
function alignMemoryPage(x) {
return ((x+4095)>>12)<<12;
@ -735,7 +732,7 @@ function callRuntimeCallbacks(callbacks) {
var callback = callbacks.shift();
var func = callback.func;
if (typeof func === 'number') {
func = FUNCTION_TABLE[func];
func = FUNCTION_TABLE_v[func]; // void()
}
func(callback.arg === undefined ? null : callback.arg);
}

Просмотреть файл

@ -311,10 +311,16 @@ var Runtime = {
return ret;
},
addFunction: function(func) {
var ret = FUNCTION_TABLE.length;
FUNCTION_TABLE.push(func);
FUNCTION_TABLE.push(0);
getFunctionTable: function(sig) { // return value, param types e.g. "vid" void (int, double)
return Module['FUNCTION_TABLE_' + sig];
},
addFunction: function(func, sig) {
assert(sig);
var table = Runtime.getFunctionTable(sig);
var ret = table.length;
table.push(func);
table.push(0);
return ret;
},
@ -328,10 +334,12 @@ var Runtime = {
funcWrappers: {},
getFuncWrapper: function(func) {
getFuncWrapper: function(func, sig) {
assert(sig);
var table = Runtime.getFunctionTable(sig);
if (!Runtime.funcWrappers[func]) {
Runtime.funcWrappers[func] = function() {
FUNCTION_TABLE[func].apply(null, arguments);
table[func].apply(null, arguments);
};
}
return Runtime.funcWrappers[func];

Просмотреть файл

@ -7489,7 +7489,7 @@ TT = %s
exec('o2 = make_run("o2", compiler=CLANG, emcc_args=["-O2", "--closure", "0"])')
# asm.js
exec('asm = make_run("asm", compiler=CLANG, emcc_args=["-O2", "--closure", "0", "-s", "ASM_JS=1"])')
exec('asm = make_run("asm", compiler=CLANG, emcc_args=["-O0", "--closure", "0", "-s", "ASM_JS=1"])')
# Make custom runs with various options
for compiler, quantum, embetter, typed_arrays, llvm_opts in [