diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-02-17 22:45:29 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-02-17 22:57:23 +0900 |
| commit | 31ac8c7fd9f28e943ae9c899e304716e8c93bc28 (patch) | |
| tree | c2d3216fe275a1f8bc7130d5ded87b092833f5f3 | |
| parent | 08ddaf4597ad3a9d22433625d11d14bde1dfeafe (diff) | |
| download | php-waddiwasi-31ac8c7fd9f28e943ae9c899e304716e8c93bc28.tar.gz php-waddiwasi-31ac8c7fd9f28e943ae9c899e304716e8c93bc28.tar.zst php-waddiwasi-31ac8c7fd9f28e943ae9c899e304716e8c93bc28.zip | |
feat: update PHP used for example to 8.5
| -rw-r--r-- | examples/compile-php-to-wasm/Dockerfile | 15 | ||||
| -rw-r--r-- | examples/compile-php-to-wasm/php-wasm.js | 3223 | ||||
| -rwxr-xr-x | examples/compile-php-to-wasm/php-wasm.wasm | bin | 5088262 -> 6507219 bytes | |||
| -rw-r--r-- | examples/php-on-wasm/emscripten_bridge.php | 103 |
4 files changed, 1727 insertions, 1614 deletions
diff --git a/examples/compile-php-to-wasm/Dockerfile b/examples/compile-php-to-wasm/Dockerfile index 1e61133..31123ae 100644 --- a/examples/compile-php-to-wasm/Dockerfile +++ b/examples/compile-php-to-wasm/Dockerfile @@ -1,6 +1,6 @@ -FROM emscripten/emsdk:3.1.74 +FROM emscripten/emsdk:5.0.1 AS wasm-builder -RUN git clone --depth=1 --branch=php-8.4.5 https://github.com/php/php-src +RUN git clone --depth=1 --branch=php-8.5.3 https://github.com/php/php-src RUN apt-get update && \ apt-get install -y --no-install-recommends \ @@ -11,25 +11,24 @@ RUN apt-get update && \ && \ : -# Define ZEND_MM_ERROR=0 for suppressing munmap() errors. +# Define ZEND_MM_ERROR=0 to suppress munmap() errors. RUN cd php-src && \ ./buildconf --force && \ emconfigure ./configure \ --disable-all \ - --disable-mbregex \ - --disable-fiber-asm \ - --disable-cli \ --disable-cgi \ + --disable-cli \ + --disable-fiber-asm \ + --disable-opcache-jit \ --disable-phpdbg \ --enable-embed=static \ - --enable-mbstring \ --without-iconv \ --without-libxml \ --without-pcre-jit \ --without-pdo-sqlite \ --without-sqlite3 \ && \ - EMCC_CFLAGS='-s ERROR_ON_UNDEFINED_SYMBOLS=0 -D ZEND_MM_ERROR=0' emmake make -j$(nproc) && \ + EMCC_CFLAGS='-D ZEND_MM_ERROR=0' emmake make -j$(nproc) && \ mv libs/libphp.a .. && \ make clean && \ git clean -fd && \ diff --git a/examples/compile-php-to-wasm/php-wasm.js b/examples/compile-php-to-wasm/php-wasm.js index e255611..b6ae873 100644 --- a/examples/compile-php-to-wasm/php-wasm.js +++ b/examples/compile-php-to-wasm/php-wasm.js @@ -1,15 +1,65 @@ +// This code implements the `-sMODULARIZE` settings by taking the generated +// JS program code (INNER_JS_CODE) and wrapping it in a factory function. -import { createRequire } from 'module'; -const require = createRequire(import.meta.url); - -var Module = (() => { - var _scriptName = import.meta.url; - - return ( -function(moduleArg = {}) { +// When targeting node and ES6 we use `await import ..` in the generated code +// so the outer function needs to be marked as async. +async function Module(moduleArg = {}) { var moduleRtn; // include: shell.js +// include: minimum_runtime_check.js +(function() { + // "30.0.0" -> 300000 + function humanReadableVersionToPacked(str) { + str = str.split('-')[0]; // Remove any trailing part from e.g. "12.53.3-alpha" + var vers = str.split('.').slice(0, 3); + while(vers.length < 3) vers.push('00'); + vers = vers.map((n, i, arr) => n.padStart(2, '0')); + return vers.join(''); + } + // 300000 -> "30.0.0" + var packedVersionToHumanReadable = n => [n / 10000 | 0, (n / 100 | 0) % 100, n % 100].join('.'); + + var TARGET_NOT_SUPPORTED = 2147483647; + + // Note: We use a typeof check here instead of optional chaining using + // globalThis because older browsers might not have globalThis defined. + var currentNodeVersion = typeof process !== 'undefined' && process.versions?.node ? humanReadableVersionToPacked(process.versions.node) : TARGET_NOT_SUPPORTED; + if (currentNodeVersion < 160000) { + throw new Error(`This emscripten-generated code requires node v${ packedVersionToHumanReadable(160000) } (detected v${packedVersionToHumanReadable(currentNodeVersion)})`); + } + + var userAgent = typeof navigator !== 'undefined' && navigator.userAgent; + if (!userAgent) { + return; + } + + var currentSafariVersion = userAgent.includes("Safari/") && !userAgent.includes("Chrome/") && userAgent.match(/Version\/(\d+\.?\d*\.?\d*)/) ? humanReadableVersionToPacked(userAgent.match(/Version\/(\d+\.?\d*\.?\d*)/)[1]) : TARGET_NOT_SUPPORTED; + if (currentSafariVersion < TARGET_NOT_SUPPORTED) { + throw new Error(`This page was compiled without support for Safari browser. Pass -sMIN_SAFARI_VERSION=${currentSafariVersion} or lower to enable support for this browser.`); + } + if (currentSafariVersion < 2147483647) { + throw new Error(`This emscripten-generated code requires Safari v${ packedVersionToHumanReadable(2147483647) } (detected v${currentSafariVersion})`); + } + + var currentFirefoxVersion = userAgent.match(/Firefox\/(\d+(?:\.\d+)?)/) ? parseFloat(userAgent.match(/Firefox\/(\d+(?:\.\d+)?)/)[1]) : TARGET_NOT_SUPPORTED; + if (currentFirefoxVersion < TARGET_NOT_SUPPORTED) { + throw new Error(`This page was compiled without support for Firefox browser. Pass -sMIN_FIREFOX_VERSION=${currentFirefoxVersion} or lower to enable support for this browser.`); + } + if (currentFirefoxVersion < 2147483647) { + throw new Error(`This emscripten-generated code requires Firefox v2147483647 (detected v${currentFirefoxVersion})`); + } + + var currentChromeVersion = userAgent.match(/Chrome\/(\d+(?:\.\d+)?)/) ? parseFloat(userAgent.match(/Chrome\/(\d+(?:\.\d+)?)/)[1]) : TARGET_NOT_SUPPORTED; + if (currentChromeVersion < TARGET_NOT_SUPPORTED) { + throw new Error(`This page was compiled without support for Chrome browser. Pass -sMIN_CHROME_VERSION=${currentChromeVersion} or lower to enable support for this browser.`); + } + if (currentChromeVersion < 2147483647) { + throw new Error(`This emscripten-generated code requires Chrome v2147483647 (detected v${currentChromeVersion})`); + } +})(); + +// end include: minimum_runtime_check.js // The Module object: Our interface to the outside world. We import // and export values on it. There are various ways Module can be used: // 1. Not defined. We create it here @@ -25,34 +75,23 @@ function(moduleArg = {}) { // can continue to use Module afterwards as well. var Module = moduleArg; -// Set up the promise that indicates the Module is initialized -var readyPromiseResolve, readyPromiseReject; -var readyPromise = new Promise((resolve, reject) => { - readyPromiseResolve = resolve; - readyPromiseReject = reject; -}); -["_memory","_php_wasm_run","___indirect_function_table","onRuntimeInitialized"].forEach((prop) => { - if (!Object.getOwnPropertyDescriptor(readyPromise, prop)) { - Object.defineProperty(readyPromise, prop, { - get: () => abort('You are getting ' + prop + ' on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js'), - set: () => abort('You are setting ' + prop + ' on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js'), - }); - } -}); - // Determine the runtime environment we are in. You can customize this by // setting the ENVIRONMENT setting at compile time (see settings.js). -var ENVIRONMENT_IS_WEB = false; -var ENVIRONMENT_IS_WORKER = false; -var ENVIRONMENT_IS_NODE = true; -var ENVIRONMENT_IS_SHELL = false; +// Attempt to auto-detect the environment +var ENVIRONMENT_IS_WEB = !!globalThis.window; +var ENVIRONMENT_IS_WORKER = !!globalThis.WorkerGlobalScope; +// N.b. Electron.js environment is simultaneously a NODE-environment, but +// also a web environment. +var ENVIRONMENT_IS_NODE = globalThis.process?.versions?.node && globalThis.process?.type != 'renderer'; +var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER; if (ENVIRONMENT_IS_NODE) { - // `require()` is no-op in an ESM module, use `createRequire()` to construct - // the require()` function. This is only necessary for multi-environment - // builds, `-sENVIRONMENT=node` emits a static import declaration instead. - // TODO: Swap all `require()`'s with `import()`'s? + // When building an ES module `require` is not normally available. + // We need to use `createRequire()` to construct the require()` function. + const { createRequire } = await import('node:module'); + /** @suppress{duplicate} */ + var require = createRequire(import.meta.url); } @@ -60,19 +99,14 @@ if (ENVIRONMENT_IS_NODE) { // refer to Module (if they choose; they can also define Module) -// Sometimes an existing Module object exists with properties -// meant to overwrite the default module functionality. Here -// we collect those properties and reapply _after_ we configure -// the current environment's defaults to avoid having to be so -// defensive during initialization. -var moduleOverrides = Object.assign({}, Module); - var arguments_ = []; var thisProgram = './this.program'; var quit_ = (status, toThrow) => { throw toThrow; }; +var _scriptName = import.meta.url; + // `/` should be present at the end if `scriptDirectory` is not empty var scriptDirectory = ''; function locateFile(path) { @@ -86,26 +120,15 @@ function locateFile(path) { var readAsync, readBinary; if (ENVIRONMENT_IS_NODE) { - if (typeof process == 'undefined' || !process.release || process.release.name !== 'node') throw new Error('not compiled for this environment (did you build to HTML and try to run it not on the web, or set ENVIRONMENT to something - like node - and run it someplace else - like on the web?)'); - - var nodeVersion = process.versions.node; - var numericVersion = nodeVersion.split('.').slice(0, 3); - numericVersion = (numericVersion[0] * 10000) + (numericVersion[1] * 100) + (numericVersion[2].split('-')[0] * 1); - var minVersion = 160000; - if (numericVersion < 160000) { - throw new Error('This emscripten-generated code requires node v16.0.0 (detected v' + nodeVersion + ')'); - } + const isNode = globalThis.process?.versions?.node && globalThis.process?.type != 'renderer'; + if (!isNode) throw new Error('not compiled for this environment (did you build to HTML and try to run it not on the web, or set ENVIRONMENT to something - like node - and run it someplace else - like on the web?)'); // These modules will usually be used on Node.js. Load them eagerly to avoid // the complexity of lazy-loading. - var fs = require('fs'); - var nodePath = require('path'); + var fs = require('node:fs'); - // EXPORT_ES6 + ENVIRONMENT_IS_NODE always requires use of import.meta.url, - // since there's no way getting the current absolute path of the module when - // support for that is not available. - if (!import.meta.url.startsWith('data:')) { - scriptDirectory = nodePath.dirname(require('url').fileURLToPath(import.meta.url)) + '/'; + if (_scriptName.startsWith('file:')) { + scriptDirectory = require('node:path').dirname(require('node:url').fileURLToPath(_scriptName)) + '/'; } // include: node_shell_read.js @@ -125,14 +148,12 @@ readAsync = async (filename, binary = true) => { return ret; }; // end include: node_shell_read.js - if (!Module['thisProgram'] && process.argv.length > 1) { + if (process.argv.length > 1) { thisProgram = process.argv[1].replace(/\\/g, '/'); } arguments_ = process.argv.slice(2); - // MODULARIZE will export the module in the proper place outside, we don't need to export here - quit_ = (status, toThrow) => { process.exitCode = status; throw toThrow; @@ -141,8 +162,6 @@ readAsync = async (filename, binary = true) => { } else if (ENVIRONMENT_IS_SHELL) { - if ((typeof process == 'object' && typeof require === 'function') || typeof window == 'object' || typeof WorkerGlobalScope != 'undefined') throw new Error('not compiled for this environment (did you build to HTML and try to run it not on the web, or set ENVIRONMENT to something - like node - and run it someplace else - like on the web?)'); - } else // Note that this includes Node.js workers when relevant (pthreads is enabled). @@ -152,40 +171,9 @@ if (ENVIRONMENT_IS_SHELL) { throw new Error('environment detection error'); } -var out = Module['print'] || console.log.bind(console); -var err = Module['printErr'] || console.error.bind(console); - -// Merge back in the overrides -Object.assign(Module, moduleOverrides); -// Free the object hierarchy contained in the overrides, this lets the GC -// reclaim data used. -moduleOverrides = null; -checkIncomingModuleAPI(); - -// Emit code to handle expected values on the Module object. This applies Module.x -// to the proper local x. This has two benefits: first, we only emit it if it is -// expected to arrive, and second, by using a local everywhere else that can be -// minified. - -if (Module['arguments']) arguments_ = Module['arguments'];legacyModuleProp('arguments', 'arguments_'); - -if (Module['thisProgram']) thisProgram = Module['thisProgram'];legacyModuleProp('thisProgram', 'thisProgram'); +var out = console.log.bind(console); +var err = console.error.bind(console); -// perform assertions in shell.js after we set up out() and err(), as otherwise if an assertion fails it cannot print the message -// Assertions on removed incoming Module JS APIs. -assert(typeof Module['memoryInitializerPrefixURL'] == 'undefined', 'Module.memoryInitializerPrefixURL option was removed, use Module.locateFile instead'); -assert(typeof Module['pthreadMainPrefixURL'] == 'undefined', 'Module.pthreadMainPrefixURL option was removed, use Module.locateFile instead'); -assert(typeof Module['cdInitializerPrefixURL'] == 'undefined', 'Module.cdInitializerPrefixURL option was removed, use Module.locateFile instead'); -assert(typeof Module['filePackagePrefixURL'] == 'undefined', 'Module.filePackagePrefixURL option was removed, use Module.locateFile instead'); -assert(typeof Module['read'] == 'undefined', 'Module.read option was removed'); -assert(typeof Module['readAsync'] == 'undefined', 'Module.readAsync option was removed (modify readAsync in JS)'); -assert(typeof Module['readBinary'] == 'undefined', 'Module.readBinary option was removed (modify readBinary in JS)'); -assert(typeof Module['setWindowTitle'] == 'undefined', 'Module.setWindowTitle option was removed (modify emscripten_set_window_title in JS)'); -assert(typeof Module['TOTAL_MEMORY'] == 'undefined', 'Module.TOTAL_MEMORY has been renamed Module.INITIAL_MEMORY'); -legacyModuleProp('asm', 'wasmExports'); -legacyModuleProp('readAsync', 'readAsync'); -legacyModuleProp('readBinary', 'readBinary'); -legacyModuleProp('setWindowTitle', 'setWindowTitle'); var IDBFS = 'IDBFS is no longer included by default; build with -lidbfs.js'; var PROXYFS = 'PROXYFS is no longer included by default; build with -lproxyfs.js'; var WORKERFS = 'WORKERFS is no longer included by default; build with -lworkerfs.js'; @@ -196,6 +184,9 @@ var OPFS = 'OPFS is no longer included by default; build with -lopfs.js'; var NODEFS = 'NODEFS is no longer included by default; build with -lnodefs.js'; +// perform assertions in shell.js after we set up out() and err(), as otherwise +// if an assertion fails it cannot print the message + assert(!ENVIRONMENT_IS_WEB, 'web environment detected but not enabled at build time. Add `web` to `-sENVIRONMENT` to enable.'); assert(!ENVIRONMENT_IS_WORKER, 'worker environment detected but not enabled at build time. Add `worker` to `-sENVIRONMENT` to enable.'); @@ -215,16 +206,14 @@ assert(!ENVIRONMENT_IS_SHELL, 'shell environment detected but not enabled at bui // An online HTML version (which may be of a different version of Emscripten) // is up at http://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html -var wasmBinary = Module['wasmBinary'];legacyModuleProp('wasmBinary', 'wasmBinary'); +var wasmBinary; -if (typeof WebAssembly != 'object') { +if (!globalThis.WebAssembly) { err('no native wasm support detected'); } // Wasm globals -var wasmMemory; - //======================================== // Runtime essentials //======================================== @@ -234,7 +223,7 @@ var wasmMemory; var ABORT = false; // set by exit() and abort(). Passed to 'onExit' handler. -// NOTE: This is also used as the process return code code in shell environments +// NOTE: This is also used as the process return code in shell environments // but only when noExitRuntime is false. var EXITSTATUS; @@ -256,49 +245,13 @@ function _free() { abort('free() called but not included in the build - add `_free` to EXPORTED_FUNCTIONS'); } -// Memory management - -var HEAP, -/** @type {!Int8Array} */ - HEAP8, -/** @type {!Uint8Array} */ - HEAPU8, -/** @type {!Int16Array} */ - HEAP16, -/** @type {!Uint16Array} */ - HEAPU16, -/** @type {!Int32Array} */ - HEAP32, -/** @type {!Uint32Array} */ - HEAPU32, -/** @type {!Float32Array} */ - HEAPF32, -/** @type {!Float64Array} */ - HEAPF64; - -// include: runtime_shared.js -function updateMemoryViews() { - var b = wasmMemory.buffer; - Module['HEAP8'] = HEAP8 = new Int8Array(b); - Module['HEAP16'] = HEAP16 = new Int16Array(b); - Module['HEAPU8'] = HEAPU8 = new Uint8Array(b); - Module['HEAPU16'] = HEAPU16 = new Uint16Array(b); - Module['HEAP32'] = HEAP32 = new Int32Array(b); - Module['HEAPU32'] = HEAPU32 = new Uint32Array(b); - Module['HEAPF32'] = HEAPF32 = new Float32Array(b); - Module['HEAPF64'] = HEAPF64 = new Float64Array(b); -} - -// end include: runtime_shared.js -assert(!Module['STACK_SIZE'], 'STACK_SIZE can no longer be set at runtime. Use -sSTACK_SIZE at link time') - -assert(typeof Int32Array != 'undefined' && typeof Float64Array !== 'undefined' && Int32Array.prototype.subarray != undefined && Int32Array.prototype.set != undefined, - 'JS engine does not provide full typed array support'); - -// If memory is defined in wasm, the user can't provide it, or set INITIAL_MEMORY -assert(!Module['wasmMemory'], 'Use of `wasmMemory` detected. Use -sIMPORTED_MEMORY to define wasmMemory externally'); -assert(!Module['INITIAL_MEMORY'], 'Detected runtime INITIAL_MEMORY setting. Use -sIMPORTED_MEMORY to define wasmMemory dynamically'); +/** + * Indicates whether filename is delivered via file protocol (as opposed to http/https) + * @noinline + */ +var isFileURI = (filename) => filename.startsWith('file://'); +// include: runtime_common.js // include: runtime_stack_check.js // Initializes the stack cookie. Called at the startup of main and at the startup of each thread in pthreads mode. function writeStackCookie() { @@ -337,158 +290,188 @@ function checkStackCookie() { } } // end include: runtime_stack_check.js -var __ATPRERUN__ = []; // functions called before the runtime is initialized -var __ATINIT__ = []; // functions called during startup -var __ATEXIT__ = []; // functions called during shutdown -var __ATPOSTRUN__ = []; // functions called after the main() is called - -var runtimeInitialized = false; +// include: runtime_exceptions.js +// end include: runtime_exceptions.js +// include: runtime_debug.js +var runtimeDebug = true; // Switch to false at runtime to disable logging at the right times -function preRun() { - if (Module['preRun']) { - if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']]; - while (Module['preRun'].length) { - addOnPreRun(Module['preRun'].shift()); - } - } - callRuntimeCallbacks(__ATPRERUN__); +// Used by XXXXX_DEBUG settings to output debug messages. +function dbg(...args) { + if (!runtimeDebug && typeof runtimeDebug != 'undefined') return; + // TODO(sbc): Make this configurable somehow. Its not always convenient for + // logging to show up as warnings. + console.warn(...args); } -function initRuntime() { - assert(!runtimeInitialized); - runtimeInitialized = true; - - checkStackCookie(); +// Endianness check +(() => { + var h16 = new Int16Array(1); + var h8 = new Int8Array(h16.buffer); + h16[0] = 0x6373; + if (h8[0] !== 0x73 || h8[1] !== 0x63) abort('Runtime error: expected the system to be little-endian! (Run with -sSUPPORT_BIG_ENDIAN to bypass)'); +})(); - -if (!Module['noFSInit'] && !FS.initialized) - FS.init(); -FS.ignorePermissions = false; +function consumedModuleProp(prop) { + if (!Object.getOwnPropertyDescriptor(Module, prop)) { + Object.defineProperty(Module, prop, { + configurable: true, + set() { + abort(`Attempt to set \`Module.${prop}\` after it has already been processed. This can happen, for example, when code is injected via '--post-js' rather than '--pre-js'`); -TTY.init(); -SOCKFS.root = FS.mount(SOCKFS, {}, null); -PIPEFS.root = FS.mount(PIPEFS, {}, null); - callRuntimeCallbacks(__ATINIT__); + } + }); + } } -function postRun() { - checkStackCookie(); - - if (Module['postRun']) { - if (typeof Module['postRun'] == 'function') Module['postRun'] = [Module['postRun']]; - while (Module['postRun'].length) { - addOnPostRun(Module['postRun'].shift()); - } - } +function makeInvalidEarlyAccess(name) { + return () => assert(false, `call to '${name}' via reference taken before Wasm module initialization`); - callRuntimeCallbacks(__ATPOSTRUN__); } -function addOnPreRun(cb) { - __ATPRERUN__.unshift(cb); +function ignoredModuleProp(prop) { + if (Object.getOwnPropertyDescriptor(Module, prop)) { + abort(`\`Module.${prop}\` was supplied but \`${prop}\` not included in INCOMING_MODULE_JS_API`); + } } -function addOnInit(cb) { - __ATINIT__.unshift(cb); +// forcing the filesystem exports a few things by default +function isExportedByForceFilesystem(name) { + return name === 'FS_createPath' || + name === 'FS_createDataFile' || + name === 'FS_createPreloadedFile' || + name === 'FS_preloadFile' || + name === 'FS_unlink' || + name === 'addRunDependency' || + // The old FS has some functionality that WasmFS lacks. + name === 'FS_createLazyFile' || + name === 'FS_createDevice' || + name === 'removeRunDependency'; } -function addOnExit(cb) { +function missingLibrarySymbol(sym) { + + // Any symbol that is not included from the JS library is also (by definition) + // not exported on the Module object. + unexportedRuntimeSymbol(sym); } -function addOnPostRun(cb) { - __ATPOSTRUN__.unshift(cb); +function unexportedRuntimeSymbol(sym) { + if (!Object.getOwnPropertyDescriptor(Module, sym)) { + Object.defineProperty(Module, sym, { + configurable: true, + get() { + var msg = `'${sym}' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the Emscripten FAQ)`; + if (isExportedByForceFilesystem(sym)) { + msg += '. Alternatively, forcing filesystem support (-sFORCE_FILESYSTEM) can export this for you'; + } + abort(msg); + }, + }); + } } -// include: runtime_math.js -// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/imul +// end include: runtime_debug.js +var readyPromiseResolve, readyPromiseReject; -// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/fround +// Memory management +var +/** @type {!Int8Array} */ + HEAP8, +/** @type {!Uint8Array} */ + HEAPU8, +/** @type {!Int16Array} */ + HEAP16, +/** @type {!Uint16Array} */ + HEAPU16, +/** @type {!Int32Array} */ + HEAP32, +/** @type {!Uint32Array} */ + HEAPU32, +/** @type {!Float32Array} */ + HEAPF32, +/** @type {!Float64Array} */ + HEAPF64; -// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/clz32 +// BigInt64Array type is not correctly defined in closure +var +/** not-@type {!BigInt64Array} */ + HEAP64, +/* BigUint64Array type is not correctly defined in closure +/** not-@type {!BigUint64Array} */ + HEAPU64; -// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/trunc +var runtimeInitialized = false; -assert(Math.imul, 'This browser does not support Math.imul(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill'); -assert(Math.fround, 'This browser does not support Math.fround(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill'); -assert(Math.clz32, 'This browser does not support Math.clz32(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill'); -assert(Math.trunc, 'This browser does not support Math.trunc(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill'); -// end include: runtime_math.js -// A counter of dependencies for calling run(). If we need to -// do asynchronous work before running, increment this and -// decrement it. Incrementing must happen in a place like -// Module.preRun (used by emcc to add file preloading). -// Note that you can add dependencies in preRun, even though -// it happens right before run - run will be postponed until -// the dependencies are met. -var runDependencies = 0; -var dependenciesFulfilled = null; // overridden to take different actions when all run dependencies are fulfilled -var runDependencyTracking = {}; -var runDependencyWatcher = null; -function getUniqueRunDependency(id) { - var orig = id; - while (1) { - if (!runDependencyTracking[id]) return id; - id = orig + Math.random(); - } -} -function addRunDependency(id) { - runDependencies++; +function updateMemoryViews() { + var b = wasmMemory.buffer; + HEAP8 = new Int8Array(b); + HEAP16 = new Int16Array(b); + HEAPU8 = new Uint8Array(b); + HEAPU16 = new Uint16Array(b); + HEAP32 = new Int32Array(b); + HEAPU32 = new Uint32Array(b); + HEAPF32 = new Float32Array(b); + HEAPF64 = new Float64Array(b); + HEAP64 = new BigInt64Array(b); + HEAPU64 = new BigUint64Array(b); +} - Module['monitorRunDependencies']?.(runDependencies); +// include: memoryprofiler.js +// end include: memoryprofiler.js +// end include: runtime_common.js +assert(globalThis.Int32Array && globalThis.Float64Array && Int32Array.prototype.subarray && Int32Array.prototype.set, + 'JS engine does not provide full typed array support'); - if (id) { - assert(!runDependencyTracking[id]); - runDependencyTracking[id] = 1; - if (runDependencyWatcher === null && typeof setInterval != 'undefined') { - // Check for missing dependencies every few seconds - runDependencyWatcher = setInterval(() => { - if (ABORT) { - clearInterval(runDependencyWatcher); - runDependencyWatcher = null; - return; - } - var shown = false; - for (var dep in runDependencyTracking) { - if (!shown) { - shown = true; - err('still waiting on run dependencies:'); - } - err(`dependency: ${dep}`); - } - if (shown) { - err('(end of list)'); - } - }, 10000); +function preRun() { + if (Module['preRun']) { + if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']]; + while (Module['preRun'].length) { + addOnPreRun(Module['preRun'].shift()); } - } else { - err('warning: run dependency added without ID'); } + consumedModuleProp('preRun'); + // Begin ATPRERUNS hooks + callRuntimeCallbacks(onPreRuns); + // End ATPRERUNS hooks } -function removeRunDependency(id) { - runDependencies--; +function initRuntime() { + assert(!runtimeInitialized); + runtimeInitialized = true; - Module['monitorRunDependencies']?.(runDependencies); + checkStackCookie(); - if (id) { - assert(runDependencyTracking[id]); - delete runDependencyTracking[id]; - } else { - err('warning: run dependency removed without ID'); - } - if (runDependencies == 0) { - if (runDependencyWatcher !== null) { - clearInterval(runDependencyWatcher); - runDependencyWatcher = null; - } - if (dependenciesFulfilled) { - var callback = dependenciesFulfilled; - dependenciesFulfilled = null; - callback(); // can add another dependenciesFulfilled + // Begin ATINITS hooks + SOCKFS.root = FS.mount(SOCKFS, {}, null); +if (!Module['noFSInit'] && !FS.initialized) FS.init(); +TTY.init(); +PIPEFS.root = FS.mount(PIPEFS, {}, null); + // End ATINITS hooks + + wasmExports['__wasm_call_ctors'](); + + // Begin ATPOSTCTORS hooks + FS.ignorePermissions = false; + // End ATPOSTCTORS hooks +} + +function postRun() { + checkStackCookie(); + // PThreads reuse the runtime from the main thread. + + if (Module['postRun']) { + if (typeof Module['postRun'] == 'function') Module['postRun'] = [Module['postRun']]; + while (Module['postRun'].length) { + addOnPostRun(Module['postRun'].shift()); } } + consumedModuleProp('postRun'); + + // Begin ATPOSTRUNS hooks + callRuntimeCallbacks(onPostRuns); + // End ATPOSTRUNS hooks } /** @param {string|number=} what */ @@ -518,31 +501,13 @@ function abort(what) { /** @suppress {checkTypes} */ var e = new WebAssembly.RuntimeError(what); - readyPromiseReject(e); + readyPromiseReject?.(e); // Throw the error whether or not MODULARIZE is set because abort is used // in code paths apart from instantiation where an exception is expected // to be thrown when abort is called. throw e; } -// include: memoryprofiler.js -// end include: memoryprofiler.js -// include: URIUtils.js -// Prefix of data URIs emitted by SINGLE_FILE and related options. -var dataURIPrefix = 'data:application/octet-stream;base64,'; - -/** - * Indicates whether filename is a base64 data URI. - * @noinline - */ -var isDataURI = (filename) => filename.startsWith(dataURIPrefix); - -/** - * Indicates whether filename is delivered via file protocol (as opposed to http/https) - * @noinline - */ -var isFileURI = (filename) => filename.startsWith('file://'); -// end include: URIUtils.js function createExportWrapper(name, nargs) { return (...args) => { assert(runtimeInitialized, `native function \`${name}\` called before runtime initialization`); @@ -554,21 +519,18 @@ function createExportWrapper(name, nargs) { }; } -// include: runtime_exceptions.js -// end include: runtime_exceptions.js +var wasmBinaryFile; + function findWasmBinary() { + if (Module['locateFile']) { - var f = 'php-wasm.wasm'; - if (!isDataURI(f)) { - return locateFile(f); - } - return f; + return locateFile('php-wasm.wasm'); } + // Use bundler-friendly `new URL(..., import.meta.url)` pattern; works in browsers too. return new URL('php-wasm.wasm', import.meta.url).href; -} -var wasmBinaryFile; +} function getBinarySync(file) { if (file == wasmBinaryFile && wasmBinary) { @@ -577,13 +539,14 @@ function getBinarySync(file) { if (readBinary) { return readBinary(file); } + // Throwing a plain string here, even though it not normally advisable since + // this gets turning into an `abort` in instantiateArrayBuffer. throw 'both async and sync fetching of the wasm failed'; } async function getWasmBinary(binaryFile) { // If we don't have the binary yet, load it asynchronously using readAsync. - if (!wasmBinary - ) { + if (!wasmBinary) { // Fetch the binary using readAsync try { var response = await readAsync(binaryFile); @@ -606,25 +569,23 @@ async function instantiateArrayBuffer(binaryFile, imports) { err(`failed to asynchronously prepare wasm: ${reason}`); // Warn on some common problems. - if (isFileURI(wasmBinaryFile)) { - err(`warning: Loading from a file URI (${wasmBinaryFile}) is not supported in most browsers. See https://emscripten.org/docs/getting_started/FAQ.html#how-do-i-run-a-local-webserver-for-testing-why-does-my-program-stall-in-downloading-or-preparing`); + if (isFileURI(binaryFile)) { + err(`warning: Loading from a file URI (${binaryFile}) is not supported in most browsers. See https://emscripten.org/docs/getting_started/FAQ.html#how-do-i-run-a-local-webserver-for-testing-why-does-my-program-stall-in-downloading-or-preparing`); } abort(reason); } } async function instantiateAsync(binary, binaryFile, imports) { - if (!binary && - typeof WebAssembly.instantiateStreaming == 'function' && - !isDataURI(binaryFile) && + if (!binary // Avoid instantiateStreaming() on Node.js environment for now, as while // Node.js v18.1.0 implements it, it does not have a full fetch() // implementation yet. // // Reference: // https://github.com/emscripten-core/emscripten/pull/16917 - !ENVIRONMENT_IS_NODE && - typeof fetch == 'function') { + && !ENVIRONMENT_IS_NODE + ) { try { var response = fetch(binaryFile, { credentials: 'same-origin' }); var instantiationResult = await WebAssembly.instantiateStreaming(response, imports); @@ -642,10 +603,11 @@ async function instantiateAsync(binary, binaryFile, imports) { function getWasmImports() { // prepare imports - return { + var imports = { 'env': wasmImports, 'wasi_snapshot_preview1': wasmImports, - } + }; + return imports; } // Create the wasm instance. @@ -658,24 +620,12 @@ async function createWasm() { function receiveInstance(instance, module) { wasmExports = instance.exports; - + assignWasmExports(wasmExports); - wasmMemory = wasmExports['memory']; - - assert(wasmMemory, 'memory not found in wasm exports'); updateMemoryViews(); - wasmTable = wasmExports['__indirect_function_table']; - - assert(wasmTable, 'table not found in wasm exports'); - - addOnInit(wasmExports['__wasm_call_ctors']); - - removeRunDependency('wasm-instantiate'); return wasmExports; } - // wait for the pthread pool (if any) - addRunDependency('wasm-instantiate'); // Prefer streaming instantiation if available. // Async compilation can be confusing when an error on the page overwrites Module @@ -689,7 +639,7 @@ async function createWasm() { trueModule = null; // TODO: Due to Closure regression https://github.com/google/closure-compiler/issues/3193, the above line no longer optimizes out down to the following line. // When the regression is fixed, can restore the above PTHREADS-enabled path. - receiveInstance(result['instance']); + return receiveInstance(result['instance']); } var info = getWasmImports(); @@ -701,152 +651,28 @@ async function createWasm() { // Also pthreads and wasm workers initialize the wasm instance through this // path. if (Module['instantiateWasm']) { - try { - return Module['instantiateWasm'](info, receiveInstance); - } catch(e) { - err(`Module.instantiateWasm callback failed with error: ${e}`); - // If instantiation fails, reject the module ready promise. - readyPromiseReject(e); - } - } - - wasmBinaryFile ??= findWasmBinary(); - - try { - var result = await instantiateAsync(wasmBinary, wasmBinaryFile, info); - receiveInstantiationResult(result); - return result; - } catch (e) { - // If instantiation fails, reject the module ready promise. - readyPromiseReject(e); - return; - } -} - -// Globals used by JS i64 conversions (see makeSetValue) -var tempDouble; -var tempI64; - -// include: runtime_debug.js -// Endianness check -(() => { - var h16 = new Int16Array(1); - var h8 = new Int8Array(h16.buffer); - h16[0] = 0x6373; - if (h8[0] !== 0x73 || h8[1] !== 0x63) throw 'Runtime error: expected the system to be little-endian! (Run with -sSUPPORT_BIG_ENDIAN to bypass)'; -})(); - -if (Module['ENVIRONMENT']) { - throw new Error('Module.ENVIRONMENT has been deprecated. To force the environment, use the ENVIRONMENT compile-time option (for example, -sENVIRONMENT=web or -sENVIRONMENT=node)'); -} - -function legacyModuleProp(prop, newName, incoming=true) { - if (!Object.getOwnPropertyDescriptor(Module, prop)) { - Object.defineProperty(Module, prop, { - configurable: true, - get() { - let extra = incoming ? ' (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)' : ''; - abort(`\`Module.${prop}\` has been replaced by \`${newName}\`` + extra); - - } - }); - } -} - -function ignoredModuleProp(prop) { - if (Object.getOwnPropertyDescriptor(Module, prop)) { - abort(`\`Module.${prop}\` was supplied but \`${prop}\` not included in INCOMING_MODULE_JS_API`); - } -} - -// forcing the filesystem exports a few things by default -function isExportedByForceFilesystem(name) { - return name === 'FS_createPath' || - name === 'FS_createDataFile' || - name === 'FS_createPreloadedFile' || - name === 'FS_unlink' || - name === 'addRunDependency' || - // The old FS has some functionality that WasmFS lacks. - name === 'FS_createLazyFile' || - name === 'FS_createDevice' || - name === 'removeRunDependency'; -} - -/** - * Intercept access to a global symbol. This enables us to give informative - * warnings/errors when folks attempt to use symbols they did not include in - * their build, or no symbols that no longer exist. - */ -function hookGlobalSymbolAccess(sym, func) { - if (typeof globalThis != 'undefined' && !Object.getOwnPropertyDescriptor(globalThis, sym)) { - Object.defineProperty(globalThis, sym, { - configurable: true, - get() { - func(); - return undefined; + return new Promise((resolve, reject) => { + try { + Module['instantiateWasm'](info, (inst, mod) => { + resolve(receiveInstance(inst, mod)); + }); + } catch(e) { + err(`Module.instantiateWasm callback failed with error: ${e}`); + reject(e); } }); } -} - -function missingGlobal(sym, msg) { - hookGlobalSymbolAccess(sym, () => { - warnOnce(`\`${sym}\` is not longer defined by emscripten. ${msg}`); - }); -} -missingGlobal('buffer', 'Please use HEAP8.buffer or wasmMemory.buffer'); -missingGlobal('asm', 'Please use wasmExports instead'); - -function missingLibrarySymbol(sym) { - hookGlobalSymbolAccess(sym, () => { - // Can't `abort()` here because it would break code that does runtime - // checks. e.g. `if (typeof SDL === 'undefined')`. - var msg = `\`${sym}\` is a library symbol and not included by default; add it to your library.js __deps or to DEFAULT_LIBRARY_FUNCS_TO_INCLUDE on the command line`; - // DEFAULT_LIBRARY_FUNCS_TO_INCLUDE requires the name as it appears in - // library.js, which means $name for a JS name with no prefix, or name - // for a JS name like _name. - var librarySymbol = sym; - if (!librarySymbol.startsWith('_')) { - librarySymbol = '$' + sym; - } - msg += ` (e.g. -sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE='${librarySymbol}')`; - if (isExportedByForceFilesystem(sym)) { - msg += '. Alternatively, forcing filesystem support (-sFORCE_FILESYSTEM) can export this for you'; - } - warnOnce(msg); - }); - - // Any symbol that is not included from the JS library is also (by definition) - // not exported on the Module object. - unexportedRuntimeSymbol(sym); -} - -function unexportedRuntimeSymbol(sym) { - if (!Object.getOwnPropertyDescriptor(Module, sym)) { - Object.defineProperty(Module, sym, { - configurable: true, - get() { - var msg = `'${sym}' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the Emscripten FAQ)`; - if (isExportedByForceFilesystem(sym)) { - msg += '. Alternatively, forcing filesystem support (-sFORCE_FILESYSTEM) can export this for you'; - } - abort(msg); - } - }); - } + wasmBinaryFile ??= findWasmBinary(); + var result = await instantiateAsync(wasmBinary, wasmBinaryFile, info); + var exports = receiveInstantiationResult(result); + return exports; } -// Used by XXXXX_DEBUG settings to output debug messages. -function dbg(...args) { - // TODO(sbc): Make this configurable somehow. Its not always convenient for - // logging to show up as warnings. - console.warn(...args); -} -// end include: runtime_debug.js -// === Body === // end include: preamble.js +// Begin JS library code + class ExitStatus { name = 'ExitStatus'; @@ -862,12 +688,18 @@ function dbg(...args) { callbacks.shift()(Module); } }; + var onPostRuns = []; + var addOnPostRun = (cb) => onPostRuns.push(cb); + + var onPreRuns = []; + var addOnPreRun = (cb) => onPreRuns.push(cb); + /** - * @param {number} ptr - * @param {string} type - */ + * @param {number} ptr + * @param {string} type + */ function getValue(ptr, type = 'i8') { if (type.endsWith('*')) type = '*'; switch (type) { @@ -875,7 +707,7 @@ function dbg(...args) { case 'i8': return HEAP8[ptr]; case 'i16': return HEAP16[((ptr)>>1)]; case 'i32': return HEAP32[((ptr)>>2)]; - case 'i64': abort('to do getValue(i64) use WASM_BIGINT'); + case 'i64': return HEAP64[((ptr)>>3)]; case 'float': return HEAPF32[((ptr)>>2)]; case 'double': return HEAPF64[((ptr)>>3)]; case '*': return HEAPU32[((ptr)>>2)]; @@ -883,21 +715,21 @@ function dbg(...args) { } } - var noExitRuntime = Module['noExitRuntime'] || true; + var noExitRuntime = true; var ptrToString = (ptr) => { - assert(typeof ptr === 'number'); - // With CAN_ADDRESS_2GB or MEMORY64, pointers are already unsigned. + assert(typeof ptr === 'number', `ptrToString expects a number, got ${typeof ptr}`); + // Convert to 32-bit unsigned value ptr >>>= 0; return '0x' + ptr.toString(16).padStart(8, '0'); }; /** - * @param {number} ptr - * @param {number} value - * @param {string} type - */ + * @param {number} ptr + * @param {number} value + * @param {string} type + */ function setValue(ptr, value, type = 'i8') { if (type.endsWith('*')) type = '*'; switch (type) { @@ -905,7 +737,7 @@ function dbg(...args) { case 'i8': HEAP8[ptr] = value; break; case 'i16': HEAP16[((ptr)>>1)] = value; break; case 'i32': HEAP32[((ptr)>>2)] = value; break; - case 'i64': abort('to do setValue(i64) use WASM_BIGINT'); + case 'i64': HEAP64[((ptr)>>3)] = BigInt(value); break; case 'float': HEAPF32[((ptr)>>2)] = value; break; case 'double': HEAPF64[((ptr)>>3)] = value; break; case '*': HEAPU32[((ptr)>>2)] = value; break; @@ -926,33 +758,41 @@ function dbg(...args) { } }; - var UTF8Decoder = typeof TextDecoder != 'undefined' ? new TextDecoder() : undefined; - /** - * Given a pointer 'idx' to a null-terminated UTF8-encoded string in the given - * array that contains uint8 values, returns a copy of that string as a - * Javascript String object. - * heapOrArray is either a regular array, or a JavaScript typed array view. - * @param {number=} idx - * @param {number=} maxBytesToRead - * @return {string} - */ - var UTF8ArrayToString = (heapOrArray, idx = 0, maxBytesToRead = NaN) => { - var endIdx = idx + maxBytesToRead; - var endPtr = idx; + + var UTF8Decoder = globalThis.TextDecoder && new TextDecoder(); + + var findStringEnd = (heapOrArray, idx, maxBytesToRead, ignoreNul) => { + var maxIdx = idx + maxBytesToRead; + if (ignoreNul) return maxIdx; // TextDecoder needs to know the byte length in advance, it doesn't stop on - // null terminator by itself. Also, use the length info to avoid running tiny - // strings through TextDecoder, since .subarray() allocates garbage. - // (As a tiny code save trick, compare endPtr against endIdx using a negation, - // so that undefined/NaN means Infinity) - while (heapOrArray[endPtr] && !(endPtr >= endIdx)) ++endPtr; + // null terminator by itself. + // As a tiny code save trick, compare idx against maxIdx using a negation, + // so that maxBytesToRead=undefined/NaN means Infinity. + while (heapOrArray[idx] && !(idx >= maxIdx)) ++idx; + return idx; + }; + + + /** + * Given a pointer 'idx' to a null-terminated UTF8-encoded string in the given + * array that contains uint8 values, returns a copy of that string as a + * Javascript String object. + * heapOrArray is either a regular array, or a JavaScript typed array view. + * @param {number=} idx + * @param {number=} maxBytesToRead + * @param {boolean=} ignoreNul - If true, the function will not stop on a NUL character. + * @return {string} + */ + var UTF8ArrayToString = (heapOrArray, idx = 0, maxBytesToRead, ignoreNul) => { + + var endPtr = findStringEnd(heapOrArray, idx, maxBytesToRead, ignoreNul); + // When using conditional TextDecoder, skip it for short strings as the overhead of the native call is not worth it. if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) { return UTF8Decoder.decode(heapOrArray.subarray(idx, endPtr)); } var str = ''; - // If building with TextDecoder, we have already computed the string length - // above, so test loop end condition against that while (idx < endPtr) { // For UTF8 byte structure, see: // http://en.wikipedia.org/wiki/UTF-8#Description @@ -981,35 +821,31 @@ function dbg(...args) { }; /** - * Given a pointer 'ptr' to a null-terminated UTF8-encoded string in the - * emscripten HEAP, returns a copy of that string as a Javascript String object. - * - * @param {number} ptr - * @param {number=} maxBytesToRead - An optional length that specifies the - * maximum number of bytes to read. You can omit this parameter to scan the - * string until the first 0 byte. If maxBytesToRead is passed, and the string - * at [ptr, ptr+maxBytesToReadr[ contains a null byte in the middle, then the - * string will cut short at that byte index (i.e. maxBytesToRead will not - * produce a string of exact length [ptr, ptr+maxBytesToRead[) N.B. mixing - * frequent uses of UTF8ToString() with and without maxBytesToRead may throw - * JS JIT optimizations off, so it is worth to consider consistently using one - * @return {string} - */ - var UTF8ToString = (ptr, maxBytesToRead) => { + * Given a pointer 'ptr' to a null-terminated UTF8-encoded string in the + * emscripten HEAP, returns a copy of that string as a Javascript String object. + * + * @param {number} ptr + * @param {number=} maxBytesToRead - An optional length that specifies the + * maximum number of bytes to read. You can omit this parameter to scan the + * string until the first 0 byte. If maxBytesToRead is passed, and the string + * at [ptr, ptr+maxBytesToReadr[ contains a null byte in the middle, then the + * string will cut short at that byte index. + * @param {boolean=} ignoreNul - If true, the function will not stop on a NUL character. + * @return {string} + */ + var UTF8ToString = (ptr, maxBytesToRead, ignoreNul) => { assert(typeof ptr == 'number', `UTF8ToString expects a number (got ${typeof ptr})`); - return ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : ''; + return ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead, ignoreNul) : ''; }; var ___assert_fail = (condition, filename, line, func) => abort(`Assertion failed: ${UTF8ToString(condition)}, at: ` + [filename ? UTF8ToString(filename) : 'unknown filename', line, func ? UTF8ToString(func) : 'unknown function']); var wasmTableMirror = []; - /** @type {WebAssembly.Table} */ - var wasmTable; + var getWasmTableEntry = (funcPtr) => { var func = wasmTableMirror[funcPtr]; if (!func) { - if (funcPtr >= wasmTableMirror.length) wasmTableMirror.length = funcPtr + 1; /** @suppress {checkTypes} */ wasmTableMirror[funcPtr] = func = wasmTable.get(funcPtr); } @@ -1019,6 +855,20 @@ function dbg(...args) { }; var ___call_sighandler = (fp, sig) => getWasmTableEntry(fp)(sig); + var initRandomFill = () => { + // This block is not needed on v19+ since crypto.getRandomValues is builtin + if (ENVIRONMENT_IS_NODE) { + var nodeCrypto = require('node:crypto'); + return (view) => nodeCrypto.randomFillSync(view); + } + + return (view) => crypto.getRandomValues(view); + }; + var randomFill = (view) => { + // Lazily init on the first invocation. + (randomFill = initRandomFill())(view); + }; + var PATH = { isAbs:(path) => path.charAt(0) === '/', splitPath:(filename) => { @@ -1050,7 +900,7 @@ function dbg(...args) { }, normalize:(path) => { var isAbsolute = PATH.isAbs(path), - trailingSlash = path.substr(-1) === '/'; + trailingSlash = path.slice(-1) === '/'; // Normalize the path path = PATH.normalizeArray(path.split('/').filter((p) => !!p), !isAbsolute).join('/'); if (!path && !isAbsolute) { @@ -1071,192 +921,145 @@ function dbg(...args) { } if (dir) { // It has a dirname, strip trailing slash - dir = dir.substr(0, dir.length - 1); + dir = dir.slice(0, -1); } return root + dir; }, - basename:(path) => { - // EMSCRIPTEN return '/'' for '/', not an empty string - if (path === '/') return '/'; - path = PATH.normalize(path); - path = path.replace(/\/$/, ""); - var lastSlash = path.lastIndexOf('/'); - if (lastSlash === -1) return path; - return path.substr(lastSlash+1); - }, - join:(...paths) => PATH.normalize(paths.join('/')), - join2:(l, r) => PATH.normalize(l + '/' + r), - }; - - var initRandomFill = () => { - if (typeof crypto == 'object' && typeof crypto['getRandomValues'] == 'function') { - // for modern web browsers - return (view) => crypto.getRandomValues(view); - } else - if (ENVIRONMENT_IS_NODE) { - // for nodejs with or without crypto support included - try { - var crypto_module = require('crypto'); - var randomFillSync = crypto_module['randomFillSync']; - if (randomFillSync) { - // nodejs with LTS crypto support - return (view) => crypto_module['randomFillSync'](view); - } - // very old nodejs with the original crypto API - var randomBytes = crypto_module['randomBytes']; - return (view) => ( - view.set(randomBytes(view.byteLength)), - // Return the original view to match modern native implementations. - view - ); - } catch (e) { - // nodejs doesn't have crypto support + basename:(path) => path && path.match(/([^\/]+|\/)\/*$/)[1], +join:(...paths) => PATH.normalize(paths.join('/')), +join2:(l, r) => PATH.normalize(l + '/' + r), +}; + + +var PATH_FS = { +resolve:(...args) => { + var resolvedPath = '', + resolvedAbsolute = false; + for (var i = args.length - 1; i >= -1 && !resolvedAbsolute; i--) { + var path = (i >= 0) ? args[i] : FS.cwd(); + // Skip empty and invalid entries + if (typeof path != 'string') { + throw new TypeError('Arguments to path.resolve must be strings'); + } else if (!path) { + return ''; // an invalid portion invalidates the whole thing } + resolvedPath = path + '/' + resolvedPath; + resolvedAbsolute = PATH.isAbs(path); } - // we couldn't find a proper implementation, as Math.random() is not suitable for /dev/random, see emscripten-core/emscripten/pull/7096 - abort('no cryptographic support found for randomDevice. consider polyfilling it if you want to use something insecure like Math.random(), e.g. put this in a --pre-js: var crypto = { getRandomValues: (array) => { for (var i = 0; i < array.length; i++) array[i] = (Math.random()*256)|0 } };'); - }; - var randomFill = (view) => { - // Lazily init on the first invocation. - return (randomFill = initRandomFill())(view); - }; - - - - var PATH_FS = { - resolve:(...args) => { - var resolvedPath = '', - resolvedAbsolute = false; - for (var i = args.length - 1; i >= -1 && !resolvedAbsolute; i--) { - var path = (i >= 0) ? args[i] : FS.cwd(); - // Skip empty and invalid entries - if (typeof path != 'string') { - throw new TypeError('Arguments to path.resolve must be strings'); - } else if (!path) { - return ''; // an invalid portion invalidates the whole thing - } - resolvedPath = path + '/' + resolvedPath; - resolvedAbsolute = PATH.isAbs(path); - } - // At this point the path should be resolved to a full absolute path, but - // handle relative paths to be safe (might happen when process.cwd() fails) - resolvedPath = PATH.normalizeArray(resolvedPath.split('/').filter((p) => !!p), !resolvedAbsolute).join('/'); - return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.'; - }, - relative:(from, to) => { - from = PATH_FS.resolve(from).substr(1); - to = PATH_FS.resolve(to).substr(1); - function trim(arr) { - var start = 0; - for (; start < arr.length; start++) { - if (arr[start] !== '') break; - } - var end = arr.length - 1; - for (; end >= 0; end--) { - if (arr[end] !== '') break; - } - if (start > end) return []; - return arr.slice(start, end - start + 1); + // At this point the path should be resolved to a full absolute path, but + // handle relative paths to be safe (might happen when process.cwd() fails) + resolvedPath = PATH.normalizeArray(resolvedPath.split('/').filter((p) => !!p), !resolvedAbsolute).join('/'); + return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.'; + }, +relative:(from, to) => { + from = PATH_FS.resolve(from).slice(1); + to = PATH_FS.resolve(to).slice(1); + function trim(arr) { + var start = 0; + for (; start < arr.length; start++) { + if (arr[start] !== '') break; } - var fromParts = trim(from.split('/')); - var toParts = trim(to.split('/')); - var length = Math.min(fromParts.length, toParts.length); - var samePartsLength = length; - for (var i = 0; i < length; i++) { - if (fromParts[i] !== toParts[i]) { - samePartsLength = i; - break; - } - } - var outputParts = []; - for (var i = samePartsLength; i < fromParts.length; i++) { - outputParts.push('..'); - } - outputParts = outputParts.concat(toParts.slice(samePartsLength)); - return outputParts.join('/'); - }, - }; - - - - var FS_stdin_getChar_buffer = []; - - var lengthBytesUTF8 = (str) => { - var len = 0; - for (var i = 0; i < str.length; ++i) { - // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code - // unit, not a Unicode code point of the character! So decode - // UTF16->UTF32->UTF8. - // See http://unicode.org/faq/utf_bom.html#utf16-3 - var c = str.charCodeAt(i); // possibly a lead surrogate - if (c <= 0x7F) { - len++; - } else if (c <= 0x7FF) { - len += 2; - } else if (c >= 0xD800 && c <= 0xDFFF) { - len += 4; ++i; - } else { - len += 3; + var end = arr.length - 1; + for (; end >= 0; end--) { + if (arr[end] !== '') break; } + if (start > end) return []; + return arr.slice(start, end - start + 1); } - return len; - }; - - var stringToUTF8Array = (str, heap, outIdx, maxBytesToWrite) => { - assert(typeof str === 'string', `stringToUTF8Array expects a string (got ${typeof str})`); - // Parameter maxBytesToWrite is not optional. Negative values, 0, null, - // undefined and false each don't write out any bytes. - if (!(maxBytesToWrite > 0)) - return 0; - - var startIdx = outIdx; - var endIdx = outIdx + maxBytesToWrite - 1; // -1 for string null terminator. - for (var i = 0; i < str.length; ++i) { - // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code - // unit, not a Unicode code point of the character! So decode - // UTF16->UTF32->UTF8. - // See http://unicode.org/faq/utf_bom.html#utf16-3 - // For UTF8 byte structure, see http://en.wikipedia.org/wiki/UTF-8#Description - // and https://www.ietf.org/rfc/rfc2279.txt - // and https://tools.ietf.org/html/rfc3629 - var u = str.charCodeAt(i); // possibly a lead surrogate - if (u >= 0xD800 && u <= 0xDFFF) { - var u1 = str.charCodeAt(++i); - u = 0x10000 + ((u & 0x3FF) << 10) | (u1 & 0x3FF); - } - if (u <= 0x7F) { - if (outIdx >= endIdx) break; - heap[outIdx++] = u; - } else if (u <= 0x7FF) { - if (outIdx + 1 >= endIdx) break; - heap[outIdx++] = 0xC0 | (u >> 6); - heap[outIdx++] = 0x80 | (u & 63); - } else if (u <= 0xFFFF) { - if (outIdx + 2 >= endIdx) break; - heap[outIdx++] = 0xE0 | (u >> 12); - heap[outIdx++] = 0x80 | ((u >> 6) & 63); - heap[outIdx++] = 0x80 | (u & 63); - } else { - if (outIdx + 3 >= endIdx) break; - if (u > 0x10FFFF) warnOnce('Invalid Unicode code point ' + ptrToString(u) + ' encountered when serializing a JS string to a UTF-8 string in wasm memory! (Valid unicode code points should be in range 0-0x10FFFF).'); - heap[outIdx++] = 0xF0 | (u >> 18); - heap[outIdx++] = 0x80 | ((u >> 12) & 63); - heap[outIdx++] = 0x80 | ((u >> 6) & 63); - heap[outIdx++] = 0x80 | (u & 63); + var fromParts = trim(from.split('/')); + var toParts = trim(to.split('/')); + var length = Math.min(fromParts.length, toParts.length); + var samePartsLength = length; + for (var i = 0; i < length; i++) { + if (fromParts[i] !== toParts[i]) { + samePartsLength = i; + break; } } - // Null-terminate the pointer to the buffer. - heap[outIdx] = 0; - return outIdx - startIdx; + var outputParts = []; + for (var i = samePartsLength; i < fromParts.length; i++) { + outputParts.push('..'); + } + outputParts = outputParts.concat(toParts.slice(samePartsLength)); + return outputParts.join('/'); + }, +}; + + + +var FS_stdin_getChar_buffer = []; + +var lengthBytesUTF8 = (str) => { + var len = 0; + for (var i = 0; i < str.length; ++i) { + // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code + // unit, not a Unicode code point of the character! So decode + // UTF16->UTF32->UTF8. + // See http://unicode.org/faq/utf_bom.html#utf16-3 + var c = str.charCodeAt(i); // possibly a lead surrogate + if (c <= 0x7F) { + len++; + } else if (c <= 0x7FF) { + len += 2; + } else if (c >= 0xD800 && c <= 0xDFFF) { + len += 4; ++i; + } else { + len += 3; + } + } + return len; + }; + +var stringToUTF8Array = (str, heap, outIdx, maxBytesToWrite) => { + assert(typeof str === 'string', `stringToUTF8Array expects a string (got ${typeof str})`); + // Parameter maxBytesToWrite is not optional. Negative values, 0, null, + // undefined and false each don't write out any bytes. + if (!(maxBytesToWrite > 0)) + return 0; + + var startIdx = outIdx; + var endIdx = outIdx + maxBytesToWrite - 1; // -1 for string null terminator. + for (var i = 0; i < str.length; ++i) { + // For UTF8 byte structure, see http://en.wikipedia.org/wiki/UTF-8#Description + // and https://www.ietf.org/rfc/rfc2279.txt + // and https://tools.ietf.org/html/rfc3629 + var u = str.codePointAt(i); + if (u <= 0x7F) { + if (outIdx >= endIdx) break; + heap[outIdx++] = u; + } else if (u <= 0x7FF) { + if (outIdx + 1 >= endIdx) break; + heap[outIdx++] = 0xC0 | (u >> 6); + heap[outIdx++] = 0x80 | (u & 63); + } else if (u <= 0xFFFF) { + if (outIdx + 2 >= endIdx) break; + heap[outIdx++] = 0xE0 | (u >> 12); + heap[outIdx++] = 0x80 | ((u >> 6) & 63); + heap[outIdx++] = 0x80 | (u & 63); + } else { + if (outIdx + 3 >= endIdx) break; + if (u > 0x10FFFF) warnOnce('Invalid Unicode code point ' + ptrToString(u) + ' encountered when serializing a JS string to a UTF-8 string in wasm memory! (Valid unicode code points should be in range 0-0x10FFFF).'); + heap[outIdx++] = 0xF0 | (u >> 18); + heap[outIdx++] = 0x80 | ((u >> 12) & 63); + heap[outIdx++] = 0x80 | ((u >> 6) & 63); + heap[outIdx++] = 0x80 | (u & 63); + // Gotcha: if codePoint is over 0xFFFF, it is represented as a surrogate pair in UTF-16. + // We need to manually skip over the second code unit for correct iteration. + i++; + } + } + // Null-terminate the pointer to the buffer. + heap[outIdx] = 0; + return outIdx - startIdx; + }; +/** @type {function(string, boolean=, number=)} */ + var intArrayFromString = (stringy, dontAddNull, length) => { + var len = length > 0 ? length : lengthBytesUTF8(stringy)+1; + var u8array = new Array(len); + var numBytesWritten = stringToUTF8Array(stringy, u8array, 0, u8array.length); + if (dontAddNull) u8array.length = numBytesWritten; + return u8array; }; - /** @type {function(string, boolean=, number=)} */ - function intArrayFromString(stringy, dontAddNull, length) { - var len = length > 0 ? length : lengthBytesUTF8(stringy)+1; - var u8array = new Array(len); - var numBytesWritten = stringToUTF8Array(stringy, u8array, 0, u8array.length); - if (dontAddNull) u8array.length = numBytesWritten; - return u8array; - } var FS_stdin_getChar = () => { if (!FS_stdin_getChar_buffer.length) { var result = null; @@ -1394,7 +1197,7 @@ function dbg(...args) { } }, fsync(tty) { - if (tty.output && tty.output.length > 0) { + if (tty.output?.length > 0) { out(UTF8ArrayToString(tty.output)); tty.output = []; } @@ -1431,7 +1234,7 @@ function dbg(...args) { } }, fsync(tty) { - if (tty.output && tty.output.length > 0) { + if (tty.output?.length > 0) { err(UTF8ArrayToString(tty.output)); tty.output = []; } @@ -1440,9 +1243,7 @@ function dbg(...args) { }; - var zeroMemory = (address, size) => { - HEAPU8.fill(0, address, address + size); - }; + var zeroMemory = (ptr, size) => HEAPU8.fill(0, ptr, ptr + size); var alignMemory = (size, alignment) => { assert(alignment, "alignment argument is required"); @@ -1461,7 +1262,7 @@ function dbg(...args) { }, createNode(parent, name, mode, dev) { if (FS.isBlkdev(mode) || FS.isFIFO(mode)) { - // no supported + // not supported throw new FS.ErrnoError(63); } MEMFS.ops_table ||= { @@ -1490,7 +1291,6 @@ function dbg(...args) { llseek: MEMFS.stream_ops.llseek, read: MEMFS.stream_ops.read, write: MEMFS.stream_ops.write, - allocate: MEMFS.stream_ops.allocate, mmap: MEMFS.stream_ops.mmap, msync: MEMFS.stream_ops.msync } @@ -1602,7 +1402,7 @@ function dbg(...args) { }, setattr(node, attr) { for (const key of ["mode", "atime", "mtime", "ctime"]) { - if (attr[key]) { + if (attr[key] != null) { node[key] = attr[key]; } } @@ -1727,10 +1527,6 @@ function dbg(...args) { } return position; }, - allocate(stream, offset, length) { - MEMFS.expandFileStorage(stream.node, offset + length); - stream.node.usedBytes = Math.max(stream.node.usedBytes, offset + length); - }, mmap(stream, length, position, prot, flags) { if (!FS.isFile(stream.node.mode)) { throw new FS.ErrnoError(43); @@ -1772,62 +1568,6 @@ function dbg(...args) { }, }; - var asyncLoad = async (url) => { - var arrayBuffer = await readAsync(url); - assert(arrayBuffer, `Loading data file "${url}" failed (no arrayBuffer).`); - return new Uint8Array(arrayBuffer); - }; - - - var FS_createDataFile = (parent, name, fileData, canRead, canWrite, canOwn) => { - FS.createDataFile(parent, name, fileData, canRead, canWrite, canOwn); - }; - - var preloadPlugins = Module['preloadPlugins'] || []; - var FS_handledByPreloadPlugin = (byteArray, fullname, finish, onerror) => { - // Ensure plugins are ready. - if (typeof Browser != 'undefined') Browser.init(); - - var handled = false; - preloadPlugins.forEach((plugin) => { - if (handled) return; - if (plugin['canHandle'](fullname)) { - plugin['handle'](byteArray, fullname, finish, onerror); - handled = true; - } - }); - return handled; - }; - var FS_createPreloadedFile = (parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn, preFinish) => { - // TODO we should allow people to just pass in a complete filename instead - // of parent and name being that we just join them anyways - var fullname = name ? PATH_FS.resolve(PATH.join2(parent, name)) : parent; - var dep = getUniqueRunDependency(`cp ${fullname}`); // might have several active requests for the same fullname - function processData(byteArray) { - function finish(byteArray) { - preFinish?.(); - if (!dontCreateFile) { - FS_createDataFile(parent, name, byteArray, canRead, canWrite, canOwn); - } - onload?.(); - removeRunDependency(dep); - } - if (FS_handledByPreloadPlugin(byteArray, fullname, finish, () => { - onerror?.(); - removeRunDependency(dep); - })) { - return; - } - finish(byteArray); - } - addRunDependency(dep); - if (typeof url == 'string') { - asyncLoad(url).then(processData, onerror); - } else { - processData(url); - } - }; - var FS_modeStringToFlags = (str) => { var flagModes = { 'r': 0, @@ -1854,8 +1594,6 @@ function dbg(...args) { - - var strError = (errno) => UTF8ToString(_strerror(errno)); var ERRNO_CODES = { @@ -1981,6 +1719,130 @@ function dbg(...args) { 'EOWNERDEAD': 62, 'ESTRPIPE': 135, }; + + var asyncLoad = async (url) => { + var arrayBuffer = await readAsync(url); + assert(arrayBuffer, `Loading data file "${url}" failed (no arrayBuffer).`); + return new Uint8Array(arrayBuffer); + }; + + + var FS_createDataFile = (...args) => FS.createDataFile(...args); + + var getUniqueRunDependency = (id) => { + var orig = id; + while (1) { + if (!runDependencyTracking[id]) return id; + id = orig + Math.random(); + } + }; + + var runDependencies = 0; + + + var dependenciesFulfilled = null; + + var runDependencyTracking = { + }; + + var runDependencyWatcher = null; + var removeRunDependency = (id) => { + runDependencies--; + + Module['monitorRunDependencies']?.(runDependencies); + + assert(id, 'removeRunDependency requires an ID'); + assert(runDependencyTracking[id]); + delete runDependencyTracking[id]; + if (runDependencies == 0) { + if (runDependencyWatcher !== null) { + clearInterval(runDependencyWatcher); + runDependencyWatcher = null; + } + if (dependenciesFulfilled) { + var callback = dependenciesFulfilled; + dependenciesFulfilled = null; + callback(); // can add another dependenciesFulfilled + } + } + }; + + + var addRunDependency = (id) => { + runDependencies++; + + Module['monitorRunDependencies']?.(runDependencies); + + assert(id, 'addRunDependency requires an ID') + assert(!runDependencyTracking[id]); + runDependencyTracking[id] = 1; + if (runDependencyWatcher === null && globalThis.setInterval) { + // Check for missing dependencies every few seconds + runDependencyWatcher = setInterval(() => { + if (ABORT) { + clearInterval(runDependencyWatcher); + runDependencyWatcher = null; + return; + } + var shown = false; + for (var dep in runDependencyTracking) { + if (!shown) { + shown = true; + err('still waiting on run dependencies:'); + } + err(`dependency: ${dep}`); + } + if (shown) { + err('(end of list)'); + } + }, 10000); + // Prevent this timer from keeping the runtime alive if nothing + // else is. + runDependencyWatcher.unref?.() + } + }; + + + var preloadPlugins = []; + var FS_handledByPreloadPlugin = async (byteArray, fullname) => { + // Ensure plugins are ready. + if (typeof Browser != 'undefined') Browser.init(); + + for (var plugin of preloadPlugins) { + if (plugin['canHandle'](fullname)) { + assert(plugin['handle'].constructor.name === 'AsyncFunction', 'Filesystem plugin handlers must be async functions (See #24914)') + return plugin['handle'](byteArray, fullname); + } + } + // If no plugin handled this file then return the original/unmodified + // byteArray. + return byteArray; + }; + var FS_preloadFile = async (parent, name, url, canRead, canWrite, dontCreateFile, canOwn, preFinish) => { + // TODO we should allow people to just pass in a complete filename instead + // of parent and name being that we just join them anyways + var fullname = name ? PATH_FS.resolve(PATH.join2(parent, name)) : parent; + var dep = getUniqueRunDependency(`cp ${fullname}`); // might have several active requests for the same fullname + addRunDependency(dep); + + try { + var byteArray = url; + if (typeof url == 'string') { + byteArray = await asyncLoad(url); + } + + byteArray = await FS_handledByPreloadPlugin(byteArray, fullname); + preFinish?.(); + if (!dontCreateFile) { + FS_createDataFile(parent, name, byteArray, canRead, canWrite, canOwn); + } + } finally { + removeRunDependency(dep); + } + }; + var FS_createPreloadedFile = (parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn, preFinish) => { + FS_preloadFile(parent, name, url, canRead, canWrite, dontCreateFile, canOwn, preFinish).then(onload).catch(onerror); + }; var FS = { root:null, mounts:[], @@ -1992,6 +1854,8 @@ function dbg(...args) { currentPath:"/", initialized:false, ignorePermissions:true, + filesystems:null, + syncFSRequests:0, ErrnoError:class extends Error { name = 'ErrnoError'; // We set the `name` property to be able to identify `FS.ErrnoError` @@ -2011,10 +1875,6 @@ function dbg(...args) { } } }, - filesystems:null, - syncFSRequests:0, - readFiles:{ - }, FSStream:class { shared = {}; get object() { @@ -2083,7 +1943,9 @@ function dbg(...args) { } }, lookupPath(path, opts = {}) { - if (!path) return { path: '', node: null }; + if (!path) { + throw new FS.ErrnoError(44); + } opts.follow_mount ??= true if (!PATH.isAbs(path)) { @@ -2093,7 +1955,7 @@ function dbg(...args) { // limit max consecutive symlinks to 40 (SYMLOOP_MAX). linkloop: for (var nlinks = 0; nlinks < 40; nlinks++) { // split the absolute path - var parts = path.split('/').filter((p) => !!p && (p !== '.')); + var parts = path.split('/').filter((p) => !!p); // start at the root var current = FS.root; @@ -2106,9 +1968,21 @@ function dbg(...args) { break; } + if (parts[i] === '.') { + continue; + } + if (parts[i] === '..') { current_path = PATH.dirname(current_path); - current = current.parent; + if (FS.isRoot(current)) { + path = current_path + '/' + parts.slice(i + 1).join('/'); + // We're making progress here, don't let many consecutive ..'s + // lead to ELOOP + nlinks--; + continue linkloop; + } else { + current = current.parent; + } continue; } @@ -2255,9 +2129,11 @@ function dbg(...args) { // return 0 if any user, group or owner bits are set. if (perms.includes('r') && !(node.mode & 292)) { return 2; - } else if (perms.includes('w') && !(node.mode & 146)) { + } + if (perms.includes('w') && !(node.mode & 146)) { return 2; - } else if (perms.includes('x') && !(node.mode & 73)) { + } + if (perms.includes('x') && !(node.mode & 73)) { return 2; } return 0; @@ -2298,10 +2174,8 @@ function dbg(...args) { if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) { return 10; } - } else { - if (FS.isDir(node.mode)) { - return 31; - } + } else if (FS.isDir(node.mode)) { + return 31; } return 0; }, @@ -2311,13 +2185,22 @@ function dbg(...args) { } if (FS.isLink(node.mode)) { return 32; - } else if (FS.isDir(node.mode)) { - if (FS.flagsToPermissionString(flags) !== 'r' || // opening for write - (flags & 512)) { // TODO: check for O_SEARCH? (== search for dir only) + } + var mode = FS.flagsToPermissionString(flags); + if (FS.isDir(node.mode)) { + // opening for write + // TODO: check for O_SEARCH? (== search for dir only) + if (mode !== 'r' || (flags & (512 | 64))) { return 31; } } - return FS.nodePermissions(node, FS.flagsToPermissionString(flags)); + return FS.nodePermissions(node, mode); + }, + checkOpExists(op, err) { + if (!op) { + throw new FS.ErrnoError(err); + } + return op; }, MAX_OPEN_FDS:4096, nextfd() { @@ -2356,6 +2239,13 @@ function dbg(...args) { stream.stream_ops?.dup?.(stream); return stream; }, + doSetAttr(stream, node, attr) { + var setattr = stream?.stream_ops.setattr; + var arg = setattr ? stream : node; + setattr ??= node.node_ops.setattr; + FS.checkOpExists(setattr, 63) + setattr(arg, attr); + }, chrdev_stream_ops:{ open(stream) { var device = FS.getDevice(stream.node.rdev); @@ -2424,12 +2314,13 @@ function dbg(...args) { }; // sync all mounts - mounts.forEach((mount) => { - if (!mount.type.syncfs) { - return done(null); + for (var mount of mounts) { + if (mount.type.syncfs) { + mount.type.syncfs(mount, populate, done); + } else { + done(null); } - mount.type.syncfs(mount, populate, done); - }); + } }, mount(type, opts, mountpoint) { if (typeof type == 'string') { @@ -2496,9 +2387,7 @@ function dbg(...args) { var mount = node.mounted; var mounts = FS.getMounts(mount); - Object.keys(FS.nameTable).forEach((hash) => { - var current = FS.nameTable[hash]; - + for (var [hash, current] of Object.entries(FS.nameTable)) { while (current) { var next = current.name_next; @@ -2508,7 +2397,7 @@ function dbg(...args) { current = next; } - }); + } // no longer a mountpoint node.mounted = null; @@ -2525,9 +2414,12 @@ function dbg(...args) { var lookup = FS.lookupPath(path, { parent: true }); var parent = lookup.node; var name = PATH.basename(path); - if (!name || name === '.' || name === '..') { + if (!name) { throw new FS.ErrnoError(28); } + if (name === '.' || name === '..') { + throw new FS.ErrnoError(20); + } var errCode = FS.mayCreate(parent, name); if (errCode) { throw new FS.ErrnoError(errCode); @@ -2538,9 +2430,18 @@ function dbg(...args) { return parent.node_ops.mknod(parent, name, mode, dev); }, statfs(path) { - + return FS.statfsNode(FS.lookupPath(path, {follow: true}).node); + }, + statfsStream(stream) { + // We keep a separate statfsStream function because noderawfs overrides + // it. In noderawfs, stream.node is sometimes null. Instead, we need to + // look at stream.path. + return FS.statfsNode(stream.node); + }, + statfsNode(node) { // NOTE: None of the defaults here are true. We're just returning safe and - // sane values. + // sane values. Currently nodefs and rawfs replace these defaults, + // other file systems leave them alone. var rtn = { bsize: 4096, frsize: 4096, @@ -2554,9 +2455,8 @@ function dbg(...args) { namelen: 255, }; - var parent = FS.lookupPath(path, {follow: true}).node; - if (parent?.node_ops.statfs) { - Object.assign(rtn, parent.node_ops.statfs(parent.mount.opts.root)); + if (node.node_ops.statfs) { + Object.assign(rtn, node.node_ops.statfs(node.mount.opts.root)); } return rtn; }, @@ -2573,9 +2473,10 @@ function dbg(...args) { mkdirTree(path, mode) { var dirs = path.split('/'); var d = ''; - for (var i = 0; i < dirs.length; ++i) { - if (!dirs[i]) continue; - d += '/' + dirs[i]; + for (var dir of dirs) { + if (!dir) continue; + if (d || PATH.isAbs(path)) d += '/'; + d += dir; try { FS.mkdir(d, mode); } catch(e) { @@ -2716,10 +2617,8 @@ function dbg(...args) { readdir(path) { var lookup = FS.lookupPath(path, { follow: true }); var node = lookup.node; - if (!node.node_ops.readdir) { - throw new FS.ErrnoError(54); - } - return node.node_ops.readdir(node); + var readdir = FS.checkOpExists(node.node_ops.readdir, 54); + return readdir(node); }, unlink(path) { var lookup = FS.lookupPath(path, { parent: true }); @@ -2759,17 +2658,28 @@ function dbg(...args) { stat(path, dontFollow) { var lookup = FS.lookupPath(path, { follow: !dontFollow }); var node = lookup.node; - if (!node) { - throw new FS.ErrnoError(44); - } - if (!node.node_ops.getattr) { - throw new FS.ErrnoError(63); - } - return node.node_ops.getattr(node); + var getattr = FS.checkOpExists(node.node_ops.getattr, 63); + return getattr(node); + }, + fstat(fd) { + var stream = FS.getStreamChecked(fd); + var node = stream.node; + var getattr = stream.stream_ops.getattr; + var arg = getattr ? stream : node; + getattr ??= node.node_ops.getattr; + FS.checkOpExists(getattr, 63) + return getattr(arg); }, lstat(path) { return FS.stat(path, true); }, + doChmod(stream, node, mode, dontFollow) { + FS.doSetAttr(stream, node, { + mode: (mode & 4095) | (node.mode & ~4095), + ctime: Date.now(), + dontFollow + }); + }, chmod(path, mode, dontFollow) { var node; if (typeof path == 'string') { @@ -2778,20 +2688,21 @@ function dbg(...args) { } else { node = path; } - if (!node.node_ops.setattr) { - throw new FS.ErrnoError(63); - } - node.node_ops.setattr(node, { - mode: (mode & 4095) | (node.mode & ~4095), - ctime: Date.now() - }); + FS.doChmod(null, node, mode, dontFollow); }, lchmod(path, mode) { FS.chmod(path, mode, true); }, fchmod(fd, mode) { var stream = FS.getStreamChecked(fd); - FS.chmod(stream.node, mode); + FS.doChmod(stream, stream.node, mode, false); + }, + doChown(stream, node, dontFollow) { + FS.doSetAttr(stream, node, { + timestamp: Date.now(), + dontFollow + // we ignore the uid / gid for now + }); }, chown(path, uid, gid, dontFollow) { var node; @@ -2801,35 +2712,16 @@ function dbg(...args) { } else { node = path; } - if (!node.node_ops.setattr) { - throw new FS.ErrnoError(63); - } - node.node_ops.setattr(node, { - timestamp: Date.now() - // we ignore the uid / gid for now - }); + FS.doChown(null, node, dontFollow); }, lchown(path, uid, gid) { FS.chown(path, uid, gid, true); }, fchown(fd, uid, gid) { var stream = FS.getStreamChecked(fd); - FS.chown(stream.node, uid, gid); + FS.doChown(stream, stream.node, false); }, - truncate(path, len) { - if (len < 0) { - throw new FS.ErrnoError(28); - } - var node; - if (typeof path == 'string') { - var lookup = FS.lookupPath(path, { follow: true }); - node = lookup.node; - } else { - node = path; - } - if (!node.node_ops.setattr) { - throw new FS.ErrnoError(63); - } + doTruncate(stream, node, len) { if (FS.isDir(node.mode)) { throw new FS.ErrnoError(31); } @@ -2840,22 +2732,36 @@ function dbg(...args) { if (errCode) { throw new FS.ErrnoError(errCode); } - node.node_ops.setattr(node, { + FS.doSetAttr(stream, node, { size: len, timestamp: Date.now() }); }, + truncate(path, len) { + if (len < 0) { + throw new FS.ErrnoError(28); + } + var node; + if (typeof path == 'string') { + var lookup = FS.lookupPath(path, { follow: true }); + node = lookup.node; + } else { + node = path; + } + FS.doTruncate(null, node, len); + }, ftruncate(fd, len) { var stream = FS.getStreamChecked(fd); - if ((stream.flags & 2097155) === 0) { + if (len < 0 || (stream.flags & 2097155) === 0) { throw new FS.ErrnoError(28); } - FS.truncate(stream.node, len); + FS.doTruncate(stream, stream.node, len); }, utime(path, atime, mtime) { var lookup = FS.lookupPath(path, { follow: true }); var node = lookup.node; - node.node_ops.setattr(node, { + var setattr = FS.checkOpExists(node.node_ops.setattr, 63); + setattr(node, { atime: atime, mtime: mtime }); @@ -2871,9 +2777,11 @@ function dbg(...args) { mode = 0; } var node; + var isDirPath; if (typeof path == 'object') { node = path; } else { + isDirPath = path.endsWith("/"); // noent_okay makes it so that if the final component of the path // doesn't exist, lookupPath returns `node: undefined`. `path` will be // updated to point to the target of all symlinks. @@ -2892,9 +2800,14 @@ function dbg(...args) { if ((flags & 128)) { throw new FS.ErrnoError(20); } + } else if (isDirPath) { + throw new FS.ErrnoError(31); } else { // node doesn't exist, try to create it - node = FS.mknod(path, mode, 0); + // Ignore the permission bits here to ensure we can `open` this new + // file below. We use chmod below to apply the permissions once the + // file is open. + node = FS.mknod(path, mode | 0o777, 0); created = true; } } @@ -2941,10 +2854,8 @@ function dbg(...args) { if (stream.stream_ops.open) { stream.stream_ops.open(stream); } - if (Module['logReadFiles'] && !(flags & 1)) { - if (!(path in FS.readFiles)) { - FS.readFiles[path] = 1; - } + if (created) { + FS.chmod(node, mode & 0o777); } return stream; }, @@ -3039,24 +2950,6 @@ function dbg(...args) { if (!seeking) stream.position += bytesWritten; return bytesWritten; }, - allocate(stream, offset, length) { - if (FS.isClosed(stream)) { - throw new FS.ErrnoError(8); - } - if (offset < 0 || length <= 0) { - throw new FS.ErrnoError(28); - } - if ((stream.flags & 2097155) === 0) { - throw new FS.ErrnoError(8); - } - if (!FS.isFile(stream.node.mode) && !FS.isDir(stream.node.mode)) { - throw new FS.ErrnoError(43); - } - if (!stream.stream_ops.allocate) { - throw new FS.ErrnoError(138); - } - stream.stream_ops.allocate(stream, offset, length); - }, mmap(stream, length, position, prot, flags) { // User requests writing to file (prot & PROT_WRITE != 0). // Checking if we have permissions to write to the file unless @@ -3097,33 +2990,29 @@ function dbg(...args) { opts.flags = opts.flags || 0; opts.encoding = opts.encoding || 'binary'; if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') { - throw new Error(`Invalid encoding type "${opts.encoding}"`); + abort(`Invalid encoding type "${opts.encoding}"`); } - var ret; var stream = FS.open(path, opts.flags); var stat = FS.stat(path); var length = stat.size; var buf = new Uint8Array(length); FS.read(stream, buf, 0, length, 0); if (opts.encoding === 'utf8') { - ret = UTF8ArrayToString(buf); - } else if (opts.encoding === 'binary') { - ret = buf; + buf = UTF8ArrayToString(buf); } FS.close(stream); - return ret; + return buf; }, writeFile(path, data, opts = {}) { opts.flags = opts.flags || 577; var stream = FS.open(path, opts.flags, opts.mode); if (typeof data == 'string') { - var buf = new Uint8Array(lengthBytesUTF8(data)+1); - var actualNumBytes = stringToUTF8Array(data, buf, 0, buf.length); - FS.write(stream, buf, 0, actualNumBytes, undefined, opts.canOwn); - } else if (ArrayBuffer.isView(data)) { + data = new Uint8Array(intArrayFromString(data, true)); + } + if (ArrayBuffer.isView(data)) { FS.write(stream, data, 0, data.byteLength, undefined, opts.canOwn); } else { - throw new Error('Unsupported data type'); + abort('Unsupported data type'); } FS.close(stream); }, @@ -3169,7 +3058,8 @@ function dbg(...args) { var randomBuffer = new Uint8Array(1024), randomLeft = 0; var randomByte = () => { if (randomLeft === 0) { - randomLeft = randomFill(randomBuffer).byteLength; + randomFill(randomBuffer); + randomLeft = randomBuffer.byteLength; } return randomBuffer[--randomLeft]; }; @@ -3277,12 +3167,10 @@ function dbg(...args) { // force-flush all streams, so we get musl std streams printed out _fflush(0); // close all of our streams - for (var i = 0; i < FS.streams.length; i++) { - var stream = FS.streams[i]; - if (!stream) { - continue; + for (var stream of FS.streams) { + if (stream) { + FS.close(stream); } - FS.close(stream); } }, findObject(path, dontResolveLastLink) { @@ -3330,7 +3218,7 @@ function dbg(...args) { try { FS.mkdir(current); } catch (e) { - // ignore EEXIST + if (e.errno != 20) throw e; } parent = current; } @@ -3419,12 +3307,11 @@ function dbg(...args) { }, forceLoadFile(obj) { if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true; - if (typeof XMLHttpRequest != 'undefined') { - throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread."); + if (globalThis.XMLHttpRequest) { + abort("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread."); } else { // Command-line. try { obj.contents = readBinary(obj.url); - obj.usedBytes = obj.contents.length; } catch (e) { throw new FS.ErrnoError(29); } @@ -3452,7 +3339,7 @@ function dbg(...args) { var xhr = new XMLHttpRequest(); xhr.open('HEAD', url, false); xhr.send(null); - if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status); + if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) abort("Couldn't load " + url + ". Status: " + xhr.status); var datalength = Number(xhr.getResponseHeader("Content-length")); var header; var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes"; @@ -3464,8 +3351,8 @@ function dbg(...args) { // Function to get a range from the remote URL. var doXHR = (from, to) => { - if (from > to) throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!"); - if (to > datalength-1) throw new Error("only " + datalength + " bytes available! programmer error!"); + if (from > to) abort("invalid range (" + from + ", " + to + ") or no bytes requested!"); + if (to > datalength-1) abort("only " + datalength + " bytes available! programmer error!"); // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available. var xhr = new XMLHttpRequest(); @@ -3479,7 +3366,7 @@ function dbg(...args) { } xhr.send(null); - if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status); + if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) abort("Couldn't load " + url + ". Status: " + xhr.status); if (xhr.response !== undefined) { return new Uint8Array(/** @type{Array<number>} */(xhr.response || [])); } @@ -3493,7 +3380,7 @@ function dbg(...args) { if (typeof lazyArray.chunks[chunkNum] == 'undefined') { lazyArray.chunks[chunkNum] = doXHR(start, end); } - if (typeof lazyArray.chunks[chunkNum] == 'undefined') throw new Error('doXHR failed!'); + if (typeof lazyArray.chunks[chunkNum] == 'undefined') abort('doXHR failed!'); return lazyArray.chunks[chunkNum]; }); @@ -3523,8 +3410,8 @@ function dbg(...args) { } } - if (typeof XMLHttpRequest != 'undefined') { - if (!ENVIRONMENT_IS_WORKER) throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc'; + if (globalThis.XMLHttpRequest) { + if (!ENVIRONMENT_IS_WORKER) abort('Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc'); var lazyArray = new LazyUint8Array(); var properties = { isDevice: false, contents: lazyArray }; } else { @@ -3549,14 +3436,12 @@ function dbg(...args) { }); // override each stream op with one that tries to force load the lazy file first var stream_ops = {}; - var keys = Object.keys(node.stream_ops); - keys.forEach((key) => { - var fn = node.stream_ops[key]; + for (const [key, fn] of Object.entries(node.stream_ops)) { stream_ops[key] = (...args) => { FS.forceLoadFile(node); return fn(...args); }; - }); + } function writeChunks(stream, buffer, offset, length, position) { var contents = stream.node.contents; if (position >= contents.length) @@ -3611,167 +3496,6 @@ function dbg(...args) { abort('FS.standardizePath has been removed; use PATH.normalize instead'); }, }; - - var SYSCALLS = { - DEFAULT_POLLMASK:5, - calculateAt(dirfd, path, allowEmpty) { - if (PATH.isAbs(path)) { - return path; - } - // relative path - var dir; - if (dirfd === -100) { - dir = FS.cwd(); - } else { - var dirstream = SYSCALLS.getStreamFromFD(dirfd); - dir = dirstream.path; - } - if (path.length == 0) { - if (!allowEmpty) { - throw new FS.ErrnoError(44);; - } - return dir; - } - return dir + '/' + path; - }, - doStat(func, path, buf) { - var stat = func(path); - HEAP32[((buf)>>2)] = stat.dev; - HEAP32[(((buf)+(4))>>2)] = stat.mode; - HEAPU32[(((buf)+(8))>>2)] = stat.nlink; - HEAP32[(((buf)+(12))>>2)] = stat.uid; - HEAP32[(((buf)+(16))>>2)] = stat.gid; - HEAP32[(((buf)+(20))>>2)] = stat.rdev; - (tempI64 = [stat.size>>>0,(tempDouble = stat.size,(+(Math.abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? (+(Math.floor((tempDouble)/4294967296.0)))>>>0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)], HEAP32[(((buf)+(24))>>2)] = tempI64[0],HEAP32[(((buf)+(28))>>2)] = tempI64[1]); - HEAP32[(((buf)+(32))>>2)] = 4096; - HEAP32[(((buf)+(36))>>2)] = stat.blocks; - var atime = stat.atime.getTime(); - var mtime = stat.mtime.getTime(); - var ctime = stat.ctime.getTime(); - (tempI64 = [Math.floor(atime / 1000)>>>0,(tempDouble = Math.floor(atime / 1000),(+(Math.abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? (+(Math.floor((tempDouble)/4294967296.0)))>>>0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)], HEAP32[(((buf)+(40))>>2)] = tempI64[0],HEAP32[(((buf)+(44))>>2)] = tempI64[1]); - HEAPU32[(((buf)+(48))>>2)] = (atime % 1000) * 1000 * 1000; - (tempI64 = [Math.floor(mtime / 1000)>>>0,(tempDouble = Math.floor(mtime / 1000),(+(Math.abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? (+(Math.floor((tempDouble)/4294967296.0)))>>>0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)], HEAP32[(((buf)+(56))>>2)] = tempI64[0],HEAP32[(((buf)+(60))>>2)] = tempI64[1]); - HEAPU32[(((buf)+(64))>>2)] = (mtime % 1000) * 1000 * 1000; - (tempI64 = [Math.floor(ctime / 1000)>>>0,(tempDouble = Math.floor(ctime / 1000),(+(Math.abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? (+(Math.floor((tempDouble)/4294967296.0)))>>>0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)], HEAP32[(((buf)+(72))>>2)] = tempI64[0],HEAP32[(((buf)+(76))>>2)] = tempI64[1]); - HEAPU32[(((buf)+(80))>>2)] = (ctime % 1000) * 1000 * 1000; - (tempI64 = [stat.ino>>>0,(tempDouble = stat.ino,(+(Math.abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? (+(Math.floor((tempDouble)/4294967296.0)))>>>0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)], HEAP32[(((buf)+(88))>>2)] = tempI64[0],HEAP32[(((buf)+(92))>>2)] = tempI64[1]); - return 0; - }, - doMsync(addr, stream, len, flags, offset) { - if (!FS.isFile(stream.node.mode)) { - throw new FS.ErrnoError(43); - } - if (flags & 2) { - // MAP_PRIVATE calls need not to be synced back to underlying fs - return 0; - } - var buffer = HEAPU8.slice(addr, addr + len); - FS.msync(stream, buffer, offset, len, flags); - }, - getStreamFromFD(fd) { - var stream = FS.getStreamChecked(fd); - return stream; - }, - varargs:undefined, - getStr(ptr) { - var ret = UTF8ToString(ptr); - return ret; - }, - }; - var ___syscall__newselect = function (nfds, readfds, writefds, exceptfds, timeout) { - try { - - // readfds are supported, - // writefds checks socket open status - // exceptfds are supported, although on web, such exceptional conditions never arise in web sockets - // and so the exceptfds list will always return empty. - // timeout is supported, although on SOCKFS and PIPEFS these are ignored and always treated as 0 - fully async - assert(nfds <= 64, 'nfds must be less than or equal to 64'); // fd sets have 64 bits // TODO: this could be 1024 based on current musl headers - - var total = 0; - - var srcReadLow = (readfds ? HEAP32[((readfds)>>2)] : 0), - srcReadHigh = (readfds ? HEAP32[(((readfds)+(4))>>2)] : 0); - var srcWriteLow = (writefds ? HEAP32[((writefds)>>2)] : 0), - srcWriteHigh = (writefds ? HEAP32[(((writefds)+(4))>>2)] : 0); - var srcExceptLow = (exceptfds ? HEAP32[((exceptfds)>>2)] : 0), - srcExceptHigh = (exceptfds ? HEAP32[(((exceptfds)+(4))>>2)] : 0); - - var dstReadLow = 0, - dstReadHigh = 0; - var dstWriteLow = 0, - dstWriteHigh = 0; - var dstExceptLow = 0, - dstExceptHigh = 0; - - var allLow = (readfds ? HEAP32[((readfds)>>2)] : 0) | - (writefds ? HEAP32[((writefds)>>2)] : 0) | - (exceptfds ? HEAP32[((exceptfds)>>2)] : 0); - var allHigh = (readfds ? HEAP32[(((readfds)+(4))>>2)] : 0) | - (writefds ? HEAP32[(((writefds)+(4))>>2)] : 0) | - (exceptfds ? HEAP32[(((exceptfds)+(4))>>2)] : 0); - - var check = (fd, low, high, val) => fd < 32 ? (low & val) : (high & val); - - for (var fd = 0; fd < nfds; fd++) { - var mask = 1 << (fd % 32); - if (!(check(fd, allLow, allHigh, mask))) { - continue; // index isn't in the set - } - - var stream = SYSCALLS.getStreamFromFD(fd); - - var flags = SYSCALLS.DEFAULT_POLLMASK; - - if (stream.stream_ops.poll) { - var timeoutInMillis = -1; - if (timeout) { - // select(2) is declared to accept "struct timeval { time_t tv_sec; suseconds_t tv_usec; }". - // However, musl passes the two values to the syscall as an array of long values. - // Note that sizeof(time_t) != sizeof(long) in wasm32. The former is 8, while the latter is 4. - // This means using "C_STRUCTS.timeval.tv_usec" leads to a wrong offset. - // So, instead, we use POINTER_SIZE. - var tv_sec = (readfds ? HEAP32[((timeout)>>2)] : 0), - tv_usec = (readfds ? HEAP32[(((timeout)+(4))>>2)] : 0); - timeoutInMillis = (tv_sec + tv_usec / 1000000) * 1000; - } - flags = stream.stream_ops.poll(stream, timeoutInMillis); - } - - if ((flags & 1) && check(fd, srcReadLow, srcReadHigh, mask)) { - fd < 32 ? (dstReadLow = dstReadLow | mask) : (dstReadHigh = dstReadHigh | mask); - total++; - } - if ((flags & 4) && check(fd, srcWriteLow, srcWriteHigh, mask)) { - fd < 32 ? (dstWriteLow = dstWriteLow | mask) : (dstWriteHigh = dstWriteHigh | mask); - total++; - } - if ((flags & 2) && check(fd, srcExceptLow, srcExceptHigh, mask)) { - fd < 32 ? (dstExceptLow = dstExceptLow | mask) : (dstExceptHigh = dstExceptHigh | mask); - total++; - } - } - - if (readfds) { - HEAP32[((readfds)>>2)] = dstReadLow; - HEAP32[(((readfds)+(4))>>2)] = dstReadHigh; - } - if (writefds) { - HEAP32[((writefds)>>2)] = dstWriteLow; - HEAP32[(((writefds)+(4))>>2)] = dstWriteHigh; - } - if (exceptfds) { - HEAP32[((exceptfds)>>2)] = dstExceptLow; - HEAP32[(((exceptfds)+(4))>>2)] = dstExceptHigh; - } - - return total; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - }; - var SOCKFS = { websocketArgs:{ }, @@ -3784,8 +3508,8 @@ function dbg(...args) { SOCKFS.callbacks[event]?.(param); }, mount(mount) { - // The incomming Module['websocket'] can be used for configuring - // configuring subprotocol/url, etc + // The incoming Module['websocket'] can be used for configuring + // subprotocol/url, etc SOCKFS.websocketArgs = Module['websocket'] || {}; // Add the Event registration mechanism to the exported websocket configuration // object so we can register network callbacks from native JavaScript too. @@ -3795,7 +3519,15 @@ function dbg(...args) { return FS.createNode(null, '/', 16895, 0); }, createSocket(family, type, protocol) { + // Emscripten only supports AF_INET + if (family != 2) { + throw new FS.ErrnoError(5); + } type &= ~526336; // Some applications may pass it; it makes no sense for a single process. + // Emscripten only supports SOCK_STREAM and SOCK_DGRAM + if (type != 1 && type != 2) { + throw new FS.ErrnoError(28); + } var streaming = type == 1; if (streaming && protocol && protocol != 6) { throw new FS.ErrnoError(66); // if SOCK_STREAM, must be tcp or 0. @@ -3908,7 +3640,7 @@ function dbg(...args) { try { // The default value is 'ws://' the replace is needed because the compiler replaces '//' comments with '#' // comments without checking context, so we'd end up with ws:#, the replace swaps the '#' for '//' again. - var url = 'ws:#'.replace('#', '//'); + var url = 'ws://'.replace('#', '//'); // Make the WebSocket subprotocol (Sec-WebSocket-Protocol) default to binary if no configuration is set. var subProtocols = 'binary'; // The default value is 'binary' // The default WebSocket options @@ -3931,7 +3663,7 @@ function dbg(...args) { } if (subProtocols !== 'null') { - // The regex trims the string (removes spaces at the beginning and end, then splits the string by + // The regex trims the string (removes spaces at the beginning and end), then splits the string by // <any space>,<any space> into an Array. Whitespace removal is important for Websockify and ws. subProtocols = subProtocols.replace(/^ +| +$/g,"").split(/ *, */); @@ -4028,7 +3760,7 @@ function dbg(...args) { data.length === 10 && data[0] === 255 && data[1] === 255 && data[2] === 255 && data[3] === 255 && data[4] === 'p'.charCodeAt(0) && data[5] === 'o'.charCodeAt(0) && data[6] === 'r'.charCodeAt(0) && data[7] === 't'.charCodeAt(0)) { - // update the peer's port and it's key in the peer map + // update the peer's port and its key in the peer map var newport = ((data[8] << 8) | data[9]); SOCKFS.websocket_sock_ops.removePeer(sock, peer); peer.port = newport; @@ -4124,6 +3856,14 @@ function dbg(...args) { } HEAP32[((arg)>>2)] = bytes; return 0; + case 21537: + var on = HEAP32[((arg)>>2)]; + if (on) { + sock.stream.flags |= 2048; + } else { + sock.stream.flags &= ~2048; + } + return 0; default: return 28; } @@ -4138,9 +3878,7 @@ function dbg(...args) { sock.server = null; } // close any peer connections - var peers = Object.keys(sock.peers); - for (var i = 0; i < peers.length; i++) { - var peer = sock.peers[peers[i]]; + for (var peer of Object.values(sock.peers)) { try { peer.socket.close(); } catch (e) { @@ -4398,23 +4136,6 @@ function dbg(...args) { return socket; }; - var Sockets = { - BUFFER_SIZE:10240, - MAX_BUFFER_SIZE:10485760, - nextFd:1, - fds:{ - }, - nextport:1, - maxport:65535, - peer:null, - connections:{ - }, - portmap:{ - }, - localAddr:4261412874, - addrPool:[33554442,50331658,67108874,83886090,100663306,117440522,134217738,150994954,167772170,184549386,201326602,218103818,234881034], - }; - var inetPton4 = (str) => { var b = str.split('.'); for (var i = 0; i < 4; i++) { @@ -4425,9 +4146,6 @@ function dbg(...args) { return (b[0] | (b[1] << 8) | (b[2] << 16) | (b[3] << 24)) >>> 0; }; - - /** @suppress {checkTypes} */ - var jstoi_q = (str) => parseInt(str); var inetPton6 = (str) => { var words; var w, offset, z, i; @@ -4448,11 +4166,11 @@ function dbg(...args) { } if (str.indexOf(".") > 0) { - // parse IPv4 embedded stress + // parse IPv4 embedded address str = str.replace(new RegExp('[.]', 'g'), ":"); words = str.split(":"); - words[words.length-4] = jstoi_q(words[words.length-4]) + jstoi_q(words[words.length-3])*256; - words[words.length-3] = jstoi_q(words[words.length-2]) + jstoi_q(words[words.length-1])*256; + words[words.length-4] = Number(words[words.length-4]) + Number(words[words.length-3])*256; + words[words.length-3] = Number(words[words.length-2]) + Number(words[words.length-1])*256; words = words.slice(0, words.length-2); } else { words = str.split(":"); @@ -4468,7 +4186,7 @@ function dbg(...args) { } offset = z-1; } else { - // parse hex to field to 16-bit value and write it in network byte-order + // parse hex field to 16-bit value and write it in network byte-order parts[w+offset] = _htons(parseInt(words[w],16)); } } else { @@ -4579,7 +4297,6 @@ function dbg(...args) { } - var inetNtop4 = (addr) => (addr & 0xff) + '.' + ((addr >> 8) & 0xff) + '.' + ((addr >> 16) & 0xff) + '.' + ((addr >> 24) & 0xff); @@ -4638,7 +4355,7 @@ function dbg(...args) { // IPv4-compatible IPv6 address if 16-bit value (bytes 11 and 12) == 0x0000 (6th word) if (parts[5] === 0) { str = "::"; - //special case IPv6 addresses + // special case IPv6 addresses if (v4part === "0.0.0.0") v4part = ""; // any/unspecified address if (v4part === "0.0.0.1") v4part = "1";// loopback address str += v4part; @@ -4734,6 +4451,84 @@ function dbg(...args) { } } + + + var SYSCALLS = { + calculateAt(dirfd, path, allowEmpty) { + if (PATH.isAbs(path)) { + return path; + } + // relative path + var dir; + if (dirfd === -100) { + dir = FS.cwd(); + } else { + var dirstream = SYSCALLS.getStreamFromFD(dirfd); + dir = dirstream.path; + } + if (path.length == 0) { + if (!allowEmpty) { + throw new FS.ErrnoError(44);; + } + return dir; + } + return dir + '/' + path; + }, + writeStat(buf, stat) { + HEAPU32[((buf)>>2)] = stat.dev; + HEAPU32[(((buf)+(4))>>2)] = stat.mode; + HEAPU32[(((buf)+(8))>>2)] = stat.nlink; + HEAPU32[(((buf)+(12))>>2)] = stat.uid; + HEAPU32[(((buf)+(16))>>2)] = stat.gid; + HEAPU32[(((buf)+(20))>>2)] = stat.rdev; + HEAP64[(((buf)+(24))>>3)] = BigInt(stat.size); + HEAP32[(((buf)+(32))>>2)] = 4096; + HEAP32[(((buf)+(36))>>2)] = stat.blocks; + var atime = stat.atime.getTime(); + var mtime = stat.mtime.getTime(); + var ctime = stat.ctime.getTime(); + HEAP64[(((buf)+(40))>>3)] = BigInt(Math.floor(atime / 1000)); + HEAPU32[(((buf)+(48))>>2)] = (atime % 1000) * 1000 * 1000; + HEAP64[(((buf)+(56))>>3)] = BigInt(Math.floor(mtime / 1000)); + HEAPU32[(((buf)+(64))>>2)] = (mtime % 1000) * 1000 * 1000; + HEAP64[(((buf)+(72))>>3)] = BigInt(Math.floor(ctime / 1000)); + HEAPU32[(((buf)+(80))>>2)] = (ctime % 1000) * 1000 * 1000; + HEAP64[(((buf)+(88))>>3)] = BigInt(stat.ino); + return 0; + }, + writeStatFs(buf, stats) { + HEAPU32[(((buf)+(4))>>2)] = stats.bsize; + HEAPU32[(((buf)+(60))>>2)] = stats.bsize; + HEAP64[(((buf)+(8))>>3)] = BigInt(stats.blocks); + HEAP64[(((buf)+(16))>>3)] = BigInt(stats.bfree); + HEAP64[(((buf)+(24))>>3)] = BigInt(stats.bavail); + HEAP64[(((buf)+(32))>>3)] = BigInt(stats.files); + HEAP64[(((buf)+(40))>>3)] = BigInt(stats.ffree); + HEAPU32[(((buf)+(48))>>2)] = stats.fsid; + HEAPU32[(((buf)+(64))>>2)] = stats.flags; // ST_NOSUID + HEAPU32[(((buf)+(56))>>2)] = stats.namelen; + }, + doMsync(addr, stream, len, flags, offset) { + if (!FS.isFile(stream.node.mode)) { + throw new FS.ErrnoError(43); + } + if (flags & 2) { + // MAP_PRIVATE calls need not to be synced back to underlying fs + return 0; + } + var buffer = HEAPU8.slice(addr, addr + len); + FS.msync(stream, buffer, offset, len, flags); + }, + getStreamFromFD(fd) { + var stream = FS.getStreamChecked(fd); + return stream; + }, + varargs:undefined, + getStr(ptr) { + var ret = UTF8ToString(ptr); + return ret; + }, + }; function ___syscall_chdir(path) { try { @@ -4787,7 +4582,7 @@ function dbg(...args) { try { path = SYSCALLS.getStr(path); - assert(flags === 0 || flags == 512); + assert(!flags || flags == 512); path = SYSCALLS.calculateAt(dirfd, path); if (amode & ~7) { // need a valid mode @@ -4812,13 +4607,24 @@ function dbg(...args) { } } + function ___syscall_fchmod(fd, mode) { + try { + + FS.fchmod(fd, mode); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + function ___syscall_fchownat(dirfd, path, owner, group, flags) { try { path = SYSCALLS.getStr(path); var nofollow = flags & 256; flags = flags & (~256); - assert(flags === 0); + assert(!flags); path = SYSCALLS.calculateAt(dirfd, path); (nofollow ? FS.lchown : FS.chown)(path, owner, group); return 0; @@ -4828,7 +4634,6 @@ function dbg(...args) { } } - /** @suppress {duplicate } */ var syscallGetVarargI = () => { assert(SYSCALLS.varargs != undefined); // the `+` prepended here is necessary to convince the JSCompiler that varargs is indeed a number. @@ -4876,7 +4681,11 @@ function dbg(...args) { } case 13: case 14: - return 0; // Pretend that the locking is successful. + // Pretend that the locking is successful. These are process-level locks, + // and Emscripten programs are a single process. If we supported linking a + // filesystem between programs, we'd need to do more here. + // See https://github.com/emscripten-core/emscripten/issues/23697 + return 0; } return -28; } catch (e) { @@ -4899,26 +4708,24 @@ function dbg(...args) { function ___syscall_fstat64(fd, buf) { try { - var stream = SYSCALLS.getStreamFromFD(fd); - return SYSCALLS.doStat(FS.stat, stream.path, buf); + return SYSCALLS.writeStat(buf, FS.fstat(fd)); } catch (e) { if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; return -e.errno; } } - var convertI32PairToI53Checked = (lo, hi) => { - assert(lo == (lo >>> 0) || lo == (lo|0)); // lo should either be a i32 or a u32 - assert(hi === (hi|0)); // hi should be a i32 - return ((hi + 0x200000) >>> 0 < 0x400001 - !!lo) ? (lo >>> 0) + hi * 4294967296 : NaN; - }; - function ___syscall_ftruncate64(fd,length_low, length_high) { - var length = convertI32PairToI53Checked(length_low, length_high); + var INT53_MAX = 9007199254740992; + + var INT53_MIN = -9007199254740992; + var bigintToI53Checked = (num) => (num < INT53_MIN || num > INT53_MAX) ? NaN : Number(num); + function ___syscall_ftruncate64(fd, length) { + length = bigintToI53Checked(length); + - try { - if (isNaN(length)) return 61; + if (isNaN(length)) return -61; FS.ftruncate(fd, length); return 0; } catch (e) { @@ -4967,12 +4774,12 @@ function dbg(...args) { var name = stream.getdents[idx]; if (name === '.') { id = stream.node.id; - type = 4; // DT_DIR + type = 4; } else if (name === '..') { var lookup = FS.lookupPath(stream.path, { parent: true }); id = lookup.node.id; - type = 4; // DT_DIR + type = 4; } else { var child; @@ -4987,14 +4794,14 @@ function dbg(...args) { throw e; } id = child.id; - type = FS.isChrdev(child.mode) ? 2 : // DT_CHR, character device. - FS.isDir(child.mode) ? 4 : // DT_DIR, directory. - FS.isLink(child.mode) ? 10 : // DT_LNK, symbolic link. - 8; // DT_REG, regular file. + type = FS.isChrdev(child.mode) ? 2 : // character device. + FS.isDir(child.mode) ? 4 : // directory + FS.isLink(child.mode) ? 10 : // symbolic link. + 8; // regular file. } assert(id); - (tempI64 = [id>>>0,(tempDouble = id,(+(Math.abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? (+(Math.floor((tempDouble)/4294967296.0)))>>>0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)], HEAP32[((dirp + pos)>>2)] = tempI64[0],HEAP32[(((dirp + pos)+(4))>>2)] = tempI64[1]); - (tempI64 = [(idx + 1) * struct_size>>>0,(tempDouble = (idx + 1) * struct_size,(+(Math.abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? (+(Math.floor((tempDouble)/4294967296.0)))>>>0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)], HEAP32[(((dirp + pos)+(8))>>2)] = tempI64[0],HEAP32[(((dirp + pos)+(12))>>2)] = tempI64[1]); + HEAP64[((dirp + pos)>>3)] = BigInt(id); + HEAP64[(((dirp + pos)+(8))>>3)] = BigInt((idx + 1) * struct_size); HEAP16[(((dirp + pos)+(16))>>1)] = 280; HEAP8[(dirp + pos)+(18)] = type; stringToUTF8(name, dirp + pos + 19, 256); @@ -5124,6 +4931,7 @@ function dbg(...args) { if (!stream.tty) return -59; return -28; // not supported } + case 21537: case 21531: { var argp = syscallGetVarargP(); return FS.ioctl(stream, op, argp); @@ -5175,7 +4983,7 @@ function dbg(...args) { try { path = SYSCALLS.getStr(path); - return SYSCALLS.doStat(FS.lstat, path, buf); + return SYSCALLS.writeStat(buf, FS.lstat(path)); } catch (e) { if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; return -e.errno; @@ -5204,7 +5012,7 @@ function dbg(...args) { flags = flags & (~6400); assert(!flags, `unknown flags in __syscall_newfstatat: ${flags}`); path = SYSCALLS.calculateAt(dirfd, path, allowEmpty); - return SYSCALLS.doStat(nofollow ? FS.lstat : FS.stat, path, buf); + return SYSCALLS.writeStat(buf, nofollow ? FS.lstat(path) : FS.stat(path)); } catch (e) { if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; return -e.errno; @@ -5239,6 +5047,7 @@ function dbg(...args) { // refcnt 2 because pipe has a read end and a write end. We need to be // able to read from the read end after write end is closed. refcnt : 2, + timestamp: new Date(), }; pipe.buckets.push({ @@ -5279,23 +5088,42 @@ function dbg(...args) { }; }, stream_ops:{ - poll(stream) { + getattr(stream) { + var node = stream.node; + var timestamp = node.pipe.timestamp; + return { + dev: 14, + ino: node.id, + mode: 0o10600, + nlink: 1, + uid: 0, + gid: 0, + rdev: 0, + size: 0, + atime: timestamp, + mtime: timestamp, + ctime: timestamp, + blksize: 4096, + blocks: 0, + }; + }, + poll(stream, timeout, notifyCallback) { var pipe = stream.node.pipe; if ((stream.flags & 2097155) === 1) { return (256 | 4); } - if (pipe.buckets.length > 0) { - for (var i = 0; i < pipe.buckets.length; i++) { - var bucket = pipe.buckets[i]; - if (bucket.offset - bucket.roffset > 0) { - return (64 | 1); - } + for (var bucket of pipe.buckets) { + if (bucket.offset - bucket.roffset > 0) { + return (64 | 1); } } return 0; }, + dup(stream) { + stream.node.pipe.refcnt++; + }, ioctl(stream, request, varargs) { return 28; }, @@ -5306,8 +5134,7 @@ function dbg(...args) { var pipe = stream.node.pipe; var currentLength = 0; - for (var i = 0; i < pipe.buckets.length; i++) { - var bucket = pipe.buckets[i]; + for (var bucket of pipe.buckets) { currentLength += bucket.offset - bucket.roffset; } @@ -5326,22 +5153,21 @@ function dbg(...args) { var totalRead = toRead; var toRemove = 0; - for (var i = 0; i < pipe.buckets.length; i++) { - var currBucket = pipe.buckets[i]; - var bucketSize = currBucket.offset - currBucket.roffset; + for (var bucket of pipe.buckets) { + var bucketSize = bucket.offset - bucket.roffset; if (toRead <= bucketSize) { - var tmpSlice = currBucket.buffer.subarray(currBucket.roffset, currBucket.offset); + var tmpSlice = bucket.buffer.subarray(bucket.roffset, bucket.offset); if (toRead < bucketSize) { tmpSlice = tmpSlice.subarray(0, toRead); - currBucket.roffset += toRead; + bucket.roffset += toRead; } else { toRemove++; } data.set(tmpSlice); break; } else { - var tmpSlice = currBucket.buffer.subarray(currBucket.roffset, currBucket.offset); + var tmpSlice = bucket.buffer.subarray(bucket.roffset, bucket.offset); data.set(tmpSlice); data = data.subarray(tmpSlice.byteLength); toRead -= tmpSlice.byteLength; @@ -5461,24 +5287,28 @@ function dbg(...args) { function ___syscall_poll(fds, nfds, timeout) { try { - var nonzero = 0; + + var count = 0; for (var i = 0; i < nfds; i++) { var pollfd = fds + 8 * i; var fd = HEAP32[((pollfd)>>2)]; var events = HEAP16[(((pollfd)+(4))>>1)]; - var mask = 32; + var flags = 32; var stream = FS.getStream(fd); if (stream) { - mask = SYSCALLS.DEFAULT_POLLMASK; if (stream.stream_ops.poll) { - mask = stream.stream_ops.poll(stream, -1); + flags = stream.stream_ops.poll(stream, -1); + } else { + flags = 5; } } - mask &= events | 8 | 16; - if (mask) nonzero++; - HEAP16[(((pollfd)+(6))>>1)] = mask; + flags &= events | 8 | 16; + if (flags) count++; + HEAP16[(((pollfd)+(6))>>1)] = flags; } - return nonzero; + + if (!count && timeout != 0) warnOnce('non-zero poll() timeout not supported: ' + timeout) + return count; } catch (e) { if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; return -e.errno; @@ -5589,7 +5419,7 @@ function dbg(...args) { try { path = SYSCALLS.getStr(path); - return SYSCALLS.doStat(FS.stat, path, buf); + return SYSCALLS.writeStat(buf, FS.stat(path)); } catch (e) { if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; return -e.errno; @@ -5599,18 +5429,8 @@ function dbg(...args) { function ___syscall_statfs64(path, size, buf) { try { - assert(size === 64); - var stats = FS.statfs(SYSCALLS.getStr(path)); - HEAP32[(((buf)+(4))>>2)] = stats.bsize; - HEAP32[(((buf)+(40))>>2)] = stats.bsize; - HEAP32[(((buf)+(8))>>2)] = stats.blocks; - HEAP32[(((buf)+(12))>>2)] = stats.bfree; - HEAP32[(((buf)+(16))>>2)] = stats.bavail; - HEAP32[(((buf)+(20))>>2)] = stats.files; - HEAP32[(((buf)+(24))>>2)] = stats.ffree; - HEAP32[(((buf)+(28))>>2)] = stats.fsid; - HEAP32[(((buf)+(44))>>2)] = stats.flags; // ST_NOSUID - HEAP32[(((buf)+(36))>>2)] = stats.namelen; + assert(size === 88); + SYSCALLS.writeStatFs(buf, FS.statfs(SYSCALLS.getStr(path))); return 0; } catch (e) { if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; @@ -5637,12 +5457,12 @@ function dbg(...args) { path = SYSCALLS.getStr(path); path = SYSCALLS.calculateAt(dirfd, path); - if (flags === 0) { + if (!flags) { FS.unlink(path); } else if (flags === 512) { FS.rmdir(path); } else { - abort('Invalid flags passed to unlinkat'); + return -28; } return 0; } catch (e) { @@ -5659,7 +5479,7 @@ function dbg(...args) { try { path = SYSCALLS.getStr(path); - assert(flags === 0); + assert(!flags); path = SYSCALLS.calculateAt(dirfd, path, true); var now = Date.now(), atime, mtime; if (!times) { @@ -5710,8 +5530,6 @@ function dbg(...args) { return inetPton4(DNS.lookup_name(nameString)); }; - var __emscripten_memcpy_js = (dest, src, num) => HEAPU8.copyWithin(dest, src, src + num); - var runtimeKeepaliveCounter = 0; var __emscripten_runtime_keepalive_clear = () => { noExitRuntime = false; @@ -5722,10 +5540,10 @@ function dbg(...args) { throw Infinity; }; - function __gmtime_js(time_low, time_high,tmPtr) { - var time = convertI32PairToI53Checked(time_low, time_high); + function __gmtime_js(time, tmPtr) { + time = bigintToI53Checked(time); + - var date = new Date(time * 1000); HEAP32[((tmPtr)>>2)] = date.getUTCSeconds(); HEAP32[(((tmPtr)+(4))>>2)] = date.getUTCMinutes(); @@ -5753,10 +5571,10 @@ function dbg(...args) { return yday; }; - function __localtime_js(time_low, time_high,tmPtr) { - var time = convertI32PairToI53Checked(time_low, time_high); + function __localtime_js(time, tmPtr) { + time = bigintToI53Checked(time); + - var date = new Date(time*1000); HEAP32[((tmPtr)>>2)] = date.getSeconds(); HEAP32[(((tmPtr)+(4))>>2)] = date.getMinutes(); @@ -5780,13 +5598,9 @@ function dbg(...args) { } - /** @suppress {duplicate } */ - var setTempRet0 = (val) => __emscripten_tempret_set(val); - var _setTempRet0 = setTempRet0; - var __mktime_js = function(tmPtr) { - var ret = (() => { + var ret = (() => { var date = new Date(HEAP32[(((tmPtr)+(20))>>2)] + 1900, HEAP32[(((tmPtr)+(16))>>2)], HEAP32[(((tmPtr)+(12))>>2)], @@ -5832,7 +5646,7 @@ function dbg(...args) { // Return time in microseconds return timeMs / 1000; })(); - return (setTempRet0((tempDouble = ret,(+(Math.abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? (+(Math.floor((tempDouble)/4294967296.0)))>>>0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)), ret>>>0); + return BigInt(ret); }; @@ -5840,13 +5654,15 @@ function dbg(...args) { - function __mmap_js(len,prot,flags,fd,offset_low, offset_high,allocated,addr) { - var offset = convertI32PairToI53Checked(offset_low, offset_high); + function __mmap_js(len, prot, flags, fd, offset, allocated, addr) { + offset = bigintToI53Checked(offset); + - try { - if (isNaN(offset)) return 61; + // musl's mmap doesn't allow values over a certain limit + // see OFF_MASK in mmap.c. + assert(!isNaN(offset)); var stream = SYSCALLS.getStreamFromFD(fd); var res = FS.mmap(stream, len, offset, prot, flags); var ptr = res.ptr; @@ -5861,10 +5677,10 @@ function dbg(...args) { } - function __munmap_js(addr,len,prot,flags,fd,offset_low, offset_high) { - var offset = convertI32PairToI53Checked(offset_low, offset_high); + function __munmap_js(addr, len, prot, flags, fd, offset) { + offset = bigintToI53Checked(offset); + - try { var stream = SYSCALLS.getStreamFromFD(fd); @@ -5911,7 +5727,6 @@ function dbg(...args) { }; - /** @suppress {duplicate } */ /** @param {boolean|number=} implicit */ var exitJS = (status, implicit) => { EXITSTATUS = status; @@ -5921,7 +5736,7 @@ function dbg(...args) { // if exit() was called explicitly, warn the user if the runtime isn't actually being shut down if (keepRuntimeAlive() && !implicit) { var msg = `program exited (with status: ${status}), but keepRuntimeAlive() is set (counter=${runtimeKeepaliveCounter}) due to an async operation, so halting execution but not exiting the runtime or preventing further async execution (you can use emscripten_force_exit, if you want to force a true shutdown)`; - readyPromiseReject(msg); + readyPromiseReject?.(msg); err(msg); } @@ -5945,10 +5760,11 @@ function dbg(...args) { return; } try { - func(); - maybeExit(); + return func(); } catch (e) { handleException(e); + } finally { + maybeExit(); } }; @@ -6035,10 +5851,10 @@ function dbg(...args) { var checkWasiClock = (clock_id) => clock_id >= 0 && clock_id <= 3; - function _clock_time_get(clk_id,ignored_precision_low, ignored_precision_high,ptime) { - var ignored_precision = convertI32PairToI53Checked(ignored_precision_low, ignored_precision_high); + function _clock_time_get(clk_id, ignored_precision, ptime) { + ignored_precision = bigintToI53Checked(ignored_precision); + - if (!checkWasiClock(clk_id)) { return 28; } @@ -6053,7 +5869,7 @@ function dbg(...args) { } // "now" is in ms, and wasi times are in ns. var nsec = Math.round(now * 1000 * 1000); - (tempI64 = [nsec>>>0,(tempDouble = nsec,(+(Math.abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? (+(Math.floor((tempDouble)/4294967296.0)))>>>0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)], HEAP32[((ptime)>>2)] = tempI64[0],HEAP32[(((ptime)+(4))>>2)] = tempI64[1]); + HEAP64[((ptime)>>3)] = BigInt(nsec); return 0; ; } @@ -6066,8 +5882,6 @@ function dbg(...args) { var _emscripten_get_heap_max = () => getHeapMax(); - - var abortOnCannotGrowMemory = (requestedSize) => { abort(`Cannot enlarge memory arrays to size ${requestedSize} bytes (OOM). Either (1) compile with -sINITIAL_MEMORY=X with X higher than the current value ${HEAP8.length}, (2) compile with -sALLOW_MEMORY_GROWTH which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with -sABORTING_MALLOC=0`); }; @@ -6086,7 +5900,7 @@ function dbg(...args) { if (!getEnvStrings.strings) { // Default values. // Browser language detection #8751 - var lang = ((typeof navigator == 'object' && navigator.languages && navigator.languages[0]) || 'C').replace('-', '_') + '.UTF-8'; + var lang = (globalThis.navigator?.language ?? 'C').replace('-', '_') + '.UTF-8'; var env = { 'USER': 'web_user', 'LOGNAME': 'web_user', @@ -6113,30 +5927,26 @@ function dbg(...args) { return getEnvStrings.strings; }; - var stringToAscii = (str, buffer) => { - for (var i = 0; i < str.length; ++i) { - assert(str.charCodeAt(i) === (str.charCodeAt(i) & 0xff)); - HEAP8[buffer++] = str.charCodeAt(i); - } - // Null-terminate the string - HEAP8[buffer] = 0; - }; var _environ_get = (__environ, environ_buf) => { var bufSize = 0; - getEnvStrings().forEach((string, i) => { + var envp = 0; + for (var string of getEnvStrings()) { var ptr = environ_buf + bufSize; - HEAPU32[(((__environ)+(i*4))>>2)] = ptr; - stringToAscii(string, ptr); - bufSize += string.length + 1; - }); + HEAPU32[(((__environ)+(envp))>>2)] = ptr; + bufSize += stringToUTF8(string, ptr, Infinity) + 1; + envp += 4; + } return 0; }; + var _environ_sizes_get = (penviron_count, penviron_buf_size) => { var strings = getEnvStrings(); HEAPU32[((penviron_count)>>2)] = strings.length; var bufSize = 0; - strings.forEach((string) => bufSize += string.length + 1); + for (var string of strings) { + bufSize += lengthBytesUTF8(string) + 1; + } HEAPU32[((penviron_buf_size)>>2)] = bufSize; return 0; }; @@ -6171,8 +5981,8 @@ function dbg(...args) { } HEAP8[pbuf] = type; HEAP16[(((pbuf)+(2))>>1)] = flags; - (tempI64 = [rightsBase>>>0,(tempDouble = rightsBase,(+(Math.abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? (+(Math.floor((tempDouble)/4294967296.0)))>>>0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)], HEAP32[(((pbuf)+(8))>>2)] = tempI64[0],HEAP32[(((pbuf)+(12))>>2)] = tempI64[1]); - (tempI64 = [rightsInheriting>>>0,(tempDouble = rightsInheriting,(+(Math.abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? (+(Math.floor((tempDouble)/4294967296.0)))>>>0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)], HEAP32[(((pbuf)+(16))>>2)] = tempI64[0],HEAP32[(((pbuf)+(20))>>2)] = tempI64[1]); + HEAP64[(((pbuf)+(8))>>3)] = BigInt(rightsBase); + HEAP64[(((pbuf)+(16))>>3)] = BigInt(rightsInheriting); return 0; } catch (e) { if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; @@ -6212,16 +6022,16 @@ function dbg(...args) { } - function _fd_seek(fd,offset_low, offset_high,whence,newOffset) { - var offset = convertI32PairToI53Checked(offset_low, offset_high); + function _fd_seek(fd, offset, whence, newOffset) { + offset = bigintToI53Checked(offset); + - try { if (isNaN(offset)) return 61; var stream = SYSCALLS.getStreamFromFD(fd); FS.llseek(stream, offset, whence); - (tempI64 = [stream.position>>>0,(tempDouble = stream.position,(+(Math.abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? (+(Math.floor((tempDouble)/4294967296.0)))>>>0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)], HEAP32[((newOffset)>>2)] = tempI64[0],HEAP32[(((newOffset)+(4))>>2)] = tempI64[1]); + HEAP64[((newOffset)>>3)] = BigInt(stream.position); if (stream.getdents && offset === 0 && whence === 0) stream.getdents = null; // reset readdir state return 0; } catch (e) { @@ -6235,10 +6045,8 @@ function dbg(...args) { try { var stream = SYSCALLS.getStreamFromFD(fd); - if (stream.stream_ops?.fsync) { - return stream.stream_ops.fsync(stream); - } - return 0; // we can't do anything synchronously; the in-memory FS is already synced to + var rtn = stream.stream_ops?.fsync?.(stream); + return rtn; } catch (e) { if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; return e.errno; @@ -6287,7 +6095,6 @@ function dbg(...args) { - var _getaddrinfo = (node, service, hint, out) => { // Note getaddrinfo currently only returns a single addrinfo with ai_next defaulting to NULL. When NULL // hints are specified or ai_family set to AF_UNSPEC or ai_socktype or ai_protocol set to 0 then we @@ -6457,15 +6264,13 @@ function dbg(...args) { return 0; }; - /** @type {function(...*):?} */ - function _getcontext( + function _getcontext(...args ) { abort('missing function: getcontext'); } _getcontext.stub = true; - /** @type {function(...*):?} */ - function _getdtablesize( + function _getdtablesize(...args ) { abort('missing function: getdtablesize'); } @@ -6473,7 +6278,6 @@ function dbg(...args) { - var _getnameinfo = (sa, salen, node, nodelen, serv, servlen, flags) => { var info = readSockaddr(sa, salen); if (info.errno) { @@ -6523,6 +6327,14 @@ function dbg(...args) { }, }; + var stringToAscii = (str, buffer) => { + for (var i = 0; i < str.length; ++i) { + assert(str.charCodeAt(i) === (str.charCodeAt(i) & 0xff)); + HEAP8[buffer++] = str.charCodeAt(i); + } + // Null-terminate the string + HEAP8[buffer] = 0; + }; var _setprotoent = (stayopen) => { // void setprotoent(int stayopen); @@ -6587,15 +6399,19 @@ function dbg(...args) { return result; }; - /** @type {function(...*):?} */ - function _makecontext( + function _initgroups(...args + ) { + abort('missing function: initgroups'); + } + _initgroups.stub = true; + + function _makecontext(...args ) { abort('missing function: makecontext'); } _makecontext.stub = true; - /** @type {function(...*):?} */ - function _posix_spawnp( + function _posix_spawnp(...args ) { abort('missing function: posix_spawnp'); } @@ -6645,7 +6461,6 @@ function dbg(...args) { - var _strptime = (buf, format, tm) => { // char *strptime(const char *restrict buf, const char *restrict format, struct tm *restrict tm); // http://pubs.opengroup.org/onlinepubs/009695399/functions/strptime.html @@ -6750,21 +6565,21 @@ function dbg(...args) { // seconds if ((value=getMatch('S'))) { - date.sec = jstoi_q(value); + date.sec = Number(value); } // minutes if ((value=getMatch('M'))) { - date.min = jstoi_q(value); + date.min = Number(value); } // hours if ((value=getMatch('H'))) { // 24h clock - date.hour = jstoi_q(value); + date.hour = Number(value); } else if ((value = getMatch('I'))) { // AM/PM clock - var hour = jstoi_q(value); + var hour = Number(value); if ((value=getMatch('p'))) { hour += value.toUpperCase()[0] === 'P' ? 12 : 0; } @@ -6774,13 +6589,13 @@ function dbg(...args) { // year if ((value=getMatch('Y'))) { // parse from four-digit year - date.year = jstoi_q(value); + date.year = Number(value); } else if ((value=getMatch('y'))) { // parse from two-digit year... - var year = jstoi_q(value); + var year = Number(value); if ((value=getMatch('C'))) { // ...and century - year += jstoi_q(value)*100; + year += Number(value)*100; } else { // ...and rule-of-thumb year += year<69 ? 2000 : 1900; @@ -6791,7 +6606,7 @@ function dbg(...args) { // month if ((value=getMatch('m'))) { // parse from month number - date.month = jstoi_q(value)-1; + date.month = Number(value)-1; } else if ((value=getMatch('b'))) { // parse from month name date.month = MONTH_NUMBERS[value.substring(0,3).toUpperCase()] || 0; @@ -6801,10 +6616,10 @@ function dbg(...args) { // day if ((value=getMatch('d'))) { // get day of month directly - date.day = jstoi_q(value); + date.day = Number(value); } else if ((value=getMatch('j'))) { // get day of month from day of year ... - var day = jstoi_q(value); + var day = Number(value); var leapYear = isLeapYear(date.year); for (var month=0; month<12; ++month) { var daysUntilMonth = arraySum(leapYear ? MONTH_DAYS_LEAP : MONTH_DAYS_REGULAR, month-1); @@ -6820,7 +6635,7 @@ function dbg(...args) { // Week number of the year (Sunday as the first day of the week) as a decimal number [00,53]. // All days in a new year preceding the first Sunday are considered to be in week 0. var weekDayNumber = DAY_NUMBERS_SUN_FIRST[weekDay]; - var weekNumber = jstoi_q(value); + var weekNumber = Number(value); // January 1st var janFirst = new Date(date.year, 0, 1); @@ -6839,7 +6654,7 @@ function dbg(...args) { // Week number of the year (Monday as the first day of the week) as a decimal number [00,53]. // All days in a new year preceding the first Monday are considered to be in week 0. var weekDayNumber = DAY_NUMBERS_MON_FIRST[weekDay]; - var weekNumber = jstoi_q(value); + var weekNumber = Number(value); // January 1st var janFirst = new Date(date.year, 0, 1); @@ -6862,7 +6677,7 @@ function dbg(...args) { // GMT offset as either 'Z' or +-HH:MM or +-HH or +-HHMM if (value.toLowerCase() === 'z'){ date.gmtoff = 0; - } else { + } else { var match = value.match(/^((?:\-|\+)\d\d):?(\d\d)?/); date.gmtoff = match[1] * 3600; if (match[2]) { @@ -6872,17 +6687,17 @@ function dbg(...args) { } /* - tm_sec int seconds after the minute 0-61* - tm_min int minutes after the hour 0-59 - tm_hour int hours since midnight 0-23 - tm_mday int day of the month 1-31 - tm_mon int months since January 0-11 - tm_year int years since 1900 - tm_wday int days since Sunday 0-6 - tm_yday int days since January 1 0-365 - tm_isdst int Daylight Saving Time flag - tm_gmtoff long offset from GMT (seconds) - */ + tm_sec int seconds after the minute 0-61* + tm_min int minutes after the hour 0-59 + tm_hour int hours since midnight 0-23 + tm_mday int day of the month 1-31 + tm_mon int months since January 0-11 + tm_year int years since 1900 + tm_wday int days since Sunday 0-6 + tm_yday int days since January 1 0-365 + tm_isdst int Daylight Saving Time flag + tm_gmtoff long offset from GMT (seconds) + */ var fullDate = new Date(date.year, date.month, date.day, date.hour, date.min, date.sec, 0); HEAP32[((tm)>>2)] = fullDate.getSeconds(); @@ -6895,17 +6710,16 @@ function dbg(...args) { HEAP32[(((tm)+(28))>>2)] = arraySum(isLeapYear(fullDate.getFullYear()) ? MONTH_DAYS_LEAP : MONTH_DAYS_REGULAR, fullDate.getMonth()-1)+fullDate.getDate()-1; HEAP32[(((tm)+(32))>>2)] = 0; HEAP32[(((tm)+(36))>>2)] = date.gmtoff; - + // we need to convert the matched sequence into an integer array to take care of UTF-8 characters > 0x7F // TODO: not sure that intArrayFromString handles all unicode characters correctly - return buf+intArrayFromString(matches[0]).length-1; + return buf+lengthBytesUTF8(matches[0]); } return 0; }; - /** @type {function(...*):?} */ - function _swapcontext( + function _swapcontext(...args ) { abort('missing function: swapcontext'); } @@ -6938,11 +6752,11 @@ function dbg(...args) { /** - * @param {string|null=} returnType - * @param {Array=} argTypes - * @param {Arguments|Array=} args - * @param {Object=} opts - */ + * @param {string|null=} returnType + * @param {Array=} argTypes + * @param {Array=} args + * @param {Object=} opts + */ var ccall = (ident, returnType, argTypes, args, opts) => { // For fast lookup of conversion functions var toC = { @@ -6994,20 +6808,543 @@ function dbg(...args) { }; FS.createPreloadedFile = FS_createPreloadedFile; - FS.staticInit(); - // Set module methods based on EXPORTED_RUNTIME_METHODS - ; + FS.preloadFile = FS_preloadFile; + FS.staticInit();; +// End JS library code + +// include: postlibrary.js +// This file is included after the automatically-generated JS library code +// but before the wasm module is created. + +{ + + // Begin ATMODULES hooks + if (Module['noExitRuntime']) noExitRuntime = Module['noExitRuntime']; +if (Module['preloadPlugins']) preloadPlugins = Module['preloadPlugins']; +if (Module['print']) out = Module['print']; +if (Module['printErr']) err = Module['printErr']; +if (Module['wasmBinary']) wasmBinary = Module['wasmBinary']; + // End ATMODULES hooks + + checkIncomingModuleAPI(); + + if (Module['arguments']) arguments_ = Module['arguments']; + if (Module['thisProgram']) thisProgram = Module['thisProgram']; + + // Assertions on removed incoming Module JS APIs. + assert(typeof Module['memoryInitializerPrefixURL'] == 'undefined', 'Module.memoryInitializerPrefixURL option was removed, use Module.locateFile instead'); + assert(typeof Module['pthreadMainPrefixURL'] == 'undefined', 'Module.pthreadMainPrefixURL option was removed, use Module.locateFile instead'); + assert(typeof Module['cdInitializerPrefixURL'] == 'undefined', 'Module.cdInitializerPrefixURL option was removed, use Module.locateFile instead'); + assert(typeof Module['filePackagePrefixURL'] == 'undefined', 'Module.filePackagePrefixURL option was removed, use Module.locateFile instead'); + assert(typeof Module['read'] == 'undefined', 'Module.read option was removed'); + assert(typeof Module['readAsync'] == 'undefined', 'Module.readAsync option was removed (modify readAsync in JS)'); + assert(typeof Module['readBinary'] == 'undefined', 'Module.readBinary option was removed (modify readBinary in JS)'); + assert(typeof Module['setWindowTitle'] == 'undefined', 'Module.setWindowTitle option was removed (modify emscripten_set_window_title in JS)'); + assert(typeof Module['TOTAL_MEMORY'] == 'undefined', 'Module.TOTAL_MEMORY has been renamed Module.INITIAL_MEMORY'); + assert(typeof Module['ENVIRONMENT'] == 'undefined', 'Module.ENVIRONMENT has been deprecated. To force the environment, use the ENVIRONMENT compile-time option (for example, -sENVIRONMENT=web or -sENVIRONMENT=node)'); + assert(typeof Module['STACK_SIZE'] == 'undefined', 'STACK_SIZE can no longer be set at runtime. Use -sSTACK_SIZE at link time') + // If memory is defined in wasm, the user can't provide it, or set INITIAL_MEMORY + assert(typeof Module['wasmMemory'] == 'undefined', 'Use of `wasmMemory` detected. Use -sIMPORTED_MEMORY to define wasmMemory externally'); + assert(typeof Module['INITIAL_MEMORY'] == 'undefined', 'Detected runtime INITIAL_MEMORY setting. Use -sIMPORTED_MEMORY to define wasmMemory dynamically'); + + if (Module['preInit']) { + if (typeof Module['preInit'] == 'function') Module['preInit'] = [Module['preInit']]; + while (Module['preInit'].length > 0) { + Module['preInit'].shift()(); + } + } + consumedModuleProp('preInit'); +} + +// Begin runtime exports + Module['ccall'] = ccall; + var missingLibrarySymbols = [ + 'writeI53ToI64', + 'writeI53ToI64Clamped', + 'writeI53ToI64Signaling', + 'writeI53ToU64Clamped', + 'writeI53ToU64Signaling', + 'readI53FromU64', + 'convertI32PairToI53', + 'convertI32PairToI53Checked', + 'convertU32PairToI53', + 'getTempRet0', + 'setTempRet0', + 'createNamedFunction', + 'growMemory', + 'withStackSave', + 'readEmAsmArgs', + 'jstoi_q', + 'autoResumeAudioContext', + 'getDynCaller', + 'dynCall', + 'runtimeKeepalivePush', + 'runtimeKeepalivePop', + 'asmjsMangle', + 'HandleAllocator', + 'addOnInit', + 'addOnPostCtor', + 'addOnPreMain', + 'addOnExit', + 'STACK_SIZE', + 'STACK_ALIGN', + 'POINTER_SIZE', + 'ASSERTIONS', + 'cwrap', + 'convertJsFunctionToWasm', + 'getEmptyTableSlot', + 'updateTableMap', + 'getFunctionAddress', + 'addFunction', + 'removeFunction', + 'intArrayToString', + 'AsciiToString', + 'UTF16ToString', + 'stringToUTF16', + 'lengthBytesUTF16', + 'UTF32ToString', + 'stringToUTF32', + 'lengthBytesUTF32', + 'stringToNewUTF8', + 'registerKeyEventCallback', + 'maybeCStringToJsString', + 'findEventTarget', + 'getBoundingClientRect', + 'fillMouseEventData', + 'registerMouseEventCallback', + 'registerWheelEventCallback', + 'registerUiEventCallback', + 'registerFocusEventCallback', + 'fillDeviceOrientationEventData', + 'registerDeviceOrientationEventCallback', + 'fillDeviceMotionEventData', + 'registerDeviceMotionEventCallback', + 'screenOrientation', + 'fillOrientationChangeEventData', + 'registerOrientationChangeEventCallback', + 'fillFullscreenChangeEventData', + 'registerFullscreenChangeEventCallback', + 'JSEvents_requestFullscreen', + 'JSEvents_resizeCanvasForFullscreen', + 'registerRestoreOldStyle', + 'hideEverythingExceptGivenElement', + 'restoreHiddenElements', + 'setLetterbox', + 'softFullscreenResizeWebGLRenderTarget', + 'doRequestFullscreen', + 'fillPointerlockChangeEventData', + 'registerPointerlockChangeEventCallback', + 'registerPointerlockErrorEventCallback', + 'requestPointerLock', + 'fillVisibilityChangeEventData', + 'registerVisibilityChangeEventCallback', + 'registerTouchEventCallback', + 'fillGamepadEventData', + 'registerGamepadEventCallback', + 'registerBeforeUnloadEventCallback', + 'fillBatteryEventData', + 'registerBatteryEventCallback', + 'setCanvasElementSize', + 'getCanvasElementSize', + 'jsStackTrace', + 'getCallstack', + 'convertPCtoSourceLocation', + 'wasiRightsToMuslOFlags', + 'wasiOFlagsToMuslOFlags', + 'safeSetTimeout', + 'setImmediateWrapped', + 'safeRequestAnimationFrame', + 'clearImmediateWrapped', + 'registerPostMainLoop', + 'registerPreMainLoop', + 'getPromise', + 'makePromise', + 'idsToPromises', + 'makePromiseCallback', + 'ExceptionInfo', + 'findMatchingCatch', + 'Browser_asyncPrepareDataCounter', + 'FS_mkdirTree', + '_setNetworkCallback', + 'heapObjectForWebGLType', + 'toTypedArrayIndex', + 'webgl_enable_ANGLE_instanced_arrays', + 'webgl_enable_OES_vertex_array_object', + 'webgl_enable_WEBGL_draw_buffers', + 'webgl_enable_WEBGL_multi_draw', + 'webgl_enable_EXT_polygon_offset_clamp', + 'webgl_enable_EXT_clip_control', + 'webgl_enable_WEBGL_polygon_mode', + 'emscriptenWebGLGet', + 'computeUnpackAlignedImageSize', + 'colorChannelsInGlTextureFormat', + 'emscriptenWebGLGetTexPixelData', + 'emscriptenWebGLGetUniform', + 'webglGetUniformLocation', + 'webglPrepareUniformLocationsBeforeFirstUse', + 'webglGetLeftBracePos', + 'emscriptenWebGLGetVertexAttrib', + '__glGetActiveAttribOrUniform', + 'writeGLArray', + 'registerWebGlEventCallback', + 'runAndAbortIfError', + 'ALLOC_NORMAL', + 'ALLOC_STACK', + 'allocate', + 'writeStringToMemory', + 'writeAsciiToMemory', + 'allocateUTF8', + 'allocateUTF8OnStack', + 'demangle', + 'stackTrace', + 'getNativeTypeSize', +]; +missingLibrarySymbols.forEach(missingLibrarySymbol) + + var unexportedSymbols = [ + 'run', + 'out', + 'err', + 'callMain', + 'abort', + 'wasmExports', + 'HEAPF32', + 'HEAPF64', + 'HEAP8', + 'HEAPU8', + 'HEAP16', + 'HEAPU16', + 'HEAP32', + 'HEAPU32', + 'HEAP64', + 'HEAPU64', + 'writeStackCookie', + 'checkStackCookie', + 'readI53FromI64', + 'INT53_MAX', + 'INT53_MIN', + 'bigintToI53Checked', + 'stackSave', + 'stackRestore', + 'stackAlloc', + 'ptrToString', + 'zeroMemory', + 'exitJS', + 'getHeapMax', + 'abortOnCannotGrowMemory', + 'ENV', + 'ERRNO_CODES', + 'strError', + 'inetPton4', + 'inetNtop4', + 'inetPton6', + 'inetNtop6', + 'readSockaddr', + 'writeSockaddr', + 'DNS', + 'Protocols', + 'Sockets', + 'timers', + 'warnOnce', + 'readEmAsmArgsArray', + 'getExecutableName', + 'handleException', + 'keepRuntimeAlive', + 'callUserCallback', + 'maybeExit', + 'asyncLoad', + 'alignMemory', + 'mmapAlloc', + 'wasmTable', + 'wasmMemory', + 'getUniqueRunDependency', + 'noExitRuntime', + 'addRunDependency', + 'removeRunDependency', + 'addOnPreRun', + 'addOnPostRun', + 'freeTableIndexes', + 'functionsInTableMap', + 'setValue', + 'getValue', + 'PATH', + 'PATH_FS', + 'UTF8Decoder', + 'UTF8ArrayToString', + 'UTF8ToString', + 'stringToUTF8Array', + 'stringToUTF8', + 'lengthBytesUTF8', + 'intArrayFromString', + 'stringToAscii', + 'UTF16Decoder', + 'stringToUTF8OnStack', + 'writeArrayToMemory', + 'JSEvents', + 'specialHTMLTargets', + 'findCanvasEventTarget', + 'currentFullscreenStrategy', + 'restoreOldWindowedStyle', + 'UNWIND_CACHE', + 'ExitStatus', + 'getEnvStrings', + 'checkWasiClock', + 'doReadv', + 'doWritev', + 'initRandomFill', + 'randomFill', + 'emSetImmediate', + 'emClearImmediate_deps', + 'emClearImmediate', + 'promiseMap', + 'uncaughtExceptionCount', + 'exceptionLast', + 'exceptionCaught', + 'Browser', + 'requestFullscreen', + 'requestFullScreen', + 'setCanvasSize', + 'getUserMedia', + 'createContext', + 'getPreloadedImageData__data', + 'wget', + 'MONTH_DAYS_REGULAR', + 'MONTH_DAYS_LEAP', + 'MONTH_DAYS_REGULAR_CUMULATIVE', + 'MONTH_DAYS_LEAP_CUMULATIVE', + 'isLeapYear', + 'ydayFromDate', + 'arraySum', + 'addDays', + 'SYSCALLS', + 'getSocketFromFD', + 'getSocketAddress', + 'preloadPlugins', + 'FS_createPreloadedFile', + 'FS_preloadFile', + 'FS_modeStringToFlags', + 'FS_getMode', + 'FS_stdin_getChar_buffer', + 'FS_stdin_getChar', + 'FS_unlink', + 'FS_createPath', + 'FS_createDevice', + 'FS_readFile', + 'FS', + 'FS_root', + 'FS_mounts', + 'FS_devices', + 'FS_streams', + 'FS_nextInode', + 'FS_nameTable', + 'FS_currentPath', + 'FS_initialized', + 'FS_ignorePermissions', + 'FS_filesystems', + 'FS_syncFSRequests', + 'FS_lookupPath', + 'FS_getPath', + 'FS_hashName', + 'FS_hashAddNode', + 'FS_hashRemoveNode', + 'FS_lookupNode', + 'FS_createNode', + 'FS_destroyNode', + 'FS_isRoot', + 'FS_isMountpoint', + 'FS_isFile', + 'FS_isDir', + 'FS_isLink', + 'FS_isChrdev', + 'FS_isBlkdev', + 'FS_isFIFO', + 'FS_isSocket', + 'FS_flagsToPermissionString', + 'FS_nodePermissions', + 'FS_mayLookup', + 'FS_mayCreate', + 'FS_mayDelete', + 'FS_mayOpen', + 'FS_checkOpExists', + 'FS_nextfd', + 'FS_getStreamChecked', + 'FS_getStream', + 'FS_createStream', + 'FS_closeStream', + 'FS_dupStream', + 'FS_doSetAttr', + 'FS_chrdev_stream_ops', + 'FS_major', + 'FS_minor', + 'FS_makedev', + 'FS_registerDevice', + 'FS_getDevice', + 'FS_getMounts', + 'FS_syncfs', + 'FS_mount', + 'FS_unmount', + 'FS_lookup', + 'FS_mknod', + 'FS_statfs', + 'FS_statfsStream', + 'FS_statfsNode', + 'FS_create', + 'FS_mkdir', + 'FS_mkdev', + 'FS_symlink', + 'FS_rename', + 'FS_rmdir', + 'FS_readdir', + 'FS_readlink', + 'FS_stat', + 'FS_fstat', + 'FS_lstat', + 'FS_doChmod', + 'FS_chmod', + 'FS_lchmod', + 'FS_fchmod', + 'FS_doChown', + 'FS_chown', + 'FS_lchown', + 'FS_fchown', + 'FS_doTruncate', + 'FS_truncate', + 'FS_ftruncate', + 'FS_utime', + 'FS_open', + 'FS_close', + 'FS_isClosed', + 'FS_llseek', + 'FS_read', + 'FS_write', + 'FS_mmap', + 'FS_msync', + 'FS_ioctl', + 'FS_writeFile', + 'FS_cwd', + 'FS_chdir', + 'FS_createDefaultDirectories', + 'FS_createDefaultDevices', + 'FS_createSpecialDirectories', + 'FS_createStandardStreams', + 'FS_staticInit', + 'FS_init', + 'FS_quit', + 'FS_findObject', + 'FS_analyzePath', + 'FS_createFile', + 'FS_createDataFile', + 'FS_forceLoadFile', + 'FS_createLazyFile', + 'FS_absolutePath', + 'FS_createFolder', + 'FS_createLink', + 'FS_joinPath', + 'FS_mmapAlloc', + 'FS_standardizePath', + 'MEMFS', + 'TTY', + 'PIPEFS', + 'SOCKFS', + 'tempFixedLengthArray', + 'miniTempWebGLFloatBuffers', + 'miniTempWebGLIntBuffers', + 'GL', + 'AL', + 'GLUT', + 'EGL', + 'GLEW', + 'IDBStore', + 'SDL', + 'SDL_gfx', + 'print', + 'printErr', + 'jstoi_s', +]; +unexportedSymbols.forEach(unexportedRuntimeSymbol); + + // End runtime exports + // Begin JS library exports + // End JS library exports + +// end include: postlibrary.js + function checkIncomingModuleAPI() { ignoredModuleProp('fetchSettings'); + ignoredModuleProp('logReadFiles'); + ignoredModuleProp('loadSplitModule'); } + +// Imports from the Wasm binary. +var _php_wasm_run = Module['_php_wasm_run'] = makeInvalidEarlyAccess('_php_wasm_run'); +var _fflush = makeInvalidEarlyAccess('_fflush'); +var _malloc = makeInvalidEarlyAccess('_malloc'); +var _strerror = makeInvalidEarlyAccess('_strerror'); +var _htons = makeInvalidEarlyAccess('_htons'); +var _ntohs = makeInvalidEarlyAccess('_ntohs'); +var _htonl = makeInvalidEarlyAccess('_htonl'); +var _emscripten_stack_get_end = makeInvalidEarlyAccess('_emscripten_stack_get_end'); +var _emscripten_stack_get_base = makeInvalidEarlyAccess('_emscripten_stack_get_base'); +var _emscripten_builtin_memalign = makeInvalidEarlyAccess('_emscripten_builtin_memalign'); +var __emscripten_timeout = makeInvalidEarlyAccess('__emscripten_timeout'); +var _setThrew = makeInvalidEarlyAccess('_setThrew'); +var _emscripten_stack_init = makeInvalidEarlyAccess('_emscripten_stack_init'); +var _emscripten_stack_get_free = makeInvalidEarlyAccess('_emscripten_stack_get_free'); +var __emscripten_stack_restore = makeInvalidEarlyAccess('__emscripten_stack_restore'); +var __emscripten_stack_alloc = makeInvalidEarlyAccess('__emscripten_stack_alloc'); +var _emscripten_stack_get_current = makeInvalidEarlyAccess('_emscripten_stack_get_current'); +var memory = makeInvalidEarlyAccess('memory'); +var __indirect_function_table = makeInvalidEarlyAccess('__indirect_function_table'); +var wasmMemory = makeInvalidEarlyAccess('wasmMemory'); +var wasmTable = makeInvalidEarlyAccess('wasmTable'); + +function assignWasmExports(wasmExports) { + assert(typeof wasmExports['php_wasm_run'] != 'undefined', 'missing Wasm export: php_wasm_run'); + assert(typeof wasmExports['fflush'] != 'undefined', 'missing Wasm export: fflush'); + assert(typeof wasmExports['malloc'] != 'undefined', 'missing Wasm export: malloc'); + assert(typeof wasmExports['strerror'] != 'undefined', 'missing Wasm export: strerror'); + assert(typeof wasmExports['htons'] != 'undefined', 'missing Wasm export: htons'); + assert(typeof wasmExports['ntohs'] != 'undefined', 'missing Wasm export: ntohs'); + assert(typeof wasmExports['htonl'] != 'undefined', 'missing Wasm export: htonl'); + assert(typeof wasmExports['emscripten_stack_get_end'] != 'undefined', 'missing Wasm export: emscripten_stack_get_end'); + assert(typeof wasmExports['emscripten_stack_get_base'] != 'undefined', 'missing Wasm export: emscripten_stack_get_base'); + assert(typeof wasmExports['emscripten_builtin_memalign'] != 'undefined', 'missing Wasm export: emscripten_builtin_memalign'); + assert(typeof wasmExports['_emscripten_timeout'] != 'undefined', 'missing Wasm export: _emscripten_timeout'); + assert(typeof wasmExports['setThrew'] != 'undefined', 'missing Wasm export: setThrew'); + assert(typeof wasmExports['emscripten_stack_init'] != 'undefined', 'missing Wasm export: emscripten_stack_init'); + assert(typeof wasmExports['emscripten_stack_get_free'] != 'undefined', 'missing Wasm export: emscripten_stack_get_free'); + assert(typeof wasmExports['_emscripten_stack_restore'] != 'undefined', 'missing Wasm export: _emscripten_stack_restore'); + assert(typeof wasmExports['_emscripten_stack_alloc'] != 'undefined', 'missing Wasm export: _emscripten_stack_alloc'); + assert(typeof wasmExports['emscripten_stack_get_current'] != 'undefined', 'missing Wasm export: emscripten_stack_get_current'); + assert(typeof wasmExports['memory'] != 'undefined', 'missing Wasm export: memory'); + assert(typeof wasmExports['__indirect_function_table'] != 'undefined', 'missing Wasm export: __indirect_function_table'); + _php_wasm_run = Module['_php_wasm_run'] = createExportWrapper('php_wasm_run', 1); + _fflush = createExportWrapper('fflush', 1); + _malloc = createExportWrapper('malloc', 1); + _strerror = createExportWrapper('strerror', 1); + _htons = createExportWrapper('htons', 1); + _ntohs = createExportWrapper('ntohs', 1); + _htonl = createExportWrapper('htonl', 1); + _emscripten_stack_get_end = wasmExports['emscripten_stack_get_end']; + _emscripten_stack_get_base = wasmExports['emscripten_stack_get_base']; + _emscripten_builtin_memalign = createExportWrapper('emscripten_builtin_memalign', 2); + __emscripten_timeout = createExportWrapper('_emscripten_timeout', 2); + _setThrew = createExportWrapper('setThrew', 2); + _emscripten_stack_init = wasmExports['emscripten_stack_init']; + _emscripten_stack_get_free = wasmExports['emscripten_stack_get_free']; + __emscripten_stack_restore = wasmExports['_emscripten_stack_restore']; + __emscripten_stack_alloc = wasmExports['_emscripten_stack_alloc']; + _emscripten_stack_get_current = wasmExports['emscripten_stack_get_current']; + memory = wasmMemory = wasmExports['memory']; + __indirect_function_table = wasmTable = wasmExports['__indirect_function_table']; +} + var wasmImports = { /** @export */ __assert_fail: ___assert_fail, /** @export */ __call_sighandler: ___call_sighandler, /** @export */ - __syscall__newselect: ___syscall__newselect, - /** @export */ __syscall_accept4: ___syscall_accept4, /** @export */ __syscall_bind: ___syscall_bind, @@ -7022,6 +7359,8 @@ var wasmImports = { /** @export */ __syscall_faccessat: ___syscall_faccessat, /** @export */ + __syscall_fchmod: ___syscall_fchmod, + /** @export */ __syscall_fchownat: ___syscall_fchownat, /** @export */ __syscall_fcntl64: ___syscall_fcntl64, @@ -7084,8 +7423,6 @@ var wasmImports = { /** @export */ _emscripten_lookup_name: __emscripten_lookup_name, /** @export */ - _emscripten_memcpy_js: __emscripten_memcpy_js, - /** @export */ _emscripten_runtime_keepalive_clear: __emscripten_runtime_keepalive_clear, /** @export */ _emscripten_throw_longjmp: __emscripten_throw_longjmp, @@ -7146,12 +7483,16 @@ var wasmImports = { /** @export */ getprotobynumber: _getprotobynumber, /** @export */ + initgroups: _initgroups, + /** @export */ invoke_i, /** @export */ invoke_ii, /** @export */ invoke_iii, /** @export */ + invoke_iiidii, + /** @export */ invoke_iiii, /** @export */ invoke_iiiii, @@ -7162,20 +7503,22 @@ var wasmImports = { /** @export */ invoke_iiiiiiiiii, /** @export */ + invoke_jii, + /** @export */ invoke_v, /** @export */ invoke_vi, /** @export */ invoke_vii, /** @export */ - invoke_viidii, - /** @export */ invoke_viii, /** @export */ invoke_viiii, /** @export */ invoke_viiiii, /** @export */ + invoke_viiiiii, + /** @export */ makecontext: _makecontext, /** @export */ posix_spawnp: _posix_spawnp, @@ -7186,28 +7529,6 @@ var wasmImports = { /** @export */ swapcontext: _swapcontext }; -var wasmExports; -createWasm(); -var ___wasm_call_ctors = createExportWrapper('__wasm_call_ctors', 0); -var _php_wasm_run = Module['_php_wasm_run'] = createExportWrapper('php_wasm_run', 1); -var _fflush = createExportWrapper('fflush', 1); -var _malloc = createExportWrapper('malloc', 1); -var _strerror = createExportWrapper('strerror', 1); -var _htons = createExportWrapper('htons', 1); -var _ntohs = createExportWrapper('ntohs', 1); -var _htonl = createExportWrapper('htonl', 1); -var _emscripten_builtin_memalign = createExportWrapper('emscripten_builtin_memalign', 2); -var __emscripten_timeout = createExportWrapper('_emscripten_timeout', 2); -var _setThrew = createExportWrapper('setThrew', 2); -var __emscripten_tempret_set = createExportWrapper('_emscripten_tempret_set', 1); -var _emscripten_stack_init = () => (_emscripten_stack_init = wasmExports['emscripten_stack_init'])(); -var _emscripten_stack_get_free = () => (_emscripten_stack_get_free = wasmExports['emscripten_stack_get_free'])(); -var _emscripten_stack_get_base = () => (_emscripten_stack_get_base = wasmExports['emscripten_stack_get_base'])(); -var _emscripten_stack_get_end = () => (_emscripten_stack_get_end = wasmExports['emscripten_stack_get_end'])(); -var __emscripten_stack_restore = (a0) => (__emscripten_stack_restore = wasmExports['_emscripten_stack_restore'])(a0); -var __emscripten_stack_alloc = (a0) => (__emscripten_stack_alloc = wasmExports['_emscripten_stack_alloc'])(a0); -var _emscripten_stack_get_current = () => (_emscripten_stack_get_current = wasmExports['emscripten_stack_get_current'])(); -var dynCall_jiji = Module['dynCall_jiji'] = createExportWrapper('dynCall_jiji', 5); function invoke_iii(index,a1,a2) { var sp = stackSave(); @@ -7330,10 +7651,10 @@ function invoke_viiii(index,a1,a2,a3,a4) { } } -function invoke_viiiii(index,a1,a2,a3,a4,a5) { +function invoke_viiiiii(index,a1,a2,a3,a4,a5,a6) { var sp = stackSave(); try { - getWasmTableEntry(index)(a1,a2,a3,a4,a5); + getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6); } catch(e) { stackRestore(sp); if (e !== e+0) throw e; @@ -7363,7 +7684,30 @@ function invoke_iiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9) { } } -function invoke_viidii(index,a1,a2,a3,a4,a5) { +function invoke_iiidii(index,a1,a2,a3,a4,a5) { + var sp = stackSave(); + try { + return getWasmTableEntry(index)(a1,a2,a3,a4,a5); + } catch(e) { + stackRestore(sp); + if (e !== e+0) throw e; + _setThrew(1, 0); + } +} + +function invoke_jii(index,a1,a2) { + var sp = stackSave(); + try { + return getWasmTableEntry(index)(a1,a2); + } catch(e) { + stackRestore(sp); + if (e !== e+0) throw e; + _setThrew(1, 0); + return 0n; + } +} + +function invoke_viiiii(index,a1,a2,a3,a4,a5) { var sp = stackSave(); try { getWasmTableEntry(index)(a1,a2,a3,a4,a5); @@ -7378,302 +7722,8 @@ function invoke_viidii(index,a1,a2,a3,a4,a5) { // include: postamble.js // === Auto-generated postamble setup entry stuff === -Module['ccall'] = ccall; -var missingLibrarySymbols = [ - 'writeI53ToI64', - 'writeI53ToI64Clamped', - 'writeI53ToI64Signaling', - 'writeI53ToU64Clamped', - 'writeI53ToU64Signaling', - 'readI53FromU64', - 'convertI32PairToI53', - 'convertU32PairToI53', - 'getTempRet0', - 'growMemory', - 'emscriptenLog', - 'readEmAsmArgs', - 'listenOnce', - 'autoResumeAudioContext', - 'dynCallLegacy', - 'getDynCaller', - 'dynCall', - 'runtimeKeepalivePush', - 'runtimeKeepalivePop', - 'asmjsMangle', - 'HandleAllocator', - 'getNativeTypeSize', - 'STACK_SIZE', - 'STACK_ALIGN', - 'POINTER_SIZE', - 'ASSERTIONS', - 'cwrap', - 'uleb128Encode', - 'sigToWasmTypes', - 'generateFuncType', - 'convertJsFunctionToWasm', - 'getEmptyTableSlot', - 'updateTableMap', - 'getFunctionAddress', - 'addFunction', - 'removeFunction', - 'reallyNegative', - 'unSign', - 'strLen', - 'reSign', - 'formatString', - 'intArrayToString', - 'AsciiToString', - 'UTF16ToString', - 'stringToUTF16', - 'lengthBytesUTF16', - 'UTF32ToString', - 'stringToUTF32', - 'lengthBytesUTF32', - 'stringToNewUTF8', - 'registerKeyEventCallback', - 'maybeCStringToJsString', - 'findEventTarget', - 'getBoundingClientRect', - 'fillMouseEventData', - 'registerMouseEventCallback', - 'registerWheelEventCallback', - 'registerUiEventCallback', - 'registerFocusEventCallback', - 'fillDeviceOrientationEventData', - 'registerDeviceOrientationEventCallback', - 'fillDeviceMotionEventData', - 'registerDeviceMotionEventCallback', - 'screenOrientation', - 'fillOrientationChangeEventData', - 'registerOrientationChangeEventCallback', - 'fillFullscreenChangeEventData', - 'registerFullscreenChangeEventCallback', - 'JSEvents_requestFullscreen', - 'JSEvents_resizeCanvasForFullscreen', - 'registerRestoreOldStyle', - 'hideEverythingExceptGivenElement', - 'restoreHiddenElements', - 'setLetterbox', - 'softFullscreenResizeWebGLRenderTarget', - 'doRequestFullscreen', - 'fillPointerlockChangeEventData', - 'registerPointerlockChangeEventCallback', - 'registerPointerlockErrorEventCallback', - 'requestPointerLock', - 'fillVisibilityChangeEventData', - 'registerVisibilityChangeEventCallback', - 'registerTouchEventCallback', - 'fillGamepadEventData', - 'registerGamepadEventCallback', - 'registerBeforeUnloadEventCallback', - 'fillBatteryEventData', - 'battery', - 'registerBatteryEventCallback', - 'setCanvasElementSize', - 'getCanvasElementSize', - 'jsStackTrace', - 'getCallstack', - 'convertPCtoSourceLocation', - 'wasiRightsToMuslOFlags', - 'wasiOFlagsToMuslOFlags', - 'safeSetTimeout', - 'setImmediateWrapped', - 'safeRequestAnimationFrame', - 'clearImmediateWrapped', - 'polyfillSetImmediate', - 'registerPostMainLoop', - 'registerPreMainLoop', - 'getPromise', - 'makePromise', - 'idsToPromises', - 'makePromiseCallback', - 'ExceptionInfo', - 'findMatchingCatch', - 'Browser_asyncPrepareDataCounter', - 'FS_unlink', - 'FS_mkdirTree', - '_setNetworkCallback', - 'heapObjectForWebGLType', - 'toTypedArrayIndex', - 'webgl_enable_ANGLE_instanced_arrays', - 'webgl_enable_OES_vertex_array_object', - 'webgl_enable_WEBGL_draw_buffers', - 'webgl_enable_WEBGL_multi_draw', - 'webgl_enable_EXT_polygon_offset_clamp', - 'webgl_enable_EXT_clip_control', - 'webgl_enable_WEBGL_polygon_mode', - 'emscriptenWebGLGet', - 'computeUnpackAlignedImageSize', - 'colorChannelsInGlTextureFormat', - 'emscriptenWebGLGetTexPixelData', - 'emscriptenWebGLGetUniform', - 'webglGetUniformLocation', - 'webglPrepareUniformLocationsBeforeFirstUse', - 'webglGetLeftBracePos', - 'emscriptenWebGLGetVertexAttrib', - '__glGetActiveAttribOrUniform', - 'writeGLArray', - 'registerWebGlEventCallback', - 'runAndAbortIfError', - 'ALLOC_NORMAL', - 'ALLOC_STACK', - 'allocate', - 'writeStringToMemory', - 'writeAsciiToMemory', - 'setErrNo', - 'demangle', - 'stackTrace', -]; -missingLibrarySymbols.forEach(missingLibrarySymbol) - -var unexportedSymbols = [ - 'run', - 'addOnPreRun', - 'addOnInit', - 'addOnPreMain', - 'addOnExit', - 'addOnPostRun', - 'addRunDependency', - 'removeRunDependency', - 'out', - 'err', - 'callMain', - 'abort', - 'wasmMemory', - 'wasmExports', - 'writeStackCookie', - 'checkStackCookie', - 'readI53FromI64', - 'convertI32PairToI53Checked', - 'stackSave', - 'stackRestore', - 'stackAlloc', - 'setTempRet0', - 'ptrToString', - 'zeroMemory', - 'exitJS', - 'getHeapMax', - 'abortOnCannotGrowMemory', - 'ENV', - 'ERRNO_CODES', - 'strError', - 'inetPton4', - 'inetNtop4', - 'inetPton6', - 'inetNtop6', - 'readSockaddr', - 'writeSockaddr', - 'DNS', - 'Protocols', - 'Sockets', - 'timers', - 'warnOnce', - 'readEmAsmArgsArray', - 'jstoi_q', - 'jstoi_s', - 'getExecutableName', - 'handleException', - 'keepRuntimeAlive', - 'callUserCallback', - 'maybeExit', - 'asyncLoad', - 'alignMemory', - 'mmapAlloc', - 'wasmTable', - 'noExitRuntime', - 'getCFunc', - 'freeTableIndexes', - 'functionsInTableMap', - 'setValue', - 'getValue', - 'PATH', - 'PATH_FS', - 'UTF8Decoder', - 'UTF8ArrayToString', - 'UTF8ToString', - 'stringToUTF8Array', - 'stringToUTF8', - 'lengthBytesUTF8', - 'intArrayFromString', - 'stringToAscii', - 'UTF16Decoder', - 'stringToUTF8OnStack', - 'writeArrayToMemory', - 'JSEvents', - 'specialHTMLTargets', - 'findCanvasEventTarget', - 'currentFullscreenStrategy', - 'restoreOldWindowedStyle', - 'UNWIND_CACHE', - 'ExitStatus', - 'getEnvStrings', - 'checkWasiClock', - 'doReadv', - 'doWritev', - 'initRandomFill', - 'randomFill', - 'promiseMap', - 'uncaughtExceptionCount', - 'exceptionLast', - 'exceptionCaught', - 'Browser', - 'getPreloadedImageData__data', - 'wget', - 'MONTH_DAYS_REGULAR', - 'MONTH_DAYS_LEAP', - 'MONTH_DAYS_REGULAR_CUMULATIVE', - 'MONTH_DAYS_LEAP_CUMULATIVE', - 'isLeapYear', - 'ydayFromDate', - 'arraySum', - 'addDays', - 'SYSCALLS', - 'getSocketFromFD', - 'getSocketAddress', - 'preloadPlugins', - 'FS_createPreloadedFile', - 'FS_modeStringToFlags', - 'FS_getMode', - 'FS_stdin_getChar_buffer', - 'FS_stdin_getChar', - 'FS_createPath', - 'FS_createDevice', - 'FS_readFile', - 'FS', - 'FS_createDataFile', - 'FS_createLazyFile', - 'MEMFS', - 'TTY', - 'PIPEFS', - 'SOCKFS', - 'tempFixedLengthArray', - 'miniTempWebGLFloatBuffers', - 'miniTempWebGLIntBuffers', - 'GL', - 'AL', - 'GLUT', - 'EGL', - 'GLEW', - 'IDBStore', - 'SDL', - 'SDL_gfx', - 'allocateUTF8', - 'allocateUTF8OnStack', - 'print', - 'printErr', -]; -unexportedSymbols.forEach(unexportedRuntimeSymbol); - - - var calledRun; -dependenciesFulfilled = function runCaller() { - // If run has never been called, and we should call run (INVOKE_RUN is true, and Module.noInitialRun is not false) - if (!calledRun) run(); - if (!calledRun) dependenciesFulfilled = runCaller; // try this again later, after new deps are fulfilled -}; - function stackCheckInit() { // This is normally called automatically during __wasm_call_ctors but need to // get these values before even running any of the ctors so we call it redundantly @@ -7686,6 +7736,7 @@ function stackCheckInit() { function run() { if (runDependencies > 0) { + dependenciesFulfilled = run; return; } @@ -7695,13 +7746,14 @@ function run() { // a preRun added a dependency, run will be called later if (runDependencies > 0) { + dependenciesFulfilled = run; return; } function doRun() { // run may have just been called through dependencies being fulfilled just in this very frame, // or while the async setStatus time below was happening - if (calledRun) return; + assert(!calledRun); calledRun = true; Module['calledRun'] = true; @@ -7709,8 +7761,9 @@ function run() { initRuntime(); - readyPromiseResolve(Module); + readyPromiseResolve?.(Module); Module['onRuntimeInitialized']?.(); + consumedModuleProp('onRuntimeInitialized'); assert(!Module['_main'], 'compiled without a main, but one is present. if you added it from JS, use Module["onRuntimeInitialized"]'); @@ -7751,7 +7804,7 @@ function checkUnflushedContent() { try { // it doesn't matter if it fails _fflush(0); // also flush in the JS FS layer - ['stdout', 'stderr'].forEach((name) => { + for (var name of ['stdout', 'stderr']) { var info = FS.analyzePath('/dev/' + name); if (!info) return; var stream = info.object; @@ -7760,7 +7813,7 @@ function checkUnflushedContent() { if (tty?.output?.length) { has = true; } - }); + } } catch(e) {} out = oldOut; err = oldErr; @@ -7769,12 +7822,11 @@ function checkUnflushedContent() { } } -if (Module['preInit']) { - if (typeof Module['preInit'] == 'function') Module['preInit'] = [Module['preInit']]; - while (Module['preInit'].length > 0) { - Module['preInit'].pop()(); - } -} +var wasmExports; + +// In modularize mode the generated code is within a factory function so we +// can use await here (since it's not top-level-await). +wasmExports = await (createWasm()); run(); @@ -7785,9 +7837,17 @@ run(); // and return either the Module itself, or a promise of the module. // // We assign to the `moduleRtn` global here and configure closure to see -// this as and extern so it won't get minified. +// this as an extern so it won't get minified. -moduleRtn = readyPromise; +if (runtimeInitialized) { + moduleRtn = Module; +} else { + // Set up the promise that indicates the Module is initialized + moduleRtn = new Promise((resolve, reject) => { + readyPromiseResolve = resolve; + readyPromiseReject = reject; + }); +} // Assertion for attempting to access module properties on the incoming // moduleArg. In the past we used this object as the prototype of the module @@ -7810,6 +7870,7 @@ for (const prop of Object.keys(Module)) { return moduleRtn; } -); -})(); + +// Export using a UMD style export, or ES6 exports if selected export default Module; + diff --git a/examples/compile-php-to-wasm/php-wasm.wasm b/examples/compile-php-to-wasm/php-wasm.wasm Binary files differindex d214beb..a822c2e 100755 --- a/examples/compile-php-to-wasm/php-wasm.wasm +++ b/examples/compile-php-to-wasm/php-wasm.wasm diff --git a/examples/php-on-wasm/emscripten_bridge.php b/examples/php-on-wasm/emscripten_bridge.php index 8fc8bae..8c16e2a 100644 --- a/examples/php-on-wasm/emscripten_bridge.php +++ b/examples/php-on-wasm/emscripten_bridge.php @@ -41,16 +41,21 @@ $imports = [ 'getprotobynumber' => makeHostFunc('(i32) -> (i32)', hostFunc__env__getprotobynumber(...)), 'strptime' => makeHostFunc('(i32, i32, i32) -> (i32)', hostFunc__env__strptime(...)), 'getnameinfo' => makeHostFunc('(i32, i32, i32, i32, i32, i32, i32) -> (i32)', hostFunc__env__getnameinfo(...)), + 'invoke_viiiiii' => makeHostFunc('(i32, i32, i32, i32, i32, i32, i32) -> ()', hostFunc__env__invoke_viiiiii(...)), + 'invoke_iiidii' => makeHostFunc('(i32, i32, i32, f64, i32, i32) -> (i32)', hostFunc__env__invoke_iiidii(...)), + 'invoke_jii' => makeHostFunc('(i32, i32, i32) -> (i64)', hostFunc__env__invoke_jii(...)), 'invoke_viidii' => makeHostFunc('(i32, i32, i32, f64, i32, i32) -> ()', hostFunc__env__invoke_viidii(...)), 'getcontext' => makeHostFunc('(i32) -> (i32)', hostFunc__env__getcontext(...)), 'makecontext' => makeHostFunc('(i32, i32, i32, i32) -> ()', hostFunc__env__makecontext(...)), 'swapcontext' => makeHostFunc('(i32, i32) -> (i32)', hostFunc__env__swapcontext(...)), + 'initgroups' => makeHostFunc('(i32, i32) -> (i32)', hostFunc__env__initgroups(...)), '__syscall_fcntl64' => makeHostFunc('(i32, i32, i32) -> (i32)', hostFunc__env____syscall_fcntl64(...)), '__syscall_ioctl' => makeHostFunc('(i32, i32, i32) -> (i32)', hostFunc__env____syscall_ioctl(...)), '__syscall_faccessat' => makeHostFunc('(i32, i32, i32, i32) -> (i32)', hostFunc__env____syscall_faccessat(...)), '__syscall_chdir' => makeHostFunc('(i32) -> (i32)', hostFunc__env____syscall_chdir(...)), '__syscall_chmod' => makeHostFunc('(i32, i32) -> (i32)', hostFunc__env____syscall_chmod(...)), '__syscall_fchownat' => makeHostFunc('(i32, i32, i32, i32, i32) -> (i32)', hostFunc__env____syscall_fchownat(...)), + '__syscall_fchmod' => makeHostFunc('(i32, i32) -> (i32)', hostFunc__env____syscall_fchmod(...)), '__syscall_dup' => makeHostFunc('(i32) -> (i32)', hostFunc__env____syscall_dup(...)), '_emscripten_memcpy_js' => makeHostFunc('(i32, i32, i32) -> ()', hostFunc__env___emscripten_memcpy_js(...)), 'emscripten_date_now' => makeHostFunc('() -> (f64)', hostFunc__env__emscripten_date_now(...)), @@ -77,7 +82,7 @@ $imports = [ '__syscall_statfs64' => makeHostFunc('(i32, i32, i32) -> (i32)', hostFunc__env____syscall_statfs64(...)), '__syscall_symlinkat' => makeHostFunc('(i32, i32, i32) -> (i32)', hostFunc__env____syscall_symlinkat(...)), 'emscripten_get_heap_max' => makeHostFunc('() -> (i32)', hostFunc__env__emscripten_get_heap_max(...)), - '_tzset_js' => makeHostFunc('(i32, i32, i32) -> ()', hostFunc__env___tzset_js(...)), + '_tzset_js' => makeHostFunc('(i32, i32, i32, i32) -> ()', hostFunc__env___tzset_js(...)), '__syscall_unlinkat' => makeHostFunc('(i32, i32, i32) -> (i32)', hostFunc__env____syscall_unlinkat(...)), '__syscall_utimensat' => makeHostFunc('(i32, i32, i32, i32) -> (i32)', hostFunc__env____syscall_utimensat(...)), 'emscripten_resize_heap' => makeHostFunc('(i32) -> (i32)', hostFunc__env__emscripten_resize_heap(...)), @@ -93,12 +98,12 @@ $imports = [ '__syscall_recvfrom' => makeHostFunc('(i32, i32, i32, i32, i32, i32) -> (i32)', hostFunc__env____syscall_recvfrom(...)), '__syscall_sendto' => makeHostFunc('(i32, i32, i32, i32, i32, i32) -> (i32)', hostFunc__env____syscall_sendto(...)), '__syscall_socket' => makeHostFunc('(i32, i32, i32, i32, i32, i32) -> (i32)', hostFunc__env____syscall_socket(...)), - '__syscall_ftruncate64' => makeHostFunc('(i32, i32, i32) -> (i32)', hostFunc__env____syscall_ftruncate64(...)), - '_mktime_js' => makeHostFunc('(i32) -> (i32)', hostFunc__env___mktime_js(...)), - '_localtime_js' => makeHostFunc('(i32, i32, i32) -> ()', hostFunc__env___localtime_js(...)), - '_gmtime_js' => makeHostFunc('(i32, i32, i32) -> ()', hostFunc__env___gmtime_js(...)), - '_munmap_js' => makeHostFunc('(i32, i32, i32, i32, i32, i32, i32) -> (i32)', hostFunc__env___munmap_js(...)), - '_mmap_js' => makeHostFunc('(i32, i32, i32, i32, i32, i32, i32, i32) -> (i32)', hostFunc__env___mmap_js(...)), + '__syscall_ftruncate64' => makeHostFunc('(i32, i64) -> (i32)', hostFunc__env____syscall_ftruncate64(...)), + '_mktime_js' => makeHostFunc('(i32) -> (i64)', hostFunc__env___mktime_js(...)), + '_localtime_js' => makeHostFunc('(i64, i32) -> ()', hostFunc__env___localtime_js(...)), + '_gmtime_js' => makeHostFunc('(i64, i32) -> ()', hostFunc__env___gmtime_js(...)), + '_munmap_js' => makeHostFunc('(i32, i32, i32, i32, i32, i64) -> (i32)', hostFunc__env___munmap_js(...)), + '_mmap_js' => makeHostFunc('(i32, i32, i32, i32, i64, i32, i32) -> (i32)', hostFunc__env___mmap_js(...)), ], 'wasi_snapshot_preview1' => [ 'environ_sizes_get' => makeHostFunc('(i32, i32) -> (i32)', hostFunc__wasi_snapshot_preview1__environ_sizes_get(...)), @@ -109,8 +114,8 @@ $imports = [ 'proc_exit' => makeHostFunc('(i32) -> ()', hostFunc__wasi_snapshot_preview1__proc_exit(...)), 'fd_sync' => makeHostFunc('(i32) -> (i32)', hostFunc__wasi_snapshot_preview1__fd_sync(...)), 'fd_fdstat_get' => makeHostFunc('(i32, i32) -> (i32)', hostFunc__wasi_snapshot_preview1__fd_fdstat_get(...)), - 'clock_time_get' => makeHostFunc('(i32, i32, i32, i32) -> (i32)', hostFunc__wasi_snapshot_preview1__clock_time_get(...)), - 'fd_seek' => makeHostFunc('(i32, i32, i32, i32, i32) -> (i32)', hostFunc__wasi_snapshot_preview1__fd_seek(...)), + 'clock_time_get' => makeHostFunc('(i32, i64, i32) -> (i32)', hostFunc__wasi_snapshot_preview1__clock_time_get(...)), + 'fd_seek' => makeHostFunc('(i32, i64, i32, i32) -> (i32)', hostFunc__wasi_snapshot_preview1__fd_seek(...)), ], ]; @@ -810,6 +815,45 @@ function hostFunc__env__getnameinfo(Runtime $runtime): void throw new \RuntimeException('env::getnameinfo: not implemented'); } +// Type: (i32, i32, i32, i32, i32, i32, i32) -> () +function hostFunc__env__invoke_viiiiii(Runtime $runtime, int $index, int $a1, int $a2, int $a3, int $a4, int $a5, int $a6): void +{ + $sp = emscripten_stack_get_current($runtime); + $func = getWasmTableEntry($runtime, $index); + $runtime->stack->pushValue($a1); + $runtime->stack->pushValue($a2); + $runtime->stack->pushValue($a3); + $runtime->stack->pushValue($a4); + $runtime->stack->pushValue($a5); + $runtime->stack->pushValue($a6); + $runtime->invokeByFuncAddr($func); +} + +// Type: (i32, i32, i32, f64, i32, i32) -> (i32) +function hostFunc__env__invoke_iiidii(Runtime $runtime, int $index, int $a1, int $a2, float $a3, int $a4, int $a5): int +{ + $sp = emscripten_stack_get_current($runtime); + $func = getWasmTableEntry($runtime, $index); + $runtime->stack->pushValue($a1); + $runtime->stack->pushValue($a2); + $runtime->stack->pushValue($a3); + $runtime->stack->pushValue($a4); + $runtime->stack->pushValue($a5); + $runtime->invokeByFuncAddr($func); + return $runtime->stack->popInt(); +} + +// Type: (i32, i32, i32) -> (i64) +function hostFunc__env__invoke_jii(Runtime $runtime, int $index, int $a1, int $a2): int +{ + $sp = emscripten_stack_get_current($runtime); + $func = getWasmTableEntry($runtime, $index); + $runtime->stack->pushValue($a1); + $runtime->stack->pushValue($a2); + $runtime->invokeByFuncAddr($func); + return $runtime->stack->popInt(); +} + // Type: (i32, i32, i32, f64, i32, i32) -> () function hostFunc__env__invoke_viidii(Runtime $runtime, int $index, int $a1, int $a2, float $a3, int $a4, int $a5): void { @@ -842,6 +886,18 @@ function hostFunc__env__swapcontext(Runtime $runtime): void } // Type: (i32, i32) -> (i32) +function hostFunc__env__initgroups(Runtime $runtime): void +{ + throw new \RuntimeException('env::initgroups: not implemented'); +} + +// Type: (i32, i32) -> (i32) +function hostFunc__env____syscall_fchmod(Runtime $runtime): void +{ + throw new \RuntimeException('env::__syscall_fchmod: not implemented'); +} + +// Type: (i32, i32) -> (i32) function hostFunc__wasi_snapshot_preview1__environ_sizes_get(Runtime $runtime): void { throw new \RuntimeException('wasi_snapshot_preview1::environ_sizes_get: not implemented'); @@ -1260,8 +1316,8 @@ function hostFunc__env__emscripten_get_heap_max(Runtime $runtime): void throw new \RuntimeException('env::emscripten_get_heap_max: not implemented'); } -// Type: (i32, i32, i32) -> () -function hostFunc__env___tzset_js(Runtime $runtime): void +// Type: (i32, i32, i32, i32) -> () +function hostFunc__env___tzset_js(Runtime $runtime, int $timezone, int $daylight, int $std_name, int $dst_name): void { // Do nothing ;) } @@ -1356,14 +1412,14 @@ function hostFunc__env____syscall_socket(Runtime $runtime): void throw new \RuntimeException('env::__syscall_socket: not implemented'); } -// Type: (i32, i32, i32) -> (i32) +// Type: (i32, i64) -> (i32) function hostFunc__env____syscall_ftruncate64(Runtime $runtime): void { throw new \RuntimeException('env::__syscall_ftruncate64: not implemented'); } -// Type: (i32, i32, i32, i32) -> (i32) -function hostFunc__wasi_snapshot_preview1__clock_time_get(Runtime $runtime, int $clk_id, int $ignored_precision_low, int $ignored_precision_high, int $ptime): int +// Type: (i32, i64, i32) -> (i32) +function hostFunc__wasi_snapshot_preview1__clock_time_get(Runtime $runtime, int $clk_id, int $ignored_precision, int $ptime): int { if ($clk_id < 0 || $clk_id > 3) { return 28; @@ -1383,10 +1439,9 @@ function hostFunc__wasi_snapshot_preview1__clock_time_get(Runtime $runtime, int return 0; } -// Type: (i32, i32, i32, i32, i32) -> (i32) -function hostFunc__wasi_snapshot_preview1__fd_seek(Runtime $runtime, int $fd, int $offset_low, int $offset_high, int $whence, int $newOffset): int +// Type: (i32, i64, i32, i32) -> (i32) +function hostFunc__wasi_snapshot_preview1__fd_seek(Runtime $runtime, int $fd, int $offset, int $whence, int $newOffset): int { - $offset = $offset_low + $offset_high * 4294967296; $file = fsGetVFileFromFd($fd); $pos = $file->seek($offset, $whence); heap64Write($runtime, $newOffset, $pos); @@ -1394,36 +1449,34 @@ function hostFunc__wasi_snapshot_preview1__fd_seek(Runtime $runtime, int $fd, in return 0; } -// Type: (i32) -> (i32) +// Type: (i32) -> (i64) function hostFunc__env___mktime_js(Runtime $runtime): void { throw new \RuntimeException('env::_mktime_js: not implemented'); } -// Type: (i32, i32, i32) -> () +// Type: (i64, i32) -> () function hostFunc__env___localtime_js(Runtime $runtime): void { throw new \RuntimeException('env::_localtime_js: not implemented'); } -// Type: (i32, i32, i32) -> () +// Type: (i64, i32) -> () function hostFunc__env___gmtime_js(Runtime $runtime): void { throw new \RuntimeException('env::_gmtime_js: not implemented'); } -// Type: (i32, i32, i32, i32, i32, i32, i32) -> (i32) +// Type: (i32, i32, i32, i32, i32, i64) -> (i32) function hostFunc__env___munmap_js(Runtime $runtime): int { // Do nothing. return 0; } -// Type: (i32, i32, i32, i32, i32, i32, i32, i32) -> (i32) -function hostFunc__env___mmap_js(Runtime $runtime, int $len, int $prot, int $flags, int $fd, int $offset_low, int $offset_high, int $allocated, int $addr): int +// Type: (i32, i32, i32, i32, i64, i32, i32) -> (i32) +function hostFunc__env___mmap_js(Runtime $runtime, int $len, int $prot, int $flags, int $fd, int $offset, int $allocated, int $addr): int { - $offset = $offset_low + $offset_high * 4294967296; - [$resultPtr, $resultAllocated] = fsMmap($runtime, $fd, $len, $offset, $prot, $flags); heap32Write($runtime, $allocated, $resultAllocated); heapU32Write($runtime, $addr, $resultPtr); |
