Skip to content

Commit 2ca9ace

Browse files
authored
reland: Unify legacy dyncall mechanisms (#24399)
This change was originally landed in #24371 but got reverted. With this change we use the MINIMAL_RUNTIME technique in all cases. That is, dyncall functions are stored in a global `dynCalls` object that maps signatures to functions. Previously we were relying on the `dynCall_xx` helpers existing on the `Module` object. This allows `-sMODULARIZE=instance` to work with `-sDYNCALL` and by extension with `-sASYNCIFY=1`.
1 parent 3e6ddb0 commit 2ca9ace

File tree

5 files changed

+27
-50
lines changed

5 files changed

+27
-50
lines changed

site/source/docs/compiling/Modularized-Output.rst

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,6 @@ fix in future releses. Current limitations include:
123123

124124
* `ccall`/`cwrap` are not supported (depends on the ``Module`` global).
125125

126-
* :ref:`dyncalls` is not supported (depends on the ``Module`` global)
127-
128-
* :ref:`asyncify` is not supported (depends on :ref:`dyncalls`)
129-
130126
* :ref:`asyncify_lazy_load_code` is not supported (depends on ``wasmExports``
131127
global)
132128

@@ -172,6 +168,10 @@ Some additional limitations are:
172168
* :ref:`abort_on_wasm_exceptions` is not supported (requires wrapping wasm
173169
exports).
174170

171+
* :ref:`dyncalls` is not supported (depends on the ``Module`` global)
172+
173+
* :ref:`asyncify` is not supported (depends on :ref:`dyncalls`)
174+
175175
* Setting :ref:`wasm` to ``0`` is not supported.
176176

177177
* Setting :ref:`wasm_async_compilation` to ``0`` is not supported.

src/lib/libcore.js

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1729,25 +1729,13 @@ addToLibrary({
17291729
},
17301730

17311731
#if DYNCALLS || !WASM_BIGINT
1732-
#if MINIMAL_RUNTIME
1733-
$dynCalls: '{}',
1734-
#endif
1735-
$dynCallLegacy__deps: [
1736-
#if MINIMAL_RUNTIME
1737-
'$dynCalls',
1738-
#endif
1739-
#if MODULARIZE == 'instance'
1740-
() => error('dynCallLegacy is not yet compatible with MODULARIZE=instance'),
1741-
#endif
1742-
],
1732+
$dynCalls__internal: true,
1733+
$dynCalls: {},
1734+
$dynCallLegacy__deps: ['$dynCalls'],
17431735
$dynCallLegacy: (sig, ptr, args) => {
17441736
sig = sig.replace(/p/g, {{{ MEMORY64 ? "'j'" : "'i'" }}})
17451737
#if ASSERTIONS
1746-
#if MINIMAL_RUNTIME
17471738
assert(sig in dynCalls, `bad function pointer type - sig is not in dynCalls: '${sig}'`);
1748-
#else
1749-
assert(('dynCall_' + sig) in Module, `bad function pointer type - dynCall function not found for sig '${sig}'`);
1750-
#endif
17511739
if (args?.length) {
17521740
#if WASM_BIGINT
17531741
// j (64-bit integer) is fine, and is implemented as a BigInt. Without
@@ -1762,11 +1750,7 @@ addToLibrary({
17621750
assert(sig.length == 1);
17631751
}
17641752
#endif
1765-
#if MINIMAL_RUNTIME
17661753
var f = dynCalls[sig];
1767-
#else
1768-
var f = Module['dynCall_' + sig];
1769-
#endif
17701754
return f(ptr, ...args);
17711755
},
17721756
#if DYNCALLS

test/test_core.py

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -212,8 +212,6 @@ def metafunc(self, jspi, *args, **kwargs):
212212
self.require_jspi()
213213
else:
214214
self.set_setting('ASYNCIFY')
215-
if self.get_setting('MODULARIZE') == 'instance':
216-
self.skipTest('MODULARIZE=instance is not compatible with ASYNCIFY=1')
217215
f(self, *args, **kwargs)
218216

219217
parameterize(metafunc, {'': (False,),
@@ -233,8 +231,6 @@ def metafunc(self, asyncify, *args, **kwargs):
233231
self.require_jspi()
234232
elif asyncify == 1:
235233
self.set_setting('ASYNCIFY')
236-
if self.get_setting('MODULARIZE') == 'instance':
237-
self.skipTest('MODULARIZE=instance is not compatible with ASYNCIFY=1')
238234
else:
239235
assert asyncify == 0
240236
f(self, *args, **kwargs)
@@ -1885,7 +1881,7 @@ def test_emscripten_get_compiler_setting(self):
18851881
self.set_setting('RETAIN_COMPILER_SETTINGS')
18861882
self.do_runf(src, read_file(output).replace('waka', utils.EMSCRIPTEN_VERSION))
18871883

1888-
@no_modularize_instance('MODULARIZE=instance is not compatible with ASYNCIFY=1')
1884+
@no_esm_integration('WASM_ESM_INTEGRATION is not compatible with ASYNCIFY=1')
18891885
def test_emscripten_has_asyncify(self):
18901886
src = r'''
18911887
#include <stdio.h>
@@ -7024,7 +7020,7 @@ def test_EXPORTED_RUNTIME_METHODS(self):
70247020
self.do_core_test('EXPORTED_RUNTIME_METHODS.c')
70257021

70267022
@also_with_minimal_runtime
7027-
@no_modularize_instance('uses dynCallLegacy')
7023+
@no_esm_integration('WASM_ESM_INTEGRATION is not compatible with DYNCALLS')
70287024
def test_dyncall_specific(self):
70297025
if self.get_setting('WASM_BIGINT') != 0 and not self.is_wasm2js():
70307026
# define DYNCALLS because this test does test calling them directly, and
@@ -7051,8 +7047,8 @@ def test_dyncall_specific(self):
70517047
'legacy': (['-sDYNCALLS'],),
70527048
})
70537049
def test_dyncall_pointers(self, args):
7054-
if args and self.get_setting('MODULARIZE') == 'instance' or self.get_setting('WASM_ESM_INTEGRATION'):
7055-
self.skipTest('dynCallLegacy is not yet compatible with MODULARIZE=instance')
7050+
if args and self.get_setting('WASM_ESM_INTEGRATION'):
7051+
self.skipTest('WASM_ESM_INTEGRATION is not compatible with DYNCALLS')
70567052
self.do_core_test('test_dyncall_pointers.c', emcc_args=args)
70577053

70587054
@also_with_wasm_bigint
@@ -8068,7 +8064,7 @@ def test_vswprintf_utf8(self):
80688064

80698065
# Test async sleeps in the presence of invoke_* calls, which can happen with
80708066
# longjmp or exceptions.
8071-
@no_modularize_instance('MODULARIZE=instance is not compatible with ASYNCIFY=1')
8067+
@no_esm_integration('WASM_ESM_INTEGRATION is not compatible with ASYNCIFY=1')
80728068
def test_asyncify_longjmp(self):
80738069
self.set_setting('ASYNCIFY')
80748070
self.set_setting('STRICT')
@@ -8128,7 +8124,7 @@ def test_async_loop(self):
81288124
self.do_runf('main.c', 'hello 0\nhello 1\nhello 2\nhello 3\nhello 4\n')
81298125

81308126
@requires_v8
8131-
@no_modularize_instance('MODULARIZE=instance is not compatible with ASYNCIFY=1')
8127+
@no_esm_integration('WASM_ESM_INTEGRATION is not compatible with ASYNCIFY=1')
81328128
def test_async_hello_v8(self):
81338129
self.test_async_hello()
81348130

@@ -8233,7 +8229,7 @@ def test_async_ccall_promise(self, exit_runtime):
82338229
self.emcc_args += ['--pre-js', 'pre.js']
82348230
self.do_runf('main.c', 'stringf: first\nsecond\n6.4')
82358231

8236-
@no_modularize_instance('MODULARIZE=instance is not compatible with ASYNCIFY=1')
8232+
@no_esm_integration('WASM_ESM_INTEGRATION is not compatible with ASYNCIFY=1')
82378233
def test_fibers_asyncify(self):
82388234
self.set_setting('ASYNCIFY')
82398235
self.maybe_closure()
@@ -8244,7 +8240,7 @@ def test_asyncify_unused(self):
82448240
# test a program not using asyncify, but the pref is set
82458241
self.do_core_test('test_hello_world.c')
82468242

8247-
@no_modularize_instance('MODULARIZE=instance is not compatible with ASYNCIFY=1')
8243+
@no_esm_integration('WASM_ESM_INTEGRATION is not compatible with ASYNCIFY=1')
82488244
@parameterized({
82498245
'normal': ([], True),
82508246
'removelist_a': (['-sASYNCIFY_REMOVE=["foo(int, double)"]'], False),
@@ -8292,7 +8288,7 @@ def test_asyncify_lists(self, args, should_pass, response=None):
82928288
# virt() manually, rather than have them inferred automatically.
82938289
'add_no_prop': (['-sASYNCIFY_IGNORE_INDIRECT', '-sASYNCIFY_ADD=["__original_main","main","virt()"]', '-sASYNCIFY_PROPAGATE_ADD=0'], True),
82948290
})
8295-
@no_modularize_instance('MODULARIZE=instance is not compatible with ASYNCIFY=1')
8291+
@no_esm_integration('WASM_ESM_INTEGRATION is not compatible with ASYNCIFY=1')
82968292
def test_asyncify_indirect_lists(self, args, should_pass):
82978293
self.set_setting('ASYNCIFY')
82988294
self.emcc_args += args
@@ -8310,7 +8306,7 @@ def test_asyncify_indirect_lists(self, args, should_pass):
83108306
raise
83118307

83128308
@with_dylink_reversed
8313-
@no_modularize_instance('MODULARIZE=instance is not compatible with ASYNCIFY=1')
8309+
@no_esm_integration('WASM_ESM_INTEGRATION is not compatible with ASYNCIFY=1')
83148310
def test_asyncify_side_module(self):
83158311
self.set_setting('ASYNCIFY')
83168312
self.set_setting('ASYNCIFY_IMPORTS', ['my_sleep'])
@@ -8340,12 +8336,12 @@ def test_asyncify_side_module(self):
83408336
''', 'before sleep\n42\n42\nafter sleep\n', header='void my_sleep(int);', force_c=True)
83418337

83428338
@no_asan('asyncify stack operations confuse asan')
8343-
@no_modularize_instance('MODULARIZE=instance is not compatible with ASYNCIFY=1')
8339+
@no_esm_integration('WASM_ESM_INTEGRATION is not compatible with ASYNCIFY=1')
83448340
def test_emscripten_scan_registers(self):
83458341
self.set_setting('ASYNCIFY')
83468342
self.do_core_test('test_emscripten_scan_registers.cpp')
83478343

8348-
@no_modularize_instance('MODULARIZE=instance is not compatible with ASYNCIFY=1')
8344+
@no_esm_integration('WASM_ESM_INTEGRATION is not compatible with ASYNCIFY=1')
83498345
def test_asyncify_assertions(self):
83508346
self.set_setting('ASYNCIFY')
83518347
self.set_setting('ASYNCIFY_IMPORTS', ['suspend'])
@@ -8354,7 +8350,7 @@ def test_asyncify_assertions(self):
83548350

83558351
@no_lsan('leaks asyncify stack during exit')
83568352
@no_asan('leaks asyncify stack during exit')
8357-
@no_modularize_instance('MODULARIZE=instance is not compatible with ASYNCIFY=1')
8353+
@no_esm_integration('WASM_ESM_INTEGRATION is not compatible with ASYNCIFY=1')
83588354
def test_asyncify_during_exit(self):
83598355
self.set_setting('ASYNCIFY')
83608356
self.set_setting('ASSERTIONS')

tools/emscripten.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -924,9 +924,6 @@ def install_debug_wrapper(sym):
924924

925925

926926
def should_export(sym):
927-
if not settings.MINIMAL_RUNTIME and sym.startswith('dynCall_') and settings.MODULARIZE != 'instance':
928-
# TODO(sbc): Can we avoid exporting the dynCall_ functions on the module.
929-
return True
930927
return settings.EXPORT_ALL or (settings.EXPORT_KEEPALIVE and sym in settings.EXPORTED_FUNCTIONS)
931928

932929

@@ -955,7 +952,7 @@ def create_receiving(function_exports, tag_exports):
955952
# var _main;
956953
# function assignWasmExports(wasmExport) {
957954
# _main = wasmExports["_main"];
958-
generate_dyncall_assignment = settings.MINIMAL_RUNTIME and settings.DYNCALLS and '$dynCall' in settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE
955+
generate_dyncall_assignment = settings.DYNCALLS and '$dynCall' in settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE
959956
exports = {name: sig for name, sig in function_exports.items() if name != building.WASM_CALL_CTORS}
960957

961958
if settings.ASSERTIONS:
@@ -985,8 +982,8 @@ def create_receiving(function_exports, tag_exports):
985982
for sym, sig in exports.items():
986983
mangled = asmjs_mangle(sym)
987984
if generate_dyncall_assignment and mangled.startswith('dynCall_'):
988-
sig = sym.replace('dynCall_', '')
989-
dynCallAssignment = f"dynCalls['{sig}'] = "
985+
sig_str = sym.replace('dynCall_', '')
986+
dynCallAssignment = f"dynCalls['{sig_str}'] = "
990987
else:
991988
dynCallAssignment = ''
992989
export_assignment = ''

tools/link.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -812,6 +812,10 @@ def phase_linker_setup(options, linker_args): # noqa: C901, PLR0912, PLR0915
812812
exit_with_error('WASM_ESM_INTEGRATION requires MODULARIZE=instance')
813813
if settings.RELOCATABLE:
814814
exit_with_error('WASM_ESM_INTEGRATION is not compatible with dynamic linking')
815+
if settings.ASYNCIFY == 1:
816+
exit_with_error('WASM_ESM_INTEGRATION is not compatible with -sASYNCIFY=1')
817+
if settings.DYNCALLS:
818+
exit_with_error('WASM_ESM_INTEGRATION is not compatible with DYNCALLS')
815819
if settings.WASM_WORKERS or settings.PTHREADS:
816820
exit_with_error('WASM_ESM_INTEGRATION is not compatible with multi-threading')
817821
if settings.USE_OFFSET_CONVERTER:
@@ -845,10 +849,6 @@ def limit_incoming_module_api():
845849
diagnostics.warning('experimental', 'MODULARIZE=instance is still experimental. Many features may not work or will change.')
846850
if not settings.EXPORT_ES6:
847851
exit_with_error('MODULARIZE=instance requires EXPORT_ES6')
848-
if settings.ASYNCIFY == 1:
849-
exit_with_error('MODULARIZE=instance is not compatible with -sASYNCIFY=1')
850-
if settings.DYNCALLS:
851-
exit_with_error('MODULARIZE=instance is not compatible with -sDYNCALLS')
852852
if settings.ASYNCIFY_LAZY_LOAD_CODE:
853853
exit_with_error('MODULARIZE=instance is not compatible with -sASYNCIFY_LAZY_LOAD_CODE')
854854
if settings.MINIMAL_RUNTIME:

0 commit comments

Comments
 (0)