Skip to content

Commit 674f2fe

Browse files
authored
Allow DECLARE_ASM_MODULE_EXPORTS=0 + WASM_ASYNC_COMPILATION (#10348)
Fixes: #10217
1 parent b1511d1 commit 674f2fe

File tree

6 files changed

+57
-55
lines changed

6 files changed

+57
-55
lines changed

emcc.py

-6
Original file line numberDiff line numberDiff line change
@@ -1674,12 +1674,6 @@ def is_supported_link_flag(f):
16741674
# async compilation requires a swappable module - we swap it in when it's ready
16751675
shared.Settings.SWAPPABLE_ASM_MODULE = 1
16761676

1677-
if shared.Settings.SWAPPABLE_ASM_MODULE and not shared.Settings.DECLARE_ASM_MODULE_EXPORTS:
1678-
# Swappable wasm module/asynchronous wasm compilation requires an indirect stub
1679-
# function generated to each function export from wasm module, so cannot use the
1680-
# concise form of grabbing exports that does not need to refer to each export individually.
1681-
exit_with_error('DECLARE_ASM_MODULE_EXPORTS=0 is not comptabible with SWAPPABLE_ASM_MODULE')
1682-
16831677
# wasm side modules have suffix .wasm
16841678
if shared.Settings.SIDE_MODULE and target.endswith('.js'):
16851679
shared.warning('output suffix .js requested, but wasm side modules are just wasm files; emitting only a .wasm, no .js')

emscripten.py

+41-40
Original file line numberDiff line numberDiff line change
@@ -1719,23 +1719,24 @@ def create_receiving(function_table_data, function_tables_defs, exported_impleme
17191719
module_exports = exported_implemented_functions + function_tables(function_table_data)
17201720
shared.Settings.MODULE_EXPORTS = [(f, f) for f in module_exports]
17211721

1722-
if not shared.Settings.SWAPPABLE_ASM_MODULE:
1723-
if runtime_assertions:
1724-
# assert on the runtime being in a valid state when calling into compiled code. The only
1725-
# exceptions are some support code.
1726-
receiving_functions = [f for f in exported_implemented_functions if f not in ('_memcpy', '_memset', '_emscripten_replace_memory', '__start_module')]
1727-
1728-
wrappers = []
1729-
for name in receiving_functions:
1730-
wrappers.append('''\
1731-
var real_%(name)s = asm["%(name)s"];
1732-
asm["%(name)s"] = function() {%(runtime_assertions)s
1733-
return real_%(name)s.apply(null, arguments);
1734-
};
1735-
''' % {'name': name, 'runtime_assertions': runtime_assertions})
1736-
receiving += '\n'.join(wrappers)
1722+
if not shared.Settings.DECLARE_ASM_MODULE_EXPORTS:
1723+
receiving += 'exportAsmFunctions(asm);'
1724+
else:
1725+
if not shared.Settings.SWAPPABLE_ASM_MODULE:
1726+
if runtime_assertions:
1727+
# assert on the runtime being in a valid state when calling into compiled code. The only
1728+
# exceptions are some support code.
1729+
receiving_functions = [f for f in exported_implemented_functions if f not in ('_memcpy', '_memset', '_emscripten_replace_memory', '__start_module')]
1730+
wrappers = []
1731+
for name in receiving_functions:
1732+
wrappers.append('''\
1733+
var real_%(name)s = asm["%(name)s"];
1734+
asm["%(name)s"] = function() {%(runtime_assertions)s
1735+
return real_%(name)s.apply(null, arguments);
1736+
};
1737+
''' % {'name': name, 'runtime_assertions': runtime_assertions})
1738+
receiving += '\n'.join(wrappers)
17371739

1738-
if shared.Settings.DECLARE_ASM_MODULE_EXPORTS:
17391740
imported_exports = [s for s in module_exports if s not in initializers]
17401741

17411742
if shared.Settings.WASM and shared.Settings.MINIMAL_RUNTIME:
@@ -1754,18 +1755,16 @@ def create_receiving(function_table_data, function_tables_defs, exported_impleme
17541755
else:
17551756
receiving += '\n'.join(['var ' + s + ' = Module["' + s + '"] = asm["' + s + '"];' for s in module_exports]) + '\n'
17561757
else:
1757-
receiving += 'exportAsmFunctions(asm);'
1758-
else:
1759-
receiving += 'Module["asm"] = asm;\n'
1760-
wrappers = []
1761-
for name in module_exports:
1762-
wrappers.append('''\
1758+
receiving += 'Module["asm"] = asm;\n'
1759+
wrappers = []
1760+
for name in module_exports:
1761+
wrappers.append('''\
17631762
var %(name)s = Module["%(name)s"] = function() {%(runtime_assertions)s
17641763
return Module["asm"]["%(name)s"].apply(null, arguments)
17651764
};
17661765
''' % {'name': name, 'runtime_assertions': runtime_assertions})
17671766

1768-
receiving += '\n'.join(wrappers)
1767+
receiving += '\n'.join(wrappers)
17691768

17701769
if shared.Settings.EXPORT_FUNCTION_TABLES and not shared.Settings.WASM:
17711770
for table in function_table_data.values():
@@ -2613,6 +2612,11 @@ def fix_import_name(g):
26132612

26142613

26152614
def create_receiving_wasm(exports, initializers):
2615+
# When not declaring asm exports this section is empty and we instead programatically export
2616+
# synbols on the global object by calling exportAsmFunctions after initialization
2617+
if not shared.Settings.DECLARE_ASM_MODULE_EXPORTS:
2618+
return ''
2619+
26162620
exports_that_are_not_initializers = [x for x in exports if x not in initializers]
26172621

26182622
receiving = []
@@ -2631,24 +2635,21 @@ def create_receiving_wasm(exports, initializers):
26312635
return real_%(mangled)s.apply(null, arguments);
26322636
};
26332637
''' % {'mangled': asmjs_mangle(e), 'e': e, 'assertions': runtime_assertions})
2634-
if shared.Settings.DECLARE_ASM_MODULE_EXPORTS:
2635-
if shared.Settings.WASM and shared.Settings.MINIMAL_RUNTIME:
2636-
# In Wasm exports are assigned inside a function to variables existing in top level JS scope, i.e.
2637-
# var _main;
2638-
# WebAssembly.instantiate(Module["wasm"], imports).then((function(output) {
2639-
# var asm = output.instance.exports;
2640-
# _main = asm["_main"];
2641-
receiving += [asmjs_mangle(s) + ' = asm["' + s + '"];' for s in exports_that_are_not_initializers]
2642-
else:
2643-
if shared.Settings.MINIMAL_RUNTIME:
2644-
# In wasm2js exports can be directly processed at top level, i.e.
2645-
# var asm = Module["asm"](asmGlobalArg, asmLibraryArg, buffer);
2646-
# var _main = asm["_main"];
2647-
receiving += ['var ' + asmjs_mangle(s) + ' = asm["' + asmjs_mangle(s) + '"];' for s in exports_that_are_not_initializers]
2648-
else:
2649-
receiving += ['var ' + asmjs_mangle(s) + ' = Module["' + asmjs_mangle(s) + '"] = asm["' + s + '"];' for s in exports]
2638+
if shared.Settings.WASM and shared.Settings.MINIMAL_RUNTIME:
2639+
# In Wasm exports are assigned inside a function to variables existing in top level JS scope, i.e.
2640+
# var _main;
2641+
# WebAssembly.instantiate(Module["wasm"], imports).then((function(output) {
2642+
# var asm = output.instance.exports;
2643+
# _main = asm["_main"];
2644+
receiving += [asmjs_mangle(s) + ' = asm["' + s + '"];' for s in exports_that_are_not_initializers]
26502645
else:
2651-
receiving.append('exportAsmFunctions(asm);')
2646+
if shared.Settings.MINIMAL_RUNTIME:
2647+
# In wasm2js exports can be directly processed at top level, i.e.
2648+
# var asm = Module["asm"](asmGlobalArg, asmLibraryArg, buffer);
2649+
# var _main = asm["_main"];
2650+
receiving += ['var ' + asmjs_mangle(s) + ' = asm["' + asmjs_mangle(s) + '"];' for s in exports_that_are_not_initializers]
2651+
else:
2652+
receiving += ['var ' + asmjs_mangle(s) + ' = Module["' + asmjs_mangle(s) + '"] = asm["' + s + '"];' for s in exports]
26522653
else:
26532654
receiving.append('Module["asm"] = asm;')
26542655
for e in exports:

src/postamble_minimal.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -129,12 +129,14 @@ WebAssembly.instantiate(Module['wasm'], imports).then(function(output) {
129129
#else
130130
asm = output.instance.exports;
131131
#endif
132-
133132
#if USE_OFFSET_CONVERTER
134133
wasmOffsetConverter = new WasmOffsetConverter(Module['wasm'], output.module);
135134
#endif
136-
135+
#if !DECLARE_ASM_MODULE_EXPORTS
136+
exportAsmFunctions(asm);
137+
#else
137138
/*** ASM_MODULE_EXPORTS ***/
139+
#endif
138140
initRuntime(asm);
139141
ready();
140142
})

src/preamble.js

+5
Original file line numberDiff line numberDiff line change
@@ -909,6 +909,11 @@ function createWasm() {
909909
exports = Asyncify.instrumentWasmExports(exports);
910910
#endif
911911
Module['asm'] = exports;
912+
#if !DECLARE_ASM_MODULE_EXPORTS
913+
// If we didn't declare the asm exports as top level enties this function
914+
// is in charge of programatically exporting them on the global object.
915+
exportAsmFunctions(exports);
916+
#endif
912917
#if STANDALONE_WASM
913918
// In pure wasm mode the memory is created in the wasm (not imported), and
914919
// then exported.

tests/test_core.py

+7-3
Original file line numberDiff line numberDiff line change
@@ -3646,7 +3646,7 @@ def dylink_test(self, main, side, expected=None, header=None, main_emcc_args=[],
36463646
print('flip')
36473647
self.dylink_test(side, main, expected, header, main_emcc_args, force_c, need_reverse=False, **kwargs)
36483648

3649-
def do_basic_dylink_test(self):
3649+
def do_basic_dylink_test(self, need_reverse=True):
36503650
self.dylink_test(r'''
36513651
#include <stdio.h>
36523652
#include "header.h"
@@ -3661,12 +3661,17 @@ def do_basic_dylink_test(self):
36613661
int sidey() {
36623662
return 11;
36633663
}
3664-
''', 'other says 11.', 'extern "C" int sidey();')
3664+
''', 'other says 11.', 'extern "C" int sidey();', need_reverse=need_reverse)
36653665

36663666
@needs_dlfcn
36673667
def test_dylink_basics(self):
36683668
self.do_basic_dylink_test()
36693669

3670+
@needs_dlfcn
3671+
def test_dylink_no_export(self):
3672+
self.set_setting('NO_DECLARE_ASM_MODULE_EXPORTS')
3673+
self.do_basic_dylink_test()
3674+
36703675
@needs_dlfcn
36713676
def test_dylink_memory_growth(self):
36723677
if not self.is_wasm():
@@ -8305,7 +8310,6 @@ def test_minimal_runtime_hello_world(self, args):
83058310

83068311
# Test that printf() works in MINIMAL_RUNTIME=1
83078312
@no_emterpreter
8308-
@no_wasm_backend('MINIMAL_RUNTIME not yet available in Wasm backend')
83098313
@parameterized({
83108314
'fs': (['-s', 'FORCE_FILESYSTEM=1'],),
83118315
'nofs': (['-s', 'NO_FILESYSTEM=1'],),

tests/test_other.py

-4
Original file line numberDiff line numberDiff line change
@@ -9536,10 +9536,6 @@ def test_add_emscripten_metadata_not_emitted(self):
95369536
def test_function_exports_are_small(self):
95379537
def test(wasm, closure, opt):
95389538
extra_args = wasm + opt + closure
9539-
if self.is_wasm_backend() and 'WASM_ASYNC_COMPILATION=0' not in extra_args:
9540-
# TODO: re-enable once we allow WASM_ASYNC_COMPILATION+DECLARE_ASM_MODULE_EXPORTS
9541-
# https://github.com/emscripten-core/emscripten/issues/10217
9542-
return
95439539
print(extra_args)
95449540
args = [PYTHON, EMCC, path_from_root('tests', 'long_function_name_in_export.c'), '-o', 'a.html', '-s', 'ENVIRONMENT=web', '-s', 'DECLARE_ASM_MODULE_EXPORTS=0', '-Werror'] + extra_args
95459541
run_process(args)

0 commit comments

Comments
 (0)