Skip to content
Merged
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
21 changes: 14 additions & 7 deletions src/lib/libexceptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@

var LibraryExceptions = {
#if !WASM_EXCEPTIONS
$uncaughtExceptionCount: 0,
#if !DISABLE_EXCEPTION_CATCHING
$exceptionLast: null,
#endif
$exceptionCaught: ' []',

// This class is the exception metadata which is prepended to each thrown object (in WASM memory).
Expand Down Expand Up @@ -80,7 +84,7 @@ var LibraryExceptions = {

// Here, we throw an exception after recording a couple of values that we need to remember
// We also remember that it was the last exception thrown as we need to know that later.
__cxa_throw__deps: ['$ExceptionInfo',
__cxa_throw__deps: ['$ExceptionInfo', '$uncaughtExceptionCount',
#if !DISABLE_EXCEPTION_CATCHING
'$exceptionLast',
'__cxa_increment_exception_refcount',
Expand All @@ -106,15 +110,16 @@ var LibraryExceptions = {
info.init(type, destructor);
#if !DISABLE_EXCEPTION_CATCHING
___cxa_increment_exception_refcount(ptr);
ptr = new CppException(ptr);

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 wonder if the new CppException stuff should go in libunwind ? Doesn't have to part of this PR, but really CppException here should probably be called something like NativeException right?

Maybe CppException is fine since we already have __cpp_exception tag (which is used for all LLVM languages not just c++)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

CppException is in the area of libcxxabi, which manages C++ exceptions, no? libunwind is basically language-agnostic; it just provides the low-level functions to throw something and unwind stack.

The reason Rust team proposed to move __cpp_exception to libunwind was for some other reasons (llvm/llvm-project#185770). Also they seem to be using __cpp_exceptions tag for Rust exceptions too (rust-lang/rust#160067 (comment)), presumably because it was easier for them to use it than adding another tag.

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.

Thats what I'm saying. I think that CppException is just and object we use the wrap native exceptions, as in any exception that comes out of wasm/llvm. So both rust and C++ share libunwind they probably both want the JS wrapper object around the native exception (to get backtraces).

I think CppException and __cpp_exception are both just slightly unfortunately named. They probably should have been called __libunwind_exception and LibunwindException maybe? Or something else that is not C++ specific I guess?

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.

The purpose of CppException if really most like JSWrapperForNativeException I think??

@aheejin aheejin Aug 13, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I think they were intended to represent C++ exceptions. __cpp_exception is a tag, and EH instructions use it to check whether the current exception is a C++ exception or a foreign one. And CppException is a container to manage EH stack traces (which libunwind is not really supposed to know about) and also it is to distinguish the exception from EmscriptenSjLj: https://github.com/emscripten-core/emscripten/blob/main/src/runtime_exceptions.js

ptr = exceptionLast = new CppException(ptr);
#endif
uncaughtExceptionCount++;
__Unwind_RaiseException(ptr);
},

// This exception will be caught twice, but while begin_catch runs twice,
// we early-exit from end_catch when the exception has been rethrown, so
// pop that here from the caught exceptions.
__cxa_rethrow__deps: ['$exceptionCaught',
__cxa_rethrow__deps: ['$exceptionCaught', '$uncaughtExceptionCount',
#if !DISABLE_EXCEPTION_CATCHING
'$exceptionLast',
'__cxa_increment_exception_refcount',
Expand All @@ -129,13 +134,14 @@ var LibraryExceptions = {
var ptr = info.excPtr;
info.set_rethrown(true);
info.set_caught(false);
uncaughtExceptionCount++;
#if !DISABLE_EXCEPTION_CATCHING
___cxa_increment_exception_refcount(ptr);
#if EXCEPTION_DEBUG
dbg('__cxa_rethrow: ' +
[ptrToString(ptr), exceptionLast, 'stack', exceptionCaught]);
#endif
ptr = new CppException(ptr);
ptr = exceptionLast = new CppException(ptr);
#endif
__Unwind_RaiseException(ptr);
},
Expand Down Expand Up @@ -208,7 +214,7 @@ var LibraryExceptions = {
return info.get_type();
},

__cxa_rethrow_primary_exception__deps: ['$ExceptionInfo',
__cxa_rethrow_primary_exception__deps: ['$ExceptionInfo', '$uncaughtExceptionCount',
#if !DISABLE_EXCEPTION_CATCHING
'$exceptionLast',
'__cxa_increment_exception_refcount',
Expand All @@ -223,9 +229,10 @@ var LibraryExceptions = {
var info = new ExceptionInfo(ptr);
info.set_rethrown(true);
info.set_caught(false);
uncaughtExceptionCount++;
#if !DISABLE_EXCEPTION_CATCHING
___cxa_increment_exception_refcount(ptr);
ptr = new CppException(ptr);
ptr = exceptionLast = new CppException(ptr);
#endif
__Unwind_RaiseException(ptr);
},
Expand Down Expand Up @@ -300,7 +307,7 @@ var LibraryExceptions = {
#if EXCEPTION_DEBUG
dbg("__resumeException " + [ptrToString(ptr), exceptionLast]);
#endif
ptr = exceptionLast ?? new CppException(ptr);
ptr = exceptionLast ??= new CppException(ptr);
#endif
__Unwind_Resume(ptr);
},
Expand Down
19 changes: 0 additions & 19 deletions src/lib/libunwind.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@
#endif

var LibraryUnwind = {
$uncaughtExceptionCount: '0',
#if !DISABLE_EXCEPTION_CATCHING
$exceptionLast: null,
#endif

_Unwind_Backtrace__deps: ['$getCallstack'],
_Unwind_Backtrace: (func, arg) => {
Expand All @@ -28,26 +24,11 @@ var LibraryUnwind = {

_Unwind_FindEnclosingFunction: (ip) => 0, // we cannot succeed

_Unwind_RaiseException__deps: ['$uncaughtExceptionCount',
#if !DISABLE_EXCEPTION_CATCHING
'$exceptionLast',
#endif
],
_Unwind_RaiseException: (ex) => {
#if !DISABLE_EXCEPTION_CATCHING
exceptionLast = ex;
uncaughtExceptionCount++;
#endif
{{{ makeThrow('ex') }}}
},

#if !DISABLE_EXCEPTION_CATCHING
_Unwind_Resume__deps: ['$exceptionLast'],
#endif
_Unwind_Resume: (ex) => {
#if !DISABLE_EXCEPTION_CATCHING
exceptionLast = ex;
#endif
{{{ makeThrow('ex') }}}
},

Expand Down
8 changes: 4 additions & 4 deletions test/codesize/test_codesize_cxx_ctors1.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"a.out.js": 19198,
"a.out.js.gz": 8107,
"a.out.js": 19208,
"a.out.js.gz": 8121,
"a.out.nodebug.wasm": 134739,
"a.out.nodebug.wasm.gz": 51534,
"total": 153937,
"total_gz": 59641,
"total": 153947,
"total_gz": 59655,
"sent": [
"__cxa_throw",
"_abort_js",
Expand Down
8 changes: 4 additions & 4 deletions test/codesize/test_codesize_cxx_ctors2.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"a.out.js": 19175,
"a.out.js.gz": 8091,
"a.out.js": 19185,
"a.out.js.gz": 8104,
"a.out.nodebug.wasm": 134168,
"a.out.nodebug.wasm.gz": 51198,
"total": 153343,
"total_gz": 59289,
"total": 153353,
"total_gz": 59302,
"sent": [
"__cxa_throw",
"_abort_js",
Expand Down
8 changes: 4 additions & 4 deletions test/codesize/test_codesize_cxx_except.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"a.out.js": 22904,
"a.out.js.gz": 9078,
"a.out.js": 22901,
"a.out.js.gz": 9079,
"a.out.nodebug.wasm": 177205,
"a.out.nodebug.wasm.gz": 59111,
"total": 200109,
"total_gz": 68189,
"total": 200106,
"total_gz": 68190,
"sent": [
"__cxa_begin_catch",
"__cxa_end_catch",
Expand Down
4 changes: 2 additions & 2 deletions test/codesize/test_codesize_cxx_mangle.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"a.out.js": 22954,
"a.out.js": 22951,
"a.out.js.gz": 9099,
"a.out.nodebug.wasm": 243485,
"a.out.nodebug.wasm.gz": 81306,
"total": 266439,
"total": 266436,
"total_gz": 90405,
"sent": [
"__cxa_begin_catch",
Expand Down
8 changes: 4 additions & 4 deletions test/codesize/test_codesize_cxx_noexcept.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"a.out.js": 19198,
"a.out.js.gz": 8107,
"a.out.js": 19208,
"a.out.js.gz": 8121,
"a.out.nodebug.wasm": 136649,
"a.out.nodebug.wasm.gz": 52153,
"total": 155847,
"total_gz": 60260,
"total": 155857,
"total_gz": 60274,
"sent": [
"__cxa_throw",
"_abort_js",
Expand Down
8 changes: 4 additions & 4 deletions test/codesize/test_codesize_cxx_wasmfs.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"a.out.js": 6594,
"a.out.js.gz": 3145,
"a.out.js": 6604,
"a.out.js.gz": 3154,
"a.out.nodebug.wasm": 174371,
"a.out.nodebug.wasm.gz": 64908,
"total": 180965,
"total_gz": 68053,
"total": 180975,
"total_gz": 68062,
"sent": [
"__cxa_throw",
"_abort_js",
Expand Down
8 changes: 4 additions & 4 deletions test/codesize/test_codesize_hello_O0.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"a.out.js": 23494,
"a.out.js.gz": 8565,
"a.out.js": 23471,
"a.out.js.gz": 8555,
"a.out.nodebug.wasm": 15115,
"a.out.nodebug.wasm.gz": 7464,
"total": 38609,
"total_gz": 16029,
"total": 38586,
"total_gz": 16019,
"sent": [
"fd_write"
],
Expand Down
1 change: 0 additions & 1 deletion test/codesize/test_codesize_minimal_O0.expected.js
Original file line number Diff line number Diff line change
Expand Up @@ -1030,7 +1030,6 @@ missingLibrarySymbols.forEach(missingLibrarySymbol)
'emClearImmediate_deps',
'emClearImmediate',
'promiseMap',
'uncaughtExceptionCount',
'Browser',
'requestFullscreen',
'setCanvasSize',
Expand Down
8 changes: 4 additions & 4 deletions test/codesize/test_codesize_minimal_O0.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"a.out.js": 18703,
"a.out.js.gz": 6742,
"a.out.js": 18680,
"a.out.js.gz": 6732,
"a.out.nodebug.wasm": 1015,
"a.out.nodebug.wasm.gz": 602,
"total": 19718,
"total_gz": 7344,
"total": 19695,
"total_gz": 7334,
"sent": [],
"imports": [],
"exports": [
Expand Down
12 changes: 6 additions & 6 deletions test/codesize/test_unoptimized_code_size.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
{
"hello_world.js": 54578,
"hello_world.js.gz": 17345,
"hello_world.js": 54550,
"hello_world.js.gz": 17328,
"hello_world.wasm": 15115,
"hello_world.wasm.gz": 7464,
"no_asserts.js": 23629,
"no_asserts.js.gz": 8288,
"no_asserts.wasm": 12229,
"no_asserts.wasm.gz": 6004,
"strict.js": 51729,
"strict.js.gz": 16348,
"strict.js": 51701,
"strict.js.gz": 16338,
"strict.wasm": 15115,
"strict.wasm.gz": 7461,
"total": 172395,
"total_gz": 62910
"total": 172339,
"total_gz": 62883
}
Loading