Skip to content

Commit 32ba9c8

Browse files
committed
[esm-integration] Allow for module argument processing
This change delays module argument processing until the init function is run. This means that at least some INCOMING_MODULE_JS_API properties can be supported with ESM integration. See #24060
1 parent 40616f0 commit 32ba9c8

File tree

81 files changed

+183
-132
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+183
-132
lines changed

eslint.config.mjs

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export default [{
3030
'src/runtime_*.js',
3131
'src/shell*.js',
3232
'src/preamble*.js',
33+
'src/postlibrary.js',
3334
'src/postamble*.js',
3435
'src/closure-externs/',
3536
'src/embind/',

src/jsifier.mjs

+6
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import assert from 'node:assert';
1111
import * as fs from 'node:fs/promises';
1212
import {
13+
ATMODULES,
1314
ATEXITS,
1415
ATINITS,
1516
ATPOSTCTORS,
@@ -823,6 +824,10 @@ function(${args}) {
823824
}
824825
writeOutput('// End JS library code\n');
825826

827+
if (!MINIMAL_RUNTIME) {
828+
includeSystemFile('postlibrary.js');
829+
}
830+
826831
if (PTHREADS) {
827832
writeOutput(`
828833
// proxiedFunctionTable specifies the list of functions that can be called
@@ -864,6 +869,7 @@ var proxiedFunctionTable = [
864869
asyncFuncs,
865870
libraryDefinitions: LibraryManager.libraryDefinitions,
866871
ATPRERUNS: ATPRERUNS.join('\n'),
872+
ATMODULES: ATMODULES.join('\n'),
867873
ATINITS: ATINITS.join('\n'),
868874
ATPOSTCTORS: ATPOSTCTORS.join('\n'),
869875
ATMAINS: ATMAINS.join('\n'),

src/lib/libcore.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -2283,7 +2283,8 @@ addToLibrary({
22832283
$wasmTable: undefined,
22842284
#endif
22852285

2286-
$noExitRuntime: "{{{ makeModuleReceiveExpr('noExitRuntime', !EXIT_RUNTIME) }}}",
2286+
$noExitRuntime__postset: () => addAtModule(makeModuleReceive('noExitRuntime')),
2287+
$noExitRuntime: {{{ !EXIT_RUNTIME }}},
22872288

22882289
// The following addOn<X> functions are for adding runtime callbacks at
22892290
// various executions points. Each addOn<X> function has a corresponding

src/lib/libembind_gen.js

+3
Original file line numberDiff line numberDiff line change
@@ -856,6 +856,9 @@ var LibraryEmbind = {
856856
$makeLegalFunctionName: () => { throw new Error('stub function should not be called'); },
857857
$runDestructors: () => { throw new Error('stub function should not be called'); },
858858
$createNamedFunction: () => { throw new Error('stub function should not be called'); },
859+
$flushPendingDeletes: () => { throw new Error('stub function should not be called'); },
860+
$setDelayFunction: () => { throw new Error('stub function should not be called'); },
861+
$PureVirtualError: () => { throw new Error('stub function should not be called'); },
859862
};
860863

861864
#if EMBIND_AOT

src/lib/libfs_shared.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
*/
66

77
addToLibrary({
8-
$preloadPlugins: "{{{ makeModuleReceiveExpr('preloadPlugins', '[]') }}}",
8+
$preloadPlugins__postset: () => addAtModule(makeModuleReceive('preloadPlugins')),
9+
$preloadPlugins: [],
910

1011
#if !MINIMAL_RUNTIME
1112
// Tries to handle an input byteArray using preload plugins. Returns true if

src/modules.mjs

+6-5
Original file line numberDiff line numberDiff line change
@@ -513,7 +513,6 @@ function exportRuntimeSymbols() {
513513
}
514514

515515
const exports = runtimeElements.map(maybeExport);
516-
exports.unshift('// Begin runtime exports');
517516
const results = exports.filter((name) => name);
518517

519518
if (ASSERTIONS && !EXPORT_ALL) {
@@ -542,7 +541,9 @@ function exportRuntimeSymbols() {
542541
}
543542
}
544543

545-
return results.join('\n') + '\n';
544+
results.unshift('// Begin runtime exports');
545+
results.push('// End runtime exports');
546+
return results.join('\n ') + '\n';
546547
}
547548

548549
function exportLibrarySymbols() {
@@ -552,12 +553,12 @@ function exportLibrarySymbols() {
552553
results.push(exportSymbol(ident));
553554
}
554555
}
555-
556-
return results.join('\n') + '\n';
556+
results.push('// End JS library exports');
557+
return results.join('\n ') + '\n';
557558
}
558559

559560
function exportJSSymbols() {
560-
return exportRuntimeSymbols() + exportLibrarySymbols();
561+
return exportRuntimeSymbols() + ' ' + exportLibrarySymbols();
561562
}
562563

563564
addToCompileTimeContext({

src/parseTools.mjs

+16-12
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,14 @@ function makeEval(code) {
720720
return ret;
721721
}
722722

723+
// Add code that runs before the wasm modules is loaded. This is the first
724+
// point at which the global `Module` object is guaranteed to exist. This hook
725+
// is mostly used to read incoming `Module` properties.
726+
export const ATMODULES = [];
727+
function addAtModule(code) {
728+
ATMODULES.push(code);
729+
}
730+
723731
// Add code to run soon after the Wasm module has been loaded. This is the first
724732
// injection point before all the other addAt<X> functions below. The code will
725733
// be executed after the runtime `onPreRuns` callbacks.
@@ -882,7 +890,7 @@ function makeModuleReceive(localName, moduleName) {
882890
if (expectToReceiveOnModule(moduleName)) {
883891
// Usually the local we use is the same as the Module property name,
884892
// but sometimes they must differ.
885-
ret = `\nif (Module['${moduleName}']) ${localName} = Module['${moduleName}'];`;
893+
ret = `if (Module['${moduleName}']) ${localName} = Module['${moduleName}'];`;
886894
}
887895
return ret;
888896
}
@@ -900,17 +908,12 @@ function makeModuleReceiveWithVar(localName, moduleName, defaultValue) {
900908
moduleName ||= localName;
901909
checkReceiving(moduleName);
902910
let ret = `var ${localName}`;
903-
if (!expectToReceiveOnModule(moduleName)) {
904-
if (defaultValue) {
905-
ret += ` = ${defaultValue}`;
906-
}
907-
ret += ';';
908-
} else {
909-
if (defaultValue) {
910-
ret += ` = Module['${moduleName}'] || ${defaultValue};`;
911-
} else {
912-
ret += ` = Module['${moduleName}'];`;
913-
}
911+
if (defaultValue) {
912+
ret += ` = ${defaultValue}`;
913+
}
914+
ret += ';';
915+
if (expectToReceiveOnModule(moduleName)) {
916+
addAtModule(`if (Module['${moduleName}']) ${localName} = Module['${moduleName}'];`);
914917
}
915918
return ret;
916919
}
@@ -1119,6 +1122,7 @@ addToCompileTimeContext({
11191122
ENVIRONMENT_IS_WORKER_THREAD,
11201123
addAtExit,
11211124
addAtPreRun,
1125+
addAtModule,
11221126
addAtInit,
11231127
addAtPostCtor,
11241128
addAtPreMain,

src/postamble.js

+13-11
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ if (ENVIRONMENT_IS_WORKER) {
2424
#include "deterministic.js"
2525
#endif
2626

27-
{{{ exportJSSymbols() }}}
28-
2927
#if ASSERTIONS
3028
var calledRun;
3129
#endif
@@ -199,7 +197,7 @@ function run() {
199197
#endif
200198

201199
#if HAS_MAIN
202-
{{{ makeModuleReceiveWithVar('noInitialRun', undefined, !INVOKE_RUN) }}}
200+
var noInitialRun = {{{ makeModuleReceiveExpr('noInitialRun', !INVOKE_RUN) }}};
203201
#if MAIN_READS_PARAMS
204202
if (!noInitialRun) callMain(args);
205203
#else
@@ -287,26 +285,30 @@ function checkUnflushedContent() {
287285
#endif // EXIT_RUNTIME
288286
#endif // ASSERTIONS
289287

288+
function preInit() {
290289
#if expectToReceiveOnModule('preInit')
291-
if (Module['preInit']) {
292-
if (typeof Module['preInit'] == 'function') Module['preInit'] = [Module['preInit']];
293-
while (Module['preInit'].length > 0) {
294-
Module['preInit'].shift()();
290+
if (Module['preInit']) {
291+
if (typeof Module['preInit'] == 'function') Module['preInit'] = [Module['preInit']];
292+
while (Module['preInit'].length > 0) {
293+
Module['preInit'].shift()();
294+
}
295295
}
296-
}
297296
#if ASSERTIONS
298-
consumedModuleProp('preInit');
297+
consumedModuleProp('preInit');
299298
#endif
300299
#endif
301-
300+
}
302301

303302
#if WASM_ESM_INTEGRATION
304303
export default function init(moduleArg = {}) {
305-
// TODO(sbc): moduleArg processing
304+
Module = moduleArg;
306305
updateMemoryViews();
306+
processModuleArgs();
307+
preInit();
307308
run();
308309
}
309310
#else
311+
preInit();
310312
run();
311313
#endif
312314

src/postamble_minimal.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55
*/
66

77
// === Auto-generated postamble setup entry stuff ===
8-
{{{ exportJSSymbols() }}}
9-
108
#if HAS_MAIN // Only if user is exporting a C main(), we will generate a run() function that can be used to launch main.
119
function run() {
1210
#if MEMORYPROFILER
@@ -136,6 +134,10 @@ WebAssembly.instantiateStreaming(fetch('{{{ TARGET_BASENAME }}}.wasm'), imports)
136134
if (!Module['wasm']) throw 'Must load WebAssembly Module in to variable Module.wasm before adding compiled output .js script to the DOM';
137135
#endif
138136

137+
<<< ATMODULES >>>
138+
139+
{{{ exportJSSymbols() }}}
140+
139141
WebAssembly.instantiate(Module['wasm'], imports).then((output) => {
140142
#endif
141143

src/postlibrary.js

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// This file is included after the automatically-generated JS library code
2+
// but before the wasm module is created.
3+
4+
#if WASM_ESM_INTEGRATION
5+
function processModuleArgs()
6+
#endif
7+
{
8+
<<< ATMODULES >>>
9+
10+
#if ASSERTIONS
11+
checkIncomingModuleAPI();
12+
#endif
13+
14+
{{{ makeModuleReceive('arguments_', 'arguments') }}}
15+
{{{ makeModuleReceive('thisProgram') }}}
16+
17+
#if ASSERTIONS
18+
// Assertions on removed incoming Module JS APIs.
19+
assert(typeof Module['memoryInitializerPrefixURL'] == 'undefined', 'Module.memoryInitializerPrefixURL option was removed, use Module.locateFile instead');
20+
assert(typeof Module['pthreadMainPrefixURL'] == 'undefined', 'Module.pthreadMainPrefixURL option was removed, use Module.locateFile instead');
21+
assert(typeof Module['cdInitializerPrefixURL'] == 'undefined', 'Module.cdInitializerPrefixURL option was removed, use Module.locateFile instead');
22+
assert(typeof Module['filePackagePrefixURL'] == 'undefined', 'Module.filePackagePrefixURL option was removed, use Module.locateFile instead');
23+
assert(typeof Module['read'] == 'undefined', 'Module.read option was removed');
24+
assert(typeof Module['readAsync'] == 'undefined', 'Module.readAsync option was removed (modify readAsync in JS)');
25+
assert(typeof Module['readBinary'] == 'undefined', 'Module.readBinary option was removed (modify readBinary in JS)');
26+
assert(typeof Module['setWindowTitle'] == 'undefined', 'Module.setWindowTitle option was removed (modify emscripten_set_window_title in JS)');
27+
assert(typeof Module['TOTAL_MEMORY'] == 'undefined', 'Module.TOTAL_MEMORY has been renamed Module.INITIAL_MEMORY');
28+
assert(typeof Module['ENVIRONMENT'] == 'undefined', 'Module.ENVIRONMENT has been deprecated. To force the environment, use the ENVIRONMENT compile-time option (for example, -sENVIRONMENT=web or -sENVIRONMENT=node)');
29+
assert(typeof Module['STACK_SIZE'] == 'undefined', 'STACK_SIZE can no longer be set at runtime. Use -sSTACK_SIZE at link time')
30+
#if !IMPORTED_MEMORY
31+
// If memory is defined in wasm, the user can't provide it, or set INITIAL_MEMORY
32+
assert(typeof Module['wasmMemory'] == 'undefined', 'Use of `wasmMemory` detected. Use -sIMPORTED_MEMORY to define wasmMemory externally');
33+
assert(typeof Module['INITIAL_MEMORY'] == 'undefined', 'Detected runtime INITIAL_MEMORY setting. Use -sIMPORTED_MEMORY to define wasmMemory dynamically');
34+
#endif
35+
#endif // ASSERTIONS
36+
37+
{{{ exportJSSymbols() }}}
38+
}

src/preamble.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -158,10 +158,6 @@ assert(typeof Int32Array != 'undefined' && typeof Float64Array !== 'undefined' &
158158
#if IMPORTED_MEMORY
159159
// In non-standalone/normal mode, we create the memory here.
160160
#include "runtime_init_memory.js"
161-
#elif ASSERTIONS
162-
// If memory is defined in wasm, the user can't provide it, or set INITIAL_MEMORY
163-
assert(!Module['wasmMemory'], 'Use of `wasmMemory` detected. Use -sIMPORTED_MEMORY to define wasmMemory externally');
164-
assert(!Module['INITIAL_MEMORY'], 'Detected runtime INITIAL_MEMORY setting. Use -sIMPORTED_MEMORY to define wasmMemory dynamically');
165161
#endif // !IMPORTED_MEMORY && ASSERTIONS
166162

167163
#if RELOCATABLE
@@ -461,8 +457,12 @@ var FS = {
461457

462458
ErrnoError() { FS.error() },
463459
};
460+
{{{
461+
addAtModule(`
464462
Module['FS_createDataFile'] = FS.createDataFile;
465463
Module['FS_createPreloadedFile'] = FS.createPreloadedFile;
464+
`);
465+
}}}
466466
#endif
467467

468468
#if ASSERTIONS

src/runtime_init_memory.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ if (!ENVIRONMENT_IS_PTHREAD) {
2121
} else
2222
#endif
2323
{
24-
{{{ makeModuleReceiveWithVar('INITIAL_MEMORY', undefined, INITIAL_MEMORY) }}}
24+
var INITIAL_MEMORY = {{{ makeModuleReceiveExpr('INITIAL_MEMORY', INITIAL_MEMORY) }}}
2525

2626
#if ASSERTIONS
2727
assert(INITIAL_MEMORY >= {{{STACK_SIZE}}}, 'INITIAL_MEMORY should be larger than STACK_SIZE, was ' + INITIAL_MEMORY + '! (STACK_SIZE=' + {{{STACK_SIZE}}} + ')');

src/shell.js

+3-25
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
// before the code. Then that object will be used in the code, and you
2222
// can continue to use Module afterwards as well.
2323
#if WASM_ESM_INTEGRATION
24-
var Module = {};
24+
var Module;
2525
#elif MODULARIZE
2626
var Module = moduleArg;
2727
#elif USE_CLOSURE_COMPILER
@@ -403,30 +403,6 @@ if (ENVIRONMENT_IS_NODE) {
403403
#endif
404404

405405
#if ASSERTIONS
406-
checkIncomingModuleAPI();
407-
#endif
408-
409-
// Emit code to handle expected values on the Module object. This applies Module.x
410-
// to the proper local x. This has two benefits: first, we only emit it if it is
411-
// expected to arrive, and second, by using a local everywhere else that can be
412-
// minified.
413-
{{{ makeModuleReceive('arguments_', 'arguments') }}}
414-
{{{ makeModuleReceive('thisProgram') }}}
415-
416-
// perform assertions in shell.js after we set up out() and err(), as otherwise if an assertion fails it cannot print the message
417-
#if ASSERTIONS
418-
// Assertions on removed incoming Module JS APIs.
419-
assert(typeof Module['memoryInitializerPrefixURL'] == 'undefined', 'Module.memoryInitializerPrefixURL option was removed, use Module.locateFile instead');
420-
assert(typeof Module['pthreadMainPrefixURL'] == 'undefined', 'Module.pthreadMainPrefixURL option was removed, use Module.locateFile instead');
421-
assert(typeof Module['cdInitializerPrefixURL'] == 'undefined', 'Module.cdInitializerPrefixURL option was removed, use Module.locateFile instead');
422-
assert(typeof Module['filePackagePrefixURL'] == 'undefined', 'Module.filePackagePrefixURL option was removed, use Module.locateFile instead');
423-
assert(typeof Module['read'] == 'undefined', 'Module.read option was removed');
424-
assert(typeof Module['readAsync'] == 'undefined', 'Module.readAsync option was removed (modify readAsync in JS)');
425-
assert(typeof Module['readBinary'] == 'undefined', 'Module.readBinary option was removed (modify readBinary in JS)');
426-
assert(typeof Module['setWindowTitle'] == 'undefined', 'Module.setWindowTitle option was removed (modify emscripten_set_window_title in JS)');
427-
assert(typeof Module['TOTAL_MEMORY'] == 'undefined', 'Module.TOTAL_MEMORY has been renamed Module.INITIAL_MEMORY');
428-
assert(typeof Module['ENVIRONMENT'] == 'undefined', 'Module.ENVIRONMENT has been deprecated. To force the environment, use the ENVIRONMENT compile-time option (for example, -sENVIRONMENT=web or -sENVIRONMENT=node)');
429-
assert(typeof Module['STACK_SIZE'] == 'undefined', 'STACK_SIZE can no longer be set at runtime. Use -sSTACK_SIZE at link time')
430406

431407
{{{ makeRemovedFSAssert('IDBFS') }}}
432408
{{{ makeRemovedFSAssert('PROXYFS') }}}
@@ -440,6 +416,8 @@ assert(typeof Module['STACK_SIZE'] == 'undefined', 'STACK_SIZE can no longer be
440416
{{{ makeRemovedFSAssert('NODEFS') }}}
441417
#endif
442418

419+
// perform assertions in shell.js after we set up out() and err(), as otherwise
420+
// if an assertion fails it cannot print the message
443421
#if PTHREADS
444422
assert(
445423
#if AUDIO_WORKLET
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
8243
1+
8271
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
19969
1+
20032
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
8230
1+
8258
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
19947
1+
20010
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
9233
1+
9263
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
23707
1+
23770
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
8187
1+
8211
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
19861
1+
19925
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
8187
1+
8211
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
19861
1+
19925
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
8259
1+
8278
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
20043
1+
20107
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
9272
1+
9300
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
23821
1+
23884
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
8243
1+
8271

0 commit comments

Comments
 (0)