Skip to content

Commit 62304e2

Browse files
authored
[EH] Use LLVM implementation for new Wasm EH (#23469)
This adds a new `WASM` mode in `ExceptionLibrary`, which uses the new standard Wasm (exnref) EH, adds a library variant for it, and make the tests use the new LLVM implementation instead of the Binaryen translator. The CI won't pass until llvm/llvm-project#123915 lands. This requires adding `-wasmexcept` and `-wasmsjlj` variants to `MINIMAL_TASKS` in `embuilder.py` because they are necessary to run coreX tests in CircleCI, because dylink coreX tests in CircleCI rellies on `./embuilder build MINIMAL_PIC --pic`, which is the sum of `MINIMAL_TASKS` and `MINIMAL_PIC_TASKS`. Because a new variant is added to `ExceptionLibrary`, this increases `SYSTEM` library size from 366M to 400M, roughly by 11%. We discussed about the possibility of not shipping the exnref libraries and let them be built on demand, but given that `SYSTEM` include all variants, I'm not sure how we are going to do that: https://github.com/emscripten-core/emscripten/blob/73ebb91029948e62b3a4cea9ccc8db2dd87162b5/embuilder.py#L174-L177
1 parent 5a327e9 commit 62304e2

File tree

12 files changed

+65
-18
lines changed

12 files changed

+65
-18
lines changed

Diff for: ChangeLog.md

+5
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ See docs/process.md for more on how version tagging works.
2020

2121
4.0.2 (in development)
2222
----------------------
23+
- The standard Wasm EH, enabled by `-sWASM_LEGACY_EXCEPTIONS=0`, now uses the
24+
LLVM backend implementation rather than the previously used Binaryen
25+
translator
26+
(https://github.com/WebAssembly/binaryen/blob/main/src/passes/TranslateEH.cpp).
27+
(#23469) No specific action from the user is required.
2328
- Added support for compiling AVX2 intrinsics, 256-bit wide intrinsic is emulated
2429
on top of 128-bit Wasm SIMD instruction set. (#23035). Pass `-msimd128 -mavx2`
2530
to enable targeting AVX2.

Diff for: embuilder.py

+5
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
MINIMAL_TASKS = [
3333
'libcompiler_rt',
3434
'libcompiler_rt-legacysjlj',
35+
'libcompiler_rt-wasmsjlj',
3536
'libcompiler_rt-ww',
3637
'libc',
3738
'libc-debug',
@@ -40,13 +41,16 @@
4041
'libc_optz-debug',
4142
'libc++abi',
4243
'libc++abi-legacyexcept',
44+
'libc++abi-wasmexcept',
4345
'libc++abi-noexcept',
4446
'libc++abi-debug',
4547
'libc++abi-debug-legacyexcept',
48+
'libc++abi-debug-wasmexcept',
4649
'libc++abi-debug-noexcept',
4750
'libc++abi-debug-ww-noexcept',
4851
'libc++',
4952
'libc++-legacyexcept',
53+
'libc++-wasmexcept',
5054
'libc++-noexcept',
5155
'libc++-ww-noexcept',
5256
'libal',
@@ -80,6 +84,7 @@
8084
'crt1_proxy_main',
8185
'crtbegin',
8286
'libunwind-legacyexcept',
87+
'libunwind-wasmexcept',
8388
'libnoexit',
8489
'sqlite3',
8590
'sqlite3-mt',

Diff for: site/source/docs/tools_reference/settings_reference.rst

+2
Original file line numberDiff line numberDiff line change
@@ -1165,6 +1165,8 @@ https://github.com/WebAssembly/exception-handling/blob/main/proposals/exception-
11651165
If false, emit instructions for the standardized exception handling proposal:
11661166
https://github.com/WebAssembly/exception-handling/blob/main/proposals/exception-handling/Exceptions.md
11671167

1168+
.. note:: Applicable during both linking and compilation
1169+
11681170
Default value: true
11691171

11701172
.. _nodejs_catch_exit:

Diff for: src/settings.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -781,7 +781,7 @@ var EXCEPTION_STACK_TRACES = false;
781781
// https://github.com/WebAssembly/exception-handling/blob/main/proposals/exception-handling/legacy/Exceptions.md
782782
// If false, emit instructions for the standardized exception handling proposal:
783783
// https://github.com/WebAssembly/exception-handling/blob/main/proposals/exception-handling/Exceptions.md
784-
// [link]
784+
// [compile+link]
785785
var WASM_LEGACY_EXCEPTIONS = true;
786786

787787
// Emscripten throws an ExitStatus exception to unwind when exit() is called.
+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
144652
1+
144531

Diff for: test/test_other.py

+3
Original file line numberDiff line numberDiff line change
@@ -3535,7 +3535,10 @@ def test_embind_tsgen_jspi(self):
35353535
'legacy': [1]
35363536
})
35373537
def test_embind_tsgen_exceptions(self, legacy):
3538+
if not legacy and shared.get_node_version(config.NODE_JS)[0] < 22:
3539+
self.skipTest('Node version needs to be 22 or greater to run tsgen with exnref')
35383540
self.set_setting('WASM_LEGACY_EXCEPTIONS', legacy)
3541+
35393542
# Check that when Wasm exceptions and assertions are enabled bindings still generate.
35403543
self.run_process([EMXX, test_file('other/embind_tsgen.cpp'),
35413544
'-lembind', '-fwasm-exceptions', '-sASSERTIONS',

Diff for: tools/building.py

+10
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,12 @@ def llvm_backend_args():
9393
elif settings.SUPPORT_LONGJMP == 'wasm':
9494
args += ['-wasm-enable-sjlj']
9595

96+
if settings.WASM_EXCEPTIONS:
97+
if settings.WASM_LEGACY_EXCEPTIONS:
98+
args += ['-wasm-use-legacy-eh']
99+
else:
100+
args += ['-wasm-use-legacy-eh=0']
101+
96102
# better (smaller, sometimes faster) codegen, see binaryen#1054
97103
# and https://bugs.llvm.org/show_bug.cgi?id=39488
98104
args += ['-disable-lsr']
@@ -277,6 +283,10 @@ def link_lld(args, target, external_symbols=None):
277283

278284
if settings.WASM_EXCEPTIONS:
279285
cmd += ['-mllvm', '-wasm-enable-eh']
286+
if settings.WASM_LEGACY_EXCEPTIONS:
287+
cmd += ['-mllvm', '-wasm-use-legacy-eh']
288+
else:
289+
cmd += ['-mllvm', '-wasm-use-legacy-eh=0']
280290
if settings.WASM_EXCEPTIONS or settings.SUPPORT_LONGJMP == 'wasm':
281291
cmd += ['-mllvm', '-exception-model=wasm']
282292

Diff for: tools/link.py

-4
Original file line numberDiff line numberDiff line change
@@ -431,10 +431,6 @@ def check_human_readable_list(items):
431431
extras = settings.BINARYEN_EXTRA_PASSES.split(',')
432432
passes += [('--' + p) if p[0] != '-' else p for p in extras if p]
433433

434-
# Run the translator to the standardized EH instructions.
435-
if not settings.WASM_LEGACY_EXCEPTIONS:
436-
passes += ['--emit-exnref']
437-
438434
# If we are going to run metadce then that means we will be running binaryen
439435
# tools after the main invocation, whose flags are determined here
440436
# (specifically we will run metadce and possibly also wasm-opt for import/

Diff for: tools/settings.py

+1
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
'INLINING_LIMIT',
8585
'DISABLE_EXCEPTION_CATCHING',
8686
'DISABLE_EXCEPTION_THROWING',
87+
'WASM_LEGACY_EXCEPTIONS',
8788
'MAIN_MODULE',
8889
'SIDE_MODULE',
8990
'RELOCATABLE',

Diff for: tools/shared.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -379,11 +379,13 @@ def node_reference_types_flags(nodejs):
379379

380380
def node_exception_flags(nodejs):
381381
node_version = get_node_version(nodejs)
382-
# Exception handling was enabled by default in node v17.
382+
# Legacy exception handling was enabled by default in node v17.
383383
if node_version and node_version < (17, 0, 0):
384384
return ['--experimental-wasm-eh']
385-
else:
386-
return []
385+
# Standard exception handling was supported behind flag in node v22.
386+
if node_version and node_version >= (22, 0, 0) and not settings.WASM_LEGACY_EXCEPTIONS:
387+
return ['--experimental-wasm-exnref']
388+
return []
387389

388390

389391
def node_pthread_flags(nodejs):

Diff for: tools/system_libs.py

+31-9
Original file line numberDiff line numberDiff line change
@@ -775,10 +775,12 @@ class Exceptions(IntEnum):
775775
- EMSCRIPTEN: Emscripten provides exception handling capability using JS
776776
emulation. This causes code size increase and performance degradation.
777777
- WASM_LEGACY: Wasm native exception handling support (legacy)
778+
- WASM: Wasm native exception handling support
778779
"""
779780
NONE = auto()
780781
EMSCRIPTEN = auto()
781782
WASM_LEGACY = auto()
783+
WASM = auto()
782784

783785

784786
class ExceptionLibrary(Library):
@@ -793,7 +795,9 @@ def get_cflags(self):
793795
elif self.eh_mode == Exceptions.EMSCRIPTEN:
794796
cflags += ['-sDISABLE_EXCEPTION_CATCHING=0']
795797
elif self.eh_mode == Exceptions.WASM_LEGACY:
796-
cflags += ['-fwasm-exceptions']
798+
cflags += ['-fwasm-exceptions', '-sWASM_LEGACY_EXCEPTIONS']
799+
elif self.eh_mode == Exceptions.WASM:
800+
cflags += ['-fwasm-exceptions', '-sWASM_LEGACY_EXCEPTIONS=0']
797801

798802
return cflags
799803

@@ -805,19 +809,25 @@ def get_base_name(self):
805809
name += '-noexcept'
806810
elif self.eh_mode == Exceptions.WASM_LEGACY:
807811
name += '-legacyexcept'
812+
elif self.eh_mode == Exceptions.WASM:
813+
name += '-wasmexcept'
808814
return name
809815

810816
@classmethod
811817
def variations(cls):
812818
combos = super().variations()
813819
return ([dict(eh_mode=Exceptions.NONE, **combo) for combo in combos] +
814820
[dict(eh_mode=Exceptions.EMSCRIPTEN, **combo) for combo in combos] +
815-
[dict(eh_mode=Exceptions.WASM_LEGACY, **combo) for combo in combos])
821+
[dict(eh_mode=Exceptions.WASM_LEGACY, **combo) for combo in combos] +
822+
[dict(eh_mode=Exceptions.WASM, **combo) for combo in combos])
816823

817824
@classmethod
818825
def get_default_variation(cls, **kwargs):
819826
if settings.WASM_EXCEPTIONS:
820-
eh_mode = Exceptions.WASM_LEGACY
827+
if settings.WASM_LEGACY_EXCEPTIONS:
828+
eh_mode = Exceptions.WASM_LEGACY
829+
else:
830+
eh_mode = Exceptions.WASM
821831
elif settings.DISABLE_EXCEPTION_CATCHING == 1:
822832
eh_mode = Exceptions.NONE
823833
else:
@@ -838,6 +848,12 @@ def get_cflags(self):
838848
'-sDISABLE_EXCEPTION_THROWING=0']
839849
elif self.eh_mode == Exceptions.WASM_LEGACY:
840850
cflags += ['-sSUPPORT_LONGJMP=wasm',
851+
'-sWASM_LEGACY_EXCEPTIONS',
852+
'-sDISABLE_EXCEPTION_THROWING',
853+
'-D__WASM_SJLJ__']
854+
elif self.eh_mode == Exceptions.WASM:
855+
cflags += ['-sSUPPORT_LONGJMP=wasm',
856+
'-sWASM_LEGACY_EXCEPTIONS=0',
841857
'-sDISABLE_EXCEPTION_THROWING',
842858
'-D__WASM_SJLJ__']
843859
return cflags
@@ -848,18 +864,24 @@ def get_base_name(self):
848864
# suffixes. Change the default to wasm exception later.
849865
if self.eh_mode == Exceptions.WASM_LEGACY:
850866
name += '-legacysjlj'
867+
elif self.eh_mode == Exceptions.WASM:
868+
name += '-wasmsjlj'
851869
return name
852870

853871
@classmethod
854872
def variations(cls):
855873
combos = super().variations()
856874
return ([dict(eh_mode=Exceptions.EMSCRIPTEN, **combo) for combo in combos] +
857-
[dict(eh_mode=Exceptions.WASM_LEGACY, **combo) for combo in combos])
875+
[dict(eh_mode=Exceptions.WASM_LEGACY, **combo) for combo in combos] +
876+
[dict(eh_mode=Exceptions.WASM, **combo) for combo in combos])
858877

859878
@classmethod
860879
def get_default_variation(cls, **kwargs):
861880
if settings.SUPPORT_LONGJMP == 'wasm':
862-
eh_mode = Exceptions.WASM_LEGACY
881+
if settings.WASM_LEGACY_EXCEPTIONS:
882+
eh_mode = Exceptions.WASM_LEGACY
883+
else:
884+
eh_mode = Exceptions.WASM
863885
else:
864886
eh_mode = Exceptions.EMSCRIPTEN
865887
return super().get_default_variation(eh_mode=eh_mode, **kwargs)
@@ -1600,7 +1622,7 @@ def get_files(self):
16001622
filenames += ['cxa_noexception.cpp']
16011623
elif self.eh_mode == Exceptions.EMSCRIPTEN:
16021624
filenames += ['cxa_exception_emscripten.cpp']
1603-
elif self.eh_mode == Exceptions.WASM_LEGACY:
1625+
elif self.eh_mode in (Exceptions.WASM_LEGACY, Exceptions.WASM):
16041626
filenames += [
16051627
'cxa_exception_storage.cpp',
16061628
'cxa_exception.cpp',
@@ -1654,7 +1676,7 @@ class libcxx(ExceptionLibrary, MTLibrary):
16541676

16551677
def get_cflags(self):
16561678
cflags = super().get_cflags()
1657-
if self.eh_mode == Exceptions.WASM_LEGACY:
1679+
if self.eh_mode in (Exceptions.WASM_LEGACY, Exceptions.WASM):
16581680
cflags.append('-D__WASM_EXCEPTIONS__')
16591681
return cflags
16601682

@@ -1677,7 +1699,7 @@ def __init__(self, **kwargs):
16771699
super().__init__(**kwargs)
16781700

16791701
def can_use(self):
1680-
return super().can_use() and self.eh_mode == Exceptions.WASM_LEGACY
1702+
return super().can_use() and self.eh_mode in (Exceptions.WASM_LEGACY, Exceptions.WASM)
16811703

16821704
def get_cflags(self):
16831705
cflags = super().get_cflags()
@@ -1688,7 +1710,7 @@ def get_cflags(self):
16881710
cflags.append('-D_LIBUNWIND_HAS_NO_EXCEPTIONS')
16891711
elif self.eh_mode == Exceptions.EMSCRIPTEN:
16901712
cflags.append('-D__EMSCRIPTEN_EXCEPTIONS__')
1691-
elif self.eh_mode == Exceptions.WASM_LEGACY:
1713+
elif self.eh_mode in (Exceptions.WASM_LEGACY, Exceptions.WASM):
16921714
cflags.append('-D__WASM_EXCEPTIONS__')
16931715
return cflags
16941716

Diff for: tools/webassembly.py

+1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ class Type(IntEnum):
7575
V128 = 0x7b # -0x5
7676
FUNCREF = 0x70 # -0x10
7777
EXTERNREF = 0x6f # -0x11
78+
EXNREF = 0x69 # -0x17
7879
VOID = 0x40 # -0x40
7980

8081

0 commit comments

Comments
 (0)