From 86ff51e4ae548e621ccbd743919bbed9688899df Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 15 May 2025 10:56:06 -0700 Subject: [PATCH] [MODULARIZE=instance] Mark -sDYNCALLS as not supported. NFC Also by extension `-sASYNCIFY=1` is not supported either. Also enable a bunch more tests --- .circleci/config.yml | 6 +++ .../docs/compiling/Modularized-Output.rst | 13 ++++--- src/lib/libccall.js | 4 ++ src/lib/libcore.js | 3 ++ src/postamble.js | 6 +-- src/wasm_worker.js | 2 + test/embind/test_unsigned.cpp | 2 +- .../codesize/test_codesize_hello_O0.gzsize | 2 +- .../codesize/test_codesize_hello_O0.jssize | 2 +- .../codesize/test_codesize_minimal_O0.gzsize | 2 +- .../codesize/test_codesize_minimal_O0.jssize | 2 +- test/other/test_unoptimized_code_size.js.size | 2 +- .../test_unoptimized_code_size_strict.js.size | 2 +- test/test_core.py | 38 ++++++++++--------- tools/link.py | 18 +++++---- 15 files changed, 64 insertions(+), 40 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 7e3f65ff64708..a86af3c4f87cb 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -813,9 +813,15 @@ jobs: instance.test_fannkuch instance.test_fasta instance.test_EXPORTED_RUNTIME_METHODS + instance.test_abort_on_exceptions* instance.test_ccall instance.test_dylink_basics* instance.test_Module_dynamicLibraries* + instance.test_dylink_argv_argc + instance.test_dlmalloc* + instance.test_dyncall* + instance.test_em_asm* + instance.test_embind* esm_integration.test_fs_js_api* esm_integration.test_inlinejs3 esm_integration.test_embind_val_basics diff --git a/site/source/docs/compiling/Modularized-Output.rst b/site/source/docs/compiling/Modularized-Output.rst index 1449be9b512bb..4570c25d7d94c 100644 --- a/site/source/docs/compiling/Modularized-Output.rst +++ b/site/source/docs/compiling/Modularized-Output.rst @@ -115,16 +115,19 @@ Limitations Some major features still do not work in this mode. Many of these we hope to fix in future releses. Current limitations include: -* Internal usage (e.g. usage within EM_JS / JS libary code) of the `Module` - object does not work. This is because symbols are exported directly using - ES6 module syntax rathar than using a global `Module` object. +* Internal usage (e.g. usage within EM_JS / JS libary code) of the ``Module`` + global does not work. This is because symbols are exported directly using + ES6 module syntax rathar than using the ``Module`` global. -* `ccall`/`cwrap` are not supported (these depend on the internal `Module` - object). +* `ccall`/`cwrap` are not supported (depends on the ``Module`` global). * :ref:`abort_on_wasm_exceptions` is not supported (requires wrapping wasm exports). +* :ref:`dyncalls` is not supported (depends on the ``Module`` global) + +* :ref:`asyncify` is not supported (depends on :ref:`dyncalls`) + * The output of file_packager is not compatible so :ref:`emcc-preload-file` and :ref:`emcc-embed-file` do not work. diff --git a/src/lib/libccall.js b/src/lib/libccall.js index 23a9014d7b857..70efba20aab53 100644 --- a/src/lib/libccall.js +++ b/src/lib/libccall.js @@ -6,6 +6,10 @@ addToLibrary({ // Returns the C function with a specified identifier (for C++, you need to do manual name mangling) +#if MODULARIZE == 'instance' + $getCFunc__deps: [() => error('ccall is not yet compatible with MODULARIZE=instance')], +#endif + $getCFunc__internal: true, $getCFunc: (ident) => { var func = Module['_' + ident]; // closure exported function #if ASSERTIONS diff --git a/src/lib/libcore.js b/src/lib/libcore.js index 58a52f4975905..64833c9ec852f 100644 --- a/src/lib/libcore.js +++ b/src/lib/libcore.js @@ -1736,6 +1736,9 @@ addToLibrary({ $dynCallLegacy__deps: [ #if MINIMAL_RUNTIME '$dynCalls', +#endif +#if MODULARIZE == 'instance' + () => error('dynCallLegacy is not yet compatible with MODULARIZE=instance'), #endif ], $dynCallLegacy: (sig, ptr, args) => { diff --git a/src/postamble.js b/src/postamble.js index d64c7f99bb0f7..c34a10ece4fe4 100644 --- a/src/postamble.js +++ b/src/postamble.js @@ -322,9 +322,9 @@ export default async function init(moduleArg = {}) { run(); } -#if PTHREADS -// When run as a pthread we run `init` immediately. -if (ENVIRONMENT_IS_PTHREAD) await init() +#if PTHREADS || WASM_WORKERS +// When run as a worker thread run `init` immediately. +if ({{{ ENVIRONMENT_IS_WORKER_THREAD() }}}) await init() #endif #if ENVIRONMENT_MAY_BE_NODE diff --git a/src/wasm_worker.js b/src/wasm_worker.js index 0ce2dc08f238a..29bfbcf847386 100644 --- a/src/wasm_worker.js +++ b/src/wasm_worker.js @@ -40,6 +40,8 @@ if (ENVIRONMENT_IS_NODE) { // Weak map of handle functions to their wrapper. Used to implement // addEventListener/removeEventListener. var wrappedHandlers = new WeakMap(); + /** @suppress {checkTypes} */ + globalThis.onmessage = null; function wrapMsgHandler(h) { var f = wrappedHandlers.get(h) if (!f) { diff --git a/test/embind/test_unsigned.cpp b/test/embind/test_unsigned.cpp index edf52fc0121c0..b09fd9eb4b15c 100644 --- a/test/embind/test_unsigned.cpp +++ b/test/embind/test_unsigned.cpp @@ -36,6 +36,6 @@ int main() // Module['set_bind_u64'](2147483648); // todo: embind does not currently support 64-bit integers. Module['set_bind_u32'](2147483648); // Module['_set_c_u64'](2147483648); // todo: embind does not currently support 64-bit integers. - Module['_set_c_u32'](2147483648); + _set_c_u32(2147483648); ); } diff --git a/test/other/codesize/test_codesize_hello_O0.gzsize b/test/other/codesize/test_codesize_hello_O0.gzsize index 81557ccd36920..936122f2314a2 100644 --- a/test/other/codesize/test_codesize_hello_O0.gzsize +++ b/test/other/codesize/test_codesize_hello_O0.gzsize @@ -1 +1 @@ -8312 +8307 diff --git a/test/other/codesize/test_codesize_hello_O0.jssize b/test/other/codesize/test_codesize_hello_O0.jssize index b723f799462d8..b97e1ca7d1870 100644 --- a/test/other/codesize/test_codesize_hello_O0.jssize +++ b/test/other/codesize/test_codesize_hello_O0.jssize @@ -1 +1 @@ -22242 +22233 diff --git a/test/other/codesize/test_codesize_minimal_O0.gzsize b/test/other/codesize/test_codesize_minimal_O0.gzsize index cc7beecdb0e0e..f42a7991541e2 100644 --- a/test/other/codesize/test_codesize_minimal_O0.gzsize +++ b/test/other/codesize/test_codesize_minimal_O0.gzsize @@ -1 +1 @@ -6617 +6613 diff --git a/test/other/codesize/test_codesize_minimal_O0.jssize b/test/other/codesize/test_codesize_minimal_O0.jssize index 02872626c939d..d582cea6656cb 100644 --- a/test/other/codesize/test_codesize_minimal_O0.jssize +++ b/test/other/codesize/test_codesize_minimal_O0.jssize @@ -1 +1 @@ -17611 +17602 diff --git a/test/other/test_unoptimized_code_size.js.size b/test/other/test_unoptimized_code_size.js.size index accdc7941d982..59c2d95ec6d03 100644 --- a/test/other/test_unoptimized_code_size.js.size +++ b/test/other/test_unoptimized_code_size.js.size @@ -1 +1 @@ -53705 +53691 diff --git a/test/other/test_unoptimized_code_size_strict.js.size b/test/other/test_unoptimized_code_size_strict.js.size index 2d384feea68ce..1d108d291a570 100644 --- a/test/other/test_unoptimized_code_size_strict.js.size +++ b/test/other/test_unoptimized_code_size_strict.js.size @@ -1 +1 @@ -51755 +51741 diff --git a/test/test_core.py b/test/test_core.py index 4cf4952ed7f9b..42cb6b946d1c0 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -1843,6 +1843,7 @@ def test_emscripten_get_compiler_setting(self): self.set_setting('RETAIN_COMPILER_SETTINGS') self.do_runf(src, read_file(output).replace('waka', utils.EMSCRIPTEN_VERSION)) + @no_modularize_instance('MODULARIZE=instance is not compatible with ASYNCIFY=1') def test_emscripten_has_asyncify(self): src = r''' #include @@ -4068,6 +4069,7 @@ def test_dylink_basics_no_modify(self): self.do_basic_dylink_test() @with_dylink_reversed + @no_modularize_instance('DECLARE_ASM_MODULE_EXPORTS=0 is not compatible with MODULARIZE') def test_dylink_no_export(self): self.set_setting('NO_DECLARE_ASM_MODULE_EXPORTS') self.do_basic_dylink_test() @@ -5147,13 +5149,8 @@ class Bar : public Foo { @needs_dylink def test_dylink_argv_argc(self): # Verify that argc and argv can be sent to main when main is in a side module - - self.emcc_args += ['--extern-pre-js', 'pre.js'] - - create_file('pre.js', ''' - var Module = { arguments: ['hello', 'world!'] } - ''') - + self.emcc_args += ['--pre-js', 'pre.js'] + create_file('pre.js', "Module['arguments'] = ['hello', 'world!']") self.dylink_test( '', # main module is empty. r''' @@ -6343,7 +6340,7 @@ def test_dlmalloc_inline(self): src = read_file(path_from_root('system/lib/dlmalloc.c')) + '\n\n\n' + read_file(test_file('dlmalloc_test.c')) self.do_run(src, '*1,0*', args=['200', '1'], force_c=True) - self.do_run('src.js', '*400,0*', args=['400', '400'], force_c=True, no_build=True) + self.do_run(self.output_name('src'), '*400,0*', args=['400', '400'], force_c=True, no_build=True) @no_asan('depends on the specifics of memory size, which for asan we are forced to increase') @no_lsan('depends on the specifics of memory size, which for lsan we are forced to increase') @@ -6356,10 +6353,11 @@ def test_dlmalloc(self): self.do_runf('dlmalloc_test.c', '*1,0*', args=['200', '1']) self.do_run(self.output_name('dlmalloc_test'), '*400,0*', args=['400', '400'], no_build=True) - self.run_process([EMCC, test_file('dlmalloc_test.c'), '-sINITIAL_MEMORY=128MB', '-o', 'src.js'] + self.get_emcc_args()) + out_js = self.output_name('dlmalloc_test') + self.run_process([EMCC, test_file('dlmalloc_test.c'), '-sINITIAL_MEMORY=128MB', '-o', out_js] + self.get_emcc_args()) - self.do_run('src.js', '*1,0*', args=['200', '1'], no_build=True) - self.do_run('src.js', '*400,0*', args=['400', '400'], no_build=True) + self.do_run(out_js, '*1,0*', args=['200', '1'], no_build=True) + self.do_run(out_js, '*400,0*', args=['400', '400'], no_build=True) # The same for new and all its variants src = read_file(test_file('new.cpp')) @@ -6974,9 +6972,9 @@ def test_EXPORTED_RUNTIME_METHODS(self): self.do_core_test('EXPORTED_RUNTIME_METHODS.c') @also_with_minimal_runtime + @no_modularize_instance('uses dynCallLegacy') + @no_wasm64('not compatible with MEMORY64') def test_dyncall_specific(self): - if self.get_setting('MEMORY64'): - self.skipTest('not compatible with MEMORY64') if self.get_setting('WASM_BIGINT') != 0 and not self.is_wasm2js(): # define DYNCALLS because this test does test calling them directly, and # in WASM_BIGINT mode we do not enable them by default (since we can do @@ -7003,7 +7001,7 @@ def test_dyncall_specific(self): }) def test_dyncall_pointers(self, args): if args: - self.skipTest('dynCallLegacy is not yet comatible with WASM_ESM_INTEGRATION') + self.skipTest('dynCallLegacy is not yet compatible with WASM_ESM_INTEGRATION') self.do_core_test('test_dyncall_pointers.c', emcc_args=args) @also_with_wasm_bigint @@ -7506,21 +7504,21 @@ def test_embind_val_cross_thread_deleted(self): self.do_runf('test_embind_val_cross_thread.cpp') def test_embind_val_coro(self): - create_file('post.js', r'''Module.onRuntimeInitialized = () => { + create_file('pre.js', r'''Module.onRuntimeInitialized = () => { Module.asyncCoro().then(console.log); }''') - self.emcc_args += ['-std=c++20', '--bind', '--post-js=post.js'] + self.emcc_args += ['-std=c++20', '--bind', '--pre-js=pre.js'] self.do_runf('embind/test_val_coro.cpp', '34\n') def test_embind_val_coro_caught(self): self.set_setting('EXCEPTION_STACK_TRACES') - create_file('post.js', r'''Module.onRuntimeInitialized = () => { + create_file('pre.js', r'''Module.onRuntimeInitialized = () => { Module.throwingCoro().then( console.log, err => console.error(`rejected with: ${err.stack}`) ); }''') - self.emcc_args += ['-std=c++20', '--bind', '--post-js=post.js', '-fexceptions'] + self.emcc_args += ['-std=c++20', '--bind', '--pre-js=pre.js', '-fexceptions'] self.do_runf('embind/test_val_coro.cpp', 'rejected with: std::runtime_error: bang from throwingCoro!\n') def test_embind_dynamic_initialization(self): @@ -9463,6 +9461,7 @@ def test_abort_on_exceptions(self): self.emcc_args += ['-lembind', '--post-js', test_file('core/test_abort_on_exceptions_post.js')] self.do_core_test('test_abort_on_exceptions.cpp', interleaved_output=False) + @no_modularize_instance('ABORT_ON_WASM_EXCEPTIONS') def test_abort_on_exceptions_main(self): # The unhandled exception wrappers should not kick in for exceptions thrown during main self.set_setting('ABORT_ON_WASM_EXCEPTIONS') @@ -9476,6 +9475,7 @@ def test_abort_on_exceptions_main(self): @node_pthreads @flaky('https://github.com/emscripten-core/emscripten/issues/20067') + @no_modularize_instance('ABORT_ON_WASM_EXCEPTIONS') def test_abort_on_exceptions_pthreads(self): self.set_setting('ABORT_ON_WASM_EXCEPTIONS') self.set_setting('PROXY_TO_PTHREAD') @@ -9500,6 +9500,7 @@ def test_emscripten_async_call(self): self.do_run_in_out_file_test('core/test_emscripten_async_call.c') @no_asan('asyncify stack operations confuse asan') + @no_modularize_instance('ASYNCIFY=1 requires DYNCALLS') @parameterized({ '': ([],), 'no_dynamic_execution': (['-sDYNAMIC_EXECUTION=0'],), @@ -9517,6 +9518,7 @@ def test_embind_lib_with_asyncify(self, args): @no_asan('asyncify stack operations confuse asan') @with_asyncify_and_jspi + @no_modularize_instance('uses ccall') def test_em_async_js(self): if not self.get_setting('ASYNCIFY'): self.set_setting('ASYNCIFY') diff --git a/tools/link.py b/tools/link.py index 59f8c05408f0b..a1ad5c6b3cd23 100644 --- a/tools/link.py +++ b/tools/link.py @@ -811,14 +811,23 @@ def limit_incoming_module_api(): else: default_setting('INCOMING_MODULE_JS_API', []) + if settings.ASYNCIFY == 1: + # See: https://github.com/emscripten-core/emscripten/issues/12065 + # See: https://github.com/emscripten-core/emscripten/issues/12066 + settings.DYNCALLS = 1 + if settings.MODULARIZE == 'instance': diagnostics.warning('experimental', 'MODULARIZE=instance is still experimental. Many features may not work or will change.') if not settings.EXPORT_ES6: exit_with_error('MODULARIZE=instance requires EXPORT_ES6') if settings.ABORT_ON_WASM_EXCEPTIONS: - exit_with_error('MODULARIZE=instance is only compatible with ABORT_ON_WASM_EXCEPTIONS') + exit_with_error('MODULARIZE=instance is not compatible with ABORT_ON_WASM_EXCEPTIONS') + if settings.ASYNCIFY == 1: + exit_with_error('MODULARIZE=instance is not compatible with -sASYNCIFY=1') + if settings.DYNCALLS: + exit_with_error('MODULARIZE=instance is not compatible with -sDYNCALLS') if options.use_preload_plugins or len(options.preload_files): - exit_with_error('MODULARIZE=instance is not compatile with --embed-file/--preload-file') + exit_with_error('MODULARIZE=instance is not compatible with --embed-file/--preload-file') if 'INCOMING_MODULE_JS_API' in user_settings: for s in ['wasmMemory', 'INITIAL_MEMORY']: if s in settings.INCOMING_MODULE_JS_API: @@ -1129,11 +1138,6 @@ def limit_incoming_module_api(): if settings.ASYNCIFY_LAZY_LOAD_CODE: settings.ASYNCIFY = 1 - if settings.ASYNCIFY == 1: - # See: https://github.com/emscripten-core/emscripten/issues/12065 - # See: https://github.com/emscripten-core/emscripten/issues/12066 - settings.DYNCALLS = 1 - settings.ASYNCIFY_ADD = unmangle_symbols_from_cmdline(settings.ASYNCIFY_ADD) settings.ASYNCIFY_REMOVE = unmangle_symbols_from_cmdline(settings.ASYNCIFY_REMOVE) settings.ASYNCIFY_ONLY = unmangle_symbols_from_cmdline(settings.ASYNCIFY_ONLY)