diff options
| author | nsfisis <nsfisis@gmail.com> | 2025-04-03 01:43:04 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2025-04-03 01:45:03 +0900 |
| commit | 6233331f23603ebab0a7aa626ff82d71426b3bd6 (patch) | |
| tree | 490affe4d44e251c996502847c2d87ed9d8cab17 /examples/compile-php-to-wasm | |
| parent | 44655d7a70ee5fd288f691a41631e8a6471d084d (diff) | |
| download | php-waddiwasi-6233331f23603ebab0a7aa626ff82d71426b3bd6.tar.gz php-waddiwasi-6233331f23603ebab0a7aa626ff82d71426b3bd6.tar.zst php-waddiwasi-6233331f23603ebab0a7aa626ff82d71426b3bd6.zip | |
feat: update php and package version
Diffstat (limited to 'examples/compile-php-to-wasm')
| -rw-r--r-- | examples/compile-php-to-wasm/Dockerfile | 4 | ||||
| -rw-r--r-- | examples/compile-php-to-wasm/php-wasm.js | 992 | ||||
| -rwxr-xr-x | examples/compile-php-to-wasm/php-wasm.wasm | bin | 4941810 -> 5088262 bytes |
3 files changed, 519 insertions, 477 deletions
diff --git a/examples/compile-php-to-wasm/Dockerfile b/examples/compile-php-to-wasm/Dockerfile index db8dd0d..1e61133 100644 --- a/examples/compile-php-to-wasm/Dockerfile +++ b/examples/compile-php-to-wasm/Dockerfile @@ -1,6 +1,6 @@ -FROM emscripten/emsdk:3.1.62 +FROM emscripten/emsdk:3.1.74 -RUN git clone --depth=1 --branch=php-8.3.9 https://github.com/php/php-src +RUN git clone --depth=1 --branch=php-8.4.5 https://github.com/php/php-src RUN apt-get update && \ apt-get install -y --no-install-recommends \ diff --git a/examples/compile-php-to-wasm/php-wasm.js b/examples/compile-php-to-wasm/php-wasm.js index 264f7f9..e255611 100644 --- a/examples/compile-php-to-wasm/php-wasm.js +++ b/examples/compile-php-to-wasm/php-wasm.js @@ -48,10 +48,6 @@ var ENVIRONMENT_IS_WORKER = false; var ENVIRONMENT_IS_NODE = true; var ENVIRONMENT_IS_SHELL = false; -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)'); -} - 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 @@ -108,27 +104,25 @@ if (ENVIRONMENT_IS_NODE) { // 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. - scriptDirectory = require('url').fileURLToPath(new URL('./', import.meta.url)); // includes trailing slash + if (!import.meta.url.startsWith('data:')) { + scriptDirectory = nodePath.dirname(require('url').fileURLToPath(import.meta.url)) + '/'; + } // include: node_shell_read.js readBinary = (filename) => { - // We need to re-wrap `file://` strings to URLs. Normalizing isn't - // necessary in that case, the path should already be absolute. - filename = isFileURI(filename) ? new URL(filename) : nodePath.normalize(filename); + // We need to re-wrap `file://` strings to URLs. + filename = isFileURI(filename) ? new URL(filename) : filename; var ret = fs.readFileSync(filename); - assert(ret.buffer); + assert(Buffer.isBuffer(ret)); return ret; }; -readAsync = (filename, binary = true) => { +readAsync = async (filename, binary = true) => { // See the comment in the `readBinary` function. - filename = isFileURI(filename) ? new URL(filename) : nodePath.normalize(filename); - return new Promise((resolve, reject) => { - fs.readFile(filename, binary ? undefined : 'utf8', (err, data) => { - if (err) reject(err); - else resolve(binary ? data.buffer : data); - }); - }); + filename = isFileURI(filename) ? new URL(filename) : filename; + var ret = fs.readFileSync(filename, binary ? undefined : 'utf8'); + assert(binary ? Buffer.isBuffer(ret) : typeof ret == 'string'); + return ret; }; // end include: node_shell_read.js if (!Module['thisProgram'] && process.argv.length > 1) { @@ -147,7 +141,7 @@ readAsync = (filename, binary = true) => { } else if (ENVIRONMENT_IS_SHELL) { - if ((typeof process == 'object' && typeof require === 'function') || typeof window == 'object' || typeof importScripts == 'function') 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?)'); + 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 @@ -177,8 +171,6 @@ if (Module['arguments']) arguments_ = Module['arguments'];legacyModuleProp('argu if (Module['thisProgram']) thisProgram = Module['thisProgram'];legacyModuleProp('thisProgram', 'thisProgram'); -if (Module['quit']) quit_ = Module['quit'];legacyModuleProp('quit', 'quit_'); - // 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'); @@ -223,8 +215,7 @@ 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; -if (Module['wasmBinary']) wasmBinary = Module['wasmBinary'];legacyModuleProp('wasmBinary', 'wasmBinary'); +var wasmBinary = Module['wasmBinary'];legacyModuleProp('wasmBinary', 'wasmBinary'); if (typeof WebAssembly != 'object') { err('no native wasm support detected'); @@ -297,6 +288,7 @@ function updateMemoryViews() { 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') @@ -345,16 +337,6 @@ function checkStackCookie() { } } // end include: runtime_stack_check.js -// include: runtime_assertions.js -// Endianness check -(function() { - 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)'; -})(); - -// end include: runtime_assertions.js var __ATPRERUN__ = []; // functions called before the runtime is initialized var __ATINIT__ = []; // functions called during startup var __ATEXIT__ = []; // functions called during shutdown @@ -379,7 +361,7 @@ function initRuntime() { checkStackCookie(); -if (!Module['noFSInit'] && !FS.init.initialized) +if (!Module['noFSInit'] && !FS.initialized) FS.init(); FS.ignorePermissions = false; @@ -439,9 +421,9 @@ assert(Math.trunc, 'This browser does not support Math.trunc(), build with LEGAC // it happens right before run - run will be postponed until // the dependencies are met. var runDependencies = 0; -var runDependencyWatcher = null; 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; @@ -519,7 +501,6 @@ function abort(what) { err(what); ABORT = true; - EXITSTATUS = 1; // Use a wasm runtime error, because a JS error might be seen as a foreign // exception, which means we'd run destructors on it. We need the error to @@ -599,26 +580,29 @@ function getBinarySync(file) { throw 'both async and sync fetching of the wasm failed'; } -function getBinaryPromise(binaryFile) { +async function getWasmBinary(binaryFile) { // If we don't have the binary yet, load it asynchronously using readAsync. if (!wasmBinary ) { // Fetch the binary using readAsync - return readAsync(binaryFile).then( - (response) => new Uint8Array(/** @type{!ArrayBuffer} */(response)), - // Fall back to getBinarySync if readAsync fails - () => getBinarySync(binaryFile) - ); + try { + var response = await readAsync(binaryFile); + return new Uint8Array(response); + } catch { + // Fall back to getBinarySync below; + } } // Otherwise, getBinarySync should be able to get it synchronously - return Promise.resolve().then(() => getBinarySync(binaryFile)); + return getBinarySync(binaryFile); } -function instantiateArrayBuffer(binaryFile, imports, receiver) { - return getBinaryPromise(binaryFile).then((binary) => { - return WebAssembly.instantiate(binary, imports); - }).then(receiver, (reason) => { +async function instantiateArrayBuffer(binaryFile, imports) { + try { + var binary = await getWasmBinary(binaryFile); + var instance = await WebAssembly.instantiate(binary, imports); + return instance; + } catch (reason) { err(`failed to asynchronously prepare wasm: ${reason}`); // Warn on some common problems. @@ -626,10 +610,10 @@ function instantiateArrayBuffer(binaryFile, imports, receiver) { 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`); } abort(reason); - }); + } } -function instantiateAsync(binary, binaryFile, imports, callback) { +async function instantiateAsync(binary, binaryFile, imports) { if (!binary && typeof WebAssembly.instantiateStreaming == 'function' && !isDataURI(binaryFile) && @@ -641,26 +625,19 @@ function instantiateAsync(binary, binaryFile, imports, callback) { // https://github.com/emscripten-core/emscripten/pull/16917 !ENVIRONMENT_IS_NODE && typeof fetch == 'function') { - return fetch(binaryFile, { credentials: 'same-origin' }).then((response) => { - // Suppress closure warning here since the upstream definition for - // instantiateStreaming only allows Promise<Repsponse> rather than - // an actual Response. - // TODO(https://github.com/google/closure-compiler/pull/3913): Remove if/when upstream closure is fixed. - /** @suppress {checkTypes} */ - var result = WebAssembly.instantiateStreaming(response, imports); - - return result.then( - callback, - function(reason) { - // We expect the most common failure cause to be a bad MIME type for the binary, - // in which case falling back to ArrayBuffer instantiation should work. - err(`wasm streaming compile failed: ${reason}`); - err('falling back to ArrayBuffer instantiation'); - return instantiateArrayBuffer(binaryFile, imports, callback); - }); - }); + try { + var response = fetch(binaryFile, { credentials: 'same-origin' }); + var instantiationResult = await WebAssembly.instantiateStreaming(response, imports); + return instantiationResult; + } catch (reason) { + // We expect the most common failure cause to be a bad MIME type for the binary, + // in which case falling back to ArrayBuffer instantiation should work. + err(`wasm streaming compile failed: ${reason}`); + err('falling back to ArrayBuffer instantiation'); + // fall back of instantiateArrayBuffer below + }; } - return instantiateArrayBuffer(binaryFile, imports, callback); + return instantiateArrayBuffer(binaryFile, imports); } function getWasmImports() { @@ -673,8 +650,7 @@ function getWasmImports() { // Create the wasm instance. // Receives the wasm imports, returns the exports. -function createWasm() { - var info = getWasmImports(); +async function createWasm() { // Load the wasm module and create an instance of using native support in the JS engine. // handle a generated wasm instance, receiving its exports and // performing other necessary setup @@ -716,6 +692,8 @@ function createWasm() { receiveInstance(result['instance']); } + var info = getWasmImports(); + // User shell pages can write their own Module.instantiateWasm = function(imports, successCallback) callback // to manually instantiate the Wasm module themselves. This allows pages to // run the instantiation parallel to any other async startup actions they are @@ -732,11 +710,17 @@ function createWasm() { } } - if (!wasmBinaryFile) wasmBinaryFile = findWasmBinary(); + wasmBinaryFile ??= findWasmBinary(); - // If instantiation fails, reject the module ready promise. - instantiateAsync(wasmBinary, wasmBinaryFile, info, receiveInstantiationResult).catch(readyPromiseReject); - return {}; // no exports yet; we'll fill them in later + 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) @@ -744,6 +728,18 @@ 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, { @@ -776,45 +772,51 @@ function isExportedByForceFilesystem(name) { name === 'removeRunDependency'; } -function missingGlobal(sym, msg) { - if (typeof globalThis != 'undefined') { +/** + * 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() { - warnOnce(`\`${sym}\` is not longer defined by emscripten. ${msg}`); + func(); return undefined; } }); } } +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) { - if (typeof globalThis != 'undefined' && !Object.getOwnPropertyDescriptor(globalThis, sym)) { - Object.defineProperty(globalThis, sym, { - configurable: true, - get() { - // 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); - return undefined; - } - }); - } + 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); @@ -846,11 +848,12 @@ function dbg(...args) { // end include: preamble.js - /** @constructor */ - function ExitStatus(status) { - this.name = 'ExitStatus'; - this.message = `Program terminated with exit(${status})`; - this.status = status; + class ExitStatus { + name = 'ExitStatus'; + constructor(status) { + this.message = `Program terminated with exit(${status})`; + this.status = status; + } } var callRuntimeCallbacks = (callbacks) => { @@ -930,18 +933,18 @@ function dbg(...args) { * 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=} idx * @param {number=} maxBytesToRead * @return {string} */ - var UTF8ArrayToString = (heapOrArray, idx, maxBytesToRead) => { + var UTF8ArrayToString = (heapOrArray, idx = 0, maxBytesToRead = NaN) => { var endIdx = idx + maxBytesToRead; var endPtr = idx; // 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 means Infinity) + // so that undefined/NaN means Infinity) while (heapOrArray[endPtr] && !(endPtr >= endIdx)) ++endPtr; if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) { @@ -996,9 +999,8 @@ function dbg(...args) { assert(typeof ptr == 'number', `UTF8ToString expects a number (got ${typeof ptr})`); return ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : ''; }; - var ___assert_fail = (condition, filename, line, func) => { + 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 = []; @@ -1008,8 +1010,10 @@ function dbg(...args) { var func = wasmTableMirror[funcPtr]; if (!func) { if (funcPtr >= wasmTableMirror.length) wasmTableMirror.length = funcPtr + 1; + /** @suppress {checkTypes} */ wasmTableMirror[funcPtr] = func = wasmTable.get(funcPtr); } + /** @suppress {checkTypes} */ assert(wasmTable.get(funcPtr) == func, 'JavaScript-side Wasm function table mirror is out of date!'); return func; }; @@ -1356,7 +1360,7 @@ function dbg(...args) { buffer[offset+i] = result; } if (bytesRead) { - stream.node.timestamp = Date.now(); + stream.node.atime = Date.now(); } return bytesRead; }, @@ -1372,7 +1376,7 @@ function dbg(...args) { throw new FS.ErrnoError(29); } if (length) { - stream.node.timestamp = Date.now(); + stream.node.mtime = stream.node.ctime = Date.now(); } return i; }, @@ -1383,7 +1387,7 @@ function dbg(...args) { }, put_char(tty, val) { if (val === null || val === 10) { - out(UTF8ArrayToString(tty.output, 0)); + out(UTF8ArrayToString(tty.output)); tty.output = []; } else { if (val != 0) tty.output.push(val); // val == 0 would cut text output off in the middle. @@ -1391,7 +1395,7 @@ function dbg(...args) { }, fsync(tty) { if (tty.output && tty.output.length > 0) { - out(UTF8ArrayToString(tty.output, 0)); + out(UTF8ArrayToString(tty.output)); tty.output = []; } }, @@ -1420,7 +1424,7 @@ function dbg(...args) { default_tty1_ops:{ put_char(tty, val) { if (val === null || val === 10) { - err(UTF8ArrayToString(tty.output, 0)); + err(UTF8ArrayToString(tty.output)); tty.output = []; } else { if (val != 0) tty.output.push(val); @@ -1428,7 +1432,7 @@ function dbg(...args) { }, fsync(tty) { if (tty.output && tty.output.length > 0) { - err(UTF8ArrayToString(tty.output, 0)); + err(UTF8ArrayToString(tty.output)); tty.output = []; } }, @@ -1438,7 +1442,6 @@ function dbg(...args) { var zeroMemory = (address, size) => { HEAPU8.fill(0, address, address + size); - return address; }; var alignMemory = (size, alignment) => { @@ -1448,13 +1451,13 @@ function dbg(...args) { var mmapAlloc = (size) => { size = alignMemory(size, 65536); var ptr = _emscripten_builtin_memalign(65536, size); - if (!ptr) return 0; - return zeroMemory(ptr, size); + if (ptr) zeroMemory(ptr, size); + return ptr; }; var MEMFS = { ops_table:null, mount(mount) { - return MEMFS.createNode(null, '/', 16384 | 511 /* 0777 */, 0); + return MEMFS.createNode(null, '/', 16895, 0); }, createNode(parent, name, mode, dev) { if (FS.isBlkdev(mode) || FS.isFIFO(mode)) { @@ -1528,11 +1531,11 @@ function dbg(...args) { node.node_ops = MEMFS.ops_table.chrdev.node; node.stream_ops = MEMFS.ops_table.chrdev.stream; } - node.timestamp = Date.now(); + node.atime = node.mtime = node.ctime = Date.now(); // add the new node to the parent if (parent) { parent.contents[name] = node; - parent.timestamp = node.timestamp; + parent.atime = parent.mtime = parent.ctime = node.atime; } return node; }, @@ -1588,9 +1591,9 @@ function dbg(...args) { } else { attr.size = 0; } - attr.atime = new Date(node.timestamp); - attr.mtime = new Date(node.timestamp); - attr.ctime = new Date(node.timestamp); + attr.atime = new Date(node.atime); + attr.mtime = new Date(node.mtime); + attr.ctime = new Date(node.ctime); // NOTE: In our implementation, st_blocks = Math.ceil(st_size/st_blksize), // but this is not required by the standard. attr.blksize = 4096; @@ -1598,46 +1601,44 @@ function dbg(...args) { return attr; }, setattr(node, attr) { - if (attr.mode !== undefined) { - node.mode = attr.mode; - } - if (attr.timestamp !== undefined) { - node.timestamp = attr.timestamp; + for (const key of ["mode", "atime", "mtime", "ctime"]) { + if (attr[key]) { + node[key] = attr[key]; + } } if (attr.size !== undefined) { MEMFS.resizeFileStorage(node, attr.size); } }, lookup(parent, name) { - throw FS.genericErrors[44]; + throw new FS.ErrnoError(44); }, mknod(parent, name, mode, dev) { return MEMFS.createNode(parent, name, mode, dev); }, rename(old_node, new_dir, new_name) { - // if we're overwriting a directory at new_name, make sure it's empty. - if (FS.isDir(old_node.mode)) { - var new_node; - try { - new_node = FS.lookupNode(new_dir, new_name); - } catch (e) { - } - if (new_node) { + var new_node; + try { + new_node = FS.lookupNode(new_dir, new_name); + } catch (e) {} + if (new_node) { + if (FS.isDir(old_node.mode)) { + // if we're overwriting a directory at new_name, make sure it's empty. for (var i in new_node.contents) { throw new FS.ErrnoError(55); } } + FS.hashRemoveNode(new_node); } // do the internal rewiring delete old_node.parent.contents[old_node.name]; - old_node.parent.timestamp = Date.now() - old_node.name = new_name; new_dir.contents[new_name] = old_node; - new_dir.timestamp = old_node.parent.timestamp; + old_node.name = new_name; + new_dir.ctime = new_dir.mtime = old_node.parent.ctime = old_node.parent.mtime = Date.now(); }, unlink(parent, name) { delete parent.contents[name]; - parent.timestamp = Date.now(); + parent.ctime = parent.mtime = Date.now(); }, rmdir(parent, name) { var node = FS.lookupNode(parent, name); @@ -1645,17 +1646,13 @@ function dbg(...args) { throw new FS.ErrnoError(55); } delete parent.contents[name]; - parent.timestamp = Date.now(); + parent.ctime = parent.mtime = Date.now(); }, readdir(node) { - var entries = ['.', '..']; - for (var key of Object.keys(node.contents)) { - entries.push(key); - } - return entries; + return ['.', '..', ...Object.keys(node.contents)]; }, symlink(parent, newname, oldpath) { - var node = MEMFS.createNode(parent, newname, 511 /* 0777 */ | 40960, 0); + var node = MEMFS.createNode(parent, newname, 0o777 | 40960, 0); node.link = oldpath; return node; }, @@ -1685,7 +1682,7 @@ function dbg(...args) { if (!length) return 0; var node = stream.node; - node.timestamp = Date.now(); + node.mtime = node.ctime = Date.now(); if (buffer.subarray && (!node.contents || node.contents.subarray)) { // This write is from a typed array to a typed array? if (canOwn) { @@ -1742,26 +1739,28 @@ function dbg(...args) { var allocated; var contents = stream.node.contents; // Only make a new copy when MAP_PRIVATE is specified. - if (!(flags & 2) && contents.buffer === HEAP8.buffer) { + if (!(flags & 2) && contents && contents.buffer === HEAP8.buffer) { // We can't emulate MAP_SHARED when the file is not backed by the // buffer we're mapping to (e.g. the HEAP buffer). allocated = false; ptr = contents.byteOffset; } else { - // Try to avoid unnecessary slices. - if (position > 0 || position + length < contents.length) { - if (contents.subarray) { - contents = contents.subarray(position, position + length); - } else { - contents = Array.prototype.slice.call(contents, position, position + length); - } - } allocated = true; ptr = mmapAlloc(length); if (!ptr) { throw new FS.ErrnoError(48); } - HEAP8.set(contents, ptr); + if (contents) { + // Try to avoid unnecessary slices. + if (position > 0 || position + length < contents.length) { + if (contents.subarray) { + contents = contents.subarray(position, position + length); + } else { + contents = Array.prototype.slice.call(contents, position, position + length); + } + } + HEAP8.set(contents, ptr); + } } return { ptr, allocated }; }, @@ -1773,24 +1772,10 @@ function dbg(...args) { }, }; - /** @param {boolean=} noRunDep */ - var asyncLoad = (url, onload, onerror, noRunDep) => { - var dep = !noRunDep ? getUniqueRunDependency(`al ${url}`) : ''; - readAsync(url).then( - (arrayBuffer) => { - assert(arrayBuffer, `Loading data file "${url}" failed (no arrayBuffer).`); - onload(new Uint8Array(arrayBuffer)); - if (dep) removeRunDependency(dep); - }, - (err) => { - if (onerror) { - onerror(); - } else { - throw `Loading data file "${url}" failed.`; - } - } - ); - if (dep) addRunDependency(dep); + var asyncLoad = async (url) => { + var arrayBuffer = await readAsync(url); + assert(arrayBuffer, `Loading data file "${url}" failed (no arrayBuffer).`); + return new Uint8Array(arrayBuffer); }; @@ -1837,7 +1822,7 @@ function dbg(...args) { } addRunDependency(dep); if (typeof url == 'string') { - asyncLoad(url, processData, onerror); + asyncLoad(url).then(processData, onerror); } else { processData(url); } @@ -1871,9 +1856,7 @@ function dbg(...args) { - var strError = (errno) => { - return UTF8ToString(_strerror(errno)); - }; + var strError = (errno) => UTF8ToString(_strerror(errno)); var ERRNO_CODES = { 'EPERM': 63, @@ -2010,6 +1993,7 @@ function dbg(...args) { initialized:false, ignorePermissions:true, ErrnoError:class extends Error { + name = 'ErrnoError'; // We set the `name` property to be able to identify `FS.ErrnoError` // - the `name` is a standard ECMA-262 property of error objects. Kind of good to have it anyway. // - when using PROXYFS, an error can come from an underlying FS @@ -2018,9 +2002,6 @@ function dbg(...args) { // we'll use the reliable test `err.name == "ErrnoError"` instead constructor(errno) { super(runtimeInitialized ? strError(errno) : ''); - // TODO(sbc): Use the inline member declaration syntax once we - // support it in acorn and closure. - this.name = 'ErrnoError'; this.errno = errno; for (var key in ERRNO_CODES) { if (ERRNO_CODES[key] === errno) { @@ -2030,16 +2011,12 @@ function dbg(...args) { } } }, - genericErrors:{ - }, filesystems:null, syncFSRequests:0, + readFiles:{ + }, FSStream:class { - constructor() { - // TODO(https://github.com/emscripten-core/emscripten/issues/21414): - // Use inline field declarations. - this.shared = {}; - } + shared = {}; get object() { return this.node; } @@ -2069,21 +2046,22 @@ function dbg(...args) { } }, FSNode:class { + node_ops = {}; + stream_ops = {}; + readMode = 292 | 73; + writeMode = 146; + mounted = null; constructor(parent, name, mode, rdev) { if (!parent) { parent = this; // root node sets parent to itself } this.parent = parent; this.mount = parent.mount; - this.mounted = null; this.id = FS.nextInode++; this.name = name; this.mode = mode; - this.node_ops = {}; - this.stream_ops = {}; this.rdev = rdev; - this.readMode = 292/*292*/ | 73/*73*/; - this.writeMode = 146/*146*/; + this.atime = this.mtime = this.ctime = Date.now(); } get read() { return (this.mode & this.readMode) === this.readMode; @@ -2105,63 +2083,70 @@ function dbg(...args) { } }, lookupPath(path, opts = {}) { - path = PATH_FS.resolve(path); - if (!path) return { path: '', node: null }; + opts.follow_mount ??= true - var defaults = { - follow_mount: true, - recurse_count: 0 - }; - opts = Object.assign(defaults, opts) - - if (opts.recurse_count > 8) { // max recursive lookup of 8 - throw new FS.ErrnoError(32); + if (!PATH.isAbs(path)) { + path = FS.cwd() + '/' + path; } - // split the absolute path - var parts = path.split('/').filter((p) => !!p); - - // start at the root - var current = FS.root; - var current_path = '/'; + // 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 !== '.')); - for (var i = 0; i < parts.length; i++) { - var islast = (i === parts.length-1); - if (islast && opts.parent) { - // stop resolving - break; - } + // start at the root + var current = FS.root; + var current_path = '/'; - current = FS.lookupNode(current, parts[i]); - current_path = PATH.join2(current_path, parts[i]); + for (var i = 0; i < parts.length; i++) { + var islast = (i === parts.length-1); + if (islast && opts.parent) { + // stop resolving + break; + } - // jump to the mount's root node if this is a mountpoint - if (FS.isMountpoint(current)) { - if (!islast || (islast && opts.follow_mount)) { - current = current.mounted.root; + if (parts[i] === '..') { + current_path = PATH.dirname(current_path); + current = current.parent; + continue; } - } - // by default, lookupPath will not follow a symlink if it is the final path component. - // setting opts.follow = true will override this behavior. - if (!islast || opts.follow) { - var count = 0; - while (FS.isLink(current.mode)) { - var link = FS.readlink(current_path); - current_path = PATH_FS.resolve(PATH.dirname(current_path), link); + current_path = PATH.join2(current_path, parts[i]); + try { + current = FS.lookupNode(current, parts[i]); + } catch (e) { + // if noent_okay is true, suppress a ENOENT in the last component + // and return an object with an undefined node. This is needed for + // resolving symlinks in the path when creating a file. + if ((e?.errno === 44) && islast && opts.noent_okay) { + return { path: current_path }; + } + throw e; + } - var lookup = FS.lookupPath(current_path, { recurse_count: opts.recurse_count + 1 }); - current = lookup.node; + // jump to the mount's root node if this is a mountpoint + if (FS.isMountpoint(current) && (!islast || opts.follow_mount)) { + current = current.mounted.root; + } - if (count++ > 40) { // limit max consecutive symlinks to 40 (SYMLOOP_MAX). - throw new FS.ErrnoError(32); + // by default, lookupPath will not follow a symlink if it is the final path component. + // setting opts.follow = true will override this behavior. + if (FS.isLink(current.mode) && (!islast || opts.follow)) { + if (!current.node_ops.readlink) { + throw new FS.ErrnoError(52); } + var link = current.node_ops.readlink(current); + if (!PATH.isAbs(link)) { + link = PATH.dirname(current_path) + '/' + link; + } + path = link + '/' + parts.slice(i + 1).join('/'); + continue linkloop; } } + return { path: current_path, node: current }; } - - return { path: current_path, node: current }; + throw new FS.ErrnoError(32); }, getPath(node) { var path; @@ -2285,6 +2270,9 @@ function dbg(...args) { return 0; }, mayCreate(dir, name) { + if (!FS.isDir(dir.mode)) { + return 54; + } try { var node = FS.lookupNode(dir, name); return 20; @@ -2549,14 +2537,35 @@ function dbg(...args) { } return parent.node_ops.mknod(parent, name, mode, dev); }, - create(path, mode) { - mode = mode !== undefined ? mode : 438 /* 0666 */; + statfs(path) { + + // NOTE: None of the defaults here are true. We're just returning safe and + // sane values. + var rtn = { + bsize: 4096, + frsize: 4096, + blocks: 1e6, + bfree: 5e5, + bavail: 5e5, + files: FS.nextInode, + ffree: FS.nextInode - 1, + fsid: 42, + flags: 2, + 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)); + } + return rtn; + }, + create(path, mode = 0o666) { mode &= 4095; mode |= 32768; return FS.mknod(path, mode, 0); }, - mkdir(path, mode) { - mode = mode !== undefined ? mode : 511 /* 0777 */; + mkdir(path, mode = 0o777) { mode &= 511 | 512; mode |= 16384; return FS.mknod(path, mode, 0); @@ -2577,7 +2586,7 @@ function dbg(...args) { mkdev(path, mode, dev) { if (typeof dev == 'undefined') { dev = mode; - mode = 438 /* 0666 */; + mode = 0o666; } mode |= 8192; return FS.mknod(path, mode, dev); @@ -2675,7 +2684,7 @@ function dbg(...args) { // do the underlying fs rename try { old_dir.node_ops.rename(old_node, new_dir, new_name); - // update old node (we do this here to avoid each backend + // update old node (we do this here to avoid each backend // needing to) old_node.parent = new_dir; } catch (e) { @@ -2745,7 +2754,7 @@ function dbg(...args) { if (!link.node_ops.readlink) { throw new FS.ErrnoError(28); } - return PATH_FS.resolve(FS.getPath(link.parent), link.node_ops.readlink(link)); + return link.node_ops.readlink(link); }, stat(path, dontFollow) { var lookup = FS.lookupPath(path, { follow: !dontFollow }); @@ -2774,7 +2783,7 @@ function dbg(...args) { } node.node_ops.setattr(node, { mode: (mode & 4095) | (node.mode & ~4095), - timestamp: Date.now() + ctime: Date.now() }); }, lchmod(path, mode) { @@ -2847,16 +2856,16 @@ function dbg(...args) { var lookup = FS.lookupPath(path, { follow: true }); var node = lookup.node; node.node_ops.setattr(node, { - timestamp: Math.max(atime, mtime) + atime: atime, + mtime: mtime }); }, - open(path, flags, mode) { + open(path, flags, mode = 0o666) { if (path === "") { throw new FS.ErrnoError(44); } flags = typeof flags == 'string' ? FS_modeStringToFlags(flags) : flags; if ((flags & 64)) { - mode = typeof mode == 'undefined' ? 438 /* 0666 */ : mode; mode = (mode & 4095) | 32768; } else { mode = 0; @@ -2865,15 +2874,15 @@ function dbg(...args) { if (typeof path == 'object') { node = path; } else { - path = PATH.normalize(path); - try { - var lookup = FS.lookupPath(path, { - follow: !(flags & 131072) - }); - node = lookup.node; - } catch (e) { - // ignore - } + // 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. + var lookup = FS.lookupPath(path, { + follow: !(flags & 131072), + noent_okay: true + }); + node = lookup.node; + path = lookup.path; } // perhaps we need to create the node var created = false; @@ -2933,7 +2942,6 @@ function dbg(...args) { stream.stream_ops.open(stream); } if (Module['logReadFiles'] && !(flags & 1)) { - if (!FS.readFiles) FS.readFiles = {}; if (!(path in FS.readFiles)) { FS.readFiles[path] = 1; } @@ -3067,6 +3075,9 @@ function dbg(...args) { if (!stream.stream_ops.mmap) { throw new FS.ErrnoError(43); } + if (!length) { + throw new FS.ErrnoError(28); + } return stream.stream_ops.mmap(stream, length, position, prot, flags); }, msync(stream, buffer, offset, length, mmapFlags) { @@ -3095,7 +3106,7 @@ function dbg(...args) { var buf = new Uint8Array(length); FS.read(stream, buf, 0, length, 0); if (opts.encoding === 'utf8') { - ret = UTF8ArrayToString(buf, 0); + ret = UTF8ArrayToString(buf); } else if (opts.encoding === 'binary') { ret = buf; } @@ -3143,6 +3154,7 @@ function dbg(...args) { FS.registerDevice(FS.makedev(1, 3), { read: () => 0, write: (stream, buffer, offset, length, pos) => length, + llseek: () => 0, }); FS.mkdev('/dev/null', FS.makedev(1, 3)); // setup /dev/tty and /dev/tty1 @@ -3176,7 +3188,10 @@ function dbg(...args) { FS.mkdir('/proc/self/fd'); FS.mount({ mount() { - var node = FS.createNode(proc_self, 'fd', 16384 | 511 /* 0777 */, 73); + var node = FS.createNode(proc_self, 'fd', 16895, 73); + node.stream_ops = { + llseek: MEMFS.stream_ops.llseek, + }; node.node_ops = { lookup(parent, name) { var fd = +name; @@ -3185,16 +3200,22 @@ function dbg(...args) { parent: null, mount: { mountpoint: 'fake' }, node_ops: { readlink: () => stream.path }, + id: fd + 1, }; ret.parent = ret; // make it look like a simple root node return ret; + }, + readdir() { + return Array.from(FS.streams.entries()) + .filter(([k, v]) => v) + .map(([k, v]) => k.toString()); } }; return node; } }, {}, '/proc/self/fd'); }, - createStandardStreams() { + createStandardStreams(input, output, error) { // TODO deprecate the old functionality of a single // input / output callback and that utilizes FS.createDevice // and instead require a unique set of stream ops @@ -3203,18 +3224,18 @@ function dbg(...args) { // default tty devices. however, if the standard streams // have been overwritten we create a unique device for // them instead. - if (Module['stdin']) { - FS.createDevice('/dev', 'stdin', Module['stdin']); + if (input) { + FS.createDevice('/dev', 'stdin', input); } else { FS.symlink('/dev/tty', '/dev/stdin'); } - if (Module['stdout']) { - FS.createDevice('/dev', 'stdout', null, Module['stdout']); + if (output) { + FS.createDevice('/dev', 'stdout', null, output); } else { FS.symlink('/dev/tty', '/dev/stdout'); } - if (Module['stderr']) { - FS.createDevice('/dev', 'stderr', null, Module['stderr']); + if (error) { + FS.createDevice('/dev', 'stderr', null, error); } else { FS.symlink('/dev/tty1', '/dev/stderr'); } @@ -3228,12 +3249,6 @@ function dbg(...args) { assert(stderr.fd === 2, `invalid handle for stderr (${stderr.fd})`); }, staticInit() { - // Some errors may happen quite a bit, to avoid overhead we reuse them (and suffer a lack of stack info) - [44].forEach((code) => { - FS.genericErrors[code] = new FS.ErrnoError(code); - FS.genericErrors[code].stack = '<generic error, no stack>'; - }); - FS.nameTable = new Array(4096); FS.mount(MEMFS, {}, '/'); @@ -3247,18 +3262,18 @@ function dbg(...args) { }; }, init(input, output, error) { - assert(!FS.init.initialized, 'FS.init was previously called. If you want to initialize later with custom parameters, remove any earlier calls (note that one is automatically added to the generated code)'); - FS.init.initialized = true; + assert(!FS.initialized, 'FS.init was previously called. If you want to initialize later with custom parameters, remove any earlier calls (note that one is automatically added to the generated code)'); + FS.initialized = true; // Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here - Module['stdin'] = input || Module['stdin']; - Module['stdout'] = output || Module['stdout']; - Module['stderr'] = error || Module['stderr']; + input ??= Module['stdin']; + output ??= Module['stdout']; + error ??= Module['stderr']; - FS.createStandardStreams(); + FS.createStandardStreams(input, output, error); }, quit() { - FS.init.initialized = false; + FS.initialized = false; // force-flush all streams, so we get musl std streams printed out _fflush(0); // close all of our streams @@ -3351,7 +3366,7 @@ function dbg(...args) { createDevice(parent, name, input, output) { var path = PATH.join2(typeof parent == 'string' ? parent : FS.getPath(parent), name); var mode = FS_getMode(!!input, !!output); - if (!FS.createDevice.major) FS.createDevice.major = 64; + FS.createDevice.major ??= 64; var dev = FS.makedev(FS.createDevice.major++, 0); // Create a fake device that a set of stream ops to emulate // the old behavior. @@ -3382,7 +3397,7 @@ function dbg(...args) { buffer[offset+i] = result; } if (bytesRead) { - stream.node.timestamp = Date.now(); + stream.node.atime = Date.now(); } return bytesRead; }, @@ -3395,7 +3410,7 @@ function dbg(...args) { } } if (length) { - stream.node.timestamp = Date.now(); + stream.node.mtime = stream.node.ctime = Date.now(); } return i; } @@ -3419,10 +3434,8 @@ function dbg(...args) { // Lazy chunked Uint8Array (implements get and length from Uint8Array). // Actual getting is abstracted away for eventual reuse. class LazyUint8Array { - constructor() { - this.lengthKnown = false; - this.chunks = []; // Loaded chunks. Index is the chunk number - } + lengthKnown = false; + chunks = []; // Loaded chunks. Index is the chunk number get(idx) { if (idx > this.length-1 || idx < 0) { return undefined; @@ -3619,7 +3632,7 @@ function dbg(...args) { } return dir; } - return PATH.join2(dir, path); + return dir + '/' + path; }, doStat(func, path, buf) { var stat = func(path); @@ -3636,11 +3649,11 @@ function dbg(...args) { 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; + 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; + 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; + 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; }, @@ -3665,7 +3678,7 @@ function dbg(...args) { return ret; }, }; - function ___syscall__newselect(nfds, readfds, writefds, exceptfds, timeout) { + var ___syscall__newselect = function (nfds, readfds, writefds, exceptfds, timeout) { try { // readfds are supported, @@ -3698,9 +3711,7 @@ function dbg(...args) { (writefds ? HEAP32[(((writefds)+(4))>>2)] : 0) | (exceptfds ? HEAP32[(((exceptfds)+(4))>>2)] : 0); - var check = function(fd, low, high, val) { - return (fd < 32 ? (low & val) : (high & val)); - }; + var check = (fd, low, high, val) => fd < 32 ? (low & val) : (high & val); for (var fd = 0; fd < nfds; fd++) { var mask = 1 << (fd % 32); @@ -3759,35 +3770,29 @@ function dbg(...args) { if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; return -e.errno; } - } + }; var SOCKFS = { + websocketArgs:{ + }, + callbacks:{ + }, + on(event, callback) { + SOCKFS.callbacks[event] = callback; + }, + emit(event, param) { + SOCKFS.callbacks[event]?.(param); + }, mount(mount) { - // If Module['websocket'] has already been defined (e.g. for configuring - // the subprotocol/url) use that, if not initialise it to a new object. - Module['websocket'] = (Module['websocket'] && - ('object' === typeof Module['websocket'])) ? Module['websocket'] : {}; - + // The incomming Module['websocket'] can be used for configuring + // 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. // For more documentation see system/include/emscripten/emscripten.h - Module['websocket']._callbacks = {}; - Module['websocket']['on'] = /** @this{Object} */ function(event, callback) { - if ('function' === typeof callback) { - this._callbacks[event] = callback; - } - return this; - }; - - Module['websocket'].emit = /** @this{Object} */ function(event, param) { - if ('function' === typeof this._callbacks[event]) { - this._callbacks[event].call(this, param); - } - }; - - // If debug is enabled register simple default logging callbacks for each Event. + (Module['websocket'] ??= {})['on'] = SOCKFS.on; - return FS.createNode(null, '/', 16384 | 511 /* 0777 */, 0); + return FS.createNode(null, '/', 16895, 0); }, createSocket(family, type, protocol) { type &= ~526336; // Some applications may pass it; it makes no sense for a single process. @@ -3869,7 +3874,7 @@ function dbg(...args) { if (!SOCKFS.nextname.current) { SOCKFS.nextname.current = 0; } - return 'socket[' + (SOCKFS.nextname.current++) + ']'; + return `socket[${SOCKFS.nextname.current++}]`; }, websocket_sock_ops:{ createPeer(sock, addr, port) { @@ -3901,17 +3906,23 @@ function dbg(...args) { } else { // create the actual websocket object and connect try { - // runtimeConfig gets set to true if WebSocket runtime configuration is available. - var runtimeConfig = (Module['websocket'] && ('object' === typeof Module['websocket'])); - // 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('#', '//'); + // 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 + var opts = undefined; - if (runtimeConfig) { - if ('string' === typeof Module['websocket']['url']) { - url = Module['websocket']['url']; // Fetch runtime WebSocket URL config. - } + // Fetch runtime WebSocket URL config. + if (SOCKFS.websocketArgs['url']) { + url = SOCKFS.websocketArgs['url']; + } + // Fetch runtime WebSocket subprotocol config. + if (SOCKFS.websocketArgs['subprotocol']) { + subProtocols = SOCKFS.websocketArgs['subprotocol']; + } else if (SOCKFS.websocketArgs['subprotocol'] === null) { + subProtocols = 'null' } if (url === 'ws://' || url === 'wss://') { // Is the supplied URL config just a prefix, if so complete it. @@ -3919,18 +3930,6 @@ function dbg(...args) { url = url + parts[0] + ":" + port + "/" + parts.slice(1).join('/'); } - // Make the WebSocket subprotocol (Sec-WebSocket-Protocol) default to binary if no configuration is set. - var subProtocols = 'binary'; // The default value is 'binary' - - if (runtimeConfig) { - if ('string' === typeof Module['websocket']['subprotocol']) { - subProtocols = Module['websocket']['subprotocol']; // Fetch runtime WebSocket subprotocol config. - } - } - - // The default WebSocket options - var opts = undefined; - if (subProtocols !== 'null') { // 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. @@ -3939,12 +3938,6 @@ function dbg(...args) { opts = subProtocols; } - // some webservers (azure) does not support subprotocol header - if (runtimeConfig && null === Module['websocket']['subprotocol']) { - subProtocols = 'null'; - opts = undefined; - } - // If node we use the ws library. var WebSocketConstructor; if (ENVIRONMENT_IS_NODE) { @@ -3964,7 +3957,7 @@ function dbg(...args) { addr, port, socket: ws, - dgram_send_queue: [] + msg_send_queue: [] }; SOCKFS.websocket_sock_ops.addPeer(sock, peer); @@ -3974,7 +3967,7 @@ function dbg(...args) { // us to override the ephemeral port reported to us by remotePort on the // remote end. if (sock.type === 2 && typeof sock.sport != 'undefined') { - peer.dgram_send_queue.push(new Uint8Array([ + peer.msg_send_queue.push(new Uint8Array([ 255, 255, 255, 255, 'p'.charCodeAt(0), 'o'.charCodeAt(0), 'r'.charCodeAt(0), 't'.charCodeAt(0), ((sock.sport & 0xff00) >> 8) , (sock.sport & 0xff) @@ -3997,13 +3990,14 @@ function dbg(...args) { var handleOpen = function () { - Module['websocket'].emit('open', sock.stream.fd); + sock.connecting = false; + SOCKFS.emit('open', sock.stream.fd); try { - var queued = peer.dgram_send_queue.shift(); + var queued = peer.msg_send_queue.shift(); while (queued) { peer.socket.send(queued); - queued = peer.dgram_send_queue.shift(); + queued = peer.msg_send_queue.shift(); } } catch (e) { // not much we can do here in the way of proper error handling as we've already @@ -4043,7 +4037,7 @@ function dbg(...args) { } sock.recv_queue.push({ addr: peer.addr, port: peer.port, data: data }); - Module['websocket'].emit('message', sock.stream.fd); + SOCKFS.emit('message', sock.stream.fd); }; if (ENVIRONMENT_IS_NODE) { @@ -4055,7 +4049,7 @@ function dbg(...args) { handleMessage((new Uint8Array(data)).buffer); // copy from node Buffer -> ArrayBuffer }); peer.socket.on('close', function() { - Module['websocket'].emit('close', sock.stream.fd); + SOCKFS.emit('close', sock.stream.fd); }); peer.socket.on('error', function(error) { // Although the ws library may pass errors that may be more descriptive than @@ -4063,13 +4057,13 @@ function dbg(...args) { // ENOTFOUND on getaddrinfo seems to be node.js specific, so using ECONNREFUSED // is still probably the most useful thing to do. sock.error = 14; // Used in getsockopt for SOL_SOCKET/SO_ERROR test. - Module['websocket'].emit('error', [sock.stream.fd, sock.error, 'ECONNREFUSED: Connection refused']); + SOCKFS.emit('error', [sock.stream.fd, sock.error, 'ECONNREFUSED: Connection refused']); // don't throw }); } else { peer.socket.onopen = handleOpen; peer.socket.onclose = function() { - Module['websocket'].emit('close', sock.stream.fd); + SOCKFS.emit('close', sock.stream.fd); }; peer.socket.onmessage = function peer_socket_onmessage(event) { handleMessage(event.data); @@ -4078,7 +4072,7 @@ function dbg(...args) { // The WebSocket spec only allows a 'simple event' to be thrown on error, // so we only really know as much as ECONNREFUSED. sock.error = 14; // Used in getsockopt for SOL_SOCKET/SO_ERROR test. - Module['websocket'].emit('error', [sock.stream.fd, sock.error, 'ECONNREFUSED: Connection refused']); + SOCKFS.emit('error', [sock.stream.fd, sock.error, 'ECONNREFUSED: Connection refused']); }; } }, @@ -4108,7 +4102,15 @@ function dbg(...args) { if ((dest && dest.socket.readyState === dest.socket.CLOSING) || (dest && dest.socket.readyState === dest.socket.CLOSED)) { - mask |= 16; + // When an non-blocking connect fails mark the socket as writable. + // Its up to the calling code to then use getsockopt with SO_ERROR to + // retrieve the error. + // See https://man7.org/linux/man-pages/man2/connect.2.html + if (sock.connecting) { + mask |= 4; + } else { + mask |= 16; + } } return mask; @@ -4199,8 +4201,10 @@ function dbg(...args) { sock.daddr = peer.addr; sock.dport = peer.port; - // always "fail" in non-blocking mode - throw new FS.ErrnoError(26); + // because we cannot synchronously block to wait for the WebSocket + // connection to complete, we return here pretending that the connection + // was a success. + sock.connecting = true; }, listen(sock, backlog) { if (!ENVIRONMENT_IS_NODE) { @@ -4216,7 +4220,7 @@ function dbg(...args) { port: sock.sport // TODO support backlog }); - Module['websocket'].emit('listen', sock.stream.fd); // Send Event with listen fd. + SOCKFS.emit('listen', sock.stream.fd); // Send Event with listen fd. sock.server.on('connection', function(ws) { if (sock.type === 1) { @@ -4229,17 +4233,17 @@ function dbg(...args) { // push to queue for accept to pick up sock.pending.push(newsock); - Module['websocket'].emit('connection', newsock.stream.fd); + SOCKFS.emit('connection', newsock.stream.fd); } else { // create a peer on the listen socket so calling sendto // with the listen socket and an address will resolve // to the correct client SOCKFS.websocket_sock_ops.createPeer(sock, ws); - Module['websocket'].emit('connection', sock.stream.fd); + SOCKFS.emit('connection', sock.stream.fd); } }); sock.server.on('close', function() { - Module['websocket'].emit('close', sock.stream.fd); + SOCKFS.emit('close', sock.stream.fd); sock.server = null; }); sock.server.on('error', function(error) { @@ -4250,7 +4254,7 @@ function dbg(...args) { // occur in a well written app as errors should get trapped in the compiled // app's own getaddrinfo call. sock.error = 23; // Used in getsockopt for SOL_SOCKET/SO_ERROR test. - Module['websocket'].emit('error', [sock.stream.fd, sock.error, 'EHOSTUNREACH: Host is unreachable']); + SOCKFS.emit('error', [sock.stream.fd, sock.error, 'EHOSTUNREACH: Host is unreachable']); // don't throw }); }, @@ -4303,8 +4307,6 @@ function dbg(...args) { if (sock.type === 1) { if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) { throw new FS.ErrnoError(53); - } else if (dest.socket.readyState === dest.socket.CONNECTING) { - throw new FS.ErrnoError(6); } } @@ -4316,21 +4318,20 @@ function dbg(...args) { buffer = buffer.buffer; } - var data; - data = buffer.slice(offset, offset + length); + var data = buffer.slice(offset, offset + length); - // if we're emulating a connection-less dgram socket and don't have - // a cached connection, queue the buffer to send upon connect and - // lie, saying the data was sent now. - if (sock.type === 2) { - if (!dest || dest.socket.readyState !== dest.socket.OPEN) { - // if we're not connected, open a new connection + // if we don't have a cached connectionless UDP datagram connection, or + // the TCP socket is still connecting, queue the message to be sent upon + // connect, and lie, saying the data was sent now. + if (!dest || dest.socket.readyState !== dest.socket.OPEN) { + // if we're not connected, open a new connection + if (sock.type === 2) { if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) { dest = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port); } - dest.dgram_send_queue.push(data); - return length; } + dest.msg_send_queue.push(data); + return length; } try { @@ -4579,9 +4580,8 @@ function dbg(...args) { - var inetNtop4 = (addr) => { - return (addr & 0xff) + '.' + ((addr >> 8) & 0xff) + '.' + ((addr >> 16) & 0xff) + '.' + ((addr >> 24) & 0xff) - }; + var inetNtop4 = (addr) => + (addr & 0xff) + '.' + ((addr >> 8) & 0xff) + '.' + ((addr >> 16) & 0xff) + '.' + ((addr >> 24) & 0xff); var inetNtop6 = (ints) => { @@ -4715,9 +4715,7 @@ function dbg(...args) { }; - /** @param {boolean=} allowNull */ - var getSocketAddress = (addrp, addrlen, allowNull) => { - if (allowNull && addrp === 0) return null; + var getSocketAddress = (addrp, addrlen) => { var info = readSockaddr(addrp, addrlen); if (info.errno) throw new FS.ErrnoError(info.errno); info.addr = DNS.lookup_addr(info.addr) || info.addr; @@ -4789,7 +4787,7 @@ function dbg(...args) { try { path = SYSCALLS.getStr(path); - assert(flags === 0); + assert(flags === 0 || flags == 512); path = SYSCALLS.calculateAt(dirfd, path); if (amode & ~7) { // need a valid mode @@ -4831,13 +4829,13 @@ function dbg(...args) { } /** @suppress {duplicate } */ - function syscallGetVarargI() { + var syscallGetVarargI = () => { assert(SYSCALLS.varargs != undefined); // the `+` prepended here is necessary to convince the JSCompiler that varargs is indeed a number. var ret = HEAP32[((+SYSCALLS.varargs)>>2)]; SYSCALLS.varargs += 4; return ret; - } + }; var syscallGetVarargP = syscallGetVarargI; @@ -4961,9 +4959,9 @@ function dbg(...args) { var pos = 0; var off = FS.llseek(stream, 0, 1); - var idx = Math.floor(off / struct_size); - - while (idx < stream.getdents.length && pos + struct_size <= count) { + var startIdx = Math.floor(off / struct_size); + var endIdx = Math.min(stream.getdents.length, startIdx + Math.floor(count/struct_size)) + for (var idx = startIdx; idx < endIdx; idx++) { var id; var type; var name = stream.getdents[idx]; @@ -4977,7 +4975,17 @@ function dbg(...args) { type = 4; // DT_DIR } else { - var child = FS.lookupNode(stream.node, name); + var child; + try { + child = FS.lookupNode(stream.node, name); + } catch (e) { + // If the entry is not a directory, file, or symlink, nodefs + // lookupNode will raise EINVAL. Skip these and continue. + if (e?.errno === 28) { + continue; + } + throw e; + } id = child.id; type = FS.isChrdev(child.mode) ? 2 : // DT_CHR, character device. FS.isDir(child.mode) ? 4 : // DT_DIR, directory. @@ -4991,7 +4999,6 @@ function dbg(...args) { HEAP8[(dirp + pos)+(18)] = type; stringToUTF8(name, dirp + pos + 19, 256); pos += struct_size; - idx += 1; } FS.llseek(stream, idx * struct_size, 0); return pos; @@ -5180,10 +5187,6 @@ function dbg(...args) { path = SYSCALLS.getStr(path); path = SYSCALLS.calculateAt(dirfd, path); - // remove a trailing slash, if one - /a/b/ has basename of '', but - // we want to create b in the context of this function - path = PATH.normalize(path); - if (path[path.length-1] === '/') path = path.substr(0, path.length-1); FS.mkdir(path, mode, 0); return 0; } catch (e) { @@ -5228,7 +5231,7 @@ function dbg(...args) { mount(mount) { // Do not pollute the real root directory or its child nodes with pipes // Looks like it is OK to create another pseudo-root node not linked to the FS.root hierarchy this way - return FS.createNode(null, '/', 16384 | 511 /* 0777 */, 0); + return FS.createNode(null, '/', 16384 | 0o777, 0); }, createPipe() { var pipe = { @@ -5557,11 +5560,11 @@ function dbg(...args) { try { var sock = getSocketFromFD(fd); - var dest = getSocketAddress(addr, addr_len, true); - if (!dest) { + if (!addr) { // send, no address provided return FS.write(sock.stream, HEAP8, message, length); } + var dest = getSocketAddress(addr, addr_len); // sendto an address return sock.sock_ops.sendmsg(sock, HEAP8, message, length, dest.addr, dest.port); } catch (e) { @@ -5596,20 +5599,18 @@ function dbg(...args) { function ___syscall_statfs64(path, size, buf) { try { - path = SYSCALLS.getStr(path); assert(size === 64); - // NOTE: None of the constants here are true. We're just returning safe and - // sane values. - HEAP32[(((buf)+(4))>>2)] = 4096; - HEAP32[(((buf)+(40))>>2)] = 4096; - HEAP32[(((buf)+(8))>>2)] = 1000000; - HEAP32[(((buf)+(12))>>2)] = 500000; - HEAP32[(((buf)+(16))>>2)] = 500000; - HEAP32[(((buf)+(20))>>2)] = FS.nextInode; - HEAP32[(((buf)+(24))>>2)] = 1000000; - HEAP32[(((buf)+(28))>>2)] = 42; - HEAP32[(((buf)+(44))>>2)] = 2; // ST_NOSUID - HEAP32[(((buf)+(36))>>2)] = 255; + 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; return 0; } catch (e) { if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; @@ -5617,11 +5618,12 @@ function dbg(...args) { } } - function ___syscall_symlink(target, linkpath) { + function ___syscall_symlinkat(target, dirfd, linkpath) { try { target = SYSCALLS.getStr(target); linkpath = SYSCALLS.getStr(linkpath); + linkpath = SYSCALLS.calculateAt(dirfd, linkpath); FS.symlink(target, linkpath); return 0; } catch (e) { @@ -5659,19 +5661,36 @@ function dbg(...args) { path = SYSCALLS.getStr(path); assert(flags === 0); path = SYSCALLS.calculateAt(dirfd, path, true); + var now = Date.now(), atime, mtime; if (!times) { - var atime = Date.now(); - var mtime = atime; + atime = now; + mtime = now; } else { var seconds = readI53FromI64(times); var nanoseconds = HEAP32[(((times)+(8))>>2)]; - atime = (seconds*1000) + (nanoseconds/(1000*1000)); + if (nanoseconds == 1073741823) { + atime = now; + } else if (nanoseconds == 1073741822) { + atime = null; + } else { + atime = (seconds*1000) + (nanoseconds/(1000*1000)); + } times += 16; seconds = readI53FromI64(times); nanoseconds = HEAP32[(((times)+(8))>>2)]; - mtime = (seconds*1000) + (nanoseconds/(1000*1000)); + if (nanoseconds == 1073741823) { + mtime = now; + } else if (nanoseconds == 1073741822) { + mtime = null; + } else { + mtime = (seconds*1000) + (nanoseconds/(1000*1000)); + } + } + // null here means UTIME_OMIT was passed. If both were set to UTIME_OMIT then + // we can skip the call completely. + if ((mtime ?? atime) !== null) { + FS.utime(path, atime, mtime); } - FS.utime(path, atime, mtime); return 0; } catch (e) { if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; @@ -5679,12 +5698,8 @@ function dbg(...args) { } } - var __abort_js = () => { + var __abort_js = () => abort('native code called abort()'); - }; - - var nowIsMonotonic = 1; - var __emscripten_get_now_is_monotonic = () => nowIsMonotonic; @@ -5697,6 +5712,7 @@ function dbg(...args) { var __emscripten_memcpy_js = (dest, src, num) => HEAPU8.copyWithin(dest, src, src + num); + var runtimeKeepaliveCounter = 0; var __emscripten_runtime_keepalive_clear = () => { noExitRuntime = false; runtimeKeepaliveCounter = 0; @@ -5884,7 +5900,6 @@ function dbg(...args) { }; - var runtimeKeepaliveCounter = 0; var keepRuntimeAlive = () => noExitRuntime || runtimeKeepaliveCounter > 0; var _proc_exit = (code) => { EXITSTATUS = code; @@ -5895,6 +5910,7 @@ function dbg(...args) { quit_(code, new ExitStatus(code)); }; + /** @suppress {duplicate } */ /** @param {boolean|number=} implicit */ var exitJS = (status, implicit) => { @@ -5937,12 +5953,7 @@ function dbg(...args) { }; - var _emscripten_get_now; - // Modern environment where performance.now() is supported: - // N.B. a shorter form "_emscripten_get_now = performance.now;" is - // unfortunately not allowed even in current browsers (e.g. FF Nightly 75). - _emscripten_get_now = () => performance.now(); - ; + var _emscripten_get_now = () => performance.now(); var __setitimer_js = (which, timeout_ms) => { // First, clear any existing timer. if (timers[which]) { @@ -5989,9 +6000,20 @@ function dbg(...args) { HEAP32[((daylight)>>2)] = Number(winterOffset != summerOffset); - var extractZone = (date) => date.toLocaleTimeString(undefined, {hour12:false, timeZoneName:'short'}).split(' ')[1]; - var winterName = extractZone(winter); - var summerName = extractZone(summer); + var extractZone = (timezoneOffset) => { + // Why inverse sign? + // Read here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTimezoneOffset + var sign = timezoneOffset >= 0 ? "-" : "+"; + + var absOffset = Math.abs(timezoneOffset) + var hours = String(Math.floor(absOffset / 60)).padStart(2, "0"); + var minutes = String(absOffset % 60).padStart(2, "0"); + + return `UTC${sign}${hours}${minutes}`; + } + + var winterName = extractZone(winterOffset); + var summerName = extractZone(summerOffset); assert(winterName); assert(summerName); assert(lengthBytesUTF8(winterName) <= 16, `timezone name truncated to fit in TZNAME_MAX (${winterName})`); @@ -6006,7 +6028,36 @@ function dbg(...args) { } }; + var _emscripten_date_now = () => Date.now(); + + var nowIsMonotonic = 1; + + 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); + + + if (!checkWasiClock(clk_id)) { + return 28; + } + var now; + // all wasi clocks but realtime are monotonic + if (clk_id === 0) { + now = _emscripten_date_now(); + } else if (nowIsMonotonic) { + now = _emscripten_get_now(); + } else { + return 52; + } + // "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]); + return 0; + ; + } + var _emscripten_err = (str) => err(UTF8ToString(str)); @@ -6016,6 +6067,7 @@ function dbg(...args) { + 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`); }; @@ -6029,9 +6081,7 @@ function dbg(...args) { var ENV = { }; - var getExecutableName = () => { - return thisProgram || './this.program'; - }; + var getExecutableName = () => thisProgram || './this.program'; var getEnvStrings = () => { if (!getEnvStrings.strings) { // Default values. @@ -6205,6 +6255,10 @@ function dbg(...args) { var curr = FS.write(stream, HEAP8, ptr, len, offset); if (curr < 0) return -1; ret += curr; + if (curr < len) { + // No more space to write. + break; + } if (typeof offset != 'undefined') { offset += curr; } @@ -6343,7 +6397,7 @@ function dbg(...args) { if (family === 2) { addr = _htonl(2130706433); } else { - addr = [0, 0, 0, 1]; + addr = [0, 0, 0, _htonl(1)]; } } ai = allocaddrinfo(family, type, proto, null, addr, port); @@ -6895,7 +6949,6 @@ function dbg(...args) { 'string': (str) => { var ret = 0; if (str !== null && str !== undefined && str !== 0) { // null string - // at most 4 bytes per UTF-8 code point, +1 for the trailing '\0' ret = stringToUTF8OnStack(str); } return ret; @@ -6909,7 +6962,6 @@ function dbg(...args) { function convertReturnValue(ret) { if (returnType === 'string') { - return UTF8ToString(ret); } if (returnType === 'boolean') return Boolean(ret); @@ -6942,7 +6994,9 @@ function dbg(...args) { }; FS.createPreloadedFile = FS_createPreloadedFile; - FS.staticInit();; + FS.staticInit(); + // Set module methods based on EXPORTED_RUNTIME_METHODS + ; function checkIncomingModuleAPI() { ignoredModuleProp('fetchSettings'); } @@ -7020,7 +7074,7 @@ var wasmImports = { /** @export */ __syscall_statfs64: ___syscall_statfs64, /** @export */ - __syscall_symlink: ___syscall_symlink, + __syscall_symlinkat: ___syscall_symlinkat, /** @export */ __syscall_unlinkat: ___syscall_unlinkat, /** @export */ @@ -7028,8 +7082,6 @@ var wasmImports = { /** @export */ _abort_js: __abort_js, /** @export */ - _emscripten_get_now_is_monotonic: __emscripten_get_now_is_monotonic, - /** @export */ _emscripten_lookup_name: __emscripten_lookup_name, /** @export */ _emscripten_memcpy_js: __emscripten_memcpy_js, @@ -7052,6 +7104,8 @@ var wasmImports = { /** @export */ _tzset_js: __tzset_js, /** @export */ + clock_time_get: _clock_time_get, + /** @export */ emscripten_date_now: _emscripten_date_now, /** @export */ emscripten_err: _emscripten_err, @@ -7122,8 +7176,6 @@ var wasmImports = { /** @export */ invoke_viiiii, /** @export */ - invoke_viiiiii, - /** @export */ makecontext: _makecontext, /** @export */ posix_spawnp: _posix_spawnp, @@ -7134,7 +7186,8 @@ var wasmImports = { /** @export */ swapcontext: _swapcontext }; -var wasmExports = createWasm(); +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); @@ -7154,8 +7207,6 @@ var _emscripten_stack_get_end = () => (_emscripten_stack_get_end = wasmExports[' 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_vij = Module['dynCall_vij'] = createExportWrapper('dynCall_vij', 4); -var dynCall_ji = Module['dynCall_ji'] = createExportWrapper('dynCall_ji', 2); var dynCall_jiji = Module['dynCall_jiji'] = createExportWrapper('dynCall_jiji', 5); function invoke_iii(index,a1,a2) { @@ -7323,17 +7374,6 @@ function invoke_viidii(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,a6); - } catch(e) { - stackRestore(sp); - if (e !== e+0) throw e; - _setThrew(1, 0); - } -} - // include: postamble.js // === Auto-generated postamble setup entry stuff === @@ -7434,14 +7474,15 @@ var missingLibrarySymbols = [ 'jsStackTrace', 'getCallstack', 'convertPCtoSourceLocation', - 'checkWasiClock', 'wasiRightsToMuslOFlags', 'wasiOFlagsToMuslOFlags', - 'createDyncallWrapper', 'safeSetTimeout', 'setImmediateWrapped', + 'safeRequestAnimationFrame', 'clearImmediateWrapped', 'polyfillSetImmediate', + 'registerPostMainLoop', + 'registerPreMainLoop', 'getPromise', 'makePromise', 'idsToPromises', @@ -7449,7 +7490,6 @@ var missingLibrarySymbols = [ 'ExceptionInfo', 'findMatchingCatch', 'Browser_asyncPrepareDataCounter', - 'setMainLoop', 'FS_unlink', 'FS_mkdirTree', '_setNetworkCallback', @@ -7459,6 +7499,9 @@ var missingLibrarySymbols = [ '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', @@ -7512,14 +7555,6 @@ var unexportedSymbols = [ 'getHeapMax', 'abortOnCannotGrowMemory', 'ENV', - 'MONTH_DAYS_REGULAR', - 'MONTH_DAYS_LEAP', - 'MONTH_DAYS_REGULAR_CUMULATIVE', - 'MONTH_DAYS_LEAP_CUMULATIVE', - 'isLeapYear', - 'ydayFromDate', - 'arraySum', - 'addDays', 'ERRNO_CODES', 'strError', 'inetPton4', @@ -7531,8 +7566,6 @@ var unexportedSymbols = [ 'DNS', 'Protocols', 'Sockets', - 'initRandomFill', - 'randomFill', 'timers', 'warnOnce', 'readEmAsmArgsArray', @@ -7574,8 +7607,11 @@ var unexportedSymbols = [ 'UNWIND_CACHE', 'ExitStatus', 'getEnvStrings', + 'checkWasiClock', 'doReadv', 'doWritev', + 'initRandomFill', + 'randomFill', 'promiseMap', 'uncaughtExceptionCount', 'exceptionLast', @@ -7583,6 +7619,14 @@ var unexportedSymbols = [ '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', @@ -7645,7 +7689,7 @@ function run() { return; } - stackCheckInit(); + stackCheckInit(); preRun(); @@ -7675,10 +7719,8 @@ function run() { if (Module['setStatus']) { Module['setStatus']('Running...'); - setTimeout(function() { - setTimeout(function() { - Module['setStatus'](''); - }, 1); + setTimeout(() => { + setTimeout(() => Module['setStatus'](''), 1); doRun(); }, 1); } else @@ -7709,7 +7751,7 @@ function checkUnflushedContent() { try { // it doesn't matter if it fails _fflush(0); // also flush in the JS FS layer - ['stdout', 'stderr'].forEach(function(name) { + ['stdout', 'stderr'].forEach((name) => { var info = FS.analyzePath('/dev/' + name); if (!info) return; var stream = info.object; diff --git a/examples/compile-php-to-wasm/php-wasm.wasm b/examples/compile-php-to-wasm/php-wasm.wasm Binary files differindex d3238d0..d214beb 100755 --- a/examples/compile-php-to-wasm/php-wasm.wasm +++ b/examples/compile-php-to-wasm/php-wasm.wasm |
