| #if !WASM_BACKEND && EMULATED_FUNCTION_POINTERS == 0 |
| var jsCallStartIndex = 1; |
| var functionPointers = new Array({{{ RESERVED_FUNCTION_POINTERS }}}); |
| #endif // !WASM_BACKEND && EMULATED_FUNCTION_POINTERS == 0 |
| |
| #if WASM |
| // Wraps a JS function as a wasm function with a given signature. |
| function convertJsFunctionToWasm(func, sig) { |
| #if WASM2JS |
| return func; |
| #else // WASM2JS |
| |
| // If the type reflection proposal is available, use the new |
| // "WebAssembly.Function" constructor. |
| // Otherwise, construct a minimal wasm module importing the JS function and |
| // re-exporting it. |
| if (typeof WebAssembly.Function === "function") { |
| var typeNames = { |
| 'i': 'i32', |
| 'j': 'i64', |
| 'f': 'f32', |
| 'd': 'f64' |
| }; |
| var type = { |
| parameters: [], |
| results: sig[0] == 'v' ? [] : [typeNames[sig[0]]] |
| }; |
| for (var i = 1; i < sig.length; ++i) { |
| type.parameters.push(typeNames[sig[i]]); |
| } |
| return new WebAssembly.Function(type, func); |
| } |
| |
| // The module is static, with the exception of the type section, which is |
| // generated based on the signature passed in. |
| var typeSection = [ |
| 0x01, // id: section, |
| 0x00, // length: 0 (placeholder) |
| 0x01, // count: 1 |
| 0x60, // form: func |
| ]; |
| var sigRet = sig.slice(0, 1); |
| var sigParam = sig.slice(1); |
| var typeCodes = { |
| 'i': 0x7f, // i32 |
| 'j': 0x7e, // i64 |
| 'f': 0x7d, // f32 |
| 'd': 0x7c, // f64 |
| }; |
| |
| // Parameters, length + signatures |
| typeSection.push(sigParam.length); |
| for (var i = 0; i < sigParam.length; ++i) { |
| typeSection.push(typeCodes[sigParam[i]]); |
| } |
| |
| // Return values, length + signatures |
| // With no multi-return in MVP, either 0 (void) or 1 (anything else) |
| if (sigRet == 'v') { |
| typeSection.push(0x00); |
| } else { |
| typeSection = typeSection.concat([0x01, typeCodes[sigRet]]); |
| } |
| |
| // Write the overall length of the type section back into the section header |
| // (excepting the 2 bytes for the section id and length) |
| typeSection[1] = typeSection.length - 2; |
| |
| // Rest of the module is static |
| var bytes = new Uint8Array([ |
| 0x00, 0x61, 0x73, 0x6d, // magic ("\0asm") |
| 0x01, 0x00, 0x00, 0x00, // version: 1 |
| ].concat(typeSection, [ |
| 0x02, 0x07, // import section |
| // (import "e" "f" (func 0 (type 0))) |
| 0x01, 0x01, 0x65, 0x01, 0x66, 0x00, 0x00, |
| 0x07, 0x05, // export section |
| // (export "f" (func 0 (type 0))) |
| 0x01, 0x01, 0x66, 0x00, 0x00, |
| ])); |
| |
| // We can compile this wasm module synchronously because it is very small. |
| // This accepts an import (at "e.f"), that it reroutes to an export (at "f") |
| var module = new WebAssembly.Module(bytes); |
| var instance = new WebAssembly.Instance(module, { |
| 'e': { |
| 'f': func |
| } |
| }); |
| var wrappedFunc = instance.exports['f']; |
| return wrappedFunc; |
| #endif // WASM2JS |
| } |
| |
| var freeTableIndexes = []; |
| |
| // Add a wasm function to the table. |
| function addFunctionWasm(func, sig) { |
| var table = wasmTable; |
| var ret; |
| // Reuse a free index if there is one, otherwise grow. |
| if (freeTableIndexes.length) { |
| ret = freeTableIndexes.pop(); |
| } else { |
| ret = table.length; |
| // Grow the table |
| try { |
| table.grow(1); |
| } catch (err) { |
| if (!(err instanceof RangeError)) { |
| throw err; |
| } |
| #if WASM_BACKEND |
| throw 'Unable to grow wasm table. Set ALLOW_TABLE_GROWTH.'; |
| #else |
| throw 'Unable to grow wasm table. Use a higher value for RESERVED_FUNCTION_POINTERS or set ALLOW_TABLE_GROWTH.'; |
| #endif |
| } |
| } |
| |
| // Set the new value. |
| try { |
| // Attempting to call this with JS function will cause of table.set() to fail |
| table.set(ret, func); |
| } catch (err) { |
| if (!(err instanceof TypeError)) { |
| throw err; |
| } |
| assert(typeof sig !== 'undefined', 'Missing signature argument to addFunction'); |
| var wrapped = convertJsFunctionToWasm(func, sig); |
| table.set(ret, wrapped); |
| } |
| |
| return ret; |
| } |
| |
| function removeFunctionWasm(index) { |
| freeTableIndexes.push(index); |
| } |
| #endif |
| |
| // 'sig' parameter is required for the llvm backend but only when func is not |
| // already a WebAssembly function. |
| function addFunction(func, sig) { |
| #if ASSERTIONS |
| assert(typeof func !== 'undefined'); |
| #if ASSERTIONS == 2 |
| if (typeof sig === 'undefined') { |
| err('warning: addFunction(): You should provide a wasm function signature string as a second argument. This is not necessary for asm.js and asm2wasm, but can be required for the LLVM wasm backend, so it is recommended for full portability.'); |
| } |
| #endif // ASSERTIONS == 2 |
| #endif // ASSERTIONS |
| |
| #if WASM_BACKEND |
| return addFunctionWasm(func, sig); |
| #else |
| |
| #if EMULATED_FUNCTION_POINTERS == 0 |
| var base = 0; |
| for (var i = base; i < base + {{{ RESERVED_FUNCTION_POINTERS }}}; i++) { |
| if (!functionPointers[i]) { |
| functionPointers[i] = func; |
| return jsCallStartIndex + i; |
| } |
| } |
| throw 'Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS.'; |
| |
| #else // EMULATED_FUNCTION_POINTERS == 0 |
| |
| #if WASM |
| return addFunctionWasm(func, sig); |
| #else |
| alignFunctionTables(); // TODO: we should rely on this being an invariant |
| var tables = getFunctionTables(); |
| var ret = -1; |
| for (var signature in tables) { |
| var table = tables[signature]; |
| if (ret < 0) ret = table.length; |
| else assert(ret === table.length); |
| table.push(func); |
| } |
| return ret; |
| #endif // WASM |
| |
| #endif // EMULATED_FUNCTION_POINTERS == 0 |
| #endif // WASM_BACKEND |
| } |
| |
| function removeFunction(index) { |
| #if WASM_BACKEND |
| removeFunctionWasm(index); |
| #else |
| |
| #if EMULATED_FUNCTION_POINTERS == 0 |
| functionPointers[index-jsCallStartIndex] = null; |
| #else |
| #if WASM |
| removeFunctionWasm(index); |
| #else |
| alignFunctionTables(); // XXX we should rely on this being an invariant |
| var tables = getFunctionTables(); |
| for (var sig in tables) { |
| tables[sig][index] = null; |
| } |
| #endif // WASM |
| |
| #endif // EMULATE_FUNCTION_POINTER_CASTS == 0 |
| #endif // WASM_BACKEND |
| } |