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