From e093157f50664f1bc4de3fe35cb550cde887ba3f Mon Sep 17 00:00:00 2001 From: stephenduong1004 Date: Tue, 11 Nov 2025 18:09:15 -0500 Subject: [PATCH 1/6] Disable assertions in tsgen When using tsgen with -sASYNCIFY=1 and assertions enabled, an assertion failure occurs: `Assertion failed: missing Wasm export: asyncify_start_unwind`. This is due to https://github.com/emscripten-core/emscripten/pull/25541. This change disables assertions when running tsgen to resolve the issue. --- tools/link.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/link.py b/tools/link.py index 6c8c78452525c..1ff60249cca66 100644 --- a/tools/link.py +++ b/tools/link.py @@ -2096,6 +2096,7 @@ def run_embind_gen(options, wasm_target, js_syms, extra_settings): outfile_js = in_temp('tsgen.js') # The Wasm outfile may be modified by emscripten.emscript, so use a temporary file. outfile_wasm = in_temp('tsgen.wasm') + settings.ASSERTIONS = 0 emscripten.emscript(wasm_target, outfile_wasm, outfile_js, js_syms, finalize=False) # Build the flags needed by Node.js to properly run the output file. node_args = [] From ff25459ab79affbf401faa3ab7d4411d5f54fa5f Mon Sep 17 00:00:00 2001 From: stephenduong1004 Date: Tue, 11 Nov 2025 18:27:50 -0500 Subject: [PATCH 2/6] Move settings.ASSERTIONS = 0 up to be with other settings modifications --- tools/link.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/link.py b/tools/link.py index 1ff60249cca66..1dfa95a896f00 100644 --- a/tools/link.py +++ b/tools/link.py @@ -2093,10 +2093,10 @@ def run_embind_gen(options, wasm_target, js_syms, extra_settings): settings.MEMORY64 = 2 # Source maps haven't been generated yet and aren't needed to run embind_gen. settings.LOAD_SOURCE_MAP = 0 + settings.ASSERTIONS = 0 outfile_js = in_temp('tsgen.js') # The Wasm outfile may be modified by emscripten.emscript, so use a temporary file. outfile_wasm = in_temp('tsgen.wasm') - settings.ASSERTIONS = 0 emscripten.emscript(wasm_target, outfile_wasm, outfile_js, js_syms, finalize=False) # Build the flags needed by Node.js to properly run the output file. node_args = [] From 7b78043ecd51f36063df0233f3048c5b85b5b057 Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Tue, 2 Dec 2025 23:13:02 +0000 Subject: [PATCH 3/6] Add test and comment. --- test/test_other.py | 4 ++++ tools/link.py | 2 ++ 2 files changed, 6 insertions(+) diff --git a/test/test_other.py b/test/test_other.py index 8123d421bdc40..9ebcb11c1d620 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -3598,6 +3598,10 @@ def test_embind_tsgen_ignore(self): self.emcc('other/embind_tsgen.cpp', extra_args) self.assertFileContents(test_file('other/embind_tsgen_ignore_3.d.ts'), read_file('embind_tsgen.d.ts')) + extra_args = ['-sASYNCIFY'] + self.emcc('other/embind_tsgen.cpp', extra_args) + self.assertFileContents(test_file('other/embind_tsgen_ignore_3.d.ts'), read_file('embind_tsgen.d.ts')) + def test_embind_tsgen_worker_env(self): self.cflags += ['-lembind', '--emit-tsd', 'embind_tsgen.d.ts'] # Passing -sWASM_WORKERS requires the 'worker' environment diff --git a/tools/link.py b/tools/link.py index 1dfa95a896f00..b1752afe03fe5 100644 --- a/tools/link.py +++ b/tools/link.py @@ -2093,6 +2093,8 @@ def run_embind_gen(options, wasm_target, js_syms, extra_settings): settings.MEMORY64 = 2 # Source maps haven't been generated yet and aren't needed to run embind_gen. settings.LOAD_SOURCE_MAP = 0 + # TS generation is run before wasm-opt so some of the assertions may be incorrect + # e.g. when -sASYNCIFY=1 `asyncify_start_unwind` is missing. settings.ASSERTIONS = 0 outfile_js = in_temp('tsgen.js') # The Wasm outfile may be modified by emscripten.emscript, so use a temporary file. From c4879c8a77b1937e42af6de224b202a8102b3bdb Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Tue, 2 Dec 2025 23:28:29 +0000 Subject: [PATCH 4/6] paramaterize tsgen test to speed it up --- test/test_other.py | 77 ++++++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 44 deletions(-) diff --git a/test/test_other.py b/test/test_other.py index 9ebcb11c1d620..1aedcdf96b54c 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -3554,53 +3554,42 @@ def test_embind_tsgen_end_to_end(self, opts, tsc_opts): @is_slow_test @requires_dev_dependency('typescript') - def test_embind_tsgen_ignore(self): + # These extra arguments are not related to TS binding generation but we want to + # verify that they do not interfere with it. + @parameterized({ + '1': [['-sALLOW_MEMORY_GROWTH=1', + '-Wno-pthreads-mem-growth', + '-sMAXIMUM_MEMORY=4GB', + '--pre-js', 'fail.js', + '--post-js', 'fail.js', + '--extern-pre-js', 'fail.js', + '--extern-post-js', 'fail.js', + '-sENVIRONMENT=worker', + '--use-preload-cache', + '--preload-file', 'fail.js', + '-O3', + '-msimd128', + '-pthread', + '-sPROXY_TO_PTHREAD', + '-sPTHREAD_POOL_SIZE=1', + '-sSINGLE_FILE', + '-lembind', # Test duplicated link option. + ], 'embind_tsgen_ignore_1.d.ts'], + '2': [['--embed-file', 'fail.js', + '-sMINIMAL_RUNTIME=2', + '-sEXPORT_ES6=1', + '-sASSERTIONS=0', + '-sSTRICT=1', + ], 'embind_tsgen_ignore_2.d.ts'], + '3': [['-sWASM=0'], 'embind_tsgen_ignore_3.d.ts'], + '4': [['-fsanitize=undefined', '-gsource-map'], 'embind_tsgen_ignore_3.d.ts'], + '5': [['-sASYNCIFY'], 'embind_tsgen_ignore_3.d.ts'], + }) + def test_embind_tsgen_ignore(self, extra_args, expected_ts_file): create_file('fail.js', 'assert(false);') self.cflags += ['-lembind', '--emit-tsd', 'embind_tsgen.d.ts'] - # These extra arguments are not related to TS binding generation but we want to - # verify that they do not interfere with it. - extra_args = ['-sALLOW_MEMORY_GROWTH=1', - '-Wno-pthreads-mem-growth', - '-sMAXIMUM_MEMORY=4GB', - '--pre-js', 'fail.js', - '--post-js', 'fail.js', - '--extern-pre-js', 'fail.js', - '--extern-post-js', 'fail.js', - '-sENVIRONMENT=worker', - '--use-preload-cache', - '--preload-file', 'fail.js', - '-O3', - '-msimd128', - '-pthread', - '-sPROXY_TO_PTHREAD', - '-sPTHREAD_POOL_SIZE=1', - '-sSINGLE_FILE', - '-lembind', # Test duplicated link option. - ] self.emcc('other/embind_tsgen.cpp', extra_args) - self.assertFileContents(test_file('other/embind_tsgen_ignore_1.d.ts'), read_file('embind_tsgen.d.ts')) - # Test these args separately since they conflict with arguments in the first test. - extra_args = ['-sMODULARIZE', - '--embed-file', 'fail.js', - '-sMINIMAL_RUNTIME=2', - '-sEXPORT_ES6=1', - '-sASSERTIONS=0', - '-sSTRICT=1'] - self.emcc('other/embind_tsgen.cpp', extra_args) - self.assertFileContents(test_file('other/embind_tsgen_ignore_2.d.ts'), read_file('embind_tsgen.d.ts')) - # Also test this separately since it conflicts with other settings. - extra_args = ['-sWASM=0'] - self.emcc('other/embind_tsgen.cpp', extra_args) - self.assertFileContents(test_file('other/embind_tsgen_ignore_3.d.ts'), read_file('embind_tsgen.d.ts')) - - extra_args = ['-fsanitize=undefined', - '-gsource-map'] - self.emcc('other/embind_tsgen.cpp', extra_args) - self.assertFileContents(test_file('other/embind_tsgen_ignore_3.d.ts'), read_file('embind_tsgen.d.ts')) - - extra_args = ['-sASYNCIFY'] - self.emcc('other/embind_tsgen.cpp', extra_args) - self.assertFileContents(test_file('other/embind_tsgen_ignore_3.d.ts'), read_file('embind_tsgen.d.ts')) + self.assertFileContents(test_file(f'other/{expected_ts_file}'), read_file('embind_tsgen.d.ts')) def test_embind_tsgen_worker_env(self): self.cflags += ['-lembind', '--emit-tsd', 'embind_tsgen.d.ts'] From 2ee68abe83e5a6d96af61faca6226eea429782df Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Tue, 2 Dec 2025 15:36:14 -0800 Subject: [PATCH 5/6] Update tools/link.py Co-authored-by: Alon Zakai --- tools/link.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/link.py b/tools/link.py index b1752afe03fe5..5112df6eeb2f7 100644 --- a/tools/link.py +++ b/tools/link.py @@ -2094,7 +2094,8 @@ def run_embind_gen(options, wasm_target, js_syms, extra_settings): # Source maps haven't been generated yet and aren't needed to run embind_gen. settings.LOAD_SOURCE_MAP = 0 # TS generation is run before wasm-opt so some of the assertions may be incorrect - # e.g. when -sASYNCIFY=1 `asyncify_start_unwind` is missing. + # e.g. when -sASYNCIFY=1 `asyncify_start_unwind` does not yet exist (that pass + # creates it). settings.ASSERTIONS = 0 outfile_js = in_temp('tsgen.js') # The Wasm outfile may be modified by emscripten.emscript, so use a temporary file. From fb69d7f185c6a411d88e7d3fbf5b337412d7ee5c Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Wed, 3 Dec 2025 22:18:46 +0000 Subject: [PATCH 6/6] remove assertions for asyncify functions --- tools/emscripten.py | 4 ++++ tools/link.py | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/emscripten.py b/tools/emscripten.py index 4d49da06eb429..c3b24f0bcf2f4 100644 --- a/tools/emscripten.py +++ b/tools/emscripten.py @@ -962,6 +962,10 @@ def create_receiving(function_exports, other_exports, library_symbols, aliases): receiving.append('\nfunction assignWasmExports(wasmExports) {') if settings.ASSERTIONS: for sym in exports: + if settings.EMBIND_GEN_MODE and sym.startswith('asyncify_'): + # EMBIND_GEN_MODE is run before binaryen so the asyncify exports that + # are created by binaryen will be missing. + continue receiving.append(f" assert(typeof wasmExports['{sym}'] != 'undefined', 'missing Wasm export: {sym}');") for sym, info in exports.items(): is_function = type(info) == webassembly.FuncType diff --git a/tools/link.py b/tools/link.py index 5112df6eeb2f7..6c8c78452525c 100644 --- a/tools/link.py +++ b/tools/link.py @@ -2093,10 +2093,6 @@ def run_embind_gen(options, wasm_target, js_syms, extra_settings): settings.MEMORY64 = 2 # Source maps haven't been generated yet and aren't needed to run embind_gen. settings.LOAD_SOURCE_MAP = 0 - # TS generation is run before wasm-opt so some of the assertions may be incorrect - # e.g. when -sASYNCIFY=1 `asyncify_start_unwind` does not yet exist (that pass - # creates it). - settings.ASSERTIONS = 0 outfile_js = in_temp('tsgen.js') # The Wasm outfile may be modified by emscripten.emscript, so use a temporary file. outfile_wasm = in_temp('tsgen.wasm')