Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
emscripten-core
GitHub Repository: emscripten-core/emscripten
Path: blob/main/src/preamble.js
4128 views
1
/**
2
* @license
3
* Copyright 2010 The Emscripten Authors
4
* SPDX-License-Identifier: MIT
5
*/
6
7
// === Preamble library stuff ===
8
9
// Documentation for the public APIs defined in this file must be updated in:
10
// site/source/docs/api_reference/preamble.js.rst
11
// A prebuilt local version of the documentation is available at:
12
// site/build/text/docs/api_reference/preamble.js.txt
13
// You can also build docs locally as HTML or other formats in site/
14
// An online HTML version (which may be of a different version of Emscripten)
15
// is up at http://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html
16
17
#if RELOCATABLE
18
{{{ makeModuleReceiveWithVar('dynamicLibraries', undefined, '[]') }}}
19
#endif
20
21
{{{ makeModuleReceiveWithVar('wasmBinary') }}}
22
23
#if WASM2JS
24
#if WASM != 2
25
// WASM == 2 includes wasm2js.js separately.
26
#include "wasm2js.js"
27
#endif
28
29
if (WebAssembly.isWasm2js) {
30
// We don't need to actually download a wasm binary, mark it as present but
31
// empty.
32
wasmBinary = [];
33
}
34
#endif
35
36
#if ASSERTIONS && WASM == 1
37
if (typeof WebAssembly != 'object') {
38
err('no native wasm support detected');
39
}
40
#endif
41
42
// Wasm globals
43
44
#if SHARED_MEMORY
45
// For sending to workers.
46
var wasmModule;
47
#endif // SHARED_MEMORY
48
49
//========================================
50
// Runtime essentials
51
//========================================
52
53
// whether we are quitting the application. no code should run after this.
54
// set in exit() and abort()
55
var ABORT = false;
56
57
// set by exit() and abort(). Passed to 'onExit' handler.
58
// NOTE: This is also used as the process return code code in shell environments
59
// but only when noExitRuntime is false.
60
var EXITSTATUS;
61
62
#if ASSERTIONS || !STRICT
63
// In STRICT mode, we only define assert() when ASSERTIONS is set. i.e. we
64
// don't define it at all in release modes. This matches the behaviour of
65
// MINIMAL_RUNTIME.
66
// TODO(sbc): Make this the default even without STRICT enabled.
67
/** @type {function(*, string=)} */
68
function assert(condition, text) {
69
if (!condition) {
70
#if ASSERTIONS
71
abort('Assertion failed' + (text ? ': ' + text : ''));
72
#else
73
// This build was created without ASSERTIONS defined. `assert()` should not
74
// ever be called in this configuration but in case there are callers in
75
// the wild leave this simple abort() implementation here for now.
76
abort(text);
77
#endif
78
}
79
}
80
#endif
81
82
#if ASSERTIONS
83
// We used to include malloc/free by default in the past. Show a helpful error in
84
// builds with assertions.
85
#if !hasExportedSymbol('malloc')
86
function _malloc() {
87
abort('malloc() called but not included in the build - add `_malloc` to EXPORTED_FUNCTIONS');
88
}
89
#endif // malloc
90
#if !hasExportedSymbol('free')
91
function _free() {
92
// Show a helpful error since we used to include free by default in the past.
93
abort('free() called but not included in the build - add `_free` to EXPORTED_FUNCTIONS');
94
}
95
#endif // free
96
#endif // ASSERTIONS
97
98
/**
99
* Indicates whether filename is delivered via file protocol (as opposed to http/https)
100
* @noinline
101
*/
102
var isFileURI = (filename) => filename.startsWith('file://');
103
104
#include "runtime_common.js"
105
106
#if ASSERTIONS
107
assert(typeof Int32Array != 'undefined' && typeof Float64Array !== 'undefined' && Int32Array.prototype.subarray != undefined && Int32Array.prototype.set != undefined,
108
'JS engine does not provide full typed array support');
109
#endif
110
111
#if RELOCATABLE
112
var __RELOC_FUNCS__ = [];
113
#endif
114
115
function preRun() {
116
#if ASSERTIONS && PTHREADS
117
assert(!ENVIRONMENT_IS_PTHREAD); // PThreads reuse the runtime from the main thread.
118
#endif
119
#if expectToReceiveOnModule('preRun')
120
if (Module['preRun']) {
121
if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']];
122
while (Module['preRun'].length) {
123
addOnPreRun(Module['preRun'].shift());
124
}
125
}
126
#if ASSERTIONS
127
consumedModuleProp('preRun');
128
#endif
129
#endif
130
<<< ATPRERUNS >>>
131
}
132
133
function initRuntime() {
134
#if RUNTIME_DEBUG
135
dbg('initRuntime');
136
#endif
137
#if ASSERTIONS
138
assert(!runtimeInitialized);
139
#endif
140
runtimeInitialized = true;
141
142
#if WASM_WORKERS
143
if (ENVIRONMENT_IS_WASM_WORKER) return _wasmWorkerInitializeRuntime();
144
#endif
145
146
#if PTHREADS
147
if (ENVIRONMENT_IS_PTHREAD) return startWorker();
148
#endif
149
150
#if STACK_OVERFLOW_CHECK >= 2
151
setStackLimits();
152
#endif
153
154
#if STACK_OVERFLOW_CHECK
155
checkStackCookie();
156
#endif
157
158
#if RELOCATABLE
159
callRuntimeCallbacks(__RELOC_FUNCS__);
160
#endif
161
162
<<< ATINITS >>>
163
164
#if hasExportedSymbol('__wasm_call_ctors')
165
#if WASM_ESM_INTEGRATION
166
___wasm_call_ctors();
167
#else
168
wasmExports['__wasm_call_ctors']();
169
#endif
170
#endif
171
172
<<< ATPOSTCTORS >>>
173
}
174
175
#if HAS_MAIN
176
function preMain() {
177
#if STACK_OVERFLOW_CHECK
178
checkStackCookie();
179
#endif
180
<<< ATMAINS >>>
181
}
182
#endif
183
184
#if EXIT_RUNTIME
185
function exitRuntime() {
186
#if RUNTIME_DEBUG
187
dbg('exitRuntime');
188
#endif
189
#if ASSERTIONS
190
assert(!runtimeExited);
191
#endif
192
#if ASYNCIFY == 1 && ASSERTIONS
193
// ASYNCIFY cannot be used once the runtime starts shutting down.
194
Asyncify.state = Asyncify.State.Disabled;
195
#endif
196
#if STACK_OVERFLOW_CHECK
197
checkStackCookie();
198
#endif
199
{{{ runIfWorkerThread('return;') }}} // PThreads reuse the runtime from the main thread.
200
#if !STANDALONE_WASM
201
___funcs_on_exit(); // Native atexit() functions
202
#endif
203
<<< ATEXITS >>>
204
#if PTHREADS
205
PThread.terminateAllThreads();
206
#endif
207
runtimeExited = true;
208
}
209
#endif
210
211
function postRun() {
212
#if STACK_OVERFLOW_CHECK
213
checkStackCookie();
214
#endif
215
{{{ runIfWorkerThread('return;') }}} // PThreads reuse the runtime from the main thread.
216
217
#if expectToReceiveOnModule('postRun')
218
if (Module['postRun']) {
219
if (typeof Module['postRun'] == 'function') Module['postRun'] = [Module['postRun']];
220
while (Module['postRun'].length) {
221
addOnPostRun(Module['postRun'].shift());
222
}
223
}
224
#if ASSERTIONS
225
consumedModuleProp('postRun');
226
#endif
227
#endif
228
229
<<< ATPOSTRUNS >>>
230
}
231
232
/** @param {string|number=} what */
233
function abort(what) {
234
#if expectToReceiveOnModule('onAbort')
235
Module['onAbort']?.(what);
236
#endif
237
238
what = 'Aborted(' + what + ')';
239
// TODO(sbc): Should we remove printing and leave it up to whoever
240
// catches the exception?
241
err(what);
242
243
ABORT = true;
244
245
#if ASSERTIONS == 0
246
what += '. Build with -sASSERTIONS for more info.';
247
#elif ASYNCIFY == 1
248
if (what.indexOf('RuntimeError: unreachable') >= 0) {
249
what += '. "unreachable" may be due to ASYNCIFY_STACK_SIZE not being large enough (try increasing it)';
250
}
251
#endif // ASSERTIONS
252
253
// Use a wasm runtime error, because a JS error might be seen as a foreign
254
// exception, which means we'd run destructors on it. We need the error to
255
// simply make the program stop.
256
// FIXME This approach does not work in Wasm EH because it currently does not assume
257
// all RuntimeErrors are from traps; it decides whether a RuntimeError is from
258
// a trap or not based on a hidden field within the object. So at the moment
259
// we don't have a way of throwing a wasm trap from JS. TODO Make a JS API that
260
// allows this in the wasm spec.
261
262
// Suppress closure compiler warning here. Closure compiler's builtin extern
263
// definition for WebAssembly.RuntimeError claims it takes no arguments even
264
// though it can.
265
// TODO(https://github.com/google/closure-compiler/pull/3913): Remove if/when upstream closure gets fixed.
266
#if WASM_EXCEPTIONS == 1
267
// See above, in the meantime, we resort to wasm code for trapping.
268
//
269
// In case abort() is called before the module is initialized, wasmExports
270
// and its exported '__trap' function is not available, in which case we throw
271
// a RuntimeError.
272
//
273
// We trap instead of throwing RuntimeError to prevent infinite-looping in
274
// Wasm EH code (because RuntimeError is considered as a foreign exception and
275
// caught by 'catch_all'), but in case throwing RuntimeError is fine because
276
// the module has not even been instantiated, even less running.
277
if (runtimeInitialized) {
278
___trap();
279
}
280
#endif
281
/** @suppress {checkTypes} */
282
var e = new WebAssembly.RuntimeError(what);
283
284
#if MODULARIZE
285
readyPromiseReject?.(e);
286
#endif
287
// Throw the error whether or not MODULARIZE is set because abort is used
288
// in code paths apart from instantiation where an exception is expected
289
// to be thrown when abort is called.
290
throw e;
291
}
292
293
#if ASSERTIONS && !('$FS' in addedLibraryItems)
294
// show errors on likely calls to FS when it was not included
295
var FS = {
296
error() {
297
abort('Filesystem support (FS) was not included. The problem is that you are using files from JS, but files were not used from C/C++, so filesystem support was not auto-included. You can force-include filesystem support with -sFORCE_FILESYSTEM');
298
},
299
init() { FS.error() },
300
createDataFile() { FS.error() },
301
createPreloadedFile() { FS.error() },
302
createLazyFile() { FS.error() },
303
open() { FS.error() },
304
mkdev() { FS.error() },
305
registerDevice() { FS.error() },
306
analyzePath() { FS.error() },
307
308
ErrnoError() { FS.error() },
309
};
310
{{{
311
addAtModule(`
312
Module['FS_createDataFile'] = FS.createDataFile;
313
Module['FS_createPreloadedFile'] = FS.createPreloadedFile;
314
`);
315
}}}
316
#endif
317
318
#if ASSERTIONS
319
function createExportWrapper(name, nargs) {
320
return (...args) => {
321
assert(runtimeInitialized, `native function \`${name}\` called before runtime initialization`);
322
#if EXIT_RUNTIME
323
assert(!runtimeExited, `native function \`${name}\` called after runtime exit (use NO_EXIT_RUNTIME to keep it alive after main() exits)`);
324
#endif
325
var f = wasmExports[name];
326
assert(f, `exported native function \`${name}\` not found`);
327
// Only assert for too many arguments. Too few can be valid since the missing arguments will be zero filled.
328
assert(args.length <= nargs, `native function \`${name}\` called with ${args.length} args but expects ${nargs}`);
329
return f(...args);
330
};
331
}
332
#endif
333
334
#if ABORT_ON_WASM_EXCEPTIONS
335
// `abortWrapperDepth` counts the recursion level of the wrapper function so
336
// that we only handle exceptions at the top level letting the exception
337
// mechanics work uninterrupted at the inner level. Additionally,
338
// `abortWrapperDepth` is also manually incremented in callMain so that we know
339
// to ignore exceptions from there since they're handled by callMain directly.
340
var abortWrapperDepth = 0;
341
342
function makeAbortWrapper(original) {
343
return (...args) => {
344
// Don't allow this function to be called if we're aborted!
345
if (ABORT) {
346
throw 'program has already aborted!';
347
}
348
349
abortWrapperDepth++;
350
try {
351
return original(...args);
352
} catch (e) {
353
if (
354
ABORT // rethrow exception if abort() was called in the original function call above
355
|| abortWrapperDepth > 1 // rethrow exceptions not caught at the top level if exception catching is enabled; rethrow from exceptions from within callMain
356
#if SUPPORT_LONGJMP == 'emscripten' // Rethrow longjmp if enabled
357
#if EXCEPTION_STACK_TRACES
358
|| e instanceof EmscriptenSjLj // EXCEPTION_STACK_TRACES=1 will throw an instance of EmscriptenSjLj
359
#else
360
|| e === Infinity // EXCEPTION_STACK_TRACES=0 will throw Infinity
361
#endif // EXCEPTION_STACK_TRACES
362
#endif
363
|| e === 'unwind'
364
) {
365
throw e;
366
}
367
368
abort('unhandled exception: ' + [e, e.stack]);
369
}
370
finally {
371
abortWrapperDepth--;
372
}
373
}
374
}
375
376
// Instrument all the exported functions to:
377
// - abort if an unhandled exception occurs
378
// - throw an exception if someone tries to call them after the program has aborted
379
// See settings.ABORT_ON_WASM_EXCEPTIONS for more info.
380
function instrumentWasmExportsWithAbort(exports) {
381
// Override the exported functions with the wrappers and copy over any other symbols
382
var instExports = {};
383
for (var name in exports) {
384
var original = exports[name];
385
if (typeof original == 'function') {
386
instExports[name] = makeAbortWrapper(original);
387
} else {
388
instExports[name] = original;
389
}
390
}
391
392
return instExports;
393
}
394
395
function instrumentWasmTableWithAbort() {
396
// Override the wasmTable get function to return the wrappers
397
var realGet = wasmTable.get;
398
var wrapperCache = {};
399
wasmTable.get = (i) => {
400
var func = realGet.call(wasmTable, {{{ toIndexType('i') }}});
401
var cached = wrapperCache[i];
402
if (!cached || cached.func !== func) {
403
cached = wrapperCache[i] = {
404
func,
405
wrapper: makeAbortWrapper(func)
406
}
407
}
408
return cached.wrapper;
409
};
410
}
411
#endif
412
413
#if !SOURCE_PHASE_IMPORTS && !WASM_ESM_INTEGRATION
414
var wasmBinaryFile;
415
416
function findWasmBinary() {
417
#if SINGLE_FILE && WASM == 1 && !WASM2JS
418
return base64Decode('<<< WASM_BINARY_DATA >>>');
419
#else
420
#if EXPORT_ES6 && !AUDIO_WORKLET
421
if (Module['locateFile']) {
422
#endif
423
return locateFile('{{{ WASM_BINARY_FILE }}}');
424
#if EXPORT_ES6 && !AUDIO_WORKLET // For an Audio Worklet, we cannot use `new URL()`.
425
}
426
#if ENVIRONMENT_MAY_BE_SHELL
427
if (ENVIRONMENT_IS_SHELL) {
428
return '{{{ WASM_BINARY_FILE }}}';
429
}
430
#endif
431
// Use bundler-friendly `new URL(..., import.meta.url)` pattern; works in browsers too.
432
return new URL('{{{ WASM_BINARY_FILE }}}', import.meta.url).href;
433
#endif
434
#endif
435
}
436
437
function getBinarySync(file) {
438
#if SINGLE_FILE && WASM == 1 && !WASM2JS
439
if (ArrayBuffer.isView(file)) {
440
return file;
441
}
442
#endif
443
#if expectToReceiveOnModule('wasmBinary') || WASM2JS
444
if (file == wasmBinaryFile && wasmBinary) {
445
return new Uint8Array(wasmBinary);
446
}
447
#endif
448
if (readBinary) {
449
return readBinary(file);
450
}
451
#if WASM_ASYNC_COMPILATION
452
throw 'both async and sync fetching of the wasm failed';
453
#else
454
throw 'sync fetching of the wasm failed: you can preload it to Module["wasmBinary"] manually, or emcc.py will do that for you when generating HTML (but not JS)';
455
#endif
456
}
457
458
async function getWasmBinary(binaryFile) {
459
#if !SINGLE_FILE
460
// If we don't have the binary yet, load it asynchronously using readAsync.
461
if (!wasmBinary) {
462
// Fetch the binary using readAsync
463
try {
464
var response = await readAsync(binaryFile);
465
return new Uint8Array(response);
466
} catch {
467
// Fall back to getBinarySync below;
468
}
469
}
470
#endif
471
472
// Otherwise, getBinarySync should be able to get it synchronously
473
return getBinarySync(binaryFile);
474
}
475
476
#if SPLIT_MODULE
477
{{{ makeModuleReceiveWithVar('loadSplitModule', undefined, 'instantiateSync') }}}
478
var splitModuleProxyHandler = {
479
get(target, prop, receiver) {
480
return (...args) => {
481
#if ASYNCIFY == 2
482
throw new Error('Placeholder function "' + prop + '" should not be called when using JSPI.');
483
#else
484
err(`placeholder function called: ${prop}`);
485
var imports = {'primary': wasmExports};
486
// Replace '.wasm' suffix with '.deferred.wasm'.
487
var deferred = wasmBinaryFile.slice(0, -5) + '.deferred.wasm'
488
loadSplitModule(deferred, imports, prop);
489
err('instantiated deferred module, continuing');
490
#if RELOCATABLE
491
// When the table is dynamically laid out, the placeholder functions names
492
// are offsets from the table base. In the main module, the table base is
493
// always 1.
494
return wasmTable.get(1 + parseInt(prop))(...args);
495
#else
496
return wasmTable.get(prop)(...args);
497
#endif
498
#endif
499
}
500
}
501
};
502
#endif
503
504
#if SPLIT_MODULE || !WASM_ASYNC_COMPILATION
505
function instantiateSync(file, info) {
506
var module;
507
var binary = getBinarySync(file);
508
#if NODE_CODE_CACHING
509
if (ENVIRONMENT_IS_NODE) {
510
var v8 = require('v8');
511
// Include the V8 version in the cache name, so that we don't try to
512
// load cached code from another version, which fails silently (it seems
513
// to load ok, but we do actually recompile the binary every time).
514
var cachedCodeFile = '{{{ WASM_BINARY_FILE }}}.' + v8.cachedDataVersionTag() + '.cached';
515
cachedCodeFile = locateFile(cachedCodeFile);
516
var hasCached = fs.existsSync(cachedCodeFile);
517
if (hasCached) {
518
#if RUNTIME_DEBUG
519
dbg('NODE_CODE_CACHING: loading module');
520
#endif
521
try {
522
module = v8.deserialize(fs.readFileSync(cachedCodeFile));
523
} catch (e) {
524
err(`NODE_CODE_CACHING: failed to deserialize, bad cache file? (${cachedCodeFile})`);
525
// Save the new compiled code when we have it.
526
hasCached = false;
527
}
528
}
529
}
530
module ||= new WebAssembly.Module(binary);
531
if (ENVIRONMENT_IS_NODE && !hasCached) {
532
#if RUNTIME_DEBUG
533
dbg('NODE_CODE_CACHING: saving module');
534
#endif
535
fs.writeFileSync(cachedCodeFile, v8.serialize(module));
536
}
537
#else // NODE_CODE_CACHING
538
module = new WebAssembly.Module(binary);
539
#endif // NODE_CODE_CACHING
540
var instance = new WebAssembly.Instance(module, info);
541
return [instance, module];
542
}
543
#endif
544
545
#if WASM_ASYNC_COMPILATION
546
async function instantiateArrayBuffer(binaryFile, imports) {
547
try {
548
var binary = await getWasmBinary(binaryFile);
549
var instance = await WebAssembly.instantiate(binary, imports);
550
return instance;
551
} catch (reason) {
552
err(`failed to asynchronously prepare wasm: ${reason}`);
553
#if WASM == 2
554
#if ENVIRONMENT_MAY_BE_NODE || ENVIRONMENT_MAY_BE_SHELL
555
if (typeof location != 'undefined') {
556
#endif
557
// WebAssembly compilation failed, try running the JS fallback instead.
558
var search = location.search;
559
if (search.indexOf('_rwasm=0') < 0) {
560
// Reload the page with the `_rwasm=0` argument
561
location.href += (search ? search + '&' : '?') + '_rwasm=0';
562
// Return a promise that never resolves. We don't want to
563
// call abort below, or return an error to our caller.
564
return new Promise(() => {});
565
}
566
#if ENVIRONMENT_MAY_BE_NODE || ENVIRONMENT_MAY_BE_SHELL
567
}
568
#endif
569
#endif // WASM == 2
570
571
#if ASSERTIONS
572
// Warn on some common problems.
573
if (isFileURI(wasmBinaryFile)) {
574
err(`warning: Loading from a file URI (${wasmBinaryFile}) is not supported in most browsers. See https://emscripten.org/docs/getting_started/FAQ.html#how-do-i-run-a-local-webserver-for-testing-why-does-my-program-stall-in-downloading-or-preparing`);
575
}
576
#endif
577
abort(reason);
578
}
579
}
580
581
async function instantiateAsync(binary, binaryFile, imports) {
582
#if !SINGLE_FILE
583
if (!binary
584
#if MIN_FIREFOX_VERSION < 58 || MIN_CHROME_VERSION < 61 || MIN_SAFARI_VERSION < 150000
585
// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/instantiateStreaming
586
&& WebAssembly.instantiateStreaming
587
#endif
588
#if ENVIRONMENT_MAY_BE_WEBVIEW
589
// Don't use streaming for file:// delivered objects in a webview, fetch them synchronously.
590
&& !isFileURI(binaryFile)
591
#endif
592
#if ENVIRONMENT_MAY_BE_NODE
593
// Avoid instantiateStreaming() on Node.js environment for now, as while
594
// Node.js v18.1.0 implements it, it does not have a full fetch()
595
// implementation yet.
596
//
597
// Reference:
598
// https://github.com/emscripten-core/emscripten/pull/16917
599
&& !ENVIRONMENT_IS_NODE
600
#endif
601
#if ENVIRONMENT_MAY_BE_SHELL
602
// Shell environments don't have fetch.
603
&& !ENVIRONMENT_IS_SHELL
604
#endif
605
) {
606
try {
607
var response = fetch(binaryFile, {{{ makeModuleReceiveExpr('fetchSettings', "{ credentials: 'same-origin' }") }}});
608
var instantiationResult = await WebAssembly.instantiateStreaming(response, imports);
609
return instantiationResult;
610
} catch (reason) {
611
// We expect the most common failure cause to be a bad MIME type for the binary,
612
// in which case falling back to ArrayBuffer instantiation should work.
613
err(`wasm streaming compile failed: ${reason}`);
614
err('falling back to ArrayBuffer instantiation');
615
// fall back of instantiateArrayBuffer below
616
};
617
}
618
#endif
619
return instantiateArrayBuffer(binaryFile, imports);
620
}
621
#endif // WASM_ASYNC_COMPILATION
622
#endif // SOURCE_PHASE_IMPORTS
623
624
#if !WASM_ESM_INTEGRATION
625
function getWasmImports() {
626
#if PTHREADS || WASM_WORKERS || (IMPORTED_MEMORY && MODULARIZE == 'instance')
627
assignWasmImports();
628
#endif
629
#if ASYNCIFY && (ASSERTIONS || ASYNCIFY == 2)
630
// instrumenting imports is used in asyncify in two ways: to add assertions
631
// that check for proper import use, and for ASYNCIFY=2 we use them to set up
632
// the Promise API on the import side.
633
#if PTHREADS || ASYNCIFY_LAZY_LOAD_CODE
634
// In pthreads builds getWasmImports is called more than once but we only
635
// and the instrument the imports once.
636
if (!wasmImports.__instrumented) {
637
wasmImports.__instrumented = true;
638
Asyncify.instrumentWasmImports(wasmImports);
639
}
640
#else
641
Asyncify.instrumentWasmImports(wasmImports);
642
#endif
643
#endif
644
// prepare imports
645
return {
646
#if MINIFY_WASM_IMPORTED_MODULES
647
'a': wasmImports,
648
#else // MINIFY_WASM_IMPORTED_MODULES
649
'env': wasmImports,
650
'{{{ WASI_MODULE_NAME }}}': wasmImports,
651
#endif // MINIFY_WASM_IMPORTED_MODULES
652
#if SPLIT_MODULE
653
'placeholder': new Proxy({}, splitModuleProxyHandler),
654
#endif
655
#if RELOCATABLE
656
'GOT.mem': new Proxy(wasmImports, GOTHandler),
657
'GOT.func': new Proxy(wasmImports, GOTHandler),
658
#endif
659
}
660
}
661
662
// Create the wasm instance.
663
// Receives the wasm imports, returns the exports.
664
{{{ asyncIf(WASM_ASYNC_COMPILATION) }}}function createWasm() {
665
// Load the wasm module and create an instance of using native support in the JS engine.
666
// handle a generated wasm instance, receiving its exports and
667
// performing other necessary setup
668
/** @param {WebAssembly.Module=} module*/
669
function receiveInstance(instance, module) {
670
wasmExports = instance.exports;
671
672
#if RELOCATABLE
673
wasmExports = relocateExports(wasmExports, {{{ GLOBAL_BASE }}});
674
#endif
675
676
#if ASYNCIFY
677
wasmExports = Asyncify.instrumentWasmExports(wasmExports);
678
#endif
679
680
#if ABORT_ON_WASM_EXCEPTIONS
681
wasmExports = instrumentWasmExportsWithAbort(wasmExports);
682
#endif
683
684
#if MAIN_MODULE
685
var metadata = getDylinkMetadata(module);
686
#if AUTOLOAD_DYLIBS
687
if (metadata.neededDynlibs) {
688
dynamicLibraries = metadata.neededDynlibs.concat(dynamicLibraries);
689
}
690
#endif
691
mergeLibSymbols(wasmExports, 'main')
692
#if '$LDSO' in addedLibraryItems
693
LDSO.init();
694
#endif
695
loadDylibs();
696
#elif RELOCATABLE
697
reportUndefinedSymbols();
698
#endif
699
700
#if MEMORY64 || CAN_ADDRESS_2GB
701
wasmExports = applySignatureConversions(wasmExports);
702
#endif
703
704
{{{ receivedSymbol('wasmExports') }}}
705
706
#if PTHREADS
707
#if MAIN_MODULE
708
registerTLSInit(wasmExports['_emscripten_tls_init'], instance.exports, metadata);
709
#else
710
registerTLSInit(wasmExports['_emscripten_tls_init']);
711
#endif
712
#endif
713
714
#if !IMPORTED_MEMORY
715
wasmMemory = wasmExports['memory'];
716
{{{ receivedSymbol('wasmMemory') }}}
717
#if ASSERTIONS
718
assert(wasmMemory, 'memory not found in wasm exports');
719
#endif
720
updateMemoryViews();
721
#endif
722
723
#if '$wasmTable' in addedLibraryItems && !RELOCATABLE
724
wasmTable = wasmExports['__indirect_function_table'];
725
{{{ receivedSymbol('wasmTable') }}}
726
#if ASSERTIONS && !PURE_WASI
727
assert(wasmTable, 'table not found in wasm exports');
728
#endif
729
#endif
730
731
#if hasExportedSymbol('__cpp_exception') && !RELOCATABLE
732
___cpp_exception = wasmExports['__cpp_exception'];
733
{{{ receivedSymbol('___cpp_exception') }}};
734
#endif
735
736
#if hasExportedSymbol('__wasm_apply_data_relocs')
737
__RELOC_FUNCS__.push(wasmExports['__wasm_apply_data_relocs']);
738
#endif
739
740
#if ABORT_ON_WASM_EXCEPTIONS
741
instrumentWasmTableWithAbort();
742
#endif
743
744
#if !DECLARE_ASM_MODULE_EXPORTS
745
// If we didn't declare the asm exports as top level enties this function
746
// is in charge of programmatically exporting them on the global object.
747
exportWasmSymbols(wasmExports);
748
#endif
749
750
#if PTHREADS || WASM_WORKERS
751
// We now have the Wasm module loaded up, keep a reference to the compiled module so we can post it to the workers.
752
wasmModule = module;
753
#endif
754
#if DECLARE_ASM_MODULE_EXPORTS
755
assignWasmExports(wasmExports);
756
#endif
757
#if WASM_ASYNC_COMPILATION && !MODULARIZE
758
removeRunDependency('wasm-instantiate');
759
#endif
760
return wasmExports;
761
}
762
#if WASM_ASYNC_COMPILATION && !MODULARIZE
763
addRunDependency('wasm-instantiate');
764
#endif
765
766
// Prefer streaming instantiation if available.
767
#if WASM_ASYNC_COMPILATION
768
#if ASSERTIONS
769
// Async compilation can be confusing when an error on the page overwrites Module
770
// (for example, if the order of elements is wrong, and the one defining Module is
771
// later), so we save Module and check it later.
772
var trueModule = Module;
773
#endif
774
function receiveInstantiationResult(result) {
775
// 'result' is a ResultObject object which has both the module and instance.
776
// receiveInstance() will swap in the exports (to Module.asm) so they can be called
777
#if ASSERTIONS
778
assert(Module === trueModule, 'the Module object should not be replaced during async compilation - perhaps the order of HTML elements is wrong?');
779
trueModule = null;
780
#endif
781
#if SHARED_MEMORY || RELOCATABLE
782
return receiveInstance(result['instance'], result['module']);
783
#else
784
// TODO: Due to Closure regression https://github.com/google/closure-compiler/issues/3193, the above line no longer optimizes out down to the following line.
785
// When the regression is fixed, can restore the above PTHREADS-enabled path.
786
return receiveInstance(result['instance']);
787
#endif
788
}
789
#endif // WASM_ASYNC_COMPILATION
790
791
var info = getWasmImports();
792
793
#if expectToReceiveOnModule('instantiateWasm')
794
// User shell pages can write their own Module.instantiateWasm = function(imports, successCallback) callback
795
// to manually instantiate the Wasm module themselves. This allows pages to
796
// run the instantiation parallel to any other async startup actions they are
797
// performing.
798
// Also pthreads and wasm workers initialize the wasm instance through this
799
// path.
800
if (Module['instantiateWasm']) {
801
return new Promise((resolve, reject) => {
802
#if ASSERTIONS
803
try {
804
#endif
805
Module['instantiateWasm'](info, (mod, inst) => {
806
resolve(receiveInstance(mod, inst));
807
});
808
#if ASSERTIONS
809
} catch(e) {
810
err(`Module.instantiateWasm callback failed with error: ${e}`);
811
reject(e);
812
}
813
#endif
814
});
815
}
816
#endif
817
818
#if PTHREADS || WASM_WORKERS
819
if ({{{ ENVIRONMENT_IS_WORKER_THREAD() }}}) {
820
// Instantiate from the module that was recieved via postMessage from
821
// the main thread. We can just use sync instantiation in the worker.
822
#if ASSERTIONS
823
assert(wasmModule, "wasmModule should have been received via postMessage");
824
#endif
825
var instance = new WebAssembly.Instance(wasmModule, getWasmImports());
826
return receiveInstance(instance, wasmModule);
827
}
828
#endif
829
830
#if SOURCE_PHASE_IMPORTS
831
var instance = await WebAssembly.instantiate(wasmModule, info);
832
var exports = receiveInstantiationResult({instance, 'module':wasmModule});
833
return exports;
834
#else
835
wasmBinaryFile ??= findWasmBinary();
836
#if WASM_ASYNC_COMPILATION
837
#if RUNTIME_DEBUG
838
dbg('asynchronously preparing wasm');
839
#endif
840
var result = await instantiateAsync(wasmBinary, wasmBinaryFile, info);
841
var exports = receiveInstantiationResult(result);
842
return exports;
843
#else // WASM_ASYNC_COMPILATION
844
var result = instantiateSync(wasmBinaryFile, info);
845
#if PTHREADS || MAIN_MODULE
846
return receiveInstance(result[0], result[1]);
847
#else
848
// TODO: Due to Closure regression https://github.com/google/closure-compiler/issues/3193,
849
// the above line no longer optimizes out down to the following line.
850
// When the regression is fixed, we can remove this if/else.
851
return receiveInstance(result[0]);
852
#endif
853
#endif // WASM_ASYNC_COMPILATION
854
#endif // SOURCE_PHASE_IMPORTS
855
}
856
#endif // WASM_ESM_INTEGRATION
857
858
#if !WASM_BIGINT
859
// Globals used by JS i64 conversions (see makeSetValue)
860
var tempDouble;
861
var tempI64;
862
#endif
863
864
#if RETAIN_COMPILER_SETTINGS
865
var compilerSettings = {{{ JSON.stringify(makeRetainedCompilerSettings()) }}} ;
866
867
function getCompilerSetting(name) {
868
if (!(name in compilerSettings)) return 'invalid compiler setting: ' + name;
869
return compilerSettings[name];
870
}
871
#endif // RETAIN_COMPILER_SETTINGS
872
873
#if MAIN_MODULE && ASYNCIFY
874
// With MAIN_MODULE + ASYNCIFY the normal method of placing stub functions in
875
// wasmImports for as-yet-undefined symbols doesn't work since ASYNCIFY then
876
// wraps these stub functions and we can't then replace them directly. Instead
877
// the stub functions call into `asyncifyStubs` which gets populated by the
878
// dynamic linker as symbols are loaded.
879
var asyncifyStubs = {};
880
#endif
881
882