diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/intertyper.js | 1 | ||||
-rw-r--r-- | src/jsifier.js | 18 | ||||
-rw-r--r-- | src/library_gl.js | 115 | ||||
-rw-r--r-- | src/modules.js | 56 | ||||
-rw-r--r-- | src/parseTools.js | 15 | ||||
-rw-r--r-- | src/preamble.js | 5 | ||||
-rw-r--r-- | src/runtime.js | 20 |
7 files changed, 136 insertions, 94 deletions
diff --git a/src/intertyper.js b/src/intertyper.js index 7db1a2fe..4957ae31 100644 --- a/src/intertyper.js +++ b/src/intertyper.js @@ -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 diff --git a/src/jsifier.js b/src/jsifier.js index 3a9d6ab5..6f40e2d4 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -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; } diff --git a/src/library_gl.js b/src/library_gl.js index b4098813..6927c3ec 100644 --- a/src/library_gl.js +++ b/src/library_gl.js @@ -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); } }, diff --git a/src/modules.js b/src/modules.js index 94fe582c..2dc6c342 100644 --- a/src/modules.js +++ b/src/modules.js @@ -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) { diff --git a/src/parseTools.js b/src/parseTools.js index 4a76a9a2..080ef6fd 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -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 { diff --git a/src/preamble.js b/src/preamble.js index 9342bf2b..931c8f51 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -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); } diff --git a/src/runtime.js b/src/runtime.js index dd14e779..8c1fbd65 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -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]; |