/** * @license * Copyright 2020 The Emscripten Authors * SPDX-License-Identifier: MIT */ #if ASSERTIONS || RUNTIME_DEBUG || AUTODEBUG var runtimeDebug = true; // Switch to false at runtime to disable logging at the right times // Used by XXXXX_DEBUG settings to output debug messages. function dbg(...args) { if (!runtimeDebug && typeof runtimeDebug != 'undefined') return; #if ENVIRONMENT_MAY_BE_NODE && (PTHREADS || WASM_WORKERS) // Avoid using the console for debugging in multi-threaded node applications // See https://github.com/emscripten-core/emscripten/issues/14804 if (ENVIRONMENT_IS_NODE) { // TODO(sbc): Unify with err/out implementation in shell.sh. var fs = require('node:fs'); var utils = require('node:util'); function stringify(a) { switch (typeof a) { case 'object': return utils.inspect(a); case 'undefined': return 'undefined'; } return a; } fs.writeSync(2, args.map(stringify).join(' ') + '\n'); } else #endif // TODO(sbc): Make this configurable somehow. Its not always convenient for // logging to show up as warnings. console.warn(...args); } #endif #if ASSERTIONS #if STANDALONE_WASM && !WASM_BIGINT err('warning: running JS from STANDALONE_WASM without WASM_BIGINT will fail if a syscall with i64 is used (in standalone mode we cannot legalize syscalls)'); #endif // Endianness check #if !SUPPORT_BIG_ENDIAN (() => { 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)'); })(); #endif 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'`); } }); } } function makeInvalidEarlyAccess(name) { return () => assert(false, `call to '${name}' via reference taken before Wasm module initialization`); } 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_preloadFile' || name === 'FS_unlink' || name === 'addRunDependency' || #if !WASMFS // The old FS has some functionality that WasmFS lacks. name === 'FS_createLazyFile' || name === 'FS_createDevice' || #endif name === 'removeRunDependency'; } #if !MODULARIZE /** * Intercept access to a symbols in the 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. * * We don't define this in MODULARIZE mode since in that mode emscripten symbols * are never placed in the global scope. */ function hookGlobalSymbolAccess(sym, func) { if (!Object.getOwnPropertyDescriptor(globalThis, sym)) { Object.defineProperty(globalThis, sym, { configurable: true, get() { func(); return undefined; } }); } } function missingGlobal(sym, msg) { hookGlobalSymbolAccess(sym, () => { warnOnce(`\`${sym}\` is no longer defined by emscripten. ${msg}`); }); } missingGlobal('buffer', 'Please use HEAP8.buffer or wasmMemory.buffer'); missingGlobal('asm', 'Please use wasmExports instead'); #endif function missingLibrarySymbol(sym) { #if !MODULARIZE 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); }); #endif // 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 PTHREADS if (ENVIRONMENT_IS_PTHREAD) { return; } #endif 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); }, #if !DECLARE_ASM_MODULE_EXPORTS // !DECLARE_ASM_MODULE_EXPORTS programmatically exports all wasm symbols // on the Module object. Ignore these attempts to set the properties // here. set(value) {} #endif }); } } #if WASM_WORKERS || PTHREADS /** * Override `err`/`out`/`dbg` to report thread / worker information */ function initWorkerLogging() { function getLogPrefix() { #if WASM_WORKERS if (wwParams?.wwID) { return `ww:${wwParams?.wwID}:` } #endif #if PTHREADS var t = 0; if (runtimeInitialized && typeof _pthread_self != 'undefined' #if EXIT_RUNTIME && !runtimeExited #endif ) { t = _pthread_self(); } return `w:${workerID},t:${ptrToString(t)}:`; #else return `ww:0:`; #endif } // Prefix all dbg() messages with the calling thread info. var origDbg = dbg; dbg = (...args) => origDbg(getLogPrefix(), ...args); #if RUNTIME_DEBUG // With RUNTIME_DEBUG also prefix all err() messages. var origErr = err; err = (...args) => origErr(getLogPrefix(), ...args); #endif } initWorkerLogging(); #endif #if ASSERTIONS == 2 var MAX_UINT8 = (2 ** 8) - 1; var MAX_UINT16 = (2 ** 16) - 1; var MAX_UINT32 = (2 ** 32) - 1; var MAX_UINT53 = (2 ** 53) - 1; var MAX_UINT64 = (2 ** 64) - 1; var MIN_INT8 = - (2 ** ( 8 - 1)); var MIN_INT16 = - (2 ** (16 - 1)); var MIN_INT32 = - (2 ** (32 - 1)); var MIN_INT53 = - (2 ** (53 - 1)); var MIN_INT64 = - (2 ** (64 - 1)); function checkInt(value, bits, min, max) { assert(Number.isInteger(Number(value)), `attempt to write non-integer (${value}) into integer heap`); assert(value <= max, `value (${value}) too large to write as ${bits}-bit value`); assert(value >= min, `value (${value}) too small to write as ${bits}-bit value`); } var checkInt1 = (value) => checkInt(value, 1, 1); var checkInt8 = (value) => checkInt(value, 8, MIN_INT8, MAX_UINT8); var checkInt16 = (value) => checkInt(value, 16, MIN_INT16, MAX_UINT16); var checkInt32 = (value) => checkInt(value, 32, MIN_INT32, MAX_UINT32); var checkInt53 = (value) => checkInt(value, 53, MIN_INT53, MAX_UINT53); var checkInt64 = (value) => checkInt(value, 64, MIN_INT64, MAX_UINT64); #endif // ASSERTIONS == 2 #endif // ASSERTIONS #if RUNTIME_DEBUG var printObjectList = []; function prettyPrint(arg) { if (typeof arg == 'undefined') return 'undefined'; if (typeof arg == 'boolean') arg = arg + 0; if (!arg) return arg; var index = printObjectList.indexOf(arg); if (index >= 0) return `<${arg}|${index}>`; if (arg.toString() == '[object HTMLImageElement]') { return arg + '\n\n'; } if (arg.byteLength) { return '{' + Array.prototype.slice.call(arg, 0, Math.min(arg.length, 400)) + '}'; } if (typeof arg == 'function') { return ''; } else if (typeof arg == 'object') { printObjectList.push(arg); return `<${arg}|${printObjectList.length-1}>`; } else if (typeof arg == 'number') { if (arg > 0) return `${ptrToString(arg)} (${arg})`; } return arg; } #endif