| // Copyright 2017 The Emscripten Authors. All rights reserved. |
| // Emscripten is available under two separate licenses, the MIT license and the |
| // University of Illinois/NCSA Open Source License. Both these licenses can be |
| // found in the LICENSE file. |
| |
| // {{PREAMBLE_ADDITIONS}} |
| |
| var STACK_ALIGN = {{{ STACK_ALIGN }}}; |
| |
| #if ASSERTIONS |
| // stack management, and other functionality that is provided by the compiled code, |
| // should not be used before it is ready |
| stackSave = stackRestore = stackAlloc = function() { |
| abort('cannot use the stack before compiled code is ready to run, and has provided stack access'); |
| }; |
| |
| function staticAlloc(size) { |
| abort('staticAlloc is no longer available at runtime; instead, perform static allocations at compile time (using makeStaticAlloc)'); |
| } |
| #endif |
| |
| function dynamicAlloc(size) { |
| #if ASSERTIONS |
| assert(DYNAMICTOP_PTR); |
| #endif |
| var ret = HEAP32[DYNAMICTOP_PTR>>2]; |
| var end = (ret + size + 15) & -16; |
| if (end <= _emscripten_get_heap_size()) { |
| HEAP32[DYNAMICTOP_PTR>>2] = end; |
| } else { |
| #if ALLOW_MEMORY_GROWTH |
| var success = _emscripten_resize_heap(end); |
| if (!success) return 0; |
| #else |
| return 0; |
| #endif |
| } |
| return ret; |
| } |
| |
| {{{ alignMemory }}} |
| |
| {{{ getNativeTypeSize }}} |
| |
| function warnOnce(text) { |
| if (!warnOnce.shown) warnOnce.shown = {}; |
| if (!warnOnce.shown[text]) { |
| warnOnce.shown[text] = 1; |
| err(text); |
| } |
| } |
| |
| var asm2wasmImports = { // special asm2wasm imports |
| "f64-rem": function(x, y) { |
| return x % y; |
| }, |
| "debugger": function() { |
| debugger; |
| } |
| #if NEED_ALL_ASM2WASM_IMPORTS |
| , |
| "f64-to-int": function(x) { |
| return x | 0; |
| }, |
| "i32s-div": function(x, y) { |
| return ((x | 0) / (y | 0)) | 0; |
| }, |
| "i32u-div": function(x, y) { |
| return ((x >>> 0) / (y >>> 0)) >>> 0; |
| }, |
| "i32s-rem": function(x, y) { |
| return ((x | 0) % (y | 0)) | 0; |
| }, |
| "i32u-rem": function(x, y) { |
| return ((x >>> 0) % (y >>> 0)) >>> 0; |
| } |
| #endif // NEED_ALL_ASM2WASM_IMPORTS |
| }; |
| |
| #if RELOCATABLE |
| // dynamic linker/loader (a-la ld.so on ELF systems) |
| var LDSO = { |
| // next free handle to use for a loaded dso. |
| // (handle=0 is avoided as it means "error" in dlopen) |
| nextHandle: 1, |
| |
| loadedLibs: { // handle -> dso [refcount, name, module, global] |
| // program itself |
| // XXX uglifyjs fails on "[-1]: {" |
| '-1': { |
| refcount: Infinity, // = nodelete |
| name: '__self__', |
| module: Module, |
| global: true |
| } |
| }, |
| |
| loadedLibNames: { // name -> handle |
| // program itself |
| '__self__': -1 |
| }, |
| } |
| |
| // fetchBinary fetches binaray data @ url. (async) |
| function fetchBinary(url) { |
| return fetch(url, { credentials: 'same-origin' }).then(function(response) { |
| if (!response['ok']) { |
| throw "failed to load binary file at '" + url + "'"; |
| } |
| return response['arrayBuffer'](); |
| }).then(function(buffer) { |
| return new Uint8Array(buffer); |
| }); |
| } |
| |
| // loadDynamicLibrary loads dynamic library @ lib URL / path and returns handle for loaded DSO. |
| // |
| // Several flags affect the loading: |
| // |
| // - if flags.global=true, symbols from the loaded library are merged into global |
| // process namespace. Flags.global is thus similar to RTLD_GLOBAL in ELF. |
| // |
| // - if flags.nodelete=true, the library will be never unloaded. Flags.nodelete |
| // is thus similar to RTLD_NODELETE in ELF. |
| // |
| // - if flags.loadAsync=true, the loading is performed asynchronously and |
| // loadDynamicLibrary returns corresponding promise. |
| // |
| // - if flags.fs is provided, it is used as FS-like interface to load library data. |
| // By default, when flags.fs=undefined, native loading capabilities of the |
| // environment are used. |
| // |
| // If a library was already loaded, it is not loaded a second time. However |
| // flags.global and flags.nodelete are handled every time a load request is made. |
| // Once a library becomes "global" or "nodelete", it cannot be removed or unloaded. |
| function loadDynamicLibrary(lib, flags) { |
| // when loadDynamicLibrary did not have flags, libraries were loaded globally & permanently |
| flags = flags || {global: true, nodelete: true} |
| |
| var handle = LDSO.loadedLibNames[lib]; |
| var dso; |
| if (handle) { |
| // the library is being loaded or has been loaded already. |
| // |
| // however it could be previously loaded only locally and if we get |
| // load request with global=true we have to make it globally visible now. |
| dso = LDSO.loadedLibs[handle]; |
| if (flags.global && !dso.global) { |
| dso.global = true; |
| if (dso.module !== 'loading') { |
| // ^^^ if module is 'loading' - symbols merging will be eventually done by the loader. |
| mergeLibSymbols(dso.module) |
| } |
| } |
| // same for "nodelete" |
| if (flags.nodelete && dso.refcount !== Infinity) { |
| dso.refcount = Infinity; |
| } |
| dso.refcount++ |
| return flags.loadAsync ? Promise.resolve(handle) : handle; |
| } |
| |
| // allocate new DSO & handle |
| handle = LDSO.nextHandle++; |
| dso = { |
| refcount: flags.nodelete ? Infinity : 1, |
| name: lib, |
| module: 'loading', |
| global: flags.global, |
| }; |
| LDSO.loadedLibNames[lib] = handle; |
| LDSO.loadedLibs[handle] = dso; |
| |
| // libData <- lib |
| function loadLibData() { |
| #if WASM |
| // for wasm, we can use fetch for async, but for fs mode we can only imitate it |
| if (flags.fs) { |
| var libData = flags.fs.readFile(lib, {encoding: 'binary'}); |
| if (!(libData instanceof Uint8Array)) { |
| libData = new Uint8Array(lib_data); |
| } |
| return flags.loadAsync ? Promise.resolve(libData) : libData; |
| } |
| |
| if (flags.loadAsync) { |
| return fetchBinary(lib); |
| } |
| // load the binary synchronously |
| return Module['readBinary'](lib); |
| #else |
| // for js we only imitate async for both native & fs modes. |
| var libData; |
| if (flags.fs) { |
| libData = flags.fs.readFile(lib, {encoding: 'utf8'}); |
| } else { |
| libData = Module['read'](lib); |
| } |
| return flags.loadAsync ? Promise.resolve(libData) : libData; |
| #endif |
| } |
| |
| // libModule <- libData |
| function createLibModule(libData) { |
| #if WASM |
| return loadWebAssemblyModule(libData, flags) |
| #else |
| var libModule = eval(libData)( |
| alignFunctionTables(), |
| Module |
| ); |
| // load dynamic libraries that this js lib depends on |
| // (wasm loads needed libraries _before_ lib in its own codepath) |
| if (libModule.dynamicLibraries) { |
| if (flags.loadAsync) { |
| return Promise.all(libModule.dynamicLibraries.map(function(dynNeeded) { |
| return loadDynamicLibrary(dynNeeded, flags); |
| })).then(function() { |
| return libModule; |
| }); |
| } |
| |
| libModule.dynamicLibraries.forEach(function(dynNeeded) { |
| loadDynamicLibrary(dynNeeded, flags); |
| }); |
| } |
| return libModule; |
| #endif |
| } |
| |
| // libModule <- lib |
| function getLibModule() { |
| // lookup preloaded cache first |
| if (Module['preloadedWasm'] !== undefined && |
| Module['preloadedWasm'][lib] !== undefined) { |
| var libModule = Module['preloadedWasm'][lib]; |
| return flags.loadAsync ? Promise.resolve(libModule) : libModule; |
| } |
| |
| // module not preloaded - load lib data and create new module from it |
| if (flags.loadAsync) { |
| return loadLibData(lib).then(function(libData) { |
| return createLibModule(libData); |
| }); |
| } |
| |
| return createLibModule(loadLibData(lib)); |
| } |
| |
| // Module.symbols <- libModule.symbols (flags.global handler) |
| function mergeLibSymbols(libModule) { |
| // add symbols into global namespace TODO: weak linking etc. |
| for (var sym in libModule) { |
| if (!libModule.hasOwnProperty(sym)) { |
| continue; |
| } |
| |
| // When RTLD_GLOBAL is enable, the symbols defined by this shared object will be made |
| // available for symbol resolution of subsequently loaded shared objects. |
| // |
| // We should copy the symbols (which include methods and variables) from SIDE_MODULE to MAIN_MODULE. |
| // |
| // Module of SIDE_MODULE has not only the symbols (which should be copied) |
| // but also others (print*, asmGlobal*, FUNCTION_TABLE_**, NAMED_GLOBALS, and so on). |
| // |
| // When the symbol (which should be copied) is method, Module._* 's type becomes function. |
| // When the symbol (which should be copied) is variable, Module._* 's type becomes number. |
| // |
| // Except for the symbol prefix (_), there is no difference in the symbols (which should be copied) and others. |
| // So this just copies over compiled symbols (which start with _). |
| if (sym[0] !== '_') { |
| continue; |
| } |
| |
| if (!Module.hasOwnProperty(sym)) { |
| Module[sym] = libModule[sym]; |
| } |
| #if ASSERTIONS == 2 |
| else { |
| var curr = Module[sym], next = libModule[sym]; |
| // don't warn on functions - might be odr, linkonce_odr, etc. |
| if (!(typeof curr === 'function' && typeof next === 'function')) { |
| err("warning: trying to dynamically load symbol '" + sym + "' (from '" + lib + "') that already exists (duplicate symbol? or weak linking, which isn't supported yet?)"); // + [curr, ' vs ', next]); |
| } |
| } |
| #endif |
| } |
| } |
| |
| // module for lib is loaded - update the dso & global namespace |
| function moduleLoaded(libModule) { |
| if (dso.global) { |
| mergeLibSymbols(libModule); |
| } |
| dso.module = libModule; |
| } |
| |
| if (flags.loadAsync) { |
| return getLibModule().then(function(libModule) { |
| moduleLoaded(libModule); |
| return handle; |
| }) |
| } |
| |
| moduleLoaded(getLibModule()); |
| return handle; |
| } |
| |
| #if WASM |
| // Loads a side module from binary data |
| function loadWebAssemblyModule(binary, flags) { |
| var int32View = new Uint32Array(new Uint8Array(binary.subarray(0, 24)).buffer); |
| assert(int32View[0] == 0x6d736100, 'need to see wasm magic number'); // \0asm |
| // we should see the dylink section right after the magic number and wasm version |
| assert(binary[8] === 0, 'need the dylink section to be first') |
| var next = 9; |
| function getLEB() { |
| var ret = 0; |
| var mul = 1; |
| while (1) { |
| var byte = binary[next++]; |
| ret += ((byte & 0x7f) * mul); |
| mul *= 0x80; |
| if (!(byte & 0x80)) break; |
| } |
| return ret; |
| } |
| var sectionSize = getLEB(); |
| assert(binary[next] === 6); next++; // size of "dylink" string |
| assert(binary[next] === 'd'.charCodeAt(0)); next++; |
| assert(binary[next] === 'y'.charCodeAt(0)); next++; |
| assert(binary[next] === 'l'.charCodeAt(0)); next++; |
| assert(binary[next] === 'i'.charCodeAt(0)); next++; |
| assert(binary[next] === 'n'.charCodeAt(0)); next++; |
| assert(binary[next] === 'k'.charCodeAt(0)); next++; |
| var memorySize = getLEB(); |
| var memoryAlign = getLEB(); |
| var tableSize = getLEB(); |
| var tableAlign = getLEB(); |
| |
| // shared libraries this module needs. We need to load them first, so that |
| // current module could resolve its imports. (see tools/shared.py |
| // WebAssembly.make_shared_library() for "dylink" section extension format) |
| var neededDynlibsCount = getLEB(); |
| var neededDynlibs = []; |
| for (var i = 0; i < neededDynlibsCount; ++i) { |
| var nameLen = getLEB(); |
| var nameUTF8 = binary.subarray(next, next + nameLen); |
| next += nameLen; |
| var name = UTF8ArrayToString(nameUTF8, 0); |
| neededDynlibs.push(name); |
| } |
| |
| // loadModule loads the wasm module after all its dependencies have been loaded. |
| // can be called both sync/async. |
| function loadModule() { |
| // alignments are powers of 2 |
| memoryAlign = Math.pow(2, memoryAlign); |
| tableAlign = Math.pow(2, tableAlign); |
| // finalize alignments and verify them |
| memoryAlign = Math.max(memoryAlign, STACK_ALIGN); // we at least need stack alignment |
| #if ASSERTIONS |
| assert(tableAlign === 1, 'invalid tableAlign ' + tableAlign); |
| #endif |
| // prepare memory |
| var memoryBase = alignMemory(getMemory(memorySize + memoryAlign), memoryAlign); // TODO: add to cleanups |
| // The static area consists of explicitly initialized data, followed by zero-initialized data. |
| // The latter may need zeroing out if the MAIN_MODULE has already used this memory area before |
| // dlopen'ing the SIDE_MODULE. Since we don't know the size of the explicitly initialized data |
| // here, we just zero the whole thing, which is suboptimal, but should at least resolve bugs |
| // from uninitialized memory. |
| for (var i = memoryBase; i < memoryBase + memorySize; ++i) HEAP8[i] = 0; |
| // prepare env imports |
| var env = asmLibraryArg; |
| // TODO: use only __memory_base and __table_base, need to update asm.js backend |
| var table = wasmTable; |
| var tableBase = table.length; |
| var originalTable = table; |
| table.grow(tableSize); |
| assert(table === originalTable); |
| // zero-initialize memory and table |
| // TODO: in some cases we can tell it is already zero initialized |
| for (var i = memoryBase; i < memoryBase + memorySize; i++) { |
| HEAP8[i] = 0; |
| } |
| for (var i = tableBase; i < tableBase + tableSize; i++) { |
| table.set(i, null); |
| } |
| // copy currently exported symbols so the new module can import them |
| for (var x in Module) { |
| if (!(x in env)) { |
| env[x] = Module[x]; |
| } |
| } |
| // TODO kill ↓↓↓ (except "symbols local to this module", it will likely be |
| // not needed if we require that if A wants symbols from B it has to link |
| // to B explicitly: similarly to -Wl,--no-undefined) |
| // |
| // wasm dynamic libraries are pure wasm, so they cannot assist in |
| // their own loading. When side module A wants to import something |
| // provided by a side module B that is loaded later, we need to |
| // add a layer of indirection, but worse, we can't even tell what |
| // to add the indirection for, without inspecting what A's imports |
| // are. To do that here, we use a JS proxy (another option would |
| // be to inspect the binary directly). |
| var proxyHandler = { |
| 'get': function(obj, prop) { |
| // symbols that should be local to this module |
| switch (prop) { |
| case '__memory_base': |
| case 'gb': |
| return memoryBase; |
| case '__table_base': |
| case 'fb': |
| return tableBase; |
| } |
| |
| if (prop in obj) { |
| return obj[prop]; // already present |
| } |
| if (prop.startsWith('g$')) { |
| // a global. the g$ function returns the global address. |
| var name = prop.substr(2); // without g$ prefix |
| return env[prop] = function() { |
| #if ASSERTIONS |
| assert(Module[name], 'missing linked global ' + name + '. perhaps a side module was not linked in? if this global was expected to arrive from a system library, try to build the MAIN_MODULE with EMCC_FORCE_STDLIBS=1 in the environment'); |
| #endif |
| return Module[name]; |
| }; |
| } |
| if (prop.startsWith('invoke_')) { |
| // A missing invoke, i.e., an invoke for a function type |
| // present in the dynamic library but not in the main JS, |
| // and the dynamic library cannot provide JS for it. Use |
| // the generic "X" invoke for it. |
| return env[prop] = invoke_X; |
| } |
| // if not a global, then a function - call it indirectly |
| return env[prop] = function() { |
| #if ASSERTIONS |
| assert(Module[prop], 'missing linked function ' + prop + '. perhaps a side module was not linked in? if this function was expected to arrive from a system library, try to build the MAIN_MODULE with EMCC_FORCE_STDLIBS=1 in the environment'); |
| #endif |
| return Module[prop].apply(null, arguments); |
| }; |
| } |
| }; |
| var info = { |
| global: { |
| 'NaN': NaN, |
| 'Infinity': Infinity, |
| }, |
| 'global.Math': Math, |
| env: new Proxy(env, proxyHandler), |
| 'asm2wasm': asm2wasmImports |
| }; |
| #if ASSERTIONS |
| var oldTable = []; |
| for (var i = 0; i < tableBase; i++) { |
| oldTable.push(table.get(i)); |
| } |
| #endif |
| |
| function postInstantiation(instance) { |
| var exports = {}; |
| #if ASSERTIONS |
| // the table should be unchanged |
| assert(table === originalTable); |
| assert(table === wasmTable); |
| if (instance.exports['table']) { |
| assert(table === instance.exports['table']); |
| } |
| // the old part of the table should be unchanged |
| for (var i = 0; i < tableBase; i++) { |
| assert(table.get(i) === oldTable[i], 'old table entries must remain the same'); |
| } |
| // verify that the new table region was filled in |
| for (var i = 0; i < tableSize; i++) { |
| assert(table.get(tableBase + i) !== undefined, 'table entry was not filled in'); |
| } |
| #endif |
| for (var e in instance.exports) { |
| var value = instance.exports[e]; |
| if (typeof value === 'object') { |
| // a breaking change in the wasm spec, globals are now objects |
| // https://github.com/WebAssembly/mutable-global/issues/1 |
| value = value.value; |
| } |
| if (typeof value === 'number') { |
| // relocate it - modules export the absolute value, they can't relocate before they export |
| #if EMULATE_FUNCTION_POINTER_CASTS |
| // it may be a function pointer |
| if (e.substr(0, 3) == 'fp$' && typeof instance.exports[e.substr(3)] === 'function') { |
| value = value + tableBase; |
| } else { |
| #endif |
| value = value + memoryBase; |
| #if EMULATE_FUNCTION_POINTER_CASTS |
| } |
| #endif |
| } |
| exports[e] = value; |
| } |
| // initialize the module |
| var init = exports['__post_instantiate']; |
| if (init) { |
| if (runtimeInitialized) { |
| init(); |
| } else { |
| // we aren't ready to run compiled code yet |
| __ATINIT__.push(init); |
| } |
| } |
| return exports; |
| } |
| |
| if (flags.loadAsync) { |
| return WebAssembly.instantiate(binary, info).then(function(result) { |
| return postInstantiation(result.instance); |
| }); |
| } else { |
| var instance = new WebAssembly.Instance(new WebAssembly.Module(binary), info); |
| return postInstantiation(instance); |
| } |
| } |
| |
| // now load needed libraries and the module itself. |
| if (flags.loadAsync) { |
| return Promise.all(neededDynlibs.map(function(dynNeeded) { |
| return loadDynamicLibrary(dynNeeded, flags); |
| })).then(function() { |
| return loadModule(); |
| }); |
| } |
| |
| neededDynlibs.forEach(function(dynNeeded) { |
| loadDynamicLibrary(dynNeeded, flags); |
| }); |
| return loadModule(); |
| } |
| Module['loadWebAssemblyModule'] = loadWebAssemblyModule; |
| |
| #endif // WASM |
| #endif // RELOCATABLE |
| |
| #if EMULATED_FUNCTION_POINTERS |
| #if WASM == 0 |
| function getFunctionTables(module) { |
| if (!module) module = Module; |
| var tables = {}; |
| for (var t in module) { |
| if (/^FUNCTION_TABLE_.*/.test(t)) { |
| var table = module[t]; |
| if (typeof table === 'object') tables[t.substr('FUNCTION_TABLE_'.length)] = table; |
| } |
| } |
| return tables; |
| } |
| |
| function alignFunctionTables(module) { |
| var tables = getFunctionTables(module); |
| var maxx = 0; |
| for (var sig in tables) { |
| maxx = Math.max(maxx, tables[sig].length); |
| } |
| assert(maxx >= 0); |
| for (var sig in tables) { |
| var table = tables[sig]; |
| while (table.length < maxx) table.push(0); |
| } |
| return maxx; |
| } |
| #endif // WASM == 0 |
| |
| #if RELOCATABLE |
| // register functions from a new module being loaded |
| function registerFunctions(sigs, newModule) { |
| sigs.forEach(function(sig) { |
| if (!Module['FUNCTION_TABLE_' + sig]) { |
| Module['FUNCTION_TABLE_' + sig] = []; |
| } |
| }); |
| var oldMaxx = alignFunctionTables(); // align the new tables we may have just added |
| var newMaxx = alignFunctionTables(newModule); |
| var maxx = oldMaxx + newMaxx; |
| sigs.forEach(function(sig) { |
| var newTable = newModule['FUNCTION_TABLE_' + sig]; |
| var oldTable = Module['FUNCTION_TABLE_' + sig]; |
| assert(newTable !== oldTable); |
| assert(oldTable.length === oldMaxx); |
| for (var i = 0; i < newTable.length; i++) { |
| oldTable.push(newTable[i]); |
| } |
| assert(oldTable.length === maxx); |
| }); |
| assert(maxx === alignFunctionTables()); // align the ones we didn't touch |
| } |
| // export this so side modules can use it |
| Module['registerFunctions'] = registerFunctions; |
| #endif // RELOCATABLE |
| #endif // EMULATED_FUNCTION_POINTERS |
| |
| #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. |
| // In the future, we may get a WebAssembly.Function constructor. Until then, |
| // we create a wasm module that takes the JS function as an import with a given |
| // signature, and re-exports that as a wasm function. |
| function convertJsFunctionToWasm(func, sig) { |
| // 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; |
| } |
| |
| // Add a wasm function to the table. |
| function addFunctionWasm(func, sig) { |
| var table = wasmTable; |
| var ret = table.length; |
| |
| // Grow the table |
| try { |
| table.grow(1); |
| } catch (err) { |
| if (!err instanceof RangeError) { |
| throw err; |
| } |
| throw 'Unable to grow wasm table. Use a higher value for RESERVED_FUNCTION_POINTERS or set ALLOW_TABLE_GROWTH.'; |
| } |
| |
| // Insert new element |
| 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) { |
| // TODO(sbc): Look into implementing this to allow re-using of table slots |
| } |
| #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 == 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 |
| |
| #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 sig in tables) { |
| var table = tables[sig]; |
| 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 |
| } |
| |
| var funcWrappers = {}; |
| |
| function getFuncWrapper(func, sig) { |
| if (!func) return; // on null pointer, return undefined |
| assert(sig); |
| if (!funcWrappers[sig]) { |
| funcWrappers[sig] = {}; |
| } |
| var sigCache = funcWrappers[sig]; |
| if (!sigCache[func]) { |
| // optimize away arguments usage in common cases |
| if (sig.length === 1) { |
| sigCache[func] = function dynCall_wrapper() { |
| return dynCall(sig, func); |
| }; |
| } else if (sig.length === 2) { |
| sigCache[func] = function dynCall_wrapper(arg) { |
| return dynCall(sig, func, [arg]); |
| }; |
| } else { |
| // general case |
| sigCache[func] = function dynCall_wrapper() { |
| return dynCall(sig, func, Array.prototype.slice.call(arguments)); |
| }; |
| } |
| } |
| return sigCache[func]; |
| } |
| |
| #if RUNTIME_DEBUG |
| var runtimeDebug = true; // Switch to false at runtime to disable logging at the right times |
| |
| var printObjectList = []; |
| |
| function prettyPrint(arg) { |
| if (typeof arg == 'undefined') return '!UNDEFINED!'; |
| if (typeof arg == 'boolean') arg = arg + 0; |
| if (!arg) return arg; |
| var index = printObjectList.indexOf(arg); |
| if (index >= 0) return '<' + arg + '|' + index + '>'; |
| if (arg.toString() == '[object HTMLImageElement]') { |
| return arg + '\n\n'; |
| } |
| if (arg.byteLength) { |
| return '{' + Array.prototype.slice.call(arg, 0, Math.min(arg.length, 400)) + '}'; // Useful for correct arrays, less so for compiled arrays, see the code below for that |
| var buf = new ArrayBuffer(32); |
| var i8buf = new Int8Array(buf); |
| var i16buf = new Int16Array(buf); |
| var f32buf = new Float32Array(buf); |
| switch(arg.toString()) { |
| case '[object Uint8Array]': |
| i8buf.set(arg.subarray(0, 32)); |
| break; |
| case '[object Float32Array]': |
| f32buf.set(arg.subarray(0, 5)); |
| break; |
| case '[object Uint16Array]': |
| i16buf.set(arg.subarray(0, 16)); |
| break; |
| default: |
| alert('unknown array for debugging: ' + arg); |
| throw 'see alert'; |
| } |
| var ret = '{' + arg.byteLength + ':\n'; |
| var arr = Array.prototype.slice.call(i8buf); |
| ret += 'i8:' + arr.toString().replace(/,/g, ',') + '\n'; |
| arr = Array.prototype.slice.call(f32buf, 0, 8); |
| ret += 'f32:' + arr.toString().replace(/,/g, ',') + '}'; |
| return ret; |
| } |
| if (typeof arg == 'object') { |
| printObjectList.push(arg); |
| return '<' + arg + '|' + (printObjectList.length-1) + '>'; |
| } |
| if (typeof arg == 'number') { |
| if (arg > 0) return '0x' + arg.toString(16) + ' (' + arg + ')'; |
| } |
| return arg; |
| } |
| #endif |
| |
| function makeBigInt(low, high, unsigned) { |
| return unsigned ? ((+((low>>>0)))+((+((high>>>0)))*4294967296.0)) : ((+((low>>>0)))+((+((high|0)))*4294967296.0)); |
| } |
| |
| function dynCall(sig, ptr, args) { |
| if (args && args.length) { |
| #if ASSERTIONS |
| assert(args.length == sig.length-1); |
| #endif |
| #if ASSERTIONS |
| assert(('dynCall_' + sig) in Module, 'bad function pointer type - no table for sig \'' + sig + '\''); |
| #endif |
| return Module['dynCall_' + sig].apply(null, [ptr].concat(args)); |
| } else { |
| #if ASSERTIONS |
| assert(sig.length == 1); |
| #endif |
| #if ASSERTIONS |
| assert(('dynCall_' + sig) in Module, 'bad function pointer type - no table for sig \'' + sig + '\''); |
| #endif |
| return Module['dynCall_' + sig].call(null, ptr); |
| } |
| } |
| |
| var tempRet0 = 0; |
| |
| var setTempRet0 = function(value) { |
| tempRet0 = value; |
| } |
| |
| var getTempRet0 = function() { |
| return tempRet0; |
| } |
| |
| #if RETAIN_COMPILER_SETTINGS |
| var compilerSettings = {{{ JSON.stringify(makeRetainedCompilerSettings()) }}} ; |
| |
| function getCompilerSetting(name) { |
| if (!(name in compilerSettings)) return 'invalid compiler setting: ' + name; |
| return compilerSettings[name]; |
| } |
| #else // RETAIN_COMPILER_SETTINGS |
| #if ASSERTIONS |
| function getCompilerSetting(name) { |
| throw 'You must build with -s RETAIN_COMPILER_SETTINGS=1 for getCompilerSetting or emscripten_get_compiler_setting to work'; |
| } |
| #endif // ASSERTIONS |
| #endif // RETAIN_COMPILER_SETTINGS |
| |
| var Runtime = { |
| #if ASSERTIONS |
| // helpful errors |
| getTempRet0: function() { abort('getTempRet0() is now a top-level function, after removing the Runtime object. Remove "Runtime."') }, |
| staticAlloc: function() { abort('staticAlloc() is now a top-level function, after removing the Runtime object. Remove "Runtime."') }, |
| stackAlloc: function() { abort('stackAlloc() is now a top-level function, after removing the Runtime object. Remove "Runtime."') }, |
| #endif |
| }; |
| |
| // The address globals begin at. Very low in memory, for code size and optimization opportunities. |
| // Above 0 is static memory, starting with globals. |
| // Then the stack. |
| // Then 'dynamic' memory for sbrk. |
| var GLOBAL_BASE = {{{ GLOBAL_BASE }}}; |
| |
| #if RELOCATABLE |
| GLOBAL_BASE = alignMemory(GLOBAL_BASE, {{{ MAX_GLOBAL_ALIGN || 1 }}}); |
| #endif |
| |
| #if WASM_BACKEND && USE_PTHREADS |
| // The wasm backend path does not have a way to set the stack max, so we can |
| // just implement this function in a trivial way |
| function establishStackSpace(base, max) { |
| stackRestore(base); |
| } |
| |
| // JS library code refers to Atomics in the manner used from asm.js, provide |
| // the same API here. |
| var Atomics_load = Atomics.load; |
| var Atomics_store = Atomics.store; |
| var Atomics_compareExchange = Atomics.compareExchange; |
| #endif |
| |