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
24 changes: 0 additions & 24 deletions src/lib/libcore.js
Original file line number Diff line number Diff line change
Expand Up @@ -1733,31 +1733,7 @@ addToLibrary({
$jstoi_q__docs: '/** @suppress {checkTypes} */',
$jstoi_q: (str) => parseInt(str),

#if LINK_AS_CXX
// libunwind

_Unwind_Backtrace__deps: ['$getCallstack'],
_Unwind_Backtrace: (func, arg) => {
var trace = getCallstack();
var parts = trace.split('\n');
for (var i = 0; i < parts.length; i++) {
var ret = {{{ makeDynCall('iii', 'func') }}}(0, arg);
if (ret) return;
}
},

_Unwind_GetIPInfo: (context, ipBefore) => abort('Unwind_GetIPInfo'),

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

_Unwind_RaiseException__deps: ['__cxa_throw'],
_Unwind_RaiseException: (ex) => {
err('Warning: _Unwind_RaiseException is not correctly implemented');
return ___cxa_throw(ex, 0, 0);
},

_Unwind_DeleteException: (ex) => err('TODO: Unwind_DeleteException'),
#endif

// special runtime support

Expand Down
39 changes: 18 additions & 21 deletions src/lib/libexceptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@

var LibraryExceptions = {
#if !WASM_EXCEPTIONS
$uncaughtExceptionCount: '0',
#if !DISABLE_EXCEPTION_CATCHING
$exceptionLast: null,
#endif
Comment on lines -9 to -12

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.

In libcxxabi native code (and thus in Wasm EH), managing information like uncaught exception count and last exception is done by libcxxabi, not libunwind. It is true in libcxxabi/libunwind that __cxa_throw calls _Unwind_RaiseException, but all exception status managing is done within libcxxabi. Wouldn't it be consistent to manage it within libexceptions.js and leave libunwind simple?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Sure, we can make it consistent in that way. I'll make a followup PR.

$exceptionCaught: ' []',

// This class is the exception metadata which is prepended to each thrown object (in WASM memory).
Expand Down Expand Up @@ -84,7 +80,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', '$uncaughtExceptionCount',
__cxa_throw__deps: ['$ExceptionInfo',
#if !DISABLE_EXCEPTION_CATCHING
'$exceptionLast',
'__cxa_increment_exception_refcount',
Expand All @@ -99,6 +95,7 @@ var LibraryExceptions = {
// 'throw' is used here.
'$decrementExceptionRefcount', '$incrementExceptionRefcount',
#endif
'_Unwind_RaiseException',
],
__cxa_throw: (ptr, type, destructor) => {
#if EXCEPTION_DEBUG
Expand All @@ -109,20 +106,20 @@ var LibraryExceptions = {
info.init(type, destructor);
#if !DISABLE_EXCEPTION_CATCHING
___cxa_increment_exception_refcount(ptr);
exceptionLast = new CppException(ptr);
ptr = new CppException(ptr);
#endif
uncaughtExceptionCount++;
{{{ makeThrow() }}}
__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', '$uncaughtExceptionCount',
__cxa_rethrow__deps: ['$exceptionCaught',
#if !DISABLE_EXCEPTION_CATCHING
'$exceptionLast',
'__cxa_increment_exception_refcount',
#endif
'_Unwind_RaiseException',
],
__cxa_rethrow: () => {
if (!exceptionCaught.length) {
Expand All @@ -132,16 +129,15 @@ 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
exceptionLast = new CppException(ptr);
ptr = new CppException(ptr);
#endif
{{{ makeThrow() }}}
__Unwind_RaiseException(ptr);
},

llvm_eh_typeid_for: (type) => type,
Expand Down Expand Up @@ -212,11 +208,12 @@ var LibraryExceptions = {
return info.get_type();
},

__cxa_rethrow_primary_exception__deps: ['$ExceptionInfo', '$uncaughtExceptionCount',
__cxa_rethrow_primary_exception__deps: ['$ExceptionInfo',
#if !DISABLE_EXCEPTION_CATCHING
'$exceptionLast',
'__cxa_increment_exception_refcount',
#endif
'_Unwind_RaiseException',
],
__cxa_rethrow_primary_exception: (ptr) => {
if (!ptr) return;
Expand All @@ -226,12 +223,11 @@ 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);
exceptionLast = new CppException(ptr);
ptr = new CppException(ptr);
#endif
{{{ makeThrow('exceptionLast') }}}
__Unwind_RaiseException(ptr);
},

// Finds a suitable catch clause for when an exception is thrown.
Expand Down Expand Up @@ -293,19 +289,20 @@ var LibraryExceptions = {
#endif
},

__resumeException__deps: [
#if !DISABLE_EXCEPTION_CATCHING
__resumeException__deps: ['$exceptionLast'],
'$exceptionLast',
#endif
'_Unwind_Resume',
],
__resumeException: (ptr) => {
#if !DISABLE_EXCEPTION_CATCHING
#if EXCEPTION_DEBUG
dbg("__resumeException " + [ptrToString(ptr), exceptionLast]);
#endif
if (!exceptionLast) {
exceptionLast = new CppException(ptr);
}
ptr = exceptionLast ?? new CppException(ptr);
#endif
{{{ makeThrow() }}}
__Unwind_Resume(ptr);
},

#endif
Expand Down
1 change: 0 additions & 1 deletion src/lib/libsigs.js
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,6 @@ sigs = {
_Unwind_DeleteException__sig: 'vp',
_Unwind_FindEnclosingFunction__sig: 'pp',
_Unwind_GetIPInfo__sig: 'ppp',
_Unwind_RaiseException__sig: 'ip',
__asctime_r__sig: 'ppp',
__assert_fail__sig: 'vppip',
__call_sighandler__sig: 'vpi',
Expand Down
57 changes: 57 additions & 0 deletions src/lib/libunwind.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
* @license
* Copyright 2026 The Emscripten Authors
* SPDX-License-Identifier: MIT
*/

#if WASM_EXCEPTIONS
#error "Internal error! WASM_EXCEPTIONS should not be enabled when including libunwind.js."
#endif

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

_Unwind_Backtrace__deps: ['$getCallstack'],
_Unwind_Backtrace: (func, arg) => {
var trace = getCallstack();
var parts = trace.split('\n');
for (var i = 0; i < parts.length; i++) {
var ret = {{{ makeDynCall('iii', 'func') }}}(0, arg);
if (ret) return;
}
},

_Unwind_GetIPInfo: (context, ipBefore) => abort('Unwind_GetIPInfo'),

_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') }}}
},

_Unwind_DeleteException: (ex) => err('TODO: Unwind_DeleteException'),
};

addToLibrary(LibraryUnwind);
4 changes: 4 additions & 0 deletions src/modules.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ function calculateLibraries() {
}
}

if (!WASM_EXCEPTIONS) {
libraries.push('libunwind.js');
}

if (!MINIMAL_RUNTIME) {
libraries.push('libbrowser.js');
libraries.push('libwget.js');
Expand Down
4 changes: 2 additions & 2 deletions src/parseTools.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -664,7 +664,7 @@ export function makeReturn64(value) {
return `(setTempRet0(${pair[1]}), ${pair[0]})`;
}

function makeThrow() {
function makeThrow(exc) {
if (DISABLE_EXCEPTION_CATCHING) {
if (ASSERTIONS) {
var assertInfo =
Expand All @@ -678,7 +678,7 @@ function makeThrow() {
return 'abort()';
}
}
return 'throw exceptionLast;';
return `throw ${exc};`;
}

function charCode(char) {
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": 19208,
"a.out.js.gz": 8121,
"a.out.js": 19198,
"a.out.js.gz": 8107,
"a.out.nodebug.wasm": 134729,
"a.out.nodebug.wasm.gz": 51522,
"total": 153937,
"total_gz": 59643,
"total": 153927,
"total_gz": 59629,
"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": 19185,
"a.out.js.gz": 8104,
"a.out.js": 19175,
"a.out.js.gz": 8091,
"a.out.nodebug.wasm": 134158,
"a.out.nodebug.wasm.gz": 51187,
"total": 153343,
"total_gz": 59291,
"total": 153333,
"total_gz": 59278,
"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": 22895,
"a.out.js.gz": 9075,
"a.out.js": 22904,
"a.out.js.gz": 9078,
"a.out.nodebug.wasm": 177195,
"a.out.nodebug.wasm.gz": 59099,
"total": 200090,
"total_gz": 68174,
"total": 200099,
"total_gz": 68177,
"sent": [
"__cxa_begin_catch",
"__cxa_end_catch",
Expand Down
8 changes: 4 additions & 4 deletions test/codesize/test_codesize_cxx_mangle.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"a.out.js": 22945,
"a.out.js.gz": 9095,
"a.out.js": 22954,
"a.out.js.gz": 9099,
"a.out.nodebug.wasm": 243475,
"a.out.nodebug.wasm.gz": 81296,
"total": 266420,
"total_gz": 90391,
"total": 266429,
"total_gz": 90395,
"sent": [
"__cxa_begin_catch",
"__cxa_end_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": 19208,
"a.out.js.gz": 8121,
"a.out.js": 19198,
"a.out.js.gz": 8107,
"a.out.nodebug.wasm": 136639,
"a.out.nodebug.wasm.gz": 52140,
"total": 155847,
"total_gz": 60261,
"total": 155837,
"total_gz": 60247,
"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": 6604,
"a.out.js.gz": 3154,
"a.out.js": 6594,
"a.out.js.gz": 3145,
"a.out.nodebug.wasm": 174361,
"a.out.nodebug.wasm.gz": 64898,
"total": 180965,
"total_gz": 68052,
"total": 180955,
"total_gz": 68043,
"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": 23471,
"a.out.js.gz": 8555,
"a.out.js": 23494,
"a.out.js.gz": 8565,
"a.out.nodebug.wasm": 15115,
"a.out.nodebug.wasm.gz": 7464,
"total": 38586,
"total_gz": 16019,
"total": 38609,
"total_gz": 16029,
"sent": [
"fd_write"
],
Expand Down
10 changes: 8 additions & 2 deletions test/codesize/test_codesize_hello_dylink_all.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"a.out.js": 267525,
"a.out.js": 267896,
"a.out.nodebug.wasm": 588311,
"total": 855836,
"total": 856207,
"sent": [
"IMG_Init",
"IMG_Load",
Expand Down Expand Up @@ -212,6 +212,12 @@
"XSendEvent",
"XSetWMHints",
"XStoreName",
"_Unwind_Backtrace",
"_Unwind_DeleteException",
"_Unwind_FindEnclosingFunction",
"_Unwind_GetIPInfo",
"_Unwind_RaiseException",
"_Unwind_Resume",
"__asctime_r",
"__assert_fail",
"__call_sighandler",
Expand Down
1 change: 1 addition & 0 deletions test/codesize/test_codesize_minimal_O0.expected.js
Original file line number Diff line number Diff line change
Expand Up @@ -1030,6 +1030,7 @@ missingLibrarySymbols.forEach(missingLibrarySymbol)
'emClearImmediate_deps',
'emClearImmediate',
'promiseMap',
'uncaughtExceptionCount',
'Browser',
'requestFullscreen',
'setCanvasSize',
Expand Down
Loading
Loading