Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
emscripten-core
GitHub Repository: emscripten-core/emscripten
Path: blob/main/src/runtime_debug.js
6162 views
1
/**
2
* @license
3
* Copyright 2020 The Emscripten Authors
4
* SPDX-License-Identifier: MIT
5
*/
6
7
#if ASSERTIONS || RUNTIME_DEBUG || AUTODEBUG
8
var runtimeDebug = true; // Switch to false at runtime to disable logging at the right times
9
10
// Used by XXXXX_DEBUG settings to output debug messages.
11
function dbg(...args) {
12
if (!runtimeDebug && typeof runtimeDebug != 'undefined') return;
13
#if ENVIRONMENT_MAY_BE_NODE && (PTHREADS || WASM_WORKERS)
14
// Avoid using the console for debugging in multi-threaded node applications
15
// See https://github.com/emscripten-core/emscripten/issues/14804
16
if (ENVIRONMENT_IS_NODE) {
17
// TODO(sbc): Unify with err/out implementation in shell.sh.
18
var fs = require('node:fs');
19
var utils = require('node:util');
20
function stringify(a) {
21
switch (typeof a) {
22
case 'object': return utils.inspect(a);
23
case 'undefined': return 'undefined';
24
}
25
return a;
26
}
27
fs.writeSync(2, args.map(stringify).join(' ') + '\n');
28
} else
29
#endif
30
// TODO(sbc): Make this configurable somehow. Its not always convenient for
31
// logging to show up as warnings.
32
console.warn(...args);
33
}
34
#endif
35
36
#if ASSERTIONS
37
38
#if STANDALONE_WASM && !WASM_BIGINT
39
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)');
40
#endif
41
42
// Endianness check
43
#if !SUPPORT_BIG_ENDIAN
44
(() => {
45
var h16 = new Int16Array(1);
46
var h8 = new Int8Array(h16.buffer);
47
h16[0] = 0x6373;
48
if (h8[0] !== 0x73 || h8[1] !== 0x63) abort('Runtime error: expected the system to be little-endian! (Run with -sSUPPORT_BIG_ENDIAN to bypass)');
49
})();
50
#endif
51
52
function consumedModuleProp(prop) {
53
if (!Object.getOwnPropertyDescriptor(Module, prop)) {
54
Object.defineProperty(Module, prop, {
55
configurable: true,
56
set() {
57
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'`);
58
59
}
60
});
61
}
62
}
63
64
function makeInvalidEarlyAccess(name) {
65
return () => assert(false, `call to '${name}' via reference taken before Wasm module initialization`);
66
67
}
68
69
function ignoredModuleProp(prop) {
70
if (Object.getOwnPropertyDescriptor(Module, prop)) {
71
abort(`\`Module.${prop}\` was supplied but \`${prop}\` not included in INCOMING_MODULE_JS_API`);
72
}
73
}
74
75
// forcing the filesystem exports a few things by default
76
function isExportedByForceFilesystem(name) {
77
return name === 'FS_createPath' ||
78
name === 'FS_createDataFile' ||
79
name === 'FS_createPreloadedFile' ||
80
name === 'FS_preloadFile' ||
81
name === 'FS_unlink' ||
82
name === 'addRunDependency' ||
83
#if !WASMFS
84
// The old FS has some functionality that WasmFS lacks.
85
name === 'FS_createLazyFile' ||
86
name === 'FS_createDevice' ||
87
#endif
88
name === 'removeRunDependency';
89
}
90
91
#if !MODULARIZE
92
/**
93
* Intercept access to a symbols in the global symbol. This enables us to give
94
* informative warnings/errors when folks attempt to use symbols they did not
95
* include in their build, or no symbols that no longer exist.
96
*
97
* We don't define this in MODULARIZE mode since in that mode emscripten symbols
98
* are never placed in the global scope.
99
*/
100
function hookGlobalSymbolAccess(sym, func) {
101
if (!Object.getOwnPropertyDescriptor(globalThis, sym)) {
102
Object.defineProperty(globalThis, sym, {
103
configurable: true,
104
get() {
105
func();
106
return undefined;
107
}
108
});
109
}
110
}
111
112
function missingGlobal(sym, msg) {
113
hookGlobalSymbolAccess(sym, () => {
114
warnOnce(`\`${sym}\` is no longer defined by emscripten. ${msg}`);
115
});
116
}
117
118
missingGlobal('buffer', 'Please use HEAP8.buffer or wasmMemory.buffer');
119
missingGlobal('asm', 'Please use wasmExports instead');
120
#endif
121
122
function missingLibrarySymbol(sym) {
123
#if !MODULARIZE
124
hookGlobalSymbolAccess(sym, () => {
125
// Can't `abort()` here because it would break code that does runtime
126
// checks. e.g. `if (typeof SDL === 'undefined')`.
127
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`;
128
// DEFAULT_LIBRARY_FUNCS_TO_INCLUDE requires the name as it appears in
129
// library.js, which means $name for a JS name with no prefix, or name
130
// for a JS name like _name.
131
var librarySymbol = sym;
132
if (!librarySymbol.startsWith('_')) {
133
librarySymbol = '$' + sym;
134
}
135
msg += ` (e.g. -sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE='${librarySymbol}')`;
136
if (isExportedByForceFilesystem(sym)) {
137
msg += '. Alternatively, forcing filesystem support (-sFORCE_FILESYSTEM) can export this for you';
138
}
139
warnOnce(msg);
140
});
141
#endif
142
143
// Any symbol that is not included from the JS library is also (by definition)
144
// not exported on the Module object.
145
unexportedRuntimeSymbol(sym);
146
}
147
148
function unexportedRuntimeSymbol(sym) {
149
#if PTHREADS
150
if (ENVIRONMENT_IS_PTHREAD) {
151
return;
152
}
153
#endif
154
if (!Object.getOwnPropertyDescriptor(Module, sym)) {
155
Object.defineProperty(Module, sym, {
156
configurable: true,
157
get() {
158
var msg = `'${sym}' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the Emscripten FAQ)`;
159
if (isExportedByForceFilesystem(sym)) {
160
msg += '. Alternatively, forcing filesystem support (-sFORCE_FILESYSTEM) can export this for you';
161
}
162
abort(msg);
163
},
164
#if !DECLARE_ASM_MODULE_EXPORTS
165
// !DECLARE_ASM_MODULE_EXPORTS programmatically exports all wasm symbols
166
// on the Module object. Ignore these attempts to set the properties
167
// here.
168
set(value) {}
169
#endif
170
});
171
}
172
}
173
174
#if WASM_WORKERS || PTHREADS
175
/**
176
* Override `err`/`out`/`dbg` to report thread / worker information
177
*/
178
function initWorkerLogging() {
179
function getLogPrefix() {
180
#if WASM_WORKERS
181
if (wwParams?.wwID) {
182
return `ww:${wwParams?.wwID}:`
183
}
184
#endif
185
#if PTHREADS
186
var t = 0;
187
if (runtimeInitialized && typeof _pthread_self != 'undefined'
188
#if EXIT_RUNTIME
189
&& !runtimeExited
190
#endif
191
) {
192
t = _pthread_self();
193
}
194
return `w:${workerID},t:${ptrToString(t)}:`;
195
#else
196
return `ww:0:`;
197
#endif
198
}
199
200
// Prefix all dbg() messages with the calling thread info.
201
var origDbg = dbg;
202
dbg = (...args) => origDbg(getLogPrefix(), ...args);
203
#if RUNTIME_DEBUG
204
// With RUNTIME_DEBUG also prefix all err() messages.
205
var origErr = err;
206
err = (...args) => origErr(getLogPrefix(), ...args);
207
#endif
208
}
209
210
initWorkerLogging();
211
#endif
212
213
#if ASSERTIONS == 2
214
215
var MAX_UINT8 = (2 ** 8) - 1;
216
var MAX_UINT16 = (2 ** 16) - 1;
217
var MAX_UINT32 = (2 ** 32) - 1;
218
var MAX_UINT53 = (2 ** 53) - 1;
219
var MAX_UINT64 = (2 ** 64) - 1;
220
221
var MIN_INT8 = - (2 ** ( 8 - 1));
222
var MIN_INT16 = - (2 ** (16 - 1));
223
var MIN_INT32 = - (2 ** (32 - 1));
224
var MIN_INT53 = - (2 ** (53 - 1));
225
var MIN_INT64 = - (2 ** (64 - 1));
226
227
function checkInt(value, bits, min, max) {
228
assert(Number.isInteger(Number(value)), `attempt to write non-integer (${value}) into integer heap`);
229
assert(value <= max, `value (${value}) too large to write as ${bits}-bit value`);
230
assert(value >= min, `value (${value}) too small to write as ${bits}-bit value`);
231
}
232
233
var checkInt1 = (value) => checkInt(value, 1, 1);
234
var checkInt8 = (value) => checkInt(value, 8, MIN_INT8, MAX_UINT8);
235
var checkInt16 = (value) => checkInt(value, 16, MIN_INT16, MAX_UINT16);
236
var checkInt32 = (value) => checkInt(value, 32, MIN_INT32, MAX_UINT32);
237
var checkInt53 = (value) => checkInt(value, 53, MIN_INT53, MAX_UINT53);
238
var checkInt64 = (value) => checkInt(value, 64, MIN_INT64, MAX_UINT64);
239
240
#endif // ASSERTIONS == 2
241
242
#endif // ASSERTIONS
243
244
#if RUNTIME_DEBUG
245
var printObjectList = [];
246
247
function prettyPrint(arg) {
248
if (typeof arg == 'undefined') return 'undefined';
249
if (typeof arg == 'boolean') arg = arg + 0;
250
if (!arg) return arg;
251
var index = printObjectList.indexOf(arg);
252
if (index >= 0) return '<' + arg + '|' + index + '>';
253
if (arg.toString() == '[object HTMLImageElement]') {
254
return arg + '\n\n';
255
}
256
if (arg.byteLength) {
257
return '{' + Array.prototype.slice.call(arg, 0, Math.min(arg.length, 400)) + '}';
258
}
259
if (typeof arg == 'function') {
260
return '<function>';
261
} else if (typeof arg == 'object') {
262
printObjectList.push(arg);
263
return '<' + arg + '|' + (printObjectList.length-1) + '>';
264
} else if (typeof arg == 'number') {
265
if (arg > 0) return ptrToString(arg) + ' (' + arg + ')';
266
}
267
return arg;
268
}
269
#endif
270
271