blob: a6e6a1823aba286bf53129dc4e135ace2e1f403b [file] [log] [blame]
/**
* @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('fs');
var utils = require('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 '<function>';
} 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