From 9829ce94f7c6b6c659b870f1d74eb272cd757719 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 20 Aug 2026 14:07:40 -0700 Subject: [PATCH 1/2] Convert a couple of EH tests to @parameterize. NFC Split out from #27575 --- test/test_other.py | 24 ++++++++++++------------ tools/feature_matrix.py | 2 ++ tools/link.py | 2 +- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/test/test_other.py b/test/test_other.py index d116ed31ead93..8a94aaf317aa4 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -8806,13 +8806,13 @@ def test_lto_flags(self): # We have LTO tests covered in 'wasmltoN' targets in test_core.py, but they # don't run as a part of Emscripten CI, so we add a separate LTO test here. @requires_wasm_eh - def test_lto_wasm_exceptions(self): + @parameterized({ + '': (['-sWASM_LEGACY_EXCEPTIONS=0'],), + 'legacy': (['-sWASM_LEGACY_EXCEPTIONS'],), + }) + def test_lto_wasm_exceptions(self, args): self.set_setting('EXCEPTION_DEBUG') - self.cflags += ['-fwasm-exceptions', '-flto'] - self.set_setting('WASM_LEGACY_EXCEPTIONS', 0) - self.do_runf_out_file('core/test_exceptions.cpp', out_suffix='_caught') - self.set_setting('WASM_LEGACY_EXCEPTIONS') - self.do_runf_out_file('core/test_exceptions.cpp', out_suffix='_caught') + self.do_runf_out_file('core/test_exceptions.cpp', out_suffix='_caught', cflags=['-fwasm-exceptions', '-flto'] + args) @parameterized({ '': ([],), @@ -12514,14 +12514,14 @@ def test_standalone_export_main(self): self.run_process([EMCC, '-sEXPORTED_FUNCTIONS=_main', '-sSTANDALONE_WASM', test_file('core/test_hello_world.c')]) @requires_wasm_eh - def test_standalone_wasm_exceptions(self): + @parameterized({ + '': (['-sWASM_LEGACY_EXCEPTIONS=0'],), + 'legacy': (['-sWASM_LEGACY_EXCEPTIONS'],), + }) + def test_standalone_wasm_exceptions(self, args): self.set_setting('STANDALONE_WASM') self.wasm_engines = [] - self.cflags += ['-fwasm-exceptions'] - self.set_setting('WASM_LEGACY_EXCEPTIONS', 0) - self.do_runf_out_file('core/test_exceptions.cpp', out_suffix='_caught') - self.set_setting('WASM_LEGACY_EXCEPTIONS') - self.do_runf_out_file('core/test_exceptions.cpp', out_suffix='_caught') + self.do_runf_out_file('core/test_exceptions.cpp', out_suffix='_caught', cflags=['-fwasm-exceptions'] + args) def test_missing_malloc_export(self): # we used to include malloc by default. show a clear error in builds with diff --git a/tools/feature_matrix.py b/tools/feature_matrix.py index 1fe4bf8d89e9b..4e3aef7988642 100644 --- a/tools/feature_matrix.py +++ b/tools/feature_matrix.py @@ -276,3 +276,5 @@ def auto_enable_features(): # compiler rather then adding them all ad-hoc as internal settings if caniuse(Feature.GROWABLE_ARRAYBUFFERS): default_setting('GROWABLE_ARRAYBUFFERS', 2) + if not caniuse(Feature.WASM_LEGACY_EXCEPTIONS): + default_setting('WASM_LEGACY_EXCEPTIONS', 0) diff --git a/tools/link.py b/tools/link.py index 63ac7476b7952..bc3ab03351de6 100644 --- a/tools/link.py +++ b/tools/link.py @@ -1567,7 +1567,7 @@ def limit_incoming_module_api(): settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$_wasmWorkerInitializeRuntime'] # Set min browser versions based on certain settings such as WASM_BIGINT, - # PTHREADS, AUDIO_WORKLET + # PTHREADS, AUDIO_WORKLET, WASM_EXCEPTIONS. # Such setting must be set before this point feature_matrix.apply_min_browser_versions() From 07353288aad18043f2427c37e8009d735adc733c Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 20 Aug 2026 13:20:19 -0700 Subject: [PATCH 2/2] Disable WASM_LEGACY_EXCEPTIONS by default The Wasm committee and browser vendors would like legacy wasm exceptions to be phased out ASAP. To that end this change disables `WASM_LEGACY_EXCEPTIONS` by default for users of `-fwasm-exceptions`. User who need to target old browsers can obviously set `-sWASM_LEGACY_EXCEPTIONS` still. Running ./emcc -fwasm-exceptions with EMCC_DEBUG=1 shows the effect this has on min browser versions: ``` feature_matrix:DEBUG: Enabling MIN_CHROME_VERSION=137 to accommodate Wasm exceptions (-fwasm-exceptions without sWASM_LEGACY_EXCEPTIONS) feature_matrix:DEBUG: Enabling MIN_FIREFOX_VERSION=131 to accommodate Wasm exceptions (-fwasm-exceptions without WASM_LEGACY_EXCEPTIONS) feature_matrix:DEBUG: Enabling MIN_SAFARI_VERSION=180400 to accommodate Wasm exceptions (-fwasm-exceptions without WASM_LEGACY_EXCEPTIONS) feature_matrix:DEBUG: Enabling MIN_NODE_VERSION=241500 to accommodate Wasm exceptions (-fwasm-exceptions without WASM_LEGACY_EXCEPTIONS) ``` --- ChangeLog.md | 5 +++++ .../docs/tools_reference/settings_reference.rst | 2 +- src/settings.js | 2 +- test/test_codesize.py | 2 +- test/test_other.py | 12 ++++++------ tools/feature_matrix.py | 6 +++--- tools/ports/freetype.py | 10 ++++++++-- tools/ports/libpng.py | 7 ++++++- tools/system_libs.py | 3 +-- 9 files changed, 32 insertions(+), 17 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index c593b7a9e7869..ae2686cbbe4b4 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -20,6 +20,11 @@ See docs/process.md for more on how version tagging works. 6.0.9 (in development) ---------------------- +- `WASM_LEGACY_EXCEPTIONS` now defaults to `false`. When `-fwasm-exceptions` is + used, Emscripten now emits instructions for the standardized WebAssembly + exception handling proposal by default. Users targeting older engines can + still opt in to the legacy exception handling proposal with + `-sWASM_LEGACY_EXCEPTIONS`. (#27575) 6.0.8 - 08/20/26 ---------------- diff --git a/site/source/docs/tools_reference/settings_reference.rst b/site/source/docs/tools_reference/settings_reference.rst index aaccc9b8823b2..e0c763e76c684 100644 --- a/site/source/docs/tools_reference/settings_reference.rst +++ b/site/source/docs/tools_reference/settings_reference.rst @@ -1175,7 +1175,7 @@ https://github.com/WebAssembly/exception-handling/blob/main/proposals/exception- .. note:: Applicable during both linking and compilation -Default value: true +Default value: false .. _asyncify: diff --git a/src/settings.js b/src/settings.js index 8101b4662c3d8..4f0a882da86ce 100644 --- a/src/settings.js +++ b/src/settings.js @@ -796,7 +796,7 @@ var EXCEPTION_STACK_TRACES = false; // If false, emit instructions for the standardized exception handling proposal: // https://github.com/WebAssembly/exception-handling/blob/main/proposals/exception-handling/Exceptions.md // [compile+link] -var WASM_LEGACY_EXCEPTIONS = true; +var WASM_LEGACY_EXCEPTIONS = false; // Whether to support async operations in the compiled code. This makes it // possible to call JS functions from synchronous-looking code in C/C++. diff --git a/test/test_codesize.py b/test/test_codesize.py index b89b585526755..2c80184ef91d4 100644 --- a/test/test_codesize.py +++ b/test/test_codesize.py @@ -366,7 +366,7 @@ def test_codesize_minimal_pthreads(self, args): # exceptions does not pull in demangling by default, which increases code size 'mangle': (['-O2', '-fexceptions', '-sEXPORTED_FUNCTIONS=_main,_free,___cxa_demangle', '-Wno-deprecated'],), # Wasm EH's code size increase is smaller than that of Emscripten EH - 'except_wasm': (['-O2', '-fwasm-exceptions', '-sWASM_LEGACY_EXCEPTIONS=0'],), + 'except_wasm': (['-O2', '-fwasm-exceptions'],), 'except_wasm_legacy': (['-O2', '-fwasm-exceptions', '-sWASM_LEGACY_EXCEPTIONS'],), # eval_ctors 1 can partially optimize, but runs into getenv() for locale # code. mode 2 ignores those and fully optimizes out the ctors diff --git a/test/test_other.py b/test/test_other.py index 8a94aaf317aa4..6ac62aa7b9ff9 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -8787,7 +8787,7 @@ def test_lto(self, args): @parameterized({ 'noexcept': (), 'except_emscripten': ('-sDISABLE_EXCEPTION_CATCHING=0',), - 'except_wasm': ('-fwasm-exceptions', '-sWASM_LEGACY_EXCEPTIONS=0'), + 'except_wasm': ('-fwasm-exceptions',), 'except_wasm_legacy': ('-fwasm-exceptions', '-sWASM_LEGACY_EXCEPTIONS'), }) def test_lto_libcxx(self, *args): @@ -12622,11 +12622,11 @@ def test_SUPPORT_LONGJMP_wasm(self): # automatically sets DISABLE_EXCEPTION_THROWING to 1, which is 0 by default, # because Emscripten EH and Wasm SjLj cannot be used at the same time. self.run_process([EMCC, test_file('core/test_longjmp.c'), '-c', '-sSUPPORT_LONGJMP=wasm', '-o', 'a.o']) - self.assertContained('try', self.get_wasm_text('a.o')) + self.assertContained('try_table', self.get_wasm_text('a.o')) - # If -sWASM_LEGACY_EXCEPTIONS=0 is provided, it uses the standard Wasm EH. - self.run_process([EMCC, test_file('core/test_longjmp.c'), '-c', '-sSUPPORT_LONGJMP=wasm', '-sWASM_LEGACY_EXCEPTIONS=0', '-o', 'b.o']) - self.assertContained('try_table', self.get_wasm_text('b.o')) + # If -sWASM_LEGACY_EXCEPTIONS is provided, it uses the legacy Wasm EH. + self.run_process([EMCC, test_file('core/test_longjmp.c'), '-c', '-sSUPPORT_LONGJMP=wasm', '-sWASM_LEGACY_EXCEPTIONS', '-o', 'b.o']) + self.assertContained('try', self.get_wasm_text('b.o')) @parameterized({ '': ([],), @@ -15243,7 +15243,7 @@ def test_SUPPORT_BIG_ENDIAN(self): 'noexcept': ('-fno-exceptions',), 'default': (), 'except': ('-sDISABLE_EXCEPTION_CATCHING=0',), - 'except_wasm': ('-fwasm-exceptions', '-sWASM_LEGACY_EXCEPTIONS=0'), + 'except_wasm': ('-fwasm-exceptions',), 'except_wasm_legacy': ('-fwasm-exceptions', '-sWASM_LEGACY_EXCEPTIONS'), }) def test_std_promise_link(self, *args): diff --git a/tools/feature_matrix.py b/tools/feature_matrix.py index 4e3aef7988642..28f7507ed67d8 100644 --- a/tools/feature_matrix.py +++ b/tools/feature_matrix.py @@ -261,11 +261,11 @@ def apply_min_browser_versions(): enable_feature(Feature.WORKER_ES6_MODULES, 'EXPORT_ES6 with -sWASM_WORKERS') if settings.OFFSCREENCANVAS_SUPPORT: enable_feature(Feature.OFFSCREENCANVAS_SUPPORT, 'OFFSCREENCANVAS_SUPPORT') - if settings.WASM_EXCEPTIONS or settings.SUPPORT_LONGJMP == 'wasm': # Wasm longjmp support will lean on Wasm (Legacy) EH + if settings.WASM_EXCEPTIONS or settings.SUPPORT_LONGJMP == 'wasm': if settings.WASM_LEGACY_EXCEPTIONS: - enable_feature(Feature.WASM_LEGACY_EXCEPTIONS, 'Wasm Legacy exceptions (-fwasm-exceptions with -sWASM_LEGACY_EXCEPTIONS=1)') + enable_feature(Feature.WASM_LEGACY_EXCEPTIONS, 'Wasm Legacy exceptions (-fwasm-exceptions with WASM_LEGACY_EXCEPTIONS)') else: - enable_feature(Feature.WASM_EXCEPTIONS, 'Wasm exceptions (-fwasm-exceptions with -sWASM_LEGACY_EXCEPTIONS=0)') + enable_feature(Feature.WASM_EXCEPTIONS, 'Wasm exceptions (-fwasm-exceptions without WASM_LEGACY_EXCEPTIONS)') if settings.GROWABLE_ARRAYBUFFERS == 2: enable_feature(Feature.GROWABLE_ARRAYBUFFERS, 'GrowableSharedArrayBuffer') diff --git a/tools/ports/freetype.py b/tools/ports/freetype.py index fb673373c0373..3775a922eb1c1 100644 --- a/tools/ports/freetype.py +++ b/tools/ports/freetype.py @@ -10,7 +10,10 @@ PKG_VERSION = '26.2.20' HASH = '460ea4dc9cc879822556d801341a1cf3efcd57a13cd4da64169603ea98873337dd19e3c8c6d9054b27d10acbbaa8d5c59b7f560c697b98dc2640bcd88f57554a' -variants = {'freetype-legacysjlj': {'SUPPORT_LONGJMP': 'wasm', 'WASM_LEGACY_EXCEPTIONS': 1}} +variants = { + 'freetype-wasmsjlj': {'SUPPORT_LONGJMP': 'wasm'}, + 'freetype-legacysjlj': {'SUPPORT_LONGJMP': 'wasm', 'WASM_LEGACY_EXCEPTIONS': 1}, +} deps = ['zlib'] @@ -20,7 +23,10 @@ def needed(settings): def get_lib_name(settings): if settings.SUPPORT_LONGJMP == 'wasm': - return 'libfreetype-legacysjlj.a' + if settings.WASM_LEGACY_EXCEPTIONS: + return 'libfreetype-legacysjlj.a' + else: + return 'libfreetype-wasmsjlj.a' else: return 'libfreetype.a' diff --git a/tools/ports/libpng.py b/tools/ports/libpng.py index 7dd62c1f07a91..12d1f04053da1 100644 --- a/tools/ports/libpng.py +++ b/tools/ports/libpng.py @@ -13,6 +13,8 @@ deps = ['zlib'] variants = { 'libpng-mt': {'PTHREADS': 1}, + 'libpng-wasmsjlj': {'SUPPORT_LONGJMP': 'wasm'}, + 'libpng-mt-wasmsjlj': {'PTHREADS': 1, 'SUPPORT_LONGJMP': 'wasm'}, 'libpng-legacysjlj': {'SUPPORT_LONGJMP': 'wasm', 'WASM_LEGACY_EXCEPTIONS': 1}, 'libpng-mt-legacysjlj': {'PTHREADS': 1, 'SUPPORT_LONGJMP': 'wasm', 'WASM_LEGACY_EXCEPTIONS': 1}, } @@ -27,7 +29,10 @@ def get_lib_name(settings): if settings.PTHREADS: suffix += '-mt' if settings.SUPPORT_LONGJMP == 'wasm': - suffix += '-legacysjlj' + if settings.WASM_LEGACY_EXCEPTIONS: + suffix += '-legacysjlj' + else: + suffix += '-wasmsjlj' return f'libpng{suffix}.a' diff --git a/tools/system_libs.py b/tools/system_libs.py index e1270eb7dab65..573e3d2a5ea77 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -807,7 +807,7 @@ def get_cflags(self): case Exceptions.WASM_LEGACY: cflags += ['-fwasm-exceptions', '-sWASM_LEGACY_EXCEPTIONS'] case Exceptions.WASM: - cflags += ['-fwasm-exceptions', '-sWASM_LEGACY_EXCEPTIONS=0'] + cflags += ['-fwasm-exceptions'] return cflags @@ -865,7 +865,6 @@ def get_cflags(self): '-D__WASM_SJLJ__'] case Exceptions.WASM: cflags += ['-sSUPPORT_LONGJMP=wasm', - '-sWASM_LEGACY_EXCEPTIONS=0', '-sDISABLE_EXCEPTION_THROWING', '-D__WASM_SJLJ__'] return cflags