diff --git a/src/jsifier.mjs b/src/jsifier.mjs index 6099e29b6e83a..f79b937ce76a5 100644 --- a/src/jsifier.mjs +++ b/src/jsifier.mjs @@ -9,6 +9,7 @@ import { ATEXITS, + ATPRERUN, ATINITS, ATMAINS, defineI64Param, @@ -773,6 +774,7 @@ var proxiedFunctionTable = [ warnings: warningOccured(), asyncFuncs, libraryDefinitions: LibraryManager.libraryDefinitions, + ATPRERUN: ATPRERUN.join('\n'), ATINITS: ATINITS.join('\n'), ATMAINS: STRICT ? '' : ATMAINS.join('\n'), ATEXITS: ATEXITS.join('\n'), diff --git a/src/lib/libfs.js b/src/lib/libfs.js index e446b5791d060..00610b9c1019d 100644 --- a/src/lib/libfs.js +++ b/src/lib/libfs.js @@ -33,7 +33,7 @@ addToLibrary({ ], $FS__postset: () => { // TODO: do we need noFSInit? - addAtInit(` + addAtPreRun(` if (!Module['noFSInit'] && !FS.initialized) FS.init(); FS.ignorePermissions = false; diff --git a/src/parseTools.mjs b/src/parseTools.mjs index dba14e92763e7..ed190e3a03281 100644 --- a/src/parseTools.mjs +++ b/src/parseTools.mjs @@ -733,6 +733,14 @@ function makeEval(code) { export const ATMAINS = []; +export const ATPRERUN = []; + +// Add code that runs after the Wasm module is loaded and the runtime ATINIT +// callbacks, but before static constructors and main are run. +function addAtPreRun(code) { + ATPRERUN.push(code); +} + export const ATINITS = []; function addAtInit(code) { @@ -1085,6 +1093,7 @@ function ENVIRONMENT_IS_WORKER_THREAD() { addToCompileTimeContext({ ATEXITS, + ATPRERUN, ATINITS, FOUR_GB, LONG_TYPE, @@ -1104,6 +1113,7 @@ addToCompileTimeContext({ ENVIRONMENT_IS_WORKER_THREAD, addAtExit, addAtInit, + addAtPreRun, asyncIf, awaitIf, buildStringArray, diff --git a/src/postamble_minimal.js b/src/postamble_minimal.js index a39967a4a87eb..80c891f416720 100644 --- a/src/postamble_minimal.js +++ b/src/postamble_minimal.js @@ -217,7 +217,7 @@ WebAssembly.instantiate(Module['wasm'], imports).then((output) => { #endif updateMemoryViews(); #endif - + <<< ATPRERUN >>> initRuntime(wasmExports); #if PTHREADS // Export Wasm module for pthread creation to access. diff --git a/src/preamble.js b/src/preamble.js index 2a422c49008ea..4c0ee93302fc5 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -187,6 +187,7 @@ function preRun() { } #endif callRuntimeCallbacks(__ATPRERUN__); + <<< ATPRERUN >>> } function initRuntime() { @@ -217,6 +218,11 @@ function initRuntime() { #if RELOCATABLE callRuntimeCallbacks(__RELOC_FUNCS__); #endif + +#if hasExportedSymbol('__wasm_call_ctors') + wasmExports['__wasm_call_ctors'](); +#endif + <<< ATINITS >>> callRuntimeCallbacks(__ATINIT__); } @@ -954,10 +960,6 @@ function getWasmImports() { #endif #endif -#if hasExportedSymbol('__wasm_call_ctors') - addOnInit(wasmExports['__wasm_call_ctors']); -#endif - #if hasExportedSymbol('__wasm_apply_data_relocs') __RELOC_FUNCS__.push(wasmExports['__wasm_apply_data_relocs']); #endif diff --git a/test/test_other.py b/test/test_other.py index 1f1c3ae61c5bf..3deae32317c18 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -8431,6 +8431,30 @@ def test_binaryen_stack_ir(self, opts, disable_and_enable): self.assertLess(err.count(DISABLE), 2) self.assertLess(err.count(ENABLE), 2) + @also_with_minimal_runtime + def test_run_order(self): + create_file('lib.js', r''' +addToLibrary({ + foo__postset: () => { + addAtPreRun("console.log(`addAtPreRun`);"); + addAtInit("console.log(`addAtInit`);"); + }, + foo: () => {}, +}); +''') + create_file('src.c', r''' + #include + void foo(); + __attribute__((constructor)) void ctor() { + printf("ctor\n"); + } + int main() { + printf("main\n"); + foo(); + } + ''') + self.do_runf('src.c', 'addAtPreRun\nctor\naddAtInit\nmain\n', emcc_args=['--js-library', 'lib.js']) + def test_override_js_execution_environment(self): create_file('main.c', r''' #include diff --git a/tools/building.py b/tools/building.py index 3d764fe82d33a..5cc38025cfd36 100644 --- a/tools/building.py +++ b/tools/building.py @@ -393,10 +393,7 @@ def acorn_optimizer(filename, passes, extra_info=None, return_output=False, work # evals ctors. if binaryen_bin is provided, it is the dir of the binaryen tool # for this, and we are in wasm mode def eval_ctors(js_file, wasm_file, debug_info): - if settings.MINIMAL_RUNTIME: - CTOR_ADD_PATTERN = f"wasmExports['{WASM_CALL_CTORS}']();" # TODO test - else: - CTOR_ADD_PATTERN = f"addOnInit(wasmExports['{WASM_CALL_CTORS}']);" + CTOR_ADD_PATTERN = f"wasmExports['{WASM_CALL_CTORS}']();" js = utils.read_file(js_file) diff --git a/tools/emscripten.py b/tools/emscripten.py index c412c77250d1b..69c21cf647ce7 100644 --- a/tools/emscripten.py +++ b/tools/emscripten.py @@ -161,6 +161,7 @@ def update_settings_glue(wasm_file, metadata, base_metadata): def apply_static_code_hooks(forwarded_json, code): + code = shared.do_replace(code, '<<< ATPRERUN >>>', str(forwarded_json['ATPRERUN'])) code = shared.do_replace(code, '<<< ATINITS >>>', str(forwarded_json['ATINITS'])) if settings.HAS_MAIN: code = shared.do_replace(code, '<<< ATMAINS >>>', str(forwarded_json['ATMAINS']))