Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
emscripten-core
GitHub Repository: emscripten-core/emscripten
Path: blob/main/src/lib/libcore.js
6162 views
1
/**
2
* @license
3
* Copyright 2010 The Emscripten Authors
4
* SPDX-License-Identifier: MIT
5
*/
6
7
//"use strict";
8
9
// An implementation of basic necessary libraries for the web. This integrates
10
// with a compiled libc and with the rest of the JS runtime.
11
//
12
// We search the Library object when there is an external function. If the
13
// entry in the Library is a function, we insert it. If it is a string, we
14
// do another lookup in the library (a simple way to write a function once,
15
// if it can be called by different names). We also allow dependencies,
16
// using __deps. Initialization code to be run after allocating all
17
// global constants can be defined by __postset.
18
//
19
// Note that the full function name will be '_' + the name in the Library
20
// object. For convenience, the short name appears here. Note that if you add a
21
// new function with an '_', it will not be found.
22
23
addToLibrary({
24
// JS aliases for native stack manipulation functions and tempret handling
25
$stackSave__deps: ['emscripten_stack_get_current'],
26
$stackSave: () => _emscripten_stack_get_current(),
27
$stackRestore__deps: ['_emscripten_stack_restore'],
28
$stackRestore: (val) => __emscripten_stack_restore(val),
29
$stackAlloc__deps: ['_emscripten_stack_alloc'],
30
$stackAlloc: (sz) => __emscripten_stack_alloc(sz),
31
$getTempRet0__deps: ['_emscripten_tempret_get'],
32
$getTempRet0: (val) => __emscripten_tempret_get(),
33
$setTempRet0__deps: ['_emscripten_tempret_set'],
34
$setTempRet0: (val) => __emscripten_tempret_set(val),
35
36
// Aliases that allow legacy names (without leading $) for the
37
// functions to continue to work in `__deps` entries.
38
stackAlloc: '$stackAlloc',
39
stackSave: '$stackSave',
40
stackRestore: '$stackSave',
41
setTempRet0: '$setTempRet0',
42
getTempRet0: '$getTempRet0',
43
44
// Assign a name to a given function. This is mostly useful for debugging
45
// purposes in cases where new functions are created at runtime.
46
$createNamedFunction: (name, func) => Object.defineProperty(func, 'name', { value: name }),
47
48
$ptrToString: (ptr) => {
49
#if ASSERTIONS
50
assert(typeof ptr === 'number', `ptrToString expects a number, got ${typeof ptr}`);
51
#endif
52
#if MEMORY64
53
// Convert to 64-bit unsigned value. We need to use BigInt here since
54
// Number cannot represent the full 64-bit range.
55
if (ptr < 0) ptr = 2n**64n + BigInt(ptr);
56
#else
57
// Convert to 32-bit unsigned value
58
ptr >>>= 0;
59
#endif
60
return '0x' + ptr.toString(16).padStart({{{ POINTER_SIZE * 2 }}}, '0');
61
},
62
63
$zeroMemory: (ptr, size) => HEAPU8.fill(0, ptr, ptr + size),
64
65
#if SAFE_HEAP
66
// Trivial wrappers around runtime functions that make these symbols available
67
// to native code.
68
segfault: '=segfault',
69
alignfault: '=alignfault',
70
#endif
71
72
// ==========================================================================
73
// JavaScript <-> C string interop
74
// ==========================================================================
75
76
#if !MINIMAL_RUNTIME
77
$exitJS__docs: '/** @param {boolean|number=} implicit */',
78
$exitJS__deps: [
79
'proc_exit',
80
#if ASSERTIONS || EXIT_RUNTIME
81
'$keepRuntimeAlive',
82
#endif
83
#if PTHREADS
84
'$exitOnMainThread',
85
#endif
86
#if PTHREADS_DEBUG || ASSERTIONS
87
'$runtimeKeepaliveCounter',
88
#endif
89
],
90
$exitJS: (status, implicit) => {
91
EXITSTATUS = status;
92
93
#if ASSERTIONS && !EXIT_RUNTIME
94
checkUnflushedContent();
95
#endif // ASSERTIONS && !EXIT_RUNTIME
96
97
#if PTHREADS
98
if (ENVIRONMENT_IS_PTHREAD) {
99
// implicit exit can never happen on a pthread
100
#if ASSERTIONS
101
assert(!implicit);
102
#endif
103
#if PTHREADS_DEBUG
104
dbg(`Pthread ${ptrToString(_pthread_self())} called exit(${status}), posting exitOnMainThread.`);
105
#endif
106
// When running in a pthread we propagate the exit back to the main thread
107
// where it can decide if the whole process should be shut down or not.
108
// The pthread may have decided not to exit its own runtime, for example
109
// because it runs a main loop, but that doesn't affect the main thread.
110
exitOnMainThread(status);
111
throw 'unwind';
112
}
113
#if PTHREADS_DEBUG
114
err(`main thread called exit(${status}): keepRuntimeAlive=${keepRuntimeAlive()} (counter=${runtimeKeepaliveCounter})`);
115
#endif // PTHREADS_DEBUG
116
#endif // PTHREADS
117
118
#if EXIT_RUNTIME
119
if (!keepRuntimeAlive()) {
120
exitRuntime();
121
}
122
#endif
123
124
#if ASSERTIONS
125
// if exit() was called explicitly, warn the user if the runtime isn't actually being shut down
126
if (keepRuntimeAlive() && !implicit) {
127
var msg = `program exited (with status: ${status}), but keepRuntimeAlive() is set (counter=${runtimeKeepaliveCounter}) due to an async operation, so halting execution but not exiting the runtime or preventing further async execution (you can use emscripten_force_exit, if you want to force a true shutdown)`;
128
#if MODULARIZE
129
readyPromiseReject?.(msg);
130
#endif // MODULARIZE
131
err(msg);
132
}
133
#endif // ASSERTIONS
134
135
_proc_exit(status);
136
},
137
#endif
138
139
#if MINIMAL_RUNTIME
140
// minimal runtime doesn't do any exit cleanup handling so just
141
// map exit directly to the lower-level proc_exit syscall.
142
exit: 'proc_exit',
143
#else
144
exit: '$exitJS',
145
#endif
146
147
// Returns a pointer ('p'), which means an i32 on wasm32 and an i64 wasm64
148
// We have a separate JS version `getHeapMax()` which can be called directly
149
// avoiding any wrapper added for wasm64.
150
emscripten_get_heap_max__deps: ['$getHeapMax'],
151
emscripten_get_heap_max: () => getHeapMax(),
152
153
$getHeapMax: () =>
154
#if ALLOW_MEMORY_GROWTH
155
#if MEMORY64 == 1
156
{{{ MAXIMUM_MEMORY }}},
157
#else
158
// Stay one Wasm page short of 4GB: while e.g. Chrome is able to allocate
159
// full 4GB Wasm memories, the size will wrap back to 0 bytes in Wasm side
160
// for any code that deals with heap sizes, which would require special
161
// casing all heap size related code to treat 0 specially.
162
{{{ Math.min(MAXIMUM_MEMORY, FOUR_GB - WASM_PAGE_SIZE) }}},
163
#endif
164
#else // no growth
165
HEAPU8.length,
166
#endif
167
168
#if ABORTING_MALLOC
169
$abortOnCannotGrowMemory: (requestedSize) => {
170
#if ASSERTIONS
171
#if ALLOW_MEMORY_GROWTH
172
abort(`Cannot enlarge memory arrays to size ${requestedSize} bytes (OOM). If you want malloc to return NULL (0) instead of this abort, do not link with -sABORTING_MALLOC (that is, the default when growth is enabled is to not abort, but you have overridden that)`);
173
#else // ALLOW_MEMORY_GROWTH
174
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`);
175
#endif // ALLOW_MEMORY_GROWTH
176
#else // ASSERTIONS
177
abort('OOM');
178
#endif // ASSERTIONS
179
},
180
#endif // ABORTING_MALLOC
181
182
// Grows the wasm memory to the given byte size, and updates the JS views to
183
// it. Returns 1 on success, 0 on error.
184
$growMemory: (size) => {
185
var oldHeapSize = wasmMemory.buffer.byteLength;
186
var pages = ((size - oldHeapSize + {{{ WASM_PAGE_SIZE - 1 }}}) / {{{ WASM_PAGE_SIZE }}}) | 0;
187
#if RUNTIME_DEBUG
188
dbg(`growMemory: ${size} (+${size - oldHeapSize} bytes / ${pages} pages)`);
189
#endif
190
try {
191
// round size grow request up to wasm page size (fixed 64KB per spec)
192
wasmMemory.grow({{{ toIndexType('pages') }}}); // .grow() takes a delta compared to the previous size
193
#if !GROWABLE_ARRAYBUFFERS
194
updateMemoryViews();
195
#endif
196
#if MEMORYPROFILER
197
if (typeof emscriptenMemoryProfiler != 'undefined') {
198
emscriptenMemoryProfiler.onMemoryResize(oldHeapSize, wasmMemory.buffer.byteLength);
199
}
200
#endif
201
return 1 /*success*/;
202
} catch(e) {
203
#if ASSERTIONS
204
err(`growMemory: Attempted to grow heap from ${oldHeapSize} bytes to ${size} bytes, but got error: ${e}`);
205
#endif
206
}
207
// implicit 0 return to save code size (caller will cast "undefined" into 0
208
// anyhow)
209
},
210
211
emscripten_resize_heap__deps: [
212
#if ABORTING_MALLOC
213
'$abortOnCannotGrowMemory',
214
#endif
215
#if ALLOW_MEMORY_GROWTH
216
#if ASSERTIONS == 2
217
'emscripten_get_now',
218
#endif
219
'$getHeapMax',
220
'$alignMemory',
221
'$growMemory',
222
#endif
223
],
224
emscripten_resize_heap: 'ip',
225
emscripten_resize_heap: (requestedSize) => {
226
var oldSize = HEAPU8.length;
227
#if !MEMORY64 && !CAN_ADDRESS_2GB
228
// With CAN_ADDRESS_2GB or MEMORY64, pointers are already unsigned.
229
requestedSize >>>= 0;
230
#endif
231
#if ALLOW_MEMORY_GROWTH == 0
232
#if ABORTING_MALLOC
233
abortOnCannotGrowMemory(requestedSize);
234
#else
235
return false; // malloc will report failure
236
#endif // ABORTING_MALLOC
237
#else // ALLOW_MEMORY_GROWTH == 0
238
// With multithreaded builds, races can happen (another thread might increase the size
239
// in between), so return a failure, and let the caller retry.
240
#if SHARED_MEMORY
241
if (requestedSize <= oldSize) {
242
return false;
243
}
244
#elif ASSERTIONS
245
assert(requestedSize > oldSize);
246
#endif
247
248
#if EMSCRIPTEN_TRACING
249
// Report old layout one last time
250
_emscripten_trace_report_memory_layout();
251
#endif
252
253
// Memory resize rules:
254
// 1. Always increase heap size to at least the requested size, rounded up
255
// to next page multiple.
256
// 2a. If MEMORY_GROWTH_LINEAR_STEP == -1, excessively resize the heap
257
// geometrically: increase the heap size according to
258
// MEMORY_GROWTH_GEOMETRIC_STEP factor (default +20%), At most
259
// overreserve by MEMORY_GROWTH_GEOMETRIC_CAP bytes (default 96MB).
260
// 2b. If MEMORY_GROWTH_LINEAR_STEP != -1, excessively resize the heap
261
// linearly: increase the heap size by at least
262
// MEMORY_GROWTH_LINEAR_STEP bytes.
263
// 3. Max size for the heap is capped at 2048MB-WASM_PAGE_SIZE, or by
264
// MAXIMUM_MEMORY, or by ASAN limit, depending on which is smallest
265
// 4. If we were unable to allocate as much memory, it may be due to
266
// over-eager decision to excessively reserve due to (3) above.
267
// Hence if an allocation fails, cut down on the amount of excess
268
// growth, in an attempt to succeed to perform a smaller allocation.
269
270
// A limit is set for how much we can grow. We should not exceed that
271
// (the wasm binary specifies it, so if we tried, we'd fail anyhow).
272
var maxHeapSize = getHeapMax();
273
if (requestedSize > maxHeapSize) {
274
#if ASSERTIONS
275
err(`Cannot enlarge memory, requested ${requestedSize} bytes, but the limit is ${maxHeapSize} bytes!`);
276
#endif
277
#if ABORTING_MALLOC
278
abortOnCannotGrowMemory(requestedSize);
279
#else
280
return false;
281
#endif
282
}
283
284
// Loop through potential heap size increases. If we attempt a too eager
285
// reservation that fails, cut down on the attempted size and reserve a
286
// smaller bump instead. (max 3 times, chosen somewhat arbitrarily)
287
for (var cutDown = 1; cutDown <= 4; cutDown *= 2) {
288
#if MEMORY_GROWTH_LINEAR_STEP == -1
289
var overGrownHeapSize = oldSize * (1 + {{{ MEMORY_GROWTH_GEOMETRIC_STEP }}} / cutDown); // ensure geometric growth
290
#if MEMORY_GROWTH_GEOMETRIC_CAP
291
// but limit overreserving (default to capping at +96MB overgrowth at most)
292
overGrownHeapSize = Math.min(overGrownHeapSize, requestedSize + {{{ MEMORY_GROWTH_GEOMETRIC_CAP }}} );
293
#endif
294
295
#else
296
var overGrownHeapSize = oldSize + {{{ MEMORY_GROWTH_LINEAR_STEP }}} / cutDown; // ensure linear growth
297
#endif
298
299
var newSize = Math.min(maxHeapSize, alignMemory(Math.max(requestedSize, overGrownHeapSize), {{{ WASM_PAGE_SIZE }}}));
300
301
#if ASSERTIONS == 2
302
var t0 = _emscripten_get_now();
303
#endif
304
var replacement = growMemory(newSize);
305
#if ASSERTIONS == 2
306
var t1 = _emscripten_get_now();
307
dbg(`Heap resize call from ${oldSize} to ${newSize} took ${(t1 - t0)} msecs. Success: ${!!replacement}`);
308
#endif
309
if (replacement) {
310
#if ASSERTIONS && WASM2JS
311
err('Warning: Enlarging memory arrays, this is not fast! ' + [oldSize, newSize]);
312
#endif
313
314
#if EMSCRIPTEN_TRACING
315
traceLogMessage("Emscripten", `Enlarging memory arrays from ${oldSize} to ${newSize}`);
316
// And now report the new layout
317
_emscripten_trace_report_memory_layout();
318
#endif
319
return true;
320
}
321
}
322
#if ASSERTIONS
323
err(`Failed to grow the heap from ${oldSize} bytes to ${newSize} bytes, not enough memory!`);
324
#endif
325
#if ABORTING_MALLOC
326
abortOnCannotGrowMemory(requestedSize);
327
#else
328
return false;
329
#endif
330
#endif // ALLOW_MEMORY_GROWTH
331
},
332
333
#if !GROWABLE_ARRAYBUFFERS
334
// Called after wasm grows memory. At that time we need to update the views.
335
// Without this notification, we'd need to check the buffer in JS every time
336
// we return from any wasm, which adds overhead. See
337
// https://github.com/WebAssembly/WASI/issues/82
338
emscripten_notify_memory_growth: (memoryIndex) => {
339
#if ASSERTIONS
340
assert(memoryIndex == 0);
341
#endif
342
updateMemoryViews();
343
},
344
#endif
345
346
_emscripten_system: (command) => {
347
#if ENVIRONMENT_MAY_BE_NODE
348
if (ENVIRONMENT_IS_NODE) {
349
if (!command) return 1; // shell is available
350
351
var cmdstr = UTF8ToString(command);
352
if (!cmdstr.length) return 0; // this is what glibc seems to do (shell works test?)
353
354
var cp = require('node:child_process');
355
var ret = cp.spawnSync(cmdstr, [], {shell:true, stdio:'inherit'});
356
357
var _W_EXITCODE = (ret, sig) => ((ret) << 8 | (sig));
358
359
// this really only can happen if process is killed by signal
360
if (ret.status === null) {
361
// sadly node doesn't expose such function
362
var signalToNumber = (sig) => {
363
// implement only the most common ones, and fallback to SIGINT
364
switch (sig) {
365
case 'SIGHUP': return {{{ cDefs.SIGHUP }}};
366
case 'SIGQUIT': return {{{ cDefs.SIGQUIT }}};
367
case 'SIGFPE': return {{{ cDefs.SIGFPE }}};
368
case 'SIGKILL': return {{{ cDefs.SIGKILL }}};
369
case 'SIGALRM': return {{{ cDefs.SIGALRM }}};
370
case 'SIGTERM': return {{{ cDefs.SIGTERM }}};
371
default: return {{{ cDefs.SIGINT }}};
372
}
373
}
374
return _W_EXITCODE(0, signalToNumber(ret.signal));
375
}
376
377
return _W_EXITCODE(ret.status, 0);
378
}
379
#endif // ENVIRONMENT_MAY_BE_NODE
380
// int system(const char *command);
381
// http://pubs.opengroup.org/onlinepubs/000095399/functions/system.html
382
// Can't call external programs.
383
if (!command) return 0; // no shell available
384
return -{{{ cDefs.ENOSYS }}};
385
},
386
387
// ==========================================================================
388
// stdlib.h
389
// ==========================================================================
390
391
#if !STANDALONE_WASM
392
// Used to implement the native `abort` symbol. Note that we use the
393
// JavaScript `abort` helper in order to implement this function, but we use a
394
// distinct name here to avoid confusing the two.
395
_abort_js: () =>
396
#if ASSERTIONS
397
abort('native code called abort()'),
398
#else
399
abort(''),
400
#endif
401
#endif
402
403
// This object can be modified by the user during startup, which affects
404
// the initial values of the environment accessible by getenv.
405
$ENV: {},
406
407
#if !STANDALONE_WASM
408
// ==========================================================================
409
// assert.h
410
// ==========================================================================
411
412
__assert_fail: (condition, filename, line, func) =>
413
abort(`Assertion failed: ${UTF8ToString(condition)}, at: ` + [filename ? UTF8ToString(filename) : 'unknown filename', line, func ? UTF8ToString(func) : 'unknown function']),
414
#endif
415
416
#if STACK_OVERFLOW_CHECK >= 2
417
// Set stack limits used by binaryen's `StackCheck` pass.
418
#if MAIN_MODULE
419
$setStackLimits__deps: ['$setDylinkStackLimits'],
420
#endif
421
$setStackLimits: () => {
422
var stackLow = _emscripten_stack_get_base();
423
var stackHigh = _emscripten_stack_get_end();
424
#if RUNTIME_DEBUG
425
dbg(`setStackLimits: ${ptrToString(stackLow)}, ${ptrToString(stackHigh)}`);
426
#endif
427
#if MAIN_MODULE
428
// With dynamic linking we could have any number of pre-loaded libraries
429
// that each need to have their stack limits set.
430
setDylinkStackLimits(stackLow, stackHigh);
431
#else
432
___set_stack_limits(stackLow, stackHigh);
433
#endif
434
},
435
#endif
436
437
$withStackSave__deps: ['$stackSave', '$stackRestore'],
438
$withStackSave: (f) => {
439
var stack = stackSave();
440
var ret = f();
441
stackRestore(stack);
442
return ret;
443
},
444
445
// ==========================================================================
446
// setjmp.h
447
// ==========================================================================
448
449
#if SUPPORT_LONGJMP == 'emscripten'
450
// In WebAssemblyLowerEmscriptenEHSjLj pass in the LLVM backend, function
451
// calls that exist in the same function with setjmp are converted to a code
452
// sequence that includes invokes, malloc, free, saveSetjmp, and
453
// emscripten_longjmp. setThrew is called from invokes, but we don't have
454
// any way to express that dependency so we use emscripten_throw_longjmp as
455
// a proxy and declare the dependency here.
456
_emscripten_throw_longjmp__deps: ['setThrew'],
457
_emscripten_throw_longjmp: () => {
458
#if EXCEPTION_STACK_TRACES
459
throw new EmscriptenSjLj;
460
#else
461
throw Infinity;
462
#endif
463
},
464
#elif !SUPPORT_LONGJMP
465
#if !INCLUDE_FULL_LIBRARY
466
// These are in order to print helpful error messages when either longjmp or
467
// setjmp is used.
468
longjmp__deps: [() => {
469
error('longjmp support was disabled (SUPPORT_LONGJMP=0), but it is required by the code (either set SUPPORT_LONGJMP=1, or remove uses of it in the project)');
470
}],
471
get setjmp__deps() {
472
return this.longjmp__deps;
473
},
474
// This is to print the correct error message when a program is built with
475
// SUPPORT_LONGJMP=1 but linked with SUPPORT_LONGJMP=0. When a program is
476
// built with SUPPORT_LONGJMP=1, the object file contains references of not
477
// longjmp but _emscripten_throw_longjmp, which is called from
478
// emscripten_longjmp.
479
get _emscripten_throw_longjmp__deps() {
480
return this.longjmp__deps;
481
},
482
#endif
483
_emscripten_throw_longjmp: () => {
484
error('longjmp support was disabled (SUPPORT_LONGJMP=0), but it is required by the code (either set SUPPORT_LONGJMP=1, or remove uses of it in the project)');
485
},
486
// will never be emitted, as the dep errors at compile time
487
longjmp: (env, value) => {
488
abort('longjmp not supported (build with -s SUPPORT_LONGJMP)');
489
},
490
setjmp: (env) => {
491
abort('setjmp not supported (build with -s SUPPORT_LONGJMP)');
492
},
493
#endif
494
495
// ==========================================================================
496
// errno.h
497
// ==========================================================================
498
499
// We use a string literal here to avoid the string quotes on the object
500
// keys being removed when processed by jsifier.
501
$ERRNO_CODES: `{
502
'EPERM': {{{ cDefs.EPERM }}},
503
'ENOENT': {{{ cDefs.ENOENT }}},
504
'ESRCH': {{{ cDefs.ESRCH }}},
505
'EINTR': {{{ cDefs.EINTR }}},
506
'EIO': {{{ cDefs.EIO }}},
507
'ENXIO': {{{ cDefs.ENXIO }}},
508
'E2BIG': {{{ cDefs.E2BIG }}},
509
'ENOEXEC': {{{ cDefs.ENOEXEC }}},
510
'EBADF': {{{ cDefs.EBADF }}},
511
'ECHILD': {{{ cDefs.ECHILD }}},
512
'EAGAIN': {{{ cDefs.EAGAIN }}},
513
'EWOULDBLOCK': {{{ cDefs.EWOULDBLOCK }}},
514
'ENOMEM': {{{ cDefs.ENOMEM }}},
515
'EACCES': {{{ cDefs.EACCES }}},
516
'EFAULT': {{{ cDefs.EFAULT }}},
517
'ENOTBLK': {{{ cDefs.ENOTBLK }}},
518
'EBUSY': {{{ cDefs.EBUSY }}},
519
'EEXIST': {{{ cDefs.EEXIST }}},
520
'EXDEV': {{{ cDefs.EXDEV }}},
521
'ENODEV': {{{ cDefs.ENODEV }}},
522
'ENOTDIR': {{{ cDefs.ENOTDIR }}},
523
'EISDIR': {{{ cDefs.EISDIR }}},
524
'EINVAL': {{{ cDefs.EINVAL }}},
525
'ENFILE': {{{ cDefs.ENFILE }}},
526
'EMFILE': {{{ cDefs.EMFILE }}},
527
'ENOTTY': {{{ cDefs.ENOTTY }}},
528
'ETXTBSY': {{{ cDefs.ETXTBSY }}},
529
'EFBIG': {{{ cDefs.EFBIG }}},
530
'ENOSPC': {{{ cDefs.ENOSPC }}},
531
'ESPIPE': {{{ cDefs.ESPIPE }}},
532
'EROFS': {{{ cDefs.EROFS }}},
533
'EMLINK': {{{ cDefs.EMLINK }}},
534
'EPIPE': {{{ cDefs.EPIPE }}},
535
'EDOM': {{{ cDefs.EDOM }}},
536
'ERANGE': {{{ cDefs.ERANGE }}},
537
'ENOMSG': {{{ cDefs.ENOMSG }}},
538
'EIDRM': {{{ cDefs.EIDRM }}},
539
'ECHRNG': {{{ cDefs.ECHRNG }}},
540
'EL2NSYNC': {{{ cDefs.EL2NSYNC }}},
541
'EL3HLT': {{{ cDefs.EL3HLT }}},
542
'EL3RST': {{{ cDefs.EL3RST }}},
543
'ELNRNG': {{{ cDefs.ELNRNG }}},
544
'EUNATCH': {{{ cDefs.EUNATCH }}},
545
'ENOCSI': {{{ cDefs.ENOCSI }}},
546
'EL2HLT': {{{ cDefs.EL2HLT }}},
547
'EDEADLK': {{{ cDefs.EDEADLK }}},
548
'ENOLCK': {{{ cDefs.ENOLCK }}},
549
'EBADE': {{{ cDefs.EBADE }}},
550
'EBADR': {{{ cDefs.EBADR }}},
551
'EXFULL': {{{ cDefs.EXFULL }}},
552
'ENOANO': {{{ cDefs.ENOANO }}},
553
'EBADRQC': {{{ cDefs.EBADRQC }}},
554
'EBADSLT': {{{ cDefs.EBADSLT }}},
555
'EDEADLOCK': {{{ cDefs.EDEADLOCK }}},
556
'EBFONT': {{{ cDefs.EBFONT }}},
557
'ENOSTR': {{{ cDefs.ENOSTR }}},
558
'ENODATA': {{{ cDefs.ENODATA }}},
559
'ETIME': {{{ cDefs.ETIME }}},
560
'ENOSR': {{{ cDefs.ENOSR }}},
561
'ENONET': {{{ cDefs.ENONET }}},
562
'ENOPKG': {{{ cDefs.ENOPKG }}},
563
'EREMOTE': {{{ cDefs.EREMOTE }}},
564
'ENOLINK': {{{ cDefs.ENOLINK }}},
565
'EADV': {{{ cDefs.EADV }}},
566
'ESRMNT': {{{ cDefs.ESRMNT }}},
567
'ECOMM': {{{ cDefs.ECOMM }}},
568
'EPROTO': {{{ cDefs.EPROTO }}},
569
'EMULTIHOP': {{{ cDefs.EMULTIHOP }}},
570
'EDOTDOT': {{{ cDefs.EDOTDOT }}},
571
'EBADMSG': {{{ cDefs.EBADMSG }}},
572
'ENOTUNIQ': {{{ cDefs.ENOTUNIQ }}},
573
'EBADFD': {{{ cDefs.EBADFD }}},
574
'EREMCHG': {{{ cDefs.EREMCHG }}},
575
'ELIBACC': {{{ cDefs.ELIBACC }}},
576
'ELIBBAD': {{{ cDefs.ELIBBAD }}},
577
'ELIBSCN': {{{ cDefs.ELIBSCN }}},
578
'ELIBMAX': {{{ cDefs.ELIBMAX }}},
579
'ELIBEXEC': {{{ cDefs.ELIBEXEC }}},
580
'ENOSYS': {{{ cDefs.ENOSYS }}},
581
'ENOTEMPTY': {{{ cDefs.ENOTEMPTY }}},
582
'ENAMETOOLONG': {{{ cDefs.ENAMETOOLONG }}},
583
'ELOOP': {{{ cDefs.ELOOP }}},
584
'EOPNOTSUPP': {{{ cDefs.EOPNOTSUPP }}},
585
'EPFNOSUPPORT': {{{ cDefs.EPFNOSUPPORT }}},
586
'ECONNRESET': {{{ cDefs.ECONNRESET }}},
587
'ENOBUFS': {{{ cDefs.ENOBUFS }}},
588
'EAFNOSUPPORT': {{{ cDefs.EAFNOSUPPORT }}},
589
'EPROTOTYPE': {{{ cDefs.EPROTOTYPE }}},
590
'ENOTSOCK': {{{ cDefs.ENOTSOCK }}},
591
'ENOPROTOOPT': {{{ cDefs.ENOPROTOOPT }}},
592
'ESHUTDOWN': {{{ cDefs.ESHUTDOWN }}},
593
'ECONNREFUSED': {{{ cDefs.ECONNREFUSED }}},
594
'EADDRINUSE': {{{ cDefs.EADDRINUSE }}},
595
'ECONNABORTED': {{{ cDefs.ECONNABORTED }}},
596
'ENETUNREACH': {{{ cDefs.ENETUNREACH }}},
597
'ENETDOWN': {{{ cDefs.ENETDOWN }}},
598
'ETIMEDOUT': {{{ cDefs.ETIMEDOUT }}},
599
'EHOSTDOWN': {{{ cDefs.EHOSTDOWN }}},
600
'EHOSTUNREACH': {{{ cDefs.EHOSTUNREACH }}},
601
'EINPROGRESS': {{{ cDefs.EINPROGRESS }}},
602
'EALREADY': {{{ cDefs.EALREADY }}},
603
'EDESTADDRREQ': {{{ cDefs.EDESTADDRREQ }}},
604
'EMSGSIZE': {{{ cDefs.EMSGSIZE }}},
605
'EPROTONOSUPPORT': {{{ cDefs.EPROTONOSUPPORT }}},
606
'ESOCKTNOSUPPORT': {{{ cDefs.ESOCKTNOSUPPORT }}},
607
'EADDRNOTAVAIL': {{{ cDefs.EADDRNOTAVAIL }}},
608
'ENETRESET': {{{ cDefs.ENETRESET }}},
609
'EISCONN': {{{ cDefs.EISCONN }}},
610
'ENOTCONN': {{{ cDefs.ENOTCONN }}},
611
'ETOOMANYREFS': {{{ cDefs.ETOOMANYREFS }}},
612
'EUSERS': {{{ cDefs.EUSERS }}},
613
'EDQUOT': {{{ cDefs.EDQUOT }}},
614
'ESTALE': {{{ cDefs.ESTALE }}},
615
'ENOTSUP': {{{ cDefs.ENOTSUP }}},
616
'ENOMEDIUM': {{{ cDefs.ENOMEDIUM }}},
617
'EILSEQ': {{{ cDefs.EILSEQ }}},
618
'EOVERFLOW': {{{ cDefs.EOVERFLOW }}},
619
'ECANCELED': {{{ cDefs.ECANCELED }}},
620
'ENOTRECOVERABLE': {{{ cDefs.ENOTRECOVERABLE }}},
621
'EOWNERDEAD': {{{ cDefs.EOWNERDEAD }}},
622
'ESTRPIPE': {{{ cDefs.ESTRPIPE }}},
623
}`,
624
625
#if PURE_WASI
626
$strError: (errno) => errno + '',
627
#else
628
$strError__deps: ['strerror', '$UTF8ToString'],
629
$strError: (errno) => UTF8ToString(_strerror(errno)),
630
#endif
631
632
#if PROXY_POSIX_SOCKETS == 0
633
// ==========================================================================
634
// netdb.h
635
// ==========================================================================
636
637
$inetPton4: (str) => {
638
var b = str.split('.');
639
for (var i = 0; i < 4; i++) {
640
var tmp = Number(b[i]);
641
if (isNaN(tmp)) return null;
642
b[i] = tmp;
643
}
644
return (b[0] | (b[1] << 8) | (b[2] << 16) | (b[3] << 24)) >>> 0;
645
},
646
$inetNtop4: (addr) =>
647
(addr & 0xff) + '.' + ((addr >> 8) & 0xff) + '.' + ((addr >> 16) & 0xff) + '.' + ((addr >> 24) & 0xff),
648
$inetPton6__deps: ['htons'],
649
$inetPton6: (str) => {
650
var words;
651
var w, offset, z, i;
652
/* http://home.deds.nl/~aeron/regex/ */
653
var valid6regx = /^((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\3)::|:\b|$))|(?!\2\3)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})$/i
654
var parts = [];
655
if (!valid6regx.test(str)) {
656
return null;
657
}
658
if (str === "::") {
659
return [0, 0, 0, 0, 0, 0, 0, 0];
660
}
661
// Z placeholder to keep track of zeros when splitting the string on ":"
662
if (str.startsWith("::")) {
663
str = str.replace("::", "Z:"); // leading zeros case
664
} else {
665
str = str.replace("::", ":Z:");
666
}
667
668
if (str.indexOf(".") > 0) {
669
// parse IPv4 embedded address
670
str = str.replace(new RegExp('[.]', 'g'), ":");
671
words = str.split(":");
672
words[words.length-4] = Number(words[words.length-4]) + Number(words[words.length-3])*256;
673
words[words.length-3] = Number(words[words.length-2]) + Number(words[words.length-1])*256;
674
words = words.slice(0, words.length-2);
675
} else {
676
words = str.split(":");
677
}
678
679
offset = 0; z = 0;
680
for (w=0; w < words.length; w++) {
681
if (typeof words[w] == 'string') {
682
if (words[w] === 'Z') {
683
// compressed zeros - write appropriate number of zero words
684
for (z = 0; z < (8 - words.length+1); z++) {
685
parts[w+z] = 0;
686
}
687
offset = z-1;
688
} else {
689
// parse hex field to 16-bit value and write it in network byte-order
690
parts[w+offset] = _htons(parseInt(words[w],16));
691
}
692
} else {
693
// parsed IPv4 words
694
parts[w+offset] = words[w];
695
}
696
}
697
return [
698
(parts[1] << 16) | parts[0],
699
(parts[3] << 16) | parts[2],
700
(parts[5] << 16) | parts[4],
701
(parts[7] << 16) | parts[6]
702
];
703
},
704
$inetNtop6__deps: ['$inetNtop4', 'ntohs'],
705
$inetNtop6: (ints) => {
706
// ref: http://www.ietf.org/rfc/rfc2373.txt - section 2.5.4
707
// Format for IPv4 compatible and mapped 128-bit IPv6 Addresses
708
// 128-bits are split into eight 16-bit words
709
// stored in network byte order (big-endian)
710
// | 80 bits | 16 | 32 bits |
711
// +-----------------------------------------------------------------+
712
// | 10 bytes | 2 | 4 bytes |
713
// +--------------------------------------+--------------------------+
714
// + 5 words | 1 | 2 words |
715
// +--------------------------------------+--------------------------+
716
// |0000..............................0000|0000| IPv4 ADDRESS | (compatible)
717
// +--------------------------------------+----+---------------------+
718
// |0000..............................0000|FFFF| IPv4 ADDRESS | (mapped)
719
// +--------------------------------------+----+---------------------+
720
var str = "";
721
var word = 0;
722
var longest = 0;
723
var lastzero = 0;
724
var zstart = 0;
725
var len = 0;
726
var i = 0;
727
var parts = [
728
ints[0] & 0xffff,
729
(ints[0] >> 16),
730
ints[1] & 0xffff,
731
(ints[1] >> 16),
732
ints[2] & 0xffff,
733
(ints[2] >> 16),
734
ints[3] & 0xffff,
735
(ints[3] >> 16)
736
];
737
738
// Handle IPv4-compatible, IPv4-mapped, loopback and any/unspecified addresses
739
740
var hasipv4 = true;
741
var v4part = "";
742
// check if the 10 high-order bytes are all zeros (first 5 words)
743
for (i = 0; i < 5; i++) {
744
if (parts[i] !== 0) { hasipv4 = false; break; }
745
}
746
747
if (hasipv4) {
748
// low-order 32-bits store an IPv4 address (bytes 13 to 16) (last 2 words)
749
v4part = inetNtop4(parts[6] | (parts[7] << 16));
750
// IPv4-mapped IPv6 address if 16-bit value (bytes 11 and 12) == 0xFFFF (6th word)
751
if (parts[5] === -1) {
752
str = "::ffff:";
753
str += v4part;
754
return str;
755
}
756
// IPv4-compatible IPv6 address if 16-bit value (bytes 11 and 12) == 0x0000 (6th word)
757
if (parts[5] === 0) {
758
str = "::";
759
// special case IPv6 addresses
760
if (v4part === "0.0.0.0") v4part = ""; // any/unspecified address
761
if (v4part === "0.0.0.1") v4part = "1";// loopback address
762
str += v4part;
763
return str;
764
}
765
}
766
767
// Handle all other IPv6 addresses
768
769
// first run to find the longest contiguous zero words
770
for (word = 0; word < 8; word++) {
771
if (parts[word] === 0) {
772
if (word - lastzero > 1) {
773
len = 0;
774
}
775
lastzero = word;
776
len++;
777
}
778
if (len > longest) {
779
longest = len;
780
zstart = word - longest + 1;
781
}
782
}
783
784
for (word = 0; word < 8; word++) {
785
if (longest > 1) {
786
// compress contiguous zeros - to produce "::"
787
if (parts[word] === 0 && word >= zstart && word < (zstart + longest) ) {
788
if (word === zstart) {
789
str += ":";
790
if (zstart === 0) str += ":"; //leading zeros case
791
}
792
continue;
793
}
794
}
795
// converts 16-bit words from big-endian to little-endian before converting to hex string
796
str += Number(_ntohs(parts[word] & 0xffff)).toString(16);
797
str += word < 7 ? ":" : "";
798
}
799
return str;
800
},
801
802
$readSockaddr__deps: ['$inetNtop4', '$inetNtop6', 'ntohs'],
803
$readSockaddr: (sa, salen) => {
804
// family / port offsets are common to both sockaddr_in and sockaddr_in6
805
var family = {{{ makeGetValue('sa', C_STRUCTS.sockaddr_in.sin_family, 'i16') }}};
806
var port = _ntohs({{{ makeGetValue('sa', C_STRUCTS.sockaddr_in.sin_port, 'u16') }}});
807
var addr;
808
809
switch (family) {
810
case {{{ cDefs.AF_INET }}}:
811
if (salen !== {{{ C_STRUCTS.sockaddr_in.__size__ }}}) {
812
return { errno: {{{ cDefs.EINVAL }}} };
813
}
814
addr = {{{ makeGetValue('sa', C_STRUCTS.sockaddr_in.sin_addr.s_addr, 'i32') }}};
815
addr = inetNtop4(addr);
816
break;
817
case {{{ cDefs.AF_INET6 }}}:
818
if (salen !== {{{ C_STRUCTS.sockaddr_in6.__size__ }}}) {
819
return { errno: {{{ cDefs.EINVAL }}} };
820
}
821
addr = [
822
{{{ makeGetValue('sa', C_STRUCTS.sockaddr_in6.sin6_addr.__in6_union.__s6_addr+0, 'i32') }}},
823
{{{ makeGetValue('sa', C_STRUCTS.sockaddr_in6.sin6_addr.__in6_union.__s6_addr+4, 'i32') }}},
824
{{{ makeGetValue('sa', C_STRUCTS.sockaddr_in6.sin6_addr.__in6_union.__s6_addr+8, 'i32') }}},
825
{{{ makeGetValue('sa', C_STRUCTS.sockaddr_in6.sin6_addr.__in6_union.__s6_addr+12, 'i32') }}}
826
];
827
addr = inetNtop6(addr);
828
break;
829
default:
830
return { errno: {{{ cDefs.EAFNOSUPPORT }}} };
831
}
832
833
return { family: family, addr: addr, port: port };
834
},
835
$writeSockaddr__docs: '/** @param {number=} addrlen */',
836
$writeSockaddr__deps: ['$inetPton4', '$inetPton6', '$zeroMemory', 'htons'],
837
$writeSockaddr: (sa, family, addr, port, addrlen) => {
838
switch (family) {
839
case {{{ cDefs.AF_INET }}}:
840
addr = inetPton4(addr);
841
zeroMemory(sa, {{{ C_STRUCTS.sockaddr_in.__size__ }}});
842
if (addrlen) {
843
{{{ makeSetValue('addrlen', 0, C_STRUCTS.sockaddr_in.__size__, 'i32') }}};
844
}
845
{{{ makeSetValue('sa', C_STRUCTS.sockaddr_in.sin_family, 'family', 'i16') }}};
846
{{{ makeSetValue('sa', C_STRUCTS.sockaddr_in.sin_addr.s_addr, 'addr', 'i32') }}};
847
{{{ makeSetValue('sa', C_STRUCTS.sockaddr_in.sin_port, '_htons(port)', 'i16') }}};
848
break;
849
case {{{ cDefs.AF_INET6 }}}:
850
addr = inetPton6(addr);
851
zeroMemory(sa, {{{ C_STRUCTS.sockaddr_in6.__size__ }}});
852
if (addrlen) {
853
{{{ makeSetValue('addrlen', 0, C_STRUCTS.sockaddr_in6.__size__, 'i32') }}};
854
}
855
{{{ makeSetValue('sa', C_STRUCTS.sockaddr_in6.sin6_family, 'family', 'i32') }}};
856
{{{ makeSetValue('sa', C_STRUCTS.sockaddr_in6.sin6_addr.__in6_union.__s6_addr+0, 'addr[0]', 'i32') }}};
857
{{{ makeSetValue('sa', C_STRUCTS.sockaddr_in6.sin6_addr.__in6_union.__s6_addr+4, 'addr[1]', 'i32') }}};
858
{{{ makeSetValue('sa', C_STRUCTS.sockaddr_in6.sin6_addr.__in6_union.__s6_addr+8, 'addr[2]', 'i32') }}};
859
{{{ makeSetValue('sa', C_STRUCTS.sockaddr_in6.sin6_addr.__in6_union.__s6_addr+12, 'addr[3]', 'i32') }}};
860
{{{ makeSetValue('sa', C_STRUCTS.sockaddr_in6.sin6_port, '_htons(port)', 'i16') }}};
861
break;
862
default:
863
return {{{ cDefs.EAFNOSUPPORT }}};
864
}
865
return 0;
866
},
867
868
// We can't actually resolve hostnames in the browser, so instead
869
// we're generating fake IP addresses with lookup_name that we can
870
// resolve later on with lookup_addr.
871
// We do the aliasing in 172.29.*.*, giving us 65536 possibilities.
872
$DNS__deps: ['$inetPton4', '$inetPton6'],
873
$DNS: {
874
address_map: {
875
id: 1,
876
addrs: {},
877
names: {}
878
},
879
880
lookup_name(name) {
881
// If the name is already a valid ipv4 / ipv6 address, don't generate a fake one.
882
var res = inetPton4(name);
883
if (res !== null) {
884
return name;
885
}
886
res = inetPton6(name);
887
if (res !== null) {
888
return name;
889
}
890
891
// See if this name is already mapped.
892
var addr;
893
894
if (DNS.address_map.addrs[name]) {
895
addr = DNS.address_map.addrs[name];
896
} else {
897
var id = DNS.address_map.id++;
898
#if ASSERTIONS
899
assert(id < 65535, 'exceeded max address mappings of 65535');
900
#endif
901
902
addr = '172.29.' + (id & 0xff) + '.' + (id & 0xff00);
903
904
DNS.address_map.names[addr] = name;
905
DNS.address_map.addrs[name] = addr;
906
}
907
908
return addr;
909
},
910
911
lookup_addr(addr) {
912
if (DNS.address_map.names[addr]) {
913
return DNS.address_map.names[addr];
914
}
915
916
return null;
917
}
918
},
919
920
_emscripten_lookup_name__deps: ['$UTF8ToString', '$DNS', '$inetPton4'],
921
_emscripten_lookup_name: (name) => {
922
// uint32_t _emscripten_lookup_name(const char *name);
923
var nameString = UTF8ToString(name);
924
return inetPton4(DNS.lookup_name(nameString));
925
},
926
927
getaddrinfo__deps: ['$DNS', '$inetPton4', '$inetNtop4', '$inetPton6', '$inetNtop6', '$writeSockaddr', 'malloc', 'htonl'],
928
getaddrinfo__proxy: 'sync',
929
getaddrinfo: (node, service, hint, out) => {
930
// Note getaddrinfo currently only returns a single addrinfo with ai_next defaulting to NULL. When NULL
931
// hints are specified or ai_family set to AF_UNSPEC or ai_socktype or ai_protocol set to 0 then we
932
// really should provide a linked list of suitable addrinfo values.
933
var addrs = [];
934
var canon = null;
935
var addr = 0;
936
var port = 0;
937
var flags = 0;
938
var family = {{{ cDefs.AF_UNSPEC }}};
939
var type = 0;
940
var proto = 0;
941
var ai, last;
942
943
function allocaddrinfo(family, type, proto, canon, addr, port) {
944
var sa, salen, ai;
945
var errno;
946
947
salen = family === {{{ cDefs.AF_INET6 }}} ?
948
{{{ C_STRUCTS.sockaddr_in6.__size__ }}} :
949
{{{ C_STRUCTS.sockaddr_in.__size__ }}};
950
addr = family === {{{ cDefs.AF_INET6 }}} ?
951
inetNtop6(addr) :
952
inetNtop4(addr);
953
sa = _malloc(salen);
954
errno = writeSockaddr(sa, family, addr, port);
955
#if ASSERTIONS
956
assert(!errno);
957
#endif
958
959
ai = _malloc({{{ C_STRUCTS.addrinfo.__size__ }}});
960
{{{ makeSetValue('ai', C_STRUCTS.addrinfo.ai_family, 'family', 'i32') }}};
961
{{{ makeSetValue('ai', C_STRUCTS.addrinfo.ai_socktype, 'type', 'i32') }}};
962
{{{ makeSetValue('ai', C_STRUCTS.addrinfo.ai_protocol, 'proto', 'i32') }}};
963
{{{ makeSetValue('ai', C_STRUCTS.addrinfo.ai_canonname, 'canon', '*') }}};
964
{{{ makeSetValue('ai', C_STRUCTS.addrinfo.ai_addr, 'sa', '*') }}};
965
if (family === {{{ cDefs.AF_INET6 }}}) {
966
{{{ makeSetValue('ai', C_STRUCTS.addrinfo.ai_addrlen, C_STRUCTS.sockaddr_in6.__size__, 'i32') }}};
967
} else {
968
{{{ makeSetValue('ai', C_STRUCTS.addrinfo.ai_addrlen, C_STRUCTS.sockaddr_in.__size__, 'i32') }}};
969
}
970
{{{ makeSetValue('ai', C_STRUCTS.addrinfo.ai_next, '0', 'i32') }}};
971
972
return ai;
973
}
974
975
if (hint) {
976
flags = {{{ makeGetValue('hint', C_STRUCTS.addrinfo.ai_flags, 'i32') }}};
977
family = {{{ makeGetValue('hint', C_STRUCTS.addrinfo.ai_family, 'i32') }}};
978
type = {{{ makeGetValue('hint', C_STRUCTS.addrinfo.ai_socktype, 'i32') }}};
979
proto = {{{ makeGetValue('hint', C_STRUCTS.addrinfo.ai_protocol, 'i32') }}};
980
}
981
if (type && !proto) {
982
proto = type === {{{ cDefs.SOCK_DGRAM }}} ? {{{ cDefs.IPPROTO_UDP }}} : {{{ cDefs.IPPROTO_TCP }}};
983
}
984
if (!type && proto) {
985
type = proto === {{{ cDefs.IPPROTO_UDP }}} ? {{{ cDefs.SOCK_DGRAM }}} : {{{ cDefs.SOCK_STREAM }}};
986
}
987
988
// If type or proto are set to zero in hints we should really be returning multiple addrinfo values, but for
989
// now default to a TCP STREAM socket so we can at least return a sensible addrinfo given NULL hints.
990
if (proto === 0) {
991
proto = {{{ cDefs.IPPROTO_TCP }}};
992
}
993
if (type === 0) {
994
type = {{{ cDefs.SOCK_STREAM }}};
995
}
996
997
if (!node && !service) {
998
return {{{ cDefs.EAI_NONAME }}};
999
}
1000
if (flags & ~({{{ cDefs.AI_PASSIVE }}}|{{{ cDefs.AI_CANONNAME }}}|{{{ cDefs.AI_NUMERICHOST }}}|
1001
{{{ cDefs.AI_NUMERICSERV }}}|{{{ cDefs.AI_V4MAPPED }}}|{{{ cDefs.AI_ALL }}}|{{{ cDefs.AI_ADDRCONFIG }}})) {
1002
return {{{ cDefs.EAI_BADFLAGS }}};
1003
}
1004
if (hint !== 0 && ({{{ makeGetValue('hint', C_STRUCTS.addrinfo.ai_flags, 'i32') }}} & {{{ cDefs.AI_CANONNAME }}}) && !node) {
1005
return {{{ cDefs.EAI_BADFLAGS }}};
1006
}
1007
if (flags & {{{ cDefs.AI_ADDRCONFIG }}}) {
1008
// TODO
1009
return {{{ cDefs.EAI_NONAME }}};
1010
}
1011
if (type !== 0 && type !== {{{ cDefs.SOCK_STREAM }}} && type !== {{{ cDefs.SOCK_DGRAM }}}) {
1012
return {{{ cDefs.EAI_SOCKTYPE }}};
1013
}
1014
if (family !== {{{ cDefs.AF_UNSPEC }}} && family !== {{{ cDefs.AF_INET }}} && family !== {{{ cDefs.AF_INET6 }}}) {
1015
return {{{ cDefs.EAI_FAMILY }}};
1016
}
1017
1018
if (service) {
1019
service = UTF8ToString(service);
1020
port = parseInt(service, 10);
1021
1022
if (isNaN(port)) {
1023
if (flags & {{{ cDefs.AI_NUMERICSERV }}}) {
1024
return {{{ cDefs.EAI_NONAME }}};
1025
}
1026
// TODO support resolving well-known service names from:
1027
// http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.txt
1028
return {{{ cDefs.EAI_SERVICE }}};
1029
}
1030
}
1031
1032
if (!node) {
1033
if (family === {{{ cDefs.AF_UNSPEC }}}) {
1034
family = {{{ cDefs.AF_INET }}};
1035
}
1036
if ((flags & {{{ cDefs.AI_PASSIVE }}}) === 0) {
1037
if (family === {{{ cDefs.AF_INET }}}) {
1038
addr = _htonl({{{ cDefs.INADDR_LOOPBACK }}});
1039
} else {
1040
addr = [0, 0, 0, _htonl(1)];
1041
}
1042
}
1043
ai = allocaddrinfo(family, type, proto, null, addr, port);
1044
{{{ makeSetValue('out', '0', 'ai', '*') }}};
1045
return 0;
1046
}
1047
1048
//
1049
// try as a numeric address
1050
//
1051
node = UTF8ToString(node);
1052
addr = inetPton4(node);
1053
if (addr !== null) {
1054
// incoming node is a valid ipv4 address
1055
if (family === {{{ cDefs.AF_UNSPEC }}} || family === {{{ cDefs.AF_INET }}}) {
1056
family = {{{ cDefs.AF_INET }}};
1057
}
1058
else if (family === {{{ cDefs.AF_INET6 }}} && (flags & {{{ cDefs.AI_V4MAPPED }}})) {
1059
addr = [0, 0, _htonl(0xffff), addr];
1060
family = {{{ cDefs.AF_INET6 }}};
1061
} else {
1062
return {{{ cDefs.EAI_NONAME }}};
1063
}
1064
} else {
1065
addr = inetPton6(node);
1066
if (addr !== null) {
1067
// incoming node is a valid ipv6 address
1068
if (family === {{{ cDefs.AF_UNSPEC }}} || family === {{{ cDefs.AF_INET6 }}}) {
1069
family = {{{ cDefs.AF_INET6 }}};
1070
} else {
1071
return {{{ cDefs.EAI_NONAME }}};
1072
}
1073
}
1074
}
1075
if (addr != null) {
1076
ai = allocaddrinfo(family, type, proto, node, addr, port);
1077
{{{ makeSetValue('out', '0', 'ai', '*') }}};
1078
return 0;
1079
}
1080
if (flags & {{{ cDefs.AI_NUMERICHOST }}}) {
1081
return {{{ cDefs.EAI_NONAME }}};
1082
}
1083
1084
//
1085
// try as a hostname
1086
//
1087
// resolve the hostname to a temporary fake address
1088
node = DNS.lookup_name(node);
1089
addr = inetPton4(node);
1090
if (family === {{{ cDefs.AF_UNSPEC }}}) {
1091
family = {{{ cDefs.AF_INET }}};
1092
} else if (family === {{{ cDefs.AF_INET6 }}}) {
1093
addr = [0, 0, _htonl(0xffff), addr];
1094
}
1095
ai = allocaddrinfo(family, type, proto, null, addr, port);
1096
{{{ makeSetValue('out', '0', 'ai', '*') }}};
1097
return 0;
1098
},
1099
1100
getnameinfo__deps: ['$DNS', '$readSockaddr', '$stringToUTF8'],
1101
getnameinfo: (sa, salen, node, nodelen, serv, servlen, flags) => {
1102
var info = readSockaddr(sa, salen);
1103
if (info.errno) {
1104
return {{{ cDefs.EAI_FAMILY }}};
1105
}
1106
var port = info.port;
1107
var addr = info.addr;
1108
1109
var overflowed = false;
1110
1111
if (node && nodelen) {
1112
var lookup;
1113
if ((flags & {{{ cDefs.NI_NUMERICHOST }}}) || !(lookup = DNS.lookup_addr(addr))) {
1114
if (flags & {{{ cDefs.NI_NAMEREQD }}}) {
1115
return {{{ cDefs.EAI_NONAME }}};
1116
}
1117
} else {
1118
addr = lookup;
1119
}
1120
var numBytesWrittenExclNull = stringToUTF8(addr, node, nodelen);
1121
1122
if (numBytesWrittenExclNull+1 >= nodelen) {
1123
overflowed = true;
1124
}
1125
}
1126
1127
if (serv && servlen) {
1128
port = '' + port;
1129
var numBytesWrittenExclNull = stringToUTF8(port, serv, servlen);
1130
1131
if (numBytesWrittenExclNull+1 >= servlen) {
1132
overflowed = true;
1133
}
1134
}
1135
1136
if (overflowed) {
1137
// Note: even when we overflow, getnameinfo() is specced to write out the truncated results.
1138
return {{{ cDefs.EAI_OVERFLOW }}};
1139
}
1140
1141
return 0;
1142
},
1143
1144
// Implement netdb.h protocol entry (getprotoent, getprotobyname, getprotobynumber, setprotoent, endprotoent)
1145
// http://pubs.opengroup.org/onlinepubs/9699919799/functions/getprotobyname.html
1146
// The Protocols object holds our 'fake' protocols 'database'.
1147
$Protocols: {
1148
list: [],
1149
map: {}
1150
},
1151
setprotoent__deps: ['$Protocols', '$stringToAscii', 'malloc'],
1152
setprotoent: (stayopen) => {
1153
// void setprotoent(int stayopen);
1154
1155
// Allocate and populate a protoent structure given a name, protocol number and array of aliases
1156
function allocprotoent(name, proto, aliases) {
1157
// write name into buffer
1158
var nameBuf = _malloc(name.length + 1);
1159
stringToAscii(name, nameBuf);
1160
1161
// write aliases into buffer
1162
var j = 0;
1163
var length = aliases.length;
1164
var aliasListBuf = _malloc((length + 1) * 4); // Use length + 1 so we have space for the terminating NULL ptr.
1165
1166
for (var i = 0; i < length; i++, j += 4) {
1167
var alias = aliases[i];
1168
var aliasBuf = _malloc(alias.length + 1);
1169
stringToAscii(alias, aliasBuf);
1170
{{{ makeSetValue('aliasListBuf', 'j', 'aliasBuf', '*') }}};
1171
}
1172
{{{ makeSetValue('aliasListBuf', 'j', '0', '*') }}}; // Terminating NULL pointer.
1173
1174
// generate protoent
1175
var pe = _malloc({{{ C_STRUCTS.protoent.__size__ }}});
1176
{{{ makeSetValue('pe', C_STRUCTS.protoent.p_name, 'nameBuf', '*') }}};
1177
{{{ makeSetValue('pe', C_STRUCTS.protoent.p_aliases, 'aliasListBuf', '*') }}};
1178
{{{ makeSetValue('pe', C_STRUCTS.protoent.p_proto, 'proto', 'i32') }}};
1179
return pe;
1180
};
1181
1182
// Populate the protocol 'database'. The entries are limited to tcp and udp, though it is fairly trivial
1183
// to add extra entries from /etc/protocols if desired - though not sure if that'd actually be useful.
1184
var list = Protocols.list;
1185
var map = Protocols.map;
1186
if (list.length === 0) {
1187
var entry = allocprotoent('tcp', 6, ['TCP']);
1188
list.push(entry);
1189
map['tcp'] = map['6'] = entry;
1190
entry = allocprotoent('udp', 17, ['UDP']);
1191
list.push(entry);
1192
map['udp'] = map['17'] = entry;
1193
}
1194
1195
_setprotoent.index = 0;
1196
},
1197
1198
endprotoent: () => {
1199
// void endprotoent(void);
1200
// We're not using a real protocol database so we don't do a real close.
1201
},
1202
1203
getprotoent__deps: ['setprotoent', '$Protocols'],
1204
getprotoent: (number) => {
1205
// struct protoent *getprotoent(void);
1206
// reads the next entry from the protocols 'database' or return NULL if 'eof'
1207
if (_setprotoent.index === Protocols.list.length) {
1208
return 0;
1209
}
1210
var result = Protocols.list[_setprotoent.index++];
1211
return result;
1212
},
1213
1214
getprotobyname__deps: ['setprotoent', '$Protocols'],
1215
getprotobyname: (name) => {
1216
// struct protoent *getprotobyname(const char *);
1217
name = UTF8ToString(name);
1218
_setprotoent(true);
1219
var result = Protocols.map[name];
1220
return result;
1221
},
1222
1223
getprotobynumber__deps: ['setprotoent', '$Protocols'],
1224
getprotobynumber: (number) => {
1225
// struct protoent *getprotobynumber(int proto);
1226
_setprotoent(true);
1227
var result = Protocols.map[number];
1228
return result;
1229
},
1230
1231
// ==========================================================================
1232
// sockets. Note that the implementation assumes all sockets are always
1233
// nonblocking
1234
// ==========================================================================
1235
#if SOCKET_WEBRTC
1236
$Sockets__deps: [
1237
() => 'var SocketIO = ' + read('../third_party/socket.io.js') + ';\n',
1238
() => 'var Peer = ' + read('../third_party/wrtcp.js') + ';\n'
1239
],
1240
#endif
1241
$Sockets: {
1242
BUFFER_SIZE: 10*1024, // initial size
1243
MAX_BUFFER_SIZE: 10*1024*1024, // maximum size we will grow the buffer
1244
1245
nextFd: 1,
1246
fds: {},
1247
nextport: 1,
1248
maxport: 65535,
1249
peer: null,
1250
connections: {},
1251
portmap: {},
1252
localAddr: 0xfe00000a, // Local address is always 10.0.0.254
1253
addrPool: [ 0x0200000a, 0x0300000a, 0x0400000a, 0x0500000a,
1254
0x0600000a, 0x0700000a, 0x0800000a, 0x0900000a, 0x0a00000a,
1255
0x0b00000a, 0x0c00000a, 0x0d00000a, 0x0e00000a] /* 0x0100000a is reserved */
1256
},
1257
1258
#endif // PROXY_POSIX_SOCKETS == 0
1259
1260
$timers: {},
1261
1262
// Helper function for setitimer that registers timers with the eventloop.
1263
// Timers always fire on the main thread, either directly from JS (here) or
1264
// or when the main thread is busy waiting calling _emscripten_yield.
1265
_setitimer_js__proxy: 'sync',
1266
_setitimer_js__deps: ['$timers', '$callUserCallback', '_emscripten_timeout', 'emscripten_get_now'],
1267
_setitimer_js: (which, timeout_ms) => {
1268
#if RUNTIME_DEBUG
1269
dbg(`setitimer_js ${which} timeout=${timeout_ms}`);
1270
#endif
1271
// First, clear any existing timer.
1272
if (timers[which]) {
1273
clearTimeout(timers[which].id);
1274
delete timers[which];
1275
}
1276
1277
// A timeout of zero simply cancels the current timeout so we have nothing
1278
// more to do.
1279
if (!timeout_ms) return 0;
1280
1281
var id = setTimeout(() => {
1282
#if ASSERTIONS
1283
assert(which in timers);
1284
#endif
1285
delete timers[which];
1286
#if RUNTIME_DEBUG
1287
dbg(`itimer fired: ${which}`);
1288
#endif
1289
callUserCallback(() => __emscripten_timeout(which, _emscripten_get_now()));
1290
}, timeout_ms);
1291
timers[which] = { id, timeout_ms };
1292
return 0;
1293
},
1294
1295
// Helper for raise() to avoid signature mismatch failures:
1296
// https://github.com/emscripten-core/posixtestsuite/issues/6
1297
__call_sighandler: (fp, sig) => {{{ makeDynCall('vi', 'fp') }}}(sig),
1298
1299
// ==========================================================================
1300
// emscripten.h
1301
// ==========================================================================
1302
1303
emscripten_run_script: (ptr) => {
1304
{{{ makeEval('eval(UTF8ToString(ptr));') }}}
1305
},
1306
1307
emscripten_run_script_int__docs: '/** @suppress{checkTypes} */',
1308
emscripten_run_script_int: (ptr) => {
1309
{{{ makeEval('return eval(UTF8ToString(ptr))|0;') }}}
1310
},
1311
1312
// Mark as `noleakcheck` otherwise lsan will report the last returned string
1313
// as a leak.
1314
emscripten_run_script_string__noleakcheck: true,
1315
emscripten_run_script_string__deps: ['$lengthBytesUTF8', '$stringToUTF8', 'realloc'],
1316
emscripten_run_script_string: (ptr) => {
1317
{{{ makeEval("var s = eval(UTF8ToString(ptr));") }}}
1318
if (s == null) {
1319
return 0;
1320
}
1321
s += '';
1322
var me = _emscripten_run_script_string;
1323
me.bufferSize = lengthBytesUTF8(s) + 1;
1324
me.buffer = _realloc(me.buffer ?? 0, me.bufferSize)
1325
stringToUTF8(s, me.buffer, me.bufferSize);
1326
return me.buffer;
1327
},
1328
1329
emscripten_random: () => Math.random(),
1330
1331
emscripten_date_now: () => Date.now(),
1332
1333
emscripten_performance_now: () => {{{ getPerformanceNow() }}}(),
1334
1335
#if PTHREADS && !AUDIO_WORKLET
1336
// Pthreads need their clocks synchronized to the execution of the main
1337
// thread, so, when using them, make sure to adjust all timings to the
1338
// respective time origins.
1339
emscripten_get_now: () => performance.timeOrigin + {{{ getPerformanceNow() }}}(),
1340
#else
1341
#if AUDIO_WORKLET // https://github.com/WebAudio/web-audio-api/issues/2413
1342
emscripten_get_now: `;
1343
// AudioWorkletGlobalScope does not have performance.now()
1344
// (https://github.com/WebAudio/web-audio-api/issues/2527), so if building
1345
// with
1346
// Audio Worklets enabled, do a dynamic check for its presence.
1347
if (globalThis.performance && {{{ getPerformanceNow() }}}) {
1348
#if PTHREADS
1349
_emscripten_get_now = () => performance.timeOrigin + {{{ getPerformanceNow() }}}();
1350
#else
1351
_emscripten_get_now = () => {{{ getPerformanceNow() }}}();
1352
#endif
1353
} else {
1354
_emscripten_get_now = Date.now;
1355
}
1356
`,
1357
#else
1358
// Modern environment where performance.now() is supported:
1359
// N.B. a shorter form "_emscripten_get_now = performance.now;" is
1360
// unfortunately not allowed even in current browsers (e.g. FF Nightly 75).
1361
emscripten_get_now: () => {{{ getPerformanceNow() }}}(),
1362
#endif
1363
#endif
1364
1365
emscripten_get_now_res: () => { // return resolution of get_now, in nanoseconds
1366
#if ENVIRONMENT_MAY_BE_NODE
1367
if (ENVIRONMENT_IS_NODE) {
1368
return 1; // nanoseconds
1369
}
1370
#endif
1371
#if AUDIO_WORKLET // https://github.com/WebAudio/web-audio-api/issues/2413
1372
if (globalThis.performance?.now == 'function') {
1373
return 1000; // microseconds (1/1000 of a millisecond)
1374
}
1375
return 1000*1000; // milliseconds
1376
#else
1377
// Modern environment where performance.now() is supported:
1378
return 1000; // microseconds (1/1000 of a millisecond)
1379
#endif
1380
},
1381
1382
// Represents whether emscripten_get_now is guaranteed monotonic; the Date.now
1383
// implementation is not :(
1384
$nowIsMonotonic__internal: true,
1385
#if AUDIO_WORKLET // // https://github.com/WebAudio/web-audio-api/issues/2413
1386
$nowIsMonotonic: `!!globalThis.performance?.now;`,
1387
#else
1388
// Modern environment where performance.now() is supported
1389
$nowIsMonotonic: 1,
1390
#endif
1391
1392
_emscripten_get_now_is_monotonic__internal: true,
1393
_emscripten_get_now_is_monotonic__deps: ['$nowIsMonotonic'],
1394
_emscripten_get_now_is_monotonic: () => nowIsMonotonic,
1395
1396
$warnOnce: (text) => {
1397
warnOnce.shown ||= {};
1398
if (!warnOnce.shown[text]) {
1399
warnOnce.shown[text] = 1;
1400
#if ENVIRONMENT_MAY_BE_NODE
1401
if (ENVIRONMENT_IS_NODE) text = 'warning: ' + text;
1402
#endif
1403
err(text);
1404
}
1405
},
1406
1407
_emscripten_log_formatted__deps: ['$getCallstack'],
1408
_emscripten_log_formatted: (flags, str) => {
1409
str = UTF8ToString(str);
1410
1411
if (flags & {{{ cDefs.EM_LOG_C_STACK | cDefs.EM_LOG_JS_STACK }}}) {
1412
str = str.replace(/\s+$/, ''); // Ensure the message and the callstack are joined cleanly with exactly one newline.
1413
str += (str.length > 0 ? '\n' : '') + getCallstack(flags);
1414
}
1415
1416
if (flags & {{{ cDefs.EM_LOG_CONSOLE }}}) {
1417
if (flags & {{{ cDefs.EM_LOG_ERROR }}}) {
1418
console.error(str);
1419
} else if (flags & {{{ cDefs.EM_LOG_WARN }}}) {
1420
console.warn(str);
1421
} else if (flags & {{{ cDefs.EM_LOG_INFO }}}) {
1422
console.info(str);
1423
} else if (flags & {{{ cDefs.EM_LOG_DEBUG }}}) {
1424
console.debug(str);
1425
} else {
1426
console.log(str);
1427
}
1428
} else if (flags & {{{ cDefs.EM_LOG_ERROR | cDefs.EM_LOG_WARN }}}) {
1429
err(str);
1430
} else {
1431
out(str);
1432
}
1433
},
1434
1435
// We never free the return values of this function so we need to allocate
1436
// using builtin_malloc to avoid LSan reporting these as leaks.
1437
#if RETAIN_COMPILER_SETTINGS
1438
emscripten_get_compiler_setting__noleakcheck: true,
1439
emscripten_get_compiler_setting__deps: ['$stringToNewUTF8'],
1440
emscripten_get_compiler_setting: (name) => {
1441
name = UTF8ToString(name);
1442
1443
var ret = getCompilerSetting(name);
1444
if (typeof ret == 'number' || typeof ret == 'boolean') return ret;
1445
1446
var cache = _emscripten_get_compiler_setting.cache ??= {};
1447
var fullret = cache[name];
1448
if (fullret) return fullret;
1449
return cache[name] = stringToNewUTF8(ret);
1450
},
1451
#else
1452
emscripten_get_compiler_setting: (name) => abort('You must build with -sRETAIN_COMPILER_SETTINGS for getCompilerSetting or emscripten_get_compiler_setting to work'),
1453
#endif
1454
1455
emscripten_has_asyncify: () => {{{ ASYNCIFY }}},
1456
1457
emscripten_debugger: () => { debugger },
1458
1459
emscripten_print_double__deps: ['$stringToUTF8', '$lengthBytesUTF8'],
1460
emscripten_print_double: (x, to, max) => {
1461
var str = x + '';
1462
if (to) return stringToUTF8(str, to, max);
1463
else return lengthBytesUTF8(str);
1464
},
1465
1466
#if USE_ASAN || USE_LSAN
1467
// When lsan is enabled noLeakCheck will temporarily disable leak checking
1468
// for the duration of the function.
1469
$noLeakCheck__deps: ['__lsan_enable', '__lsan_disable'],
1470
$noLeakCheck__docs: '/** @suppress{checkTypes} */',
1471
$noLeakCheck: (func) => {
1472
if (runtimeInitialized) ___lsan_disable();
1473
try {
1474
return func();
1475
} finally {
1476
if (runtimeInitialized) ___lsan_enable();
1477
}
1478
},
1479
#endif
1480
1481
#if USE_ASAN || USE_LSAN || UBSAN_RUNTIME
1482
_emscripten_sanitizer_use_colors: () => {
1483
var setting = Module['printWithColors'];
1484
if (setting !== undefined) {
1485
return setting;
1486
}
1487
return ENVIRONMENT_IS_NODE && process.stderr.isTTY;
1488
},
1489
1490
_emscripten_sanitizer_get_option__deps: ['$stringToNewUTF8', '$UTF8ToString'],
1491
_emscripten_sanitizer_get_option__sig: 'pp',
1492
_emscripten_sanitizer_get_option: (name) => stringToNewUTF8(Module[UTF8ToString(name)] || ''),
1493
#endif
1494
1495
$readEmAsmArgsArray: [],
1496
$readEmAsmArgs__deps: ['$readEmAsmArgsArray'],
1497
$readEmAsmArgs: (sigPtr, buf) => {
1498
#if ASSERTIONS
1499
// Nobody should have mutated _readEmAsmArgsArray underneath us to be something else than an array.
1500
assert(Array.isArray(readEmAsmArgsArray));
1501
// The input buffer is allocated on the stack, so it must be stack-aligned.
1502
assert(buf % {{{ STACK_ALIGN }}} == 0);
1503
#endif
1504
readEmAsmArgsArray.length = 0;
1505
var ch;
1506
// Most arguments are i32s, so shift the buffer pointer so it is a plain
1507
// index into HEAP32.
1508
while (ch = HEAPU8[sigPtr++]) {
1509
#if ASSERTIONS
1510
var chr = String.fromCharCode(ch);
1511
var validChars = ['d', 'f', 'i', 'p'];
1512
#if WASM_BIGINT
1513
// In WASM_BIGINT mode we support passing i64 values as bigint.
1514
validChars.push('j');
1515
#endif
1516
assert(validChars.includes(chr), `Invalid character ${ch}("${chr}") in readEmAsmArgs! Use only [${validChars}], and do not specify "v" for void return argument.`);
1517
#endif
1518
// Floats are always passed as doubles, so all types except for 'i'
1519
// are 8 bytes and require alignment.
1520
var wide = (ch != {{{ charCode('i') }}});
1521
#if !MEMORY64
1522
wide &= (ch != {{{ charCode('p') }}});
1523
#endif
1524
buf += wide && (buf % 8) ? 4 : 0;
1525
readEmAsmArgsArray.push(
1526
// Special case for pointers under wasm64 or CAN_ADDRESS_2GB mode.
1527
ch == {{{ charCode('p') }}} ? {{{ makeGetValue('buf', 0, '*') }}} :
1528
#if WASM_BIGINT
1529
ch == {{{ charCode('j') }}} ? {{{ makeGetValue('buf', 0, 'i64') }}} :
1530
#endif
1531
ch == {{{ charCode('i') }}} ?
1532
{{{ makeGetValue('buf', 0, 'i32') }}} :
1533
{{{ makeGetValue('buf', 0, 'double') }}}
1534
);
1535
buf += wide ? 8 : 4;
1536
}
1537
return readEmAsmArgsArray;
1538
},
1539
1540
#if HAVE_EM_ASM
1541
$runEmAsmFunction__deps: ['$readEmAsmArgs'],
1542
$runEmAsmFunction: (code, sigPtr, argbuf) => {
1543
var args = readEmAsmArgs(sigPtr, argbuf);
1544
#if ASSERTIONS
1545
assert(ASM_CONSTS.hasOwnProperty(code), `No EM_ASM constant found at address ${code}. The loaded WebAssembly file is likely out of sync with the generated JavaScript.`);
1546
#endif
1547
return ASM_CONSTS[code](...args);
1548
},
1549
1550
emscripten_asm_const_int__deps: ['$runEmAsmFunction'],
1551
emscripten_asm_const_int: (code, sigPtr, argbuf) => {
1552
return runEmAsmFunction(code, sigPtr, argbuf);
1553
},
1554
emscripten_asm_const_double__deps: ['$runEmAsmFunction'],
1555
emscripten_asm_const_double: (code, sigPtr, argbuf) => {
1556
return runEmAsmFunction(code, sigPtr, argbuf);
1557
},
1558
1559
emscripten_asm_const_ptr__deps: ['$runEmAsmFunction'],
1560
emscripten_asm_const_ptr: (code, sigPtr, argbuf) => {
1561
return runEmAsmFunction(code, sigPtr, argbuf);
1562
},
1563
1564
$runMainThreadEmAsm__deps: ['$readEmAsmArgs',
1565
#if PTHREADS
1566
'$proxyToMainThread'
1567
#endif
1568
],
1569
$runMainThreadEmAsm: (emAsmAddr, sigPtr, argbuf, sync) => {
1570
var args = readEmAsmArgs(sigPtr, argbuf);
1571
#if PTHREADS
1572
if (ENVIRONMENT_IS_PTHREAD) {
1573
// EM_ASM functions are variadic, receiving the actual arguments as a buffer
1574
// in memory. the last parameter (argBuf) points to that data. We need to
1575
// always un-variadify that, *before proxying*, as in the async case this
1576
// is a stack allocation that LLVM made, which may go away before the main
1577
// thread gets the message. For that reason we handle proxying *after* the
1578
// call to readEmAsmArgs, and therefore we do that manually here instead
1579
// of using __proxy. (And for simplicity, do the same in the sync
1580
// case as well, even though it's not strictly necessary, to keep the two
1581
// code paths as similar as possible on both sides.)
1582
return proxyToMainThread(0, emAsmAddr, sync, ...args);
1583
}
1584
#endif
1585
#if ASSERTIONS
1586
assert(ASM_CONSTS.hasOwnProperty(emAsmAddr), `No EM_ASM constant found at address ${emAsmAddr}. The loaded WebAssembly file is likely out of sync with the generated JavaScript.`);
1587
#endif
1588
return ASM_CONSTS[emAsmAddr](...args);
1589
},
1590
emscripten_asm_const_int_sync_on_main_thread__deps: ['$runMainThreadEmAsm'],
1591
emscripten_asm_const_int_sync_on_main_thread: (emAsmAddr, sigPtr, argbuf) => runMainThreadEmAsm(emAsmAddr, sigPtr, argbuf, 1),
1592
1593
emscripten_asm_const_ptr_sync_on_main_thread__deps: ['$runMainThreadEmAsm'],
1594
emscripten_asm_const_ptr_sync_on_main_thread: (emAsmAddr, sigPtr, argbuf) => runMainThreadEmAsm(emAsmAddr, sigPtr, argbuf, 1),
1595
1596
emscripten_asm_const_double_sync_on_main_thread: 'emscripten_asm_const_int_sync_on_main_thread',
1597
emscripten_asm_const_async_on_main_thread__deps: ['$runMainThreadEmAsm'],
1598
emscripten_asm_const_async_on_main_thread: (emAsmAddr, sigPtr, argbuf) => runMainThreadEmAsm(emAsmAddr, sigPtr, argbuf, 0),
1599
#endif
1600
1601
#if !DECLARE_ASM_MODULE_EXPORTS
1602
// When DECLARE_ASM_MODULE_EXPORTS is set, this function is programmatically
1603
// created during linking. See `create_receiving` in `emscripten.py`.
1604
// When DECLARE_ASM_MODULE_EXPORTS=0 is set, `assignWasmExports` is instead
1605
// defined here as a normal JS library function.
1606
$assignWasmExports__deps: ['$asmjsMangle',
1607
#if DYNCALLS || !WASM_BIGINT
1608
, '$dynCalls'
1609
#endif
1610
],
1611
$assignWasmExports: (wasmExports) => {
1612
for (var [name, exportedSymbol] of Object.entries(wasmExports)) {
1613
name = asmjsMangle(name);
1614
#if DYNCALLS || !WASM_BIGINT
1615
if (name.startsWith('dynCall_')) {
1616
dynCalls[name.substr(8)] = exportedSymbol;
1617
}
1618
#endif
1619
// Special handling for Wasm globals. See `create_receiving` for the
1620
// static version of this code.
1621
if (typeof exportedSymbol.value != 'undefined') {
1622
#if MEMORY64
1623
exportedSymbol = Number(exportedSymbol.value);
1624
#else
1625
exportedSymbol = exportedSymbol.value
1626
#endif
1627
}
1628
#if MINIMAL_RUNTIME
1629
globalThis[name] = exportedSymbol;
1630
#else
1631
globalThis[name] = Module[name] = exportedSymbol;
1632
#endif
1633
}
1634
exportAliases(wasmExports);
1635
},
1636
#endif
1637
1638
// Parses as much of the given JS string to an integer, with quiet error
1639
// handling (returns a NaN on error). E.g. jstoi_q("123abc") returns 123.
1640
// Note that "smart" radix handling is employed for input string:
1641
// "0314" is parsed as octal, and "0x1234" is parsed as base-16.
1642
$jstoi_q__docs: '/** @suppress {checkTypes} */',
1643
$jstoi_q: (str) => parseInt(str),
1644
1645
#if LINK_AS_CXX
1646
// libunwind
1647
1648
_Unwind_Backtrace__deps: ['$getCallstack'],
1649
_Unwind_Backtrace: (func, arg) => {
1650
var trace = getCallstack();
1651
var parts = trace.split('\n');
1652
for (var i = 0; i < parts.length; i++) {
1653
var ret = {{{ makeDynCall('iii', 'func') }}}(0, arg);
1654
if (ret !== 0) return;
1655
}
1656
},
1657
1658
_Unwind_GetIPInfo: (context, ipBefore) => abort('Unwind_GetIPInfo'),
1659
1660
_Unwind_FindEnclosingFunction: (ip) => 0, // we cannot succeed
1661
1662
_Unwind_RaiseException__deps: ['__cxa_throw'],
1663
_Unwind_RaiseException: (ex) => {
1664
err('Warning: _Unwind_RaiseException is not correctly implemented');
1665
return ___cxa_throw(ex, 0, 0);
1666
},
1667
1668
_Unwind_DeleteException: (ex) => err('TODO: Unwind_DeleteException'),
1669
#endif
1670
1671
// special runtime support
1672
1673
#if STACK_OVERFLOW_CHECK
1674
// Used by wasm-emscripten-finalize to implement STACK_OVERFLOW_CHECK
1675
__handle_stack_overflow__deps: ['emscripten_stack_get_base', 'emscripten_stack_get_end', '$ptrToString'],
1676
__handle_stack_overflow: (requested) => {
1677
var base = _emscripten_stack_get_base();
1678
var end = _emscripten_stack_get_end();
1679
abort(`stack overflow (Attempt to set SP to ${ptrToString(requested)}` +
1680
`, with stack limits [${ptrToString(end)} - ${ptrToString(base)}` +
1681
']). If you require more stack space build with -sSTACK_SIZE=<bytes>');
1682
},
1683
#endif
1684
1685
#if MINIMAL_RUNTIME // MINIMAL_RUNTIME does not have a global runtime variable thisProgram
1686
$getExecutableName: () => {
1687
#if ENVIRONMENT_MAY_BE_NODE
1688
if (ENVIRONMENT_IS_NODE && process.argv.length > 1) {
1689
return process.argv[1].replace(/\\/g, '/');
1690
}
1691
#endif
1692
return "./this.program";
1693
},
1694
#else
1695
$getExecutableName: () => thisProgram || './this.program',
1696
#endif
1697
1698
// Receives a Web Audio context plus a set of elements to listen for user
1699
// input events on, and registers a context resume() for them. This lets
1700
// audio work properly in an automatic way, as browsers won't let audio run
1701
// without user interaction.
1702
$autoResumeAudioContext: (ctx) => {
1703
for (var event of ['keydown', 'mousedown', 'touchstart']) {
1704
for (var element of [document, document.getElementById('canvas')]) {
1705
element?.addEventListener(event, () => {
1706
if (ctx.state === 'suspended') ctx.resume();
1707
}, { 'once': true });
1708
}
1709
}
1710
},
1711
1712
#if DYNCALLS || !WASM_BIGINT
1713
$dynCalls__internal: true,
1714
$dynCalls: {},
1715
$dynCallLegacy__deps: ['$dynCalls'],
1716
$dynCallLegacy: (sig, ptr, args) => {
1717
sig = sig.replace(/p/g, {{{ MEMORY64 ? "'j'" : "'i'" }}})
1718
#if ASSERTIONS
1719
assert(sig in dynCalls, `bad function pointer type - sig is not in dynCalls: '${sig}'`);
1720
if (args?.length) {
1721
#if WASM_BIGINT
1722
// j (64-bit integer) is fine, and is implemented as a BigInt. Without
1723
// legalization, the number of parameters should match (j is not expanded
1724
// into two i's).
1725
assert(args.length === sig.length - 1);
1726
#else
1727
// j (64-bit integer) must be passed in as two numbers [low 32, high 32].
1728
assert(args.length === sig.substring(1).replace(/j/g, '--').length);
1729
#endif
1730
} else {
1731
assert(sig.length == 1);
1732
}
1733
#endif
1734
var f = dynCalls[sig];
1735
return f(ptr, ...args);
1736
},
1737
$dynCall__deps: [
1738
#if DYNCALLS || !WASM_BIGINT
1739
'$dynCallLegacy',
1740
#endif
1741
#if !DYNCALLS
1742
'$getWasmTableEntry',
1743
#endif
1744
],
1745
#endif
1746
1747
// Used in library code to get JS function from wasm function pointer.
1748
// All callers should use direct table access where possible and only fall
1749
// back to this function if needed.
1750
$getDynCaller__deps: ['$dynCall'],
1751
$getDynCaller: (sig, ptr, promising = false) => {
1752
#if ASSERTIONS && !DYNCALLS
1753
assert(sig.includes('j') || sig.includes('p'), 'getDynCaller should only be called with i64 sigs')
1754
#endif
1755
return (...args) => dynCall(sig, ptr, args, promising);
1756
},
1757
1758
$dynCall: (sig, ptr, args = [], promising = false) => {
1759
#if ASSERTIONS
1760
assert(ptr, `null function pointer in dynCall`);
1761
#endif
1762
#if ASSERTIONS && (DYNCALLS || !WASM_BIGINT || !JSPI)
1763
assert(!promising, 'async dynCall is not supported in this mode')
1764
#endif
1765
#if MEMORY64
1766
// With MEMORY64 we have an additional step to convert `p` arguments to
1767
// bigint. This is the runtime equivalent of the wrappers we create for wasm
1768
// exports in `emscripten.py:create_wasm64_wrappers`.
1769
for (var i = 1; i < sig.length; ++i) {
1770
if (sig[i] == 'p') args[i-1] = BigInt(args[i-1]);
1771
}
1772
#endif
1773
#if DYNCALLS
1774
var rtn = dynCallLegacy(sig, ptr, args);
1775
#else
1776
#if !WASM_BIGINT
1777
// Without WASM_BIGINT support we cannot directly call function with i64 as
1778
// part of their signature, so we rely on the dynCall functions generated by
1779
// wasm-emscripten-finalize
1780
if (sig.includes('j')) {
1781
return dynCallLegacy(sig, ptr, args);
1782
}
1783
#endif
1784
#if ASSERTIONS
1785
assert(getWasmTableEntry(ptr), `missing table entry in dynCall: ${ptr}`);
1786
#endif
1787
var func = getWasmTableEntry(ptr);
1788
#if JSPI
1789
if (promising) {
1790
func = WebAssembly.promising(func);
1791
}
1792
#endif
1793
var rtn = func(...args);
1794
#endif // DYNCALLS
1795
1796
function convert(rtn) {
1797
#if MEMORY64
1798
return sig[0] == 'p' ? Number(rtn) : rtn;
1799
#elif CAN_ADDRESS_2GB
1800
return sig[0] == 'p' ? rtn >>> 0 : rtn;
1801
#else
1802
return rtn;
1803
#endif
1804
}
1805
1806
#if JSPI
1807
if (promising) {
1808
return rtn.then(convert);
1809
}
1810
#endif
1811
return convert(rtn);
1812
},
1813
1814
$callRuntimeCallbacks__internal: true,
1815
$callRuntimeCallbacks: (callbacks) => {
1816
while (callbacks.length > 0) {
1817
// Pass the module as the first argument.
1818
callbacks.shift()(Module);
1819
}
1820
},
1821
1822
#if SHRINK_LEVEL == 0 || ASYNCIFY == 2
1823
// A mirror copy of contents of wasmTable in JS side, to avoid relatively
1824
// slow wasmTable.get() call. Only used when not compiling with -Os, -Oz, or
1825
// JSPI which needs to instrument the functions.
1826
$wasmTableMirror__internal: true,
1827
$wasmTableMirror: [],
1828
1829
$setWasmTableEntry__internal: true,
1830
$setWasmTableEntry__deps: ['$wasmTableMirror', '$wasmTable'],
1831
$setWasmTableEntry: (idx, func) => {
1832
/** @suppress {checkTypes} */
1833
wasmTable.set({{{ toIndexType('idx') }}}, func);
1834
// With ABORT_ON_WASM_EXCEPTIONS wasmTable.get is overridden to return wrapped
1835
// functions so we need to call it here to retrieve the potential wrapper correctly
1836
// instead of just storing 'func' directly into wasmTableMirror
1837
/** @suppress {checkTypes} */
1838
wasmTableMirror[idx] = wasmTable.get({{{ toIndexType('idx') }}});
1839
},
1840
1841
$getWasmTableEntry__internal: true,
1842
$getWasmTableEntry__deps: ['$wasmTableMirror', '$wasmTable'],
1843
$getWasmTableEntry: (funcPtr) => {
1844
#if MEMORY64
1845
// Function pointers should show up as numbers, even under wasm64, but
1846
// we still have some places where bigint values can flow here.
1847
// https://github.com/emscripten-core/emscripten/issues/18200
1848
funcPtr = Number(funcPtr);
1849
#endif
1850
var func = wasmTableMirror[funcPtr];
1851
if (!func) {
1852
/** @suppress {checkTypes} */
1853
wasmTableMirror[funcPtr] = func = wasmTable.get({{{ toIndexType('funcPtr') }}});
1854
#if ASYNCIFY == 2
1855
if (Asyncify.isAsyncExport(func)) {
1856
wasmTableMirror[funcPtr] = func = Asyncify.makeAsyncFunction(func);
1857
}
1858
#endif
1859
}
1860
#if ASSERTIONS && ASYNCIFY != 2 // With JSPI the function stored in the table will be a wrapper.
1861
/** @suppress {checkTypes} */
1862
assert(wasmTable.get({{{ toIndexType('funcPtr') }}}) == func, 'JavaScript-side Wasm function table mirror is out of date!');
1863
#endif
1864
return func;
1865
},
1866
1867
#else
1868
1869
$setWasmTableEntry__docs: '/** @suppress{checkTypes} */',
1870
$setWasmTableEntry__deps: ['$wasmTable'],
1871
$setWasmTableEntry: (idx, func) => wasmTable.set({{{ toIndexType('idx') }}}, func),
1872
1873
$getWasmTableEntry__docs: '/** @suppress{checkTypes} */',
1874
$getWasmTableEntry__deps: ['$wasmTable'],
1875
$getWasmTableEntry: (funcPtr) => {
1876
// In -Os and -Oz builds, do not implement a JS side wasm table mirror for small
1877
// code size, but directly access wasmTable, which is a bit slower as uncached.
1878
return wasmTable.get({{{ toIndexType('funcPtr') }}});
1879
},
1880
#endif // SHRINK_LEVEL == 0
1881
1882
// Callable in pthread without __proxy needed.
1883
emscripten_exit_with_live_runtime: () => {
1884
{{{ runtimeKeepalivePush() }}}
1885
throw 'unwind';
1886
},
1887
1888
#if !MINIMAL_RUNTIME
1889
_emscripten_runtime_keepalive_clear__deps: ['$runtimeKeepaliveCounter'],
1890
#endif
1891
_emscripten_runtime_keepalive_clear: () => {
1892
#if isSymbolNeeded('$noExitRuntime')
1893
noExitRuntime = false;
1894
#endif
1895
#if !MINIMAL_RUNTIME
1896
runtimeKeepaliveCounter = 0;
1897
#endif
1898
},
1899
1900
emscripten_force_exit__deps: ['exit', '_emscripten_runtime_keepalive_clear',
1901
#if !EXIT_RUNTIME && ASSERTIONS
1902
'$warnOnce',
1903
#endif
1904
],
1905
emscripten_force_exit__proxy: 'sync',
1906
emscripten_force_exit: (status) => {
1907
#if RUNTIME_DEBUG
1908
dbg('emscripten_force_exit');
1909
#endif
1910
#if !EXIT_RUNTIME && ASSERTIONS
1911
warnOnce('emscripten_force_exit cannot actually shut down the runtime, as the build does not have EXIT_RUNTIME set');
1912
#endif
1913
__emscripten_runtime_keepalive_clear();
1914
_exit(status);
1915
},
1916
1917
emscripten_out: (str) => out(UTF8ToString(str)),
1918
emscripten_outn: (str, len) => out(UTF8ToString(str, len)),
1919
1920
emscripten_err: (str) => err(UTF8ToString(str)),
1921
emscripten_errn: (str, len) => err(UTF8ToString(str, len)),
1922
1923
#if ASSERTIONS || RUNTIME_DEBUG
1924
emscripten_dbg: (str) => dbg(UTF8ToString(str)),
1925
emscripten_dbgn: (str, len) => dbg(UTF8ToString(str, len)),
1926
1927
emscripten_dbg_backtrace: (str) => {
1928
dbg(UTF8ToString(str) + '\n' + new Error().stack);
1929
},
1930
#endif
1931
1932
// Use program_invocation_short_name and program_invocation_name in compiled
1933
// programs. This function is for implementing them.
1934
_emscripten_get_progname__deps: ['$getExecutableName', '$stringToUTF8'],
1935
_emscripten_get_progname: (str, len) => stringToUTF8(getExecutableName(), str, len),
1936
1937
emscripten_console_log: (str) => {
1938
#if ASSERTIONS
1939
assert(typeof str == 'number');
1940
#endif
1941
console.log(UTF8ToString(str));
1942
},
1943
1944
emscripten_console_warn: (str) => {
1945
#if ASSERTIONS
1946
assert(typeof str == 'number');
1947
#endif
1948
console.warn(UTF8ToString(str));
1949
},
1950
1951
emscripten_console_error: (str) => {
1952
#if ASSERTIONS
1953
assert(typeof str == 'number');
1954
#endif
1955
console.error(UTF8ToString(str));
1956
},
1957
1958
emscripten_console_trace: (str) => {
1959
#if ASSERTIONS
1960
assert(typeof str == 'number');
1961
#endif
1962
console.trace(UTF8ToString(str));
1963
},
1964
1965
emscripten_throw_number: (number) => {
1966
throw number;
1967
},
1968
1969
emscripten_throw_string: (str) => {
1970
#if ASSERTIONS
1971
assert(typeof str == 'number');
1972
#endif
1973
throw UTF8ToString(str);
1974
},
1975
1976
#if !MINIMAL_RUNTIME
1977
#if STACK_OVERFLOW_CHECK
1978
$handleException__deps: ['emscripten_stack_get_current'],
1979
#endif
1980
$handleException: (e) => {
1981
// Certain exception types we do not treat as errors since they are used for
1982
// internal control flow.
1983
// 1. ExitStatus, which is thrown by exit()
1984
// 2. "unwind", which is thrown by emscripten_unwind_to_js_event_loop() and others
1985
// that wish to return to JS event loop.
1986
if (e instanceof ExitStatus || e == 'unwind') {
1987
#if RUNTIME_DEBUG
1988
dbg(`handleException: unwinding: EXITSTATUS=${EXITSTATUS}`);
1989
#endif
1990
return EXITSTATUS;
1991
}
1992
#if STACK_OVERFLOW_CHECK
1993
checkStackCookie();
1994
if (e instanceof WebAssembly.RuntimeError) {
1995
if (_emscripten_stack_get_current() <= 0) {
1996
err('Stack overflow detected. You can try increasing -sSTACK_SIZE (currently set to {{{ STACK_SIZE }}})');
1997
}
1998
}
1999
#endif
2000
#if RUNTIME_DEBUG
2001
dbg("handleException: got unexpected exception, calling quit_")
2002
#endif
2003
quit_(1, e);
2004
},
2005
2006
$runtimeKeepaliveCounter__internal: true,
2007
$runtimeKeepaliveCounter: 0,
2008
2009
#if isSymbolNeeded('$noExitRuntime')
2010
// If the `noExitRuntime` symbol is included in the build then
2011
// keepRuntimeAlive is always conditional since its state can change
2012
// at runtime.
2013
$keepRuntimeAlive__deps: ['$runtimeKeepaliveCounter'],
2014
$keepRuntimeAlive: () => noExitRuntime || runtimeKeepaliveCounter > 0,
2015
#elif !EXIT_RUNTIME && !PTHREADS
2016
// When `noExitRuntime` is not included and EXIT_RUNTIME=0 then we know the
2017
// runtime can never exit (i.e. should always be kept alive).
2018
// However, since pthreads themselves always need to be able to exit we
2019
// have to track `runtimeKeepaliveCounter` in that case.
2020
$keepRuntimeAlive: () => true,
2021
#else
2022
$keepRuntimeAlive__deps: ['$runtimeKeepaliveCounter'],
2023
$keepRuntimeAlive: () => runtimeKeepaliveCounter > 0,
2024
#endif
2025
2026
// Callable in pthread without __proxy needed.
2027
$runtimeKeepalivePush__deps: ['$runtimeKeepaliveCounter'],
2028
$runtimeKeepalivePush__sig: 'v',
2029
$runtimeKeepalivePush: () => {
2030
runtimeKeepaliveCounter += 1;
2031
#if RUNTIME_DEBUG
2032
dbg(`runtimeKeepalivePush -> counter=${runtimeKeepaliveCounter}`);
2033
#endif
2034
},
2035
2036
$runtimeKeepalivePop__deps: ['$runtimeKeepaliveCounter'],
2037
$runtimeKeepalivePop__sig: 'v',
2038
$runtimeKeepalivePop: () => {
2039
#if ASSERTIONS
2040
assert(runtimeKeepaliveCounter > 0);
2041
#endif
2042
runtimeKeepaliveCounter -= 1;
2043
#if RUNTIME_DEBUG
2044
dbg(`runtimeKeepalivePop -> counter=${runtimeKeepaliveCounter}`);
2045
#endif
2046
},
2047
2048
emscripten_runtime_keepalive_push: '$runtimeKeepalivePush',
2049
emscripten_runtime_keepalive_pop: '$runtimeKeepalivePop',
2050
emscripten_runtime_keepalive_check: '$keepRuntimeAlive',
2051
2052
// Used to call user callbacks from the embedder / event loop. For example
2053
// setTimeout or any other kind of event handler that calls into user case
2054
// needs to use this wrapper.
2055
//
2056
// The job of this wrapper is the handle emscripten-specific exceptions such
2057
// as ExitStatus and 'unwind' and prevent these from escaping to the top
2058
// level.
2059
$callUserCallback__deps: ['$handleException', '$maybeExit'],
2060
$callUserCallback: (func) => {
2061
#if EXIT_RUNTIME
2062
if (runtimeExited || ABORT) {
2063
#else
2064
if (ABORT) {
2065
#endif
2066
#if ASSERTIONS
2067
err('user callback triggered after runtime exited or application aborted. Ignoring.');
2068
#endif
2069
return;
2070
}
2071
try {
2072
return func();
2073
} catch (e) {
2074
handleException(e);
2075
} finally {
2076
maybeExit();
2077
}
2078
},
2079
2080
$maybeExit__deps: ['exit', '$handleException', '$keepRuntimeAlive',
2081
#if PTHREADS
2082
'_emscripten_thread_exit',
2083
#endif
2084
#if RUNTIME_DEBUG >= 2
2085
'$runtimeKeepaliveCounter',
2086
#endif
2087
],
2088
$maybeExit: () => {
2089
#if EXIT_RUNTIME
2090
if (runtimeExited) {
2091
return;
2092
}
2093
#endif
2094
#if RUNTIME_DEBUG >= 2
2095
dbg(`maybeExit: user callback done: runtimeKeepaliveCounter=${runtimeKeepaliveCounter}`);
2096
#endif
2097
if (!keepRuntimeAlive()) {
2098
#if RUNTIME_DEBUG
2099
dbg(`maybeExit: calling exit() implicitly after user callback completed: ${EXITSTATUS}`);
2100
#endif
2101
try {
2102
#if PTHREADS
2103
if (ENVIRONMENT_IS_PTHREAD) {
2104
// exit the current thread, but only if there is one active.
2105
// TODO(https://github.com/emscripten-core/emscripten/issues/25076):
2106
// Unify this check with the runtimeExited check above
2107
if (_pthread_self()) __emscripten_thread_exit(EXITSTATUS);
2108
return;
2109
}
2110
#endif
2111
_exit(EXITSTATUS);
2112
} catch (e) {
2113
handleException(e);
2114
}
2115
}
2116
},
2117
2118
$asyncLoad: async (url) => {
2119
var arrayBuffer = await readAsync(url);
2120
#if ASSERTIONS
2121
assert(arrayBuffer, `Loading data file "${url}" failed (no arrayBuffer).`);
2122
#endif
2123
return new Uint8Array(arrayBuffer);
2124
},
2125
2126
#else // MINIMAL_RUNTIME
2127
$callUserCallback: (func) => {
2128
// MINIMAL_RUNTIME doesn't support the runtimeKeepalive stuff, but under
2129
// some circumstances it supportes `runtimeExited`
2130
#if EXIT_RUNTIME
2131
if (runtimeExited) {
2132
#if ASSERTIONS
2133
err('user callback triggered after runtime exited or application aborted. Ignoring.');
2134
#endif
2135
return;
2136
}
2137
#endif
2138
func();
2139
},
2140
#endif // MINIMAL_RUNTIME
2141
2142
$asmjsMangle: (x) => {
2143
if (x == '__main_argc_argv') {
2144
x = 'main';
2145
}
2146
#if DYNCALLS
2147
return x.startsWith('dynCall_') ? x : '_' + x;
2148
#else
2149
return '_' + x;
2150
#endif
2151
},
2152
2153
$alignMemory: (size, alignment) => {
2154
#if ASSERTIONS
2155
assert(alignment, "alignment argument is required");
2156
#endif
2157
return Math.ceil(size / alignment) * alignment;
2158
},
2159
2160
// Allocate memory for an mmap operation. This allocates space of the right
2161
// page-aligned size, and clears the allocated space.
2162
#if hasExportedSymbol('emscripten_builtin_memalign')
2163
$mmapAlloc__deps: ['$zeroMemory', '$alignMemory'],
2164
#endif
2165
$mmapAlloc: (size) => {
2166
#if hasExportedSymbol('emscripten_builtin_memalign')
2167
size = alignMemory(size, {{{ WASM_PAGE_SIZE }}});
2168
var ptr = _emscripten_builtin_memalign({{{ WASM_PAGE_SIZE }}}, size);
2169
if (ptr) zeroMemory(ptr, size);
2170
return ptr;
2171
#elif ASSERTIONS
2172
abort('internal error: mmapAlloc called but `emscripten_builtin_memalign` native symbol not exported');
2173
#else
2174
abort();
2175
#endif
2176
},
2177
2178
#if RELOCATABLE
2179
// Globals that are normally exported from the wasm module but in relocatable
2180
// mode are created here and imported by the module.
2181
__stack_pointer: "new WebAssembly.Global({'value': '{{{ POINTER_WASM_TYPE }}}', 'mutable': true}, {{{ to64(STACK_HIGH) }}})",
2182
// tell the memory segments where to place themselves
2183
__memory_base: "new WebAssembly.Global({'value': '{{{ POINTER_WASM_TYPE }}}', 'mutable': false}, {{{ to64(GLOBAL_BASE) }}})",
2184
// the wasm backend reserves slot 0 for the NULL function pointer
2185
__table_base: "new WebAssembly.Global({'value': '{{{ POINTER_WASM_TYPE }}}', 'mutable': false}, {{{ to64(TABLE_BASE) }}})",
2186
#if MEMORY64 == 2
2187
__memory_base32: "new WebAssembly.Global({'value': 'i32', 'mutable': false}, {{{ GLOBAL_BASE }}})",
2188
#endif
2189
#if MEMORY64
2190
__table_base32: {{{ TABLE_BASE }}},
2191
#endif
2192
// To support such allocations during startup, track them on __heap_base and
2193
// then when the main module is loaded it reads that value and uses it to
2194
// initialize sbrk (the main module is relocatable itself, and so it does not
2195
// have __heap_base hardcoded into it - it receives it from JS as an extern
2196
// global, basically).
2197
__heap_base: '{{{ HEAP_BASE }}}',
2198
__stack_high: '{{{ STACK_HIGH }}}',
2199
__stack_low: '{{{ STACK_LOW }}}',
2200
__global_base: '{{{ GLOBAL_BASE }}}',
2201
#endif // RELOCATABLE
2202
2203
_emscripten_fs_load_embedded_files__deps: ['$FS', '$PATH'],
2204
_emscripten_fs_load_embedded_files: (ptr) => {
2205
#if RUNTIME_DEBUG
2206
dbg('preloading data files');
2207
#endif
2208
do {
2209
var name_addr = {{{ makeGetValue('ptr', '0', '*') }}};
2210
ptr += {{{ POINTER_SIZE }}};
2211
var len = {{{ makeGetValue('ptr', '0', '*') }}};
2212
ptr += {{{ POINTER_SIZE }}};
2213
var content = {{{ makeGetValue('ptr', '0', '*') }}};
2214
ptr += {{{ POINTER_SIZE }}};
2215
var name = UTF8ToString(name_addr)
2216
#if RUNTIME_DEBUG
2217
dbg(`preloading files: ${name}`);
2218
#endif
2219
FS.createPath('/', PATH.dirname(name), true, true);
2220
// canOwn this data in the filesystem, it is a slice of wasm memory that will never change
2221
FS.createDataFile(name, null, HEAP8.subarray(content, content + len), true, true, true);
2222
} while ({{{ makeGetValue('ptr', '0', '*') }}});
2223
#if RUNTIME_DEBUG
2224
dbg('done preloading data files');
2225
#endif
2226
},
2227
2228
$HandleAllocator: class {
2229
allocated = [undefined];
2230
freelist = [];
2231
get(id) {
2232
#if ASSERTIONS
2233
assert(this.allocated[id] !== undefined, `invalid handle: ${id}`);
2234
#endif
2235
return this.allocated[id];
2236
}
2237
has(id) {
2238
return this.allocated[id] !== undefined;
2239
}
2240
allocate(handle) {
2241
var id = this.freelist.pop() || this.allocated.length;
2242
this.allocated[id] = handle;
2243
return id;
2244
}
2245
free(id) {
2246
#if ASSERTIONS
2247
assert(this.allocated[id] !== undefined);
2248
#endif
2249
// Set the slot to `undefined` rather than using `delete` here since
2250
// apparently arrays with holes in them can be less efficient.
2251
this.allocated[id] = undefined;
2252
this.freelist.push(id);
2253
}
2254
},
2255
2256
$wasmTable__docs: '/** @type {WebAssembly.Table} */',
2257
#if RELOCATABLE
2258
// In RELOCATABLE mode we create the table in JS.
2259
$wasmTable: `=new WebAssembly.Table({
2260
'initial': {{{ toIndexType(INITIAL_TABLE) }}},
2261
#if !ALLOW_TABLE_GROWTH
2262
'maximum': {{{ toIndexType(INITIAL_TABLE) }}},
2263
#endif
2264
#if MEMORY64 == 1
2265
'address': 'i64',
2266
#endif
2267
'element': 'anyfunc'
2268
});
2269
`,
2270
#else
2271
// `wasmTable` is a JS alias for the Wasm `__indirect_function_table` export
2272
$wasmTable: '__indirect_function_table',
2273
#endif
2274
2275
#if IMPORTED_MEMORY
2276
// This gets defined in src/runtime_init_memory.js
2277
$wasmMemory: undefined,
2278
#else
2279
// `wasmMemory` is a JS alias for the Wasm `memory` export
2280
$wasmMemory: 'memory',
2281
#endif
2282
2283
$getUniqueRunDependency: (id) => {
2284
#if ASSERTIONS
2285
var orig = id;
2286
while (1) {
2287
if (!runDependencyTracking[id]) return id;
2288
id = orig + Math.random();
2289
}
2290
#else
2291
return id;
2292
#endif
2293
},
2294
2295
$noExitRuntime__postset: () => addAtModule(makeModuleReceive('noExitRuntime')),
2296
$noExitRuntime: {{{ !EXIT_RUNTIME }}},
2297
2298
#if !MINIMAL_RUNTIME
2299
// A counter of dependencies for calling run(). If we need to
2300
// do asynchronous work before running, increment this and
2301
// decrement it. Incrementing must happen in a place like
2302
// Module.preRun (used by emcc to add file preloading).
2303
// Note that you can add dependencies in preRun, even though
2304
// it happens right before run - run will be postponed until
2305
// the dependencies are met.
2306
$runDependencies__internal: true,
2307
$runDependencies: 0,
2308
// overridden to take different actions when all run dependencies are fulfilled
2309
$dependenciesFulfilled__internal: true,
2310
$dependenciesFulfilled: null,
2311
#if ASSERTIONS
2312
$runDependencyTracking__internal: true,
2313
$runDependencyTracking: {},
2314
$runDependencyWatcher__internal: true,
2315
$runDependencyWatcher: null,
2316
#endif
2317
2318
$addRunDependency__deps: ['$runDependencies', '$removeRunDependency',
2319
#if ASSERTIONS
2320
'$runDependencyTracking',
2321
'$runDependencyWatcher',
2322
#endif
2323
],
2324
$addRunDependency: (id) => {
2325
runDependencies++;
2326
2327
#if expectToReceiveOnModule('monitorRunDependencies')
2328
Module['monitorRunDependencies']?.(runDependencies);
2329
#endif
2330
2331
#if ASSERTIONS
2332
#if RUNTIME_DEBUG
2333
dbg('addRunDependency', id);
2334
#endif
2335
assert(id, 'addRunDependency requires an ID')
2336
assert(!runDependencyTracking[id]);
2337
runDependencyTracking[id] = 1;
2338
if (runDependencyWatcher === null && globalThis.setInterval) {
2339
// Check for missing dependencies every few seconds
2340
runDependencyWatcher = setInterval(() => {
2341
if (ABORT) {
2342
clearInterval(runDependencyWatcher);
2343
runDependencyWatcher = null;
2344
return;
2345
}
2346
var shown = false;
2347
for (var dep in runDependencyTracking) {
2348
if (!shown) {
2349
shown = true;
2350
err('still waiting on run dependencies:');
2351
}
2352
err(`dependency: ${dep}`);
2353
}
2354
if (shown) {
2355
err('(end of list)');
2356
}
2357
}, 10000);
2358
#if ENVIRONMENT_MAY_BE_NODE
2359
// Prevent this timer from keeping the runtime alive if nothing
2360
// else is.
2361
runDependencyWatcher.unref?.()
2362
#endif
2363
}
2364
#endif
2365
},
2366
2367
$removeRunDependency__deps: ['$runDependencies', '$dependenciesFulfilled',
2368
#if ASSERTIONS
2369
'$runDependencyTracking',
2370
'$runDependencyWatcher',
2371
#endif
2372
],
2373
$removeRunDependency: (id) => {
2374
runDependencies--;
2375
2376
#if expectToReceiveOnModule('monitorRunDependencies')
2377
Module['monitorRunDependencies']?.(runDependencies);
2378
#endif
2379
2380
#if ASSERTIONS
2381
#if RUNTIME_DEBUG
2382
dbg('removeRunDependency', id);
2383
#endif
2384
assert(id, 'removeRunDependency requires an ID');
2385
assert(runDependencyTracking[id]);
2386
delete runDependencyTracking[id];
2387
#endif
2388
if (runDependencies == 0) {
2389
#if ASSERTIONS
2390
if (runDependencyWatcher !== null) {
2391
clearInterval(runDependencyWatcher);
2392
runDependencyWatcher = null;
2393
}
2394
#endif
2395
if (dependenciesFulfilled) {
2396
var callback = dependenciesFulfilled;
2397
dependenciesFulfilled = null;
2398
callback(); // can add another dependenciesFulfilled
2399
}
2400
}
2401
},
2402
#endif
2403
2404
// The following addOn<X> functions are for adding runtime callbacks at
2405
// various executions points. Each addOn<X> function has a corresponding
2406
// compiled time version named addAt<X> that will instead inline during
2407
// compilation (see parseTools.mjs).
2408
// Note: if there are both runtime and compile time code, the runtime
2409
// callbacks will be invoked before the compile time code.
2410
2411
// See ATPRERUNS in parseTools.mjs for more information.
2412
$onPreRuns: [],
2413
$onPreRuns__internal: true,
2414
$onPreRuns__deps: ['$callRuntimeCallbacks'],
2415
$onPreRuns__postset: () => {
2416
ATPRERUNS.unshift('callRuntimeCallbacks(onPreRuns);');
2417
},
2418
$addOnPreRun__deps: ['$onPreRuns'],
2419
$addOnPreRun: (cb) => onPreRuns.push(cb),
2420
// See ATINITS in parseTools.mjs for more information.
2421
$onInits: [],
2422
$onInits__internal: true,
2423
$onInits__deps: ['$callRuntimeCallbacks'],
2424
$onInits__postset: () => {
2425
ATINITS.unshift('callRuntimeCallbacks(onInits);');
2426
},
2427
$addOnInit__deps: ['$onInits'],
2428
$addOnInit: (cb) => onInits.push(cb),
2429
// See ATPOSTCTORS in parseTools.mjs for more information.
2430
$onPostCtors: [],
2431
$onPostCtors__internal: true,
2432
$onPostCtors__deps: ['$callRuntimeCallbacks'],
2433
$onPostCtors__postset: () => {
2434
ATPOSTCTORS.unshift('callRuntimeCallbacks(onPostCtors);');
2435
},
2436
$addOnPostCtor__deps: ['$onPostCtors'],
2437
$addOnPostCtor: (cb) => onPostCtors.push(cb),
2438
// See ATMAINS in parseTools.mjs for more information.
2439
$onMains: [],
2440
$onMains__internal: true,
2441
$onMains__deps: ['$callRuntimeCallbacks'],
2442
$onMains__postset: () => {
2443
ATMAINS.unshift('callRuntimeCallbacks(onMains);');
2444
},
2445
$addOnPreMain__deps: ['$onMains'],
2446
$addOnPreMain: (cb) => onMains.push(cb),
2447
// See ATEXITS in parseTools.mjs for more information.
2448
$onExits: [],
2449
$onExits__internal: true,
2450
$onExits__deps: ['$callRuntimeCallbacks'],
2451
$onExits__postset: () => {
2452
ATEXITS.unshift('callRuntimeCallbacks(onExits);');
2453
},
2454
$addOnExit__deps: ['$onExits'],
2455
$addOnExit: (cb) => onExits.push(cb),
2456
// See ATPOSTRUNS in parseTools.mjs for more information.
2457
$onPostRuns: [],
2458
$onPostRuns__internal: true,
2459
$onPostRuns__deps: ['$callRuntimeCallbacks'],
2460
$onPostRuns__postset: () => {
2461
ATPOSTRUNS.unshift('callRuntimeCallbacks(onPostRuns);');
2462
},
2463
$addOnPostRun__deps: ['$onPostRuns'],
2464
$addOnPostRun: (cb) => onPostRuns.push(cb),
2465
2466
// We used to define these globals unconditionally in support code.
2467
// Instead, we now define them here so folks can pull it in explicitly, on
2468
// demand.
2469
$STACK_SIZE: {{{ STACK_SIZE }}},
2470
$STACK_ALIGN: {{{ STACK_ALIGN }}},
2471
$POINTER_SIZE: {{{ POINTER_SIZE }}},
2472
$ASSERTIONS: {{{ ASSERTIONS }}},
2473
});
2474
2475
function autoAddDeps(lib, name) {
2476
for (const item of Object.keys(lib)) {
2477
if (!isDecorator(item)) {
2478
lib[item + '__deps'] ??= [];
2479
lib[item + '__deps'].push(name);
2480
}
2481
}
2482
}
2483
2484
#if LEGACY_RUNTIME
2485
// Library functions that were previously included as runtime functions are
2486
// automatically included when `LEGACY_RUNTIME` is set.
2487
extraLibraryFuncs.push(
2488
'$addFunction',
2489
'$removeFunction',
2490
'$allocate',
2491
'$ALLOC_NORMAL',
2492
'$ALLOC_STACK',
2493
'$AsciiToString',
2494
'$stringToAscii',
2495
'$UTF16ToString',
2496
'$stringToUTF16',
2497
'$lengthBytesUTF16',
2498
'$UTF32ToString',
2499
'$stringToUTF32',
2500
'$lengthBytesUTF32',
2501
'$stringToNewUTF8',
2502
'$stringToUTF8OnStack',
2503
'$writeStringToMemory',
2504
'$writeArrayToMemory',
2505
'$writeAsciiToMemory',
2506
'$intArrayFromString',
2507
'$intArrayToString',
2508
'$warnOnce',
2509
'$ccall',
2510
'$cwrap',
2511
'$ExitStatus',
2512
'$UTF8ArrayToString',
2513
'$UTF8ToString',
2514
'$stringToUTF8Array',
2515
'$stringToUTF8',
2516
'$lengthBytesUTF8',
2517
);
2518
#endif
2519
2520
function wrapSyscallFunction(x, library, isWasi) {
2521
if (isJsOnlySymbol(x) || isDecorator(x)) {
2522
return;
2523
}
2524
2525
var t = library[x];
2526
if (typeof t == 'string') return;
2527
t = t.toString();
2528
2529
// If a syscall uses FS, but !SYSCALLS_REQUIRE_FILESYSTEM, then the user
2530
// has disabled the filesystem or we have proven some other way that this will
2531
// not be called in practice, and do not need that code.
2532
if (!SYSCALLS_REQUIRE_FILESYSTEM && t.includes('FS.')) {
2533
library[x + '__deps'] = [];
2534
t = modifyJSFunction(t, (args, body) => {
2535
return `(${args}) => {\n` +
2536
(ASSERTIONS ? "abort('it should not be possible to operate on streams when !SYSCALLS_REQUIRE_FILESYSTEM');\n" : '') +
2537
'}';
2538
});
2539
}
2540
2541
var isVariadic = !isWasi && t.includes(', varargs');
2542
#if SYSCALLS_REQUIRE_FILESYSTEM
2543
var canThrow = library[x + '__nothrow'] !== true;
2544
#else
2545
var canThrow = false;
2546
#endif
2547
2548
library[x + '__deps'] ??= [];
2549
2550
#if PURE_WASI && !GROWABLE_ARRAYBUFFERS
2551
// In PURE_WASI mode we can't assume the wasm binary was built by emscripten
2552
// and politely notify us on memory growth. Instead we have to check for
2553
// possible memory growth on each syscall.
2554
var pre = '\nif (!HEAPU8.byteLength) _emscripten_notify_memory_growth(0);\n'
2555
library[x + '__deps'].push('emscripten_notify_memory_growth');
2556
#else
2557
var pre = '';
2558
#endif
2559
var post = '';
2560
if (isVariadic) {
2561
pre += 'SYSCALLS.varargs = varargs;\n';
2562
}
2563
2564
#if SYSCALL_DEBUG
2565
if (isVariadic) {
2566
if (canThrow) {
2567
post += 'finally { SYSCALLS.varargs = undefined; }\n';
2568
} else {
2569
post += 'SYSCALLS.varargs = undefined;\n';
2570
}
2571
}
2572
pre += `dbg('syscall! ${x}: [' + Array.prototype.slice.call(arguments) + ']');\n`;
2573
pre += "var canWarn = true;\n";
2574
pre += "var ret = (() => {";
2575
post += "})();\n";
2576
post += "if (ret && ret < 0 && canWarn) {\n";
2577
post += " dbg(`error: syscall may have failed with ${-ret} (${strError(-ret)})`);\n";
2578
post += "}\n";
2579
post += "dbg(`syscall return: ${ret}`);\n";
2580
post += "return ret;\n";
2581
// Emit dependency to strError() since we added use of it above.
2582
library[x + '__deps'].push('$strError');
2583
#endif
2584
delete library[x + '__nothrow'];
2585
var handler = '';
2586
if (canThrow) {
2587
pre += 'try {\n';
2588
handler +=
2589
"} catch (e) {\n" +
2590
" if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;\n";
2591
#if SYSCALL_DEBUG
2592
handler +=
2593
" dbg(`error: syscall failed with ${e.errno} (${strError(e.errno)})`);\n" +
2594
" canWarn = false;\n";
2595
#endif
2596
// Musl syscalls are negated.
2597
if (isWasi) {
2598
handler += " return e.errno;\n";
2599
} else {
2600
// Musl syscalls are negated.
2601
handler += " return -e.errno;\n";
2602
}
2603
handler += "}\n";
2604
}
2605
post = handler + post;
2606
2607
if (pre || post) {
2608
t = modifyJSFunction(t, (args, body, async_) => `${async_}function (${args}) {\n${pre}${body}${post}}\n`);
2609
}
2610
2611
library[x] = eval('(' + t + ')');
2612
// Automatically add dependency on `$SYSCALLS`
2613
if (!WASMFS && t.includes('SYSCALLS')) {
2614
library[x + '__deps'].push('$SYSCALLS');
2615
}
2616
#if PTHREADS
2617
// Most syscalls need to happen on the main JS thread (e.g. because the
2618
// filesystem is in JS and on that thread). Proxy synchronously to there.
2619
// There are some exceptions, syscalls that we know are ok to just run in
2620
// any thread; those are marked as not being proxied with
2621
// __proxy: false
2622
// A syscall without a return value could perhaps be proxied asynchronously
2623
// instead of synchronously, and marked with
2624
// __proxy: 'async'
2625
// (but essentially all syscalls do have return values).
2626
if (library[x + '__proxy'] === undefined) {
2627
library[x + '__proxy'] = 'sync';
2628
}
2629
#endif
2630
}
2631
2632