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