Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ See docs/process.md for more on how version tagging works.

- JavaScript library symbols can now use the `__force` and `__export`
decorators to control inclusion and export visibility. (#27436)
- `-fwasm-exceptions` now links the Wasm EH runtime (libunwind and the
`__cpp_exception` tag) independently of C++ linking, so Wasm EH objects from
non-C++ frontends (e.g. rustc, which links via `emcc`) link without
requiring `em++` or `-sDEFAULT_TO_CXX`.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add PR number here.


6.0.6 - 08/05/26
----------------
Expand Down
23 changes: 0 additions & 23 deletions system/lib/libcxxabi/src/__cpp_exception.S

This file was deleted.

15 changes: 15 additions & 0 deletions system/lib/libunwind/src/Unwind-wasm.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,21 @@ _Unwind_RaiseException(_Unwind_Exception *exception_object) {
__builtin_wasm_throw(0, exception_object);
}

// Define the `__cpp_exception` symbol which `__builtin_wasm_throw` above will
// reference. This is defined here in `libunwind` as the single canonical
// definition for this API and it's required for users to ensure that there's
// only one copy of `libunwind` within a wasm module to ensure this is only
// defined once and exactly once.
__asm__(".globl __cpp_exception\n"
#if defined(__wasm32__)
".tagtype __cpp_exception i32\n"
#elif defined(__wasm64__)
".tagtype __cpp_exception i64\n"
#else
#error "Unsupported Wasm architecture"
#endif
"__cpp_exception:\n");

/// Called by __cxa_end_catch.
_LIBUNWIND_EXPORT void
_Unwind_DeleteException(_Unwind_Exception *exception_object) {
Expand Down
33 changes: 30 additions & 3 deletions test/test_other.py
Original file line number Diff line number Diff line change
Expand Up @@ -8833,9 +8833,10 @@ def test_exceptions_c_linker(self):
self.assert_fail([EMCC, '-sSTRICT', test_file('other/test_exceptions_c_linker.c')], 'error: undefined symbol: __cxa_find_matching_catch_1')

@parameterized({
# TODO: Add wasm_eh modes once the libunwind Wasm EH followup PR lands
'': ([],),
'exceptions': (['-fexceptions'],),
'wasm_eh': (['-fwasm-exceptions'],),
'wasm_legacy_eh': (['-fwasm-exceptions', '-sWASM_LEGACY_EXCEPTIONS'],),
Comment on lines 8837 to +8839

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use @with_all_eh_sjlj instead of this?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIUC that does not include the empty case (i.e. no exception handling)?

})
def test_libunwind(self, cflags):
src = r'''
Expand Down Expand Up @@ -14621,10 +14622,36 @@ def test_wasi_with_sjlj(self):

# When using Wasm exception, SUPPORT_LONGJMP defaults to 'wasm', which does
# not use the JS-based support. This should succeed.
# -fwasm-exceptions exports __cpp_exception, so this is necessary
self.set_setting('DEFAULT_TO_CXX')
self.do_runf('core/test_longjmp.c', cflags=['-fwasm-exceptions'])

def test_cpp_exception_tag(self):
# Wasm EH throw/catch sites reference the `__cpp_exception` tag directly,
# regardless of source language (e.g. rustc objects), so an object whose
# only undefined symbol is the tag must still pull in its libunwind definition.
create_file('throw.S', '''
.tagtype __cpp_exception i32
Comment thread
guybedford marked this conversation as resolved.
.text
.globl throw_tag
throw_tag:
.functype throw_tag (i32) -> ()
local.get 0
throw __cpp_exception
end_function
''')
create_file('main.c', r'''
#include <stdio.h>
void throw_tag(int);
int main(int argc, char* argv[]) {
if (argc > 100) {
throw_tag(argc);
}
printf("done\n");
return 0;
}
''')
# -mexception-handling is needed for the assembler to accept `throw`.
self.do_runf('main.c', 'done\n', cflags=['throw.S', '-fwasm-exceptions', '-mexception-handling'])
Comment thread
guybedford marked this conversation as resolved.

def test_memory_init_file_unsupported(self):
self.assert_fail([EMCC, test_file('hello_world.c'), '-Werror', '--memory-init-file=1'], 'error: --memory-init-file is no longer supported')

Expand Down
10 changes: 7 additions & 3 deletions tools/system_libs.py
Original file line number Diff line number Diff line change
Expand Up @@ -1686,7 +1686,6 @@ def get_files(self):
'stdlib_typeinfo.cpp',
'private_typeinfo.cpp',
'cxa_exception_js_utils.cpp',
'__cpp_exception.S',
]
match self.eh_mode:
case Exceptions.NONE:
Expand Down Expand Up @@ -2484,8 +2483,13 @@ def add_sanitizer_libs():
add_library('libc++')
if settings.LINK_AS_CXX or sanitize:
add_library('libc++abi')
if settings.WASM_EXCEPTIONS:
add_library('libunwind')
if settings.WASM_EXCEPTIONS:
# Wasm EH objects can come from any language frontend (e.g. rust), so the
# unwinding runtime and the `__cpp_exception` tag it defines are linked
# independently of C++. When WASM_EXCEPTIONS is not enabled, `_Unwind_*`
# symbols are instead provided by JS stubs in libcore.js (under
# LINK_AS_CXX).
Comment on lines +2489 to +2491

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean we need LINK_AS_CXX in case of Emscripten EH? This sounds weird. If LINK_AS_CXX should not be required for linking linbunwind in Wasm EH, shouldn't that be true also for Emscripten EH too?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this full comment is no longer needed. libunwind should always be linked into all programs one or another. I should have known that before.

How about just:

`libunwind` is implement in JS, and not nativly, when Emscripten EH is used.

add_library('libunwind')

if settings.PROXY_POSIX_SOCKETS:
add_library('libsockets_proxy')
Expand Down
Loading