Skip to content

Commit

Permalink
[EH] Add WASM_LEGACY_EXCEPTIONS option
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
aheejin committed Jan 10, 2025
1 parent 675698d commit 2421158
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 47 deletions.
8 changes: 8 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 6 additions & 7 deletions site/source/docs/tools_reference/settings_reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down
10 changes: 6 additions & 4 deletions src/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
24 changes: 12 additions & 12 deletions test/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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')
Expand Down Expand Up @@ -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)
Expand All @@ -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):
Expand Down
16 changes: 8 additions & 8 deletions test/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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')
Expand All @@ -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
Expand Down Expand Up @@ -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()
Expand All @@ -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')
Expand Down Expand Up @@ -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)
Expand Down
30 changes: 16 additions & 14 deletions test/test_other.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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',
Expand Down Expand Up @@ -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']),
Expand Down Expand Up @@ -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))
Expand All @@ -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({
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions tools/link.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 2421158

Please sign in to comment.