Skip to content

Commit 3ae2e6e

Browse files
committed
Enable EM_JS in side modules
This works in a similar way to EM_ASM. See #18228. Depends on WebAssembly/binaryen#5780
1 parent b020474 commit 3ae2e6e

File tree

8 files changed

+61
-3
lines changed

8 files changed

+61
-3
lines changed

emcc.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,7 @@ def process_dynamic_libs(dylibs, lib_dirs):
831831
for dylib in dylibs:
832832
exports = webassembly.get_exports(dylib)
833833
exports = set(e.name for e in exports)
834+
exports = [utils.removeprefix(e, '__em_js__') for e in exports]
834835
settings.SIDE_MODULE_EXPORTS.extend(sorted(exports))
835836

836837
imports = webassembly.get_imports(dylib)

emscripten.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -344,8 +344,6 @@ def emscript(in_wasm, out_wasm, outfile_js, memfile, js_syms):
344344
diagnostics.warning('em-js-i64', 'using 64-bit arguments in EM_JS function without WASM_BIGINT is not yet fully supported: `%s` (%s, %s)', em_js_func, c_sig, signature.params)
345345

346346
if settings.SIDE_MODULE:
347-
if metadata.emJsFuncs:
348-
exit_with_error('EM_JS is not supported in side modules')
349347
logger.debug('emscript: skipping remaining js glue generation')
350348
return
351349

src/library_dylink.js

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,9 @@ var LibraryDylink = {
178178
'__wasm_call_ctors',
179179
'__start_em_asm',
180180
'__stop_em_asm',
181-
].includes(symName)
181+
'__start_em_js',
182+
'__stop_em_js',
183+
].includes(symName) || symName.startsWith('__em_js__')
182184
#if SPLIT_MODULE
183185
// Exports synthesized by wasm-split should be prefixed with '%'
184186
|| symName[0] == '%'
@@ -779,6 +781,29 @@ var LibraryDylink = {
779781
start = HEAPU8.indexOf(0, start) + 1;
780782
}
781783
}
784+
785+
function addEmJs(name, sig, body) {
786+
sig = sig.slice(1, -1).split(',');
787+
var args = [];
788+
for (var i in sig) {
789+
args.push(sig[i].split(' ').pop());
790+
}
791+
var func = `(${args}) => ${body};`;
792+
#if DYLINK_DEBUG
793+
dbg(`adding new EM_JS function: ${name} = ${func}`);
794+
#endif
795+
{{{ makeEval('wasmImports[name] = eval(func)') }}};
796+
}
797+
798+
for (var name in moduleExports) {
799+
if (name.startsWith('__em_js__')) {
800+
var start = moduleExports[name]
801+
{{{ from64('start') }}}
802+
var jsString = UTF8ToString(start);
803+
var parts = jsString.split('<::>');
804+
addEmJs(name.replace('__em_js__', ''), parts[0], parts[1]);
805+
}
806+
}
782807
#endif
783808

784809
// initialize the module

test/core/test_em_js_main.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#include <stdio.h>
2+
#include <emscripten.h>
3+
4+
int test_side();
5+
6+
int main() {
7+
printf("in main\n");
8+
return test_side();
9+
}

test/core/test_em_js_main.out

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
in main
2+
hello from side module 42 + hello

test/core/test_em_js_side.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#include <emscripten/em_js.h>
2+
#include <stdio.h>
3+
4+
EM_JS(void*, js_side_func, (int num, char* ptr), {
5+
out(`hello from side module ${num} + ${UTF8ToString(ptr)}`);
6+
return 99;
7+
});
8+
9+
void test_side() {
10+
js_side_func(42, "hello");
11+
}

test/test_core.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2322,6 +2322,11 @@ def test_em_js_address_taken(self):
23222322
self.set_setting('MAIN_MODULE', 2)
23232323
self.do_core_test('test_em_js_address_taken.c')
23242324

2325+
@needs_dylink
2326+
def test_em_js_side_module(self):
2327+
self.build(test_file('core/test_em_js_side.c'), js_outfile=False, emcc_args=['-sSIDE_MODULE'], output_basename='side')
2328+
self.do_core_test('test_em_js_main.c', emcc_args=['-sMAIN_MODULE=2', 'side.wasm'])
2329+
23252330
def test_runtime_stacksave(self):
23262331
self.do_runf(test_file('core/test_runtime_stacksave.c'), 'success')
23272332

tools/utils.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,13 @@ def safe_ensure_dirs(dirname):
2929
os.makedirs(dirname, exist_ok=True)
3030

3131

32+
# TODO(sbc): Replace with str.removeprefix once we update to python3.9
33+
def removeprefix(string, prefix):
34+
if string.startswith(prefix):
35+
return string[len(prefix):]
36+
return string
37+
38+
3239
@contextlib.contextmanager
3340
def chdir(dir):
3441
"""A context manager that performs actions in the given directory."""

0 commit comments

Comments
 (0)