From 2421158ba7958d6a3350e53419eceb46233fa6ab Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Fri, 10 Jan 2025 13:19:53 +0000 Subject: [PATCH] [EH] Add WASM_LEGACY_EXCEPTIONS option This replaces the existing `WASM_EXNREF` option with `WASM_LEGACY_EXCEPTIONS` option, in an effort to make the new standardized exnref proposal the 'default' state and the legacy proposal needs to be separately enabled an option. But given that most users haven't switched to the new proposal and major web browsers haven't turned it on by default, this `WASM_LEGACY_EXCEPTIONS` is turned on by default for the moment. This changes the following function names in `test/common.py` as well: - `require(s)_wasm_eh` -> `require(s)_wasm_legacy_eh` - `require(s)_wasm_exnref` -> `require(s)_wasm_eh` The test names and suffixes will be changed in a follow-up. --- ChangeLog.md | 8 +++++ .../tools_reference/settings_reference.rst | 13 ++++---- src/settings.js | 10 ++++--- test/common.py | 24 +++++++-------- test/test_core.py | 16 +++++----- test/test_other.py | 30 ++++++++++--------- tools/link.py | 4 +-- 7 files changed, 58 insertions(+), 47 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 67160174211a6..6470a3bb61b86 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -20,6 +20,14 @@ See docs/process.md for more on how version tagging works. 4.0.0 (in development) ---------------------- +- `-sWASM_LEAGCY_EXCEPTIONS` option is added. If true, it will emit instructions + for the legacy Wasm exception handling proposal + (https://github.com/WebAssembly/exception-handling/blob/main/proposals/exception-handling/legacy/Exceptions.md), + and if false, the new standardized exception handling proposal + (https://github.com/WebAssembly/exception-handling/blob/main/proposals/exception-handling/Exceptions.md). + This option defaults to true, given that major web browsers do not support the + new proposal by default yet. This option replaces the existing + `-sWASM_EXNREF`, whose meaning was the opposite. - compiler-rt, libcxx, libcxxabi, and libunwind were updated to LLVM 19.1.6. (#22937, #22994, and #23294) - The default Safari version targeted by Emscripten has been raised from 14.1 diff --git a/site/source/docs/tools_reference/settings_reference.rst b/site/source/docs/tools_reference/settings_reference.rst index 38778c1213291..ec60292cd91ec 100644 --- a/site/source/docs/tools_reference/settings_reference.rst +++ b/site/source/docs/tools_reference/settings_reference.rst @@ -1155,16 +1155,15 @@ This option implies EXPORT_EXCEPTION_HANDLING_HELPERS. Default value: false -.. _wasm_exnref: +.. _wasm_legacy_exceptions: -WASM_EXNREF -=========== +WASM_LEGACY_EXCEPTIONS +====================== -Emit instructions for the new Wasm exception handling proposal with exnref, -which was adopted on Oct 2023. The implementation of the new proposal is -still in progress and this feature is currently experimental. +Emit instructions for the legacy exception handling proposal. If false, emit +instructions for the standardized exception proposal with exnref. -Default value: false +Default value: true .. _nodejs_catch_exit: diff --git a/src/settings.js b/src/settings.js index bf5c236460ca7..ad53c4b34ecd1 100644 --- a/src/settings.js +++ b/src/settings.js @@ -777,11 +777,13 @@ var EXPORT_EXCEPTION_HANDLING_HELPERS = false; // [link] var EXCEPTION_STACK_TRACES = false; -// Emit instructions for the new Wasm exception handling proposal with exnref, -// which was adopted on Oct 2023. The implementation of the new proposal is -// still in progress and this feature is currently experimental. +// If true, emit instructions for the legacy Wasm exception handling proposal: +// https://github.com/WebAssembly/exception-handling/blob/main/proposals/exception-handling/legacy/Exceptions.md +// If false, emit instructions for the standardized exception handling proposal +// with exnref: +// https://github.com/WebAssembly/exception-handling/blob/main/proposals/exception-handling/Exceptions.md // [link] -var WASM_EXNREF = false; +var WASM_LEGACY_EXCEPTIONS = true; // Emscripten throws an ExitStatus exception to unwind when exit() is called. // Without this setting enabled this can show up as a top level unhandled diff --git a/test/common.py b/test/common.py index 402105fc7ecd9..d4b55c0483860 100644 --- a/test/common.py +++ b/test/common.py @@ -277,23 +277,23 @@ def decorated(self, *args, **kwargs): return decorated -def requires_wasm_eh(func): +def requires_wasm_legacy_eh(func): assert callable(func) @wraps(func) def decorated(self, *args, **kwargs): - self.require_wasm_eh() + self.require_wasm_legacy_eh() return func(self, *args, **kwargs) return decorated -def requires_wasm_exnref(func): +def requires_wasm_eh(func): assert callable(func) @wraps(func) def decorated(self, *args, **kwargs): - self.require_wasm_exnref() + self.require_wasm_eh() return func(self, *args, **kwargs) return decorated @@ -647,10 +647,9 @@ def metafunc(self, mode, *args, **kwargs): self.emcc_args.append('-fwasm-exceptions') self.set_setting('SUPPORT_LONGJMP', 'wasm') if mode == 'wasm': - self.require_wasm_eh() + self.require_wasm_legacy_eh() if mode == 'wasm_exnref': - self.require_wasm_exnref() - self.set_setting('WASM_EXNREF') + self.require_wasm_eh() f(self, *args, **kwargs) else: self.set_setting('DISABLE_EXCEPTION_CATCHING', 0) @@ -683,10 +682,9 @@ def metafunc(self, mode, *args, **kwargs): self.skipTest('Wasm EH does not work with asan yet') self.set_setting('SUPPORT_LONGJMP', 'wasm') if mode == 'wasm': - self.require_wasm_eh() + self.require_wasm_legacy_eh() if mode == 'wasm_exnref': - self.require_wasm_exnref() - self.set_setting('WASM_EXNREF') + self.require_wasm_eh() f(self, *args, **kwargs) else: self.set_setting('SUPPORT_LONGJMP', 'emscripten') @@ -997,7 +995,8 @@ def require_simd(self): else: self.fail('either d8 or node >= 16 required to run wasm64 tests. Use EMTEST_SKIP_SIMD to skip') - def require_wasm_eh(self): + def require_wasm_legacy_eh(self): + self.set_setting('WASM_LEGACY_EXCEPTIONS') nodejs = self.get_nodejs() if nodejs: version = shared.get_node_version(nodejs) @@ -1015,7 +1014,8 @@ def require_wasm_eh(self): else: self.fail('either d8 or node >= 17 required to run wasm-eh tests. Use EMTEST_SKIP_EH to skip') - def require_wasm_exnref(self): + def require_wasm_eh(self): + self.set_setting('WASM_LEGACY_EXCEPTIONS', 0) nodejs = self.get_nodejs() if nodejs: if self.node_is_canary(nodejs): diff --git a/test/test_core.py b/test/test_core.py index f22252f32ce66..48867a3f41998 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -28,7 +28,7 @@ from common import read_file, read_binary, requires_v8, requires_node, requires_wasm2js, requires_node_canary from common import compiler_for, crossplatform, no_4gb, no_2gb, also_with_minimal_runtime from common import with_all_fs, also_with_nodefs, also_with_nodefs_both, also_with_noderawfs, also_with_wasmfs -from common import with_all_eh_sjlj, with_all_sjlj, also_with_standalone_wasm, can_do_standalone, no_wasm64, requires_wasm_exnref +from common import with_all_eh_sjlj, with_all_sjlj, also_with_standalone_wasm, can_do_standalone, no_wasm64, requires_wasm_eh from common import NON_ZERO, WEBIDL_BINDER, EMBUILDER, PYTHON import clang_native @@ -856,7 +856,7 @@ def test_longjmp_zero(self): self.skipTest('https://github.com/emscripten-core/emscripten/issues/21533') self.do_core_test('test_longjmp_zero.c') - @requires_wasm_exnref + @requires_wasm_eh def test_longjmp_with_and_without_exceptions(self): # Emscripten SjLj with and without Emscripten EH support self.set_setting('SUPPORT_LONGJMP', 'emscripten') @@ -875,8 +875,8 @@ def test_longjmp_with_and_without_exceptions(self): self.emcc_args.append('-fwasm-exceptions') for arg in ('-fwasm-exceptions', '-fno-exceptions'): self.do_core_test('test_longjmp.c', emcc_args=[arg]) - # Wasm SjLj with and with new EH (exnref) support - self.set_setting('WASM_EXNREF') + # Wasm SjLj with and with the standardized EH (exnref) support + self.set_setting('WASM_LEGACY_EXCEPTIONS', 0) self.do_core_test('test_longjmp.c', emcc_args=['-fwasm-exceptions']) @with_all_sjlj @@ -994,7 +994,7 @@ def test_exceptions(self): self.maybe_closure() self.do_run_in_out_file_test('core/test_exceptions.cpp', out_suffix='_caught') - @requires_wasm_exnref + @requires_wasm_eh def test_exceptions_with_and_without_longjmp(self): self.set_setting('EXCEPTION_DEBUG') self.maybe_closure() @@ -1014,8 +1014,8 @@ def test_exceptions_with_and_without_longjmp(self): for support_longjmp in (0, 'wasm'): self.set_setting('SUPPORT_LONGJMP', support_longjmp) self.do_run_in_out_file_test('core/test_exceptions.cpp', out_suffix='_caught') - # Wasm new EH (exnref) with and without Wasm SjLj support - self.set_setting('WASM_EXNREF') + # Wasm standardized EH (exnref) with and without Wasm SjLj support + self.set_setting('WASM_LEGACY_EXCEPTIONS', 0) for support_longjmp in (0, 'wasm'): self.set_setting('SUPPORT_LONGJMP', support_longjmp) self.do_run_in_out_file_test('core/test_exceptions.cpp', out_suffix='_caught') @@ -1519,7 +1519,7 @@ def clear_all_relevant_settings(self): self.clear_setting('DISABLE_EXCEPTION_CATCHING') self.clear_setting('SUPPORT_LONGJMP') self.clear_setting('ASYNCIFY') - self.clear_setting('WASM_EXNREF') + self.clear_setting('WASM_LEGACY_EXCEPTIONS') # Emscripten EH and Wasm EH cannot be enabled at the same time self.set_setting('DISABLE_EXCEPTION_CATCHING', 0) diff --git a/test/test_other.py b/test/test_other.py index 214ec48c6d1fa..b3fe776db3053 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -35,7 +35,7 @@ from common import env_modify, no_mac, no_windows, only_windows, requires_native_clang, with_env_modify from common import create_file, parameterized, NON_ZERO, node_pthreads, TEST_ROOT, test_file from common import compiler_for, EMBUILDER, requires_v8, requires_node, requires_wasm64, requires_node_canary -from common import requires_wasm_exnref, crossplatform, with_all_eh_sjlj, with_all_sjlj +from common import requires_wasm_eh, crossplatform, with_all_eh_sjlj, with_all_sjlj from common import also_with_standalone_wasm, also_with_wasm2js, also_with_noderawfs, also_with_wasmfs from common import also_with_minimal_runtime, also_with_wasm_bigint, also_with_wasm64, flaky from common import EMTEST_BUILD_VERBOSE, PYTHON, WEBIDL_BINDER @@ -3539,7 +3539,7 @@ def test_embind_tsgen_jspi(self): 'wasm_exnref': [1] }) def test_embind_tsgen_exceptions(self, wasm_exnref): - self.set_setting('WASM_EXNREF', wasm_exnref) + self.set_setting('WASM_LEGACY_EXCEPTIONS', wasm_exnref == 1) # Check that when Wasm exceptions and assertions are enabled bindings still generate. self.run_process([EMXX, test_file('other/embind_tsgen.cpp'), '-lembind', '-fwasm-exceptions', '-sASSERTIONS', @@ -8928,8 +8928,8 @@ def test_codesize_minimal_pthreads(self): 'mangle': (['-O2', '-fexceptions', '-sDEMANGLE_SUPPORT', '-Wno-deprecated'], [], ['waka']), # noqa # Wasm EH's code size increase is smaller than that of Emscripten EH - 'except_wasm': (['-O2', '-fwasm-exceptions'], [], ['waka']), - 'except_wasm_exnref': (['-O2', '-fwasm-exceptions', '-sWASM_EXNREF'], [], ['waka']), + 'except_wasm': (['-O2', '-fwasm-exceptions', '-sWASM_LEGACY_EXCEPTIONS'], [], ['waka']), + 'except_wasm_exnref': (['-O2', '-fwasm-exceptions', '-sWASM_LEGACY_EXCEPTIONS=0'], [], ['waka']), # eval_ctors 1 can partially optimize, but runs into getenv() for locale # code. mode 2 ignores those and fully optimizes out the ctors 'ctors1': (['-O2', '-sEVAL_CTORS'], [], ['waka']), @@ -9230,8 +9230,8 @@ def test_lto(self, args): @parameterized({ 'noexcept': [], 'except': ['-sDISABLE_EXCEPTION_CATCHING=0'], - 'except_wasm': ['-fwasm-exceptions'], - 'except_wasm_exnref': ['-fwasm-exceptions', '-sWASM_EXNREF'] + 'except_wasm': ['-fwasm-exceptions', '-sWASM_LEGACY_EXCEPTIONS'], + 'except_wasm_exnref': ['-fwasm-exceptions', '-sWASM_LEGACY_EXCEPTIONS=0'] }) def test_lto_libcxx(self, *args): self.run_process([EMXX, test_file('hello_libcxx.cpp'), '-flto'] + list(args)) @@ -9250,13 +9250,14 @@ 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_exnref + @requires_wasm_eh def test_lto_wasm_exceptions(self): self.set_setting('EXCEPTION_DEBUG') + self.set_setting('WASM_LEGACY_EXCEPTIONS') self.emcc_args += ['-fwasm-exceptions', '-flto'] self.do_run_in_out_file_test('core/test_exceptions.cpp', out_suffix='_caught') # New Wasm EH with exnref - self.set_setting('WASM_EXNREF') + self.set_setting('WASM_LEGACY_EXCEPTIONS', 0) self.do_run_in_out_file_test('core/test_exceptions.cpp', out_suffix='_caught') @parameterized({ @@ -9319,7 +9320,7 @@ def test_exceptions_stack_trace_and_message(self): # optional 'traceStack' option in WebAssembly.Exception constructor # (https://developer.mozilla.org/en-US/docs/WebAssembly/JavaScript_interface/Exception/Exception) # and embeds stack traces unconditionally. Change this back to - # self.require_wasm_eh() if this issue is fixed later. + # self.require_wasm_legacy_eh() if this issue is fixed later. self.require_v8() # Stack traces are enabled when either of ASSERTIONS or @@ -9360,7 +9361,7 @@ def test_exceptions_rethrow_stack_trace_and_message(self): # optional 'traceStack' option in WebAssembly.Exception constructor # (https://developer.mozilla.org/en-US/docs/WebAssembly/JavaScript_interface/Exception/Exception) # and embeds stack traces unconditionally. Change this back to - # self.require_wasm_eh() if this issue is fixed later. + # self.require_wasm_legacy_eh() if this issue is fixed later. self.require_v8() # Rethrowing exception currently loses the stack trace before the rethrowing # due to how rethrowing is implemented. So in the examples below we don't @@ -12759,15 +12760,16 @@ def test_standalone_export_main(self): # We should consider making this a warning since the `_main` export is redundant. self.run_process([EMCC, '-sEXPORTED_FUNCTIONS=_main', '-sSTANDALONE_WASM', test_file('core/test_hello_world.c')]) - @requires_wasm_exnref + @requires_wasm_eh def test_standalone_wasm_exceptions(self): self.set_setting('STANDALONE_WASM') self.set_setting('WASM_BIGINT') self.wasm_engines = [] self.emcc_args += ['-fwasm-exceptions'] + self.set_setting('WASM_LEGACY_EXCEPTIONS') self.do_run_in_out_file_test('core/test_exceptions.cpp', out_suffix='_caught') # New Wasm EH with exnref - self.set_setting('WASM_EXNREF') + self.set_setting('WASM_LEGACY_EXCEPTIONS', 0) self.do_run_in_out_file_test('core/test_exceptions.cpp', out_suffix='_caught') def test_missing_malloc_export(self): @@ -15308,8 +15310,8 @@ def test_SUPPORT_BIG_ENDIAN(self): 'noexcept': ['-fno-exceptions'], 'default': [], 'except': ['-sDISABLE_EXCEPTION_CATCHING=0'], - 'except_wasm': ['-fwasm-exceptions'], - 'except_wasm_exnref': ['-fwasm-exceptions', '-sWASM_EXNREF'] + 'except_wasm': ['-fwasm-exceptions', '-sWASM_LEGACY_EXCEPTIONS'], + 'except_wasm_exnref': ['-fwasm-exceptions', '-sWASM_LEGACY_EXCEPTIONS=0'] }) def test_std_promise_link(self, *args): # Regression test for a bug where std::promise's destructor caused a link diff --git a/tools/link.py b/tools/link.py index 36131ea1c4fe2..5d625eaa492ac 100644 --- a/tools/link.py +++ b/tools/link.py @@ -432,8 +432,8 @@ def check_human_readable_list(items): extras = settings.BINARYEN_EXTRA_PASSES.split(',') passes += [('--' + p) if p[0] != '-' else p for p in extras if p] - # Run the translator to the new EH instructions with exnref - if settings.WASM_EXNREF: + # Run the translator to the new standardized EH instructions with exnref + if not settings.WASM_LEGACY_EXCEPTIONS: passes += ['--emit-exnref'] # If we are going to run metadce then that means we will be running binaryen