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
4 changes: 0 additions & 4 deletions src/lib/libcore.js
Original file line number Diff line number Diff line change
Expand Up @@ -484,11 +484,7 @@ addToLibrary({
// a proxy and declare the dependency here.
_emscripten_throw_longjmp__deps: ['setThrew'],
_emscripten_throw_longjmp: () => {
#if EXCEPTION_STACK_TRACES
throw new EmscriptenSjLj;
#else
throw Infinity;
#endif
},
#elif !SUPPORT_LONGJMP
#if !INCLUDE_FULL_LIBRARY
Expand Down
7 changes: 0 additions & 7 deletions src/lib/libdylink.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,16 +93,9 @@ var LibraryDylink = {
} catch(e) {
stackRestore(sp);
// Create a try-catch guard that rethrows the Emscripten EH exception.
#if EXCEPTION_STACK_TRACES
// Exceptions thrown from C++ and longjmps will be an instance of
// EmscriptenEH.
if (!(e instanceof EmscriptenEH)) throw e;
#else
// Exceptions thrown from C++ will be a pointer (number) and longjmp
// will throw the number Infinity. Use the compact and fast "e !== e+0"
// test to check if e was not a Number.
if (e !== e+0) throw e;
#endif
_setThrew(1, 0);
#if WASM_BIGINT
// In theory this if statement could be done on
Expand Down
23 changes: 3 additions & 20 deletions src/lib/libemval.js
Original file line number Diff line number Diff line change
Expand Up @@ -393,35 +393,18 @@ ${functionBody}
},

_emval_throw__deps: ['$Emval',
#if !WASM_EXCEPTIONS
#if !WASM_EXCEPTIONS && !DISABLE_EXCEPTION_CATCHING
'$exceptionLast',
#endif
],
_emval_throw: (object) => {
object = Emval.toValue(object);
#if !WASM_EXCEPTIONS
#if !WASM_EXCEPTIONS && !DISABLE_EXCEPTION_CATCHING
Copy link
Member

Choose a reason for hiding this comment

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

Should the latter be !DISABLE_EXCEPTION_THROWING? We allow throwing exceptions even when DISABLE_EXCEPTION_CATCHING is true. We should be throwing CppException and not a number in that case too, no?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

No, I believe that then catching is disabled we just abort instead of throwing so there should be nothing to actually throw.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

WDYT @aheejin , OK to land this? Tests seems happy.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, forgot that we call abort in that case. LGTM

// If we are throwing Emcripten C++ exception, set exceptionLast, as we do
// in __cxa_throw. When EXCEPTION_STACK_TRACES is set, a C++ exception will
// be an instance of EmscriptenEH, and when EXCEPTION_STACK_TRACES is not
// set, it will be a pointer (number).
//
// This is different from __cxa_throw() in libexception.js because
// __cxa_throw() is called from the user C++ code when the 'throw' keyword
// is used, and the value thrown is a C++ pointer. When
// EXCEPTION_STACK_TRACES is true, we wrap it with CppException. But this
// _emval_throw is called when we throw whatever is contained in 'object',
// which can be anything including a CppException object, or a number, or
// other JS object. So we don't use storeException() wrapper here and we
// throw it as is.
#if EXCEPTION_STACK_TRACES
// in __cxa_throw. C++ exception will be an instance of CppEmscripten.
if (object instanceof CppException) {
exceptionLast = object;
}
#else
if (object === object+0) { // Check if it is a number
exceptionLast = object;
}
#endif
#endif
throw object;
},
Expand Down
58 changes: 37 additions & 21 deletions src/lib/libexceptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
var LibraryExceptions = {
#if !WASM_EXCEPTIONS
$uncaughtExceptionCount: '0',
$exceptionLast: '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 @@ -82,14 +84,15 @@ 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', '$exceptionLast', '$uncaughtExceptionCount',
__cxa_throw__deps: ['$ExceptionInfo', '$uncaughtExceptionCount',
#if !DISABLE_EXCEPTION_CATCHING
'$exceptionLast',
'__cxa_increment_exception_refcount',
#endif
#if EXCEPTION_STACK_TRACES
// When EXCEPTION_STACK_TRACES is enabled, storeException contains a call to
// 'new CppException', whose constructor calls getExceptionMessage. We can't
// track the dependency there, so we track it here.
// When EXCEPTION_STACK_TRACES is enabled, the 'CppException' constructor
// calls getExceptionMessage. We can't track the dependency there, so we
// track it here.
'$getExceptionMessage',
// These functions can be necessary to prevent memory leaks from the JS
// side. Even though they are not used it here directly, we export them when
Expand All @@ -106,17 +109,18 @@ var LibraryExceptions = {
info.init(type, destructor);
#if !DISABLE_EXCEPTION_CATCHING
___cxa_increment_exception_refcount(ptr);
exceptionLast = new CppException(ptr);
#endif
{{{ storeException('exceptionLast', 'ptr') }}}
uncaughtExceptionCount++;
{{{ makeThrow('exceptionLast') }}}
{{{ makeThrow() }}}
},

// 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', '$exceptionLast', '$uncaughtExceptionCount',
__cxa_rethrow__deps: ['$exceptionCaught', '$uncaughtExceptionCount',
#if !DISABLE_EXCEPTION_CATCHING
'$exceptionLast',
'__cxa_increment_exception_refcount',
#endif
],
Expand All @@ -135,13 +139,13 @@ var LibraryExceptions = {
}
#if !DISABLE_EXCEPTION_CATCHING
___cxa_increment_exception_refcount(ptr);
#endif
#if EXCEPTION_DEBUG
dbg('__cxa_rethrow, popped ' +
[ptrToString(ptr), exceptionLast, 'stack', exceptionCaught]);
#endif
{{{ storeException('exceptionLast', 'ptr') }}}
{{{ makeThrow('exceptionLast') }}}
exceptionLast = new CppException(ptr);
#endif
{{{ makeThrow() }}}
},

llvm_eh_typeid_for: (type) => type,
Expand All @@ -166,7 +170,11 @@ var LibraryExceptions = {
// and free the exception. Note that if the dynCall on the destructor fails
// due to calling apply on undefined, that means that the destructor is
// an invalid index into the FUNCTION_TABLE, so something has gone wrong.
__cxa_end_catch__deps: ['$exceptionCaught', '$exceptionLast', '__cxa_decrement_exception_refcount', 'setThrew'],
__cxa_end_catch__deps: ['$exceptionCaught', '__cxa_decrement_exception_refcount', 'setThrew',
#if !DISABLE_EXCEPTION_CATCHING
'$exceptionLast',
#endif
],
__cxa_end_catch: () => {
// Clear state flag.
_setThrew(0, 0);
Expand All @@ -177,10 +185,12 @@ var LibraryExceptions = {
var info = exceptionCaught.pop();

#if EXCEPTION_DEBUG
dbg('__cxa_end_catch popped ' + [info, exceptionLast, 'stack', exceptionCaught]);
dbg('__cxa_end_catch popped ' + [info, 'stack', exceptionCaught]);
#endif
___cxa_decrement_exception_refcount(info.excPtr);
exceptionLast = 0; // XXX in decRef?
#if !DISABLE_EXCEPTION_CATCHING
exceptionLast = null; // XXX in decRef?
#endif
},

__cxa_uncaught_exceptions__deps: ['$uncaughtExceptionCount'],
Expand Down Expand Up @@ -224,14 +234,15 @@ var LibraryExceptions = {
// unwinding using 'if' blocks around each function, so the remaining
// functionality boils down to picking a suitable 'catch' block.
// We'll do that here, instead, to keep things simpler.
#if !DISABLE_EXCEPTION_CATCHING
$findMatchingCatch__deps: ['$exceptionLast', '$ExceptionInfo', '__cxa_can_catch', '$setTempRet0'],
#endif
$findMatchingCatch: (args) => {
var thrown =
#if EXCEPTION_STACK_TRACES
exceptionLast?.excPtr;
#if DISABLE_EXCEPTION_CATCHING
setTempRet0(0);
return 0;
#else
exceptionLast;
#endif
var thrown = exceptionLast?.excPtr;
if (!thrown) {
// just pass through the null ptr
setTempRet0(0);
Expand Down Expand Up @@ -270,17 +281,22 @@ var LibraryExceptions = {
}
setTempRet0(thrownType);
return thrown;
#endif
},

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

#endif
Expand Down
28 changes: 13 additions & 15 deletions src/parseTools.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -648,22 +648,21 @@ export function makeReturn64(value) {
return `(setTempRet0(${pair[1]}), ${pair[0]})`;
}

function makeThrow(excPtr) {
if (ASSERTIONS && DISABLE_EXCEPTION_CATCHING) {
var assertInfo =
'Exception thrown, but exception catching is not enabled. Compile with -sNO_DISABLE_EXCEPTION_CATCHING or -sEXCEPTION_CATCHING_ALLOWED=[..] to catch.';
if (MAIN_MODULE) {
assertInfo +=
' (note: in dynamic linking, if a side module wants exceptions, the main module must be built with that support)';
function makeThrow() {
if (DISABLE_EXCEPTION_CATCHING) {
if (ASSERTIONS) {
var assertInfo =
'Exception thrown, but exception catching is not enabled. Compile with -sNO_DISABLE_EXCEPTION_CATCHING or -sEXCEPTION_CATCHING_ALLOWED=[..] to catch.';
if (MAIN_MODULE) {
assertInfo +=
' (note: in dynamic linking, if a side module wants exceptions, the main module must be built with that support)';
}
return `assert(false, '${assertInfo}');`;
} else {
return 'abort()';
}
return `assert(false, '${assertInfo}');`;
}
return `throw ${excPtr};`;
}

function storeException(varName, excPtr) {
var exceptionToStore = EXCEPTION_STACK_TRACES ? `new CppException(${excPtr})` : `${excPtr}`;
return `${varName} = ${exceptionToStore};`;
return 'throw exceptionLast;';
}

function charCode(char) {
Expand Down Expand Up @@ -1255,7 +1254,6 @@ addToCompileTimeContext({
runtimeKeepalivePop,
runtimeKeepalivePush,
splitI64,
storeException,
to64,
toIndexType,
nodePthreadDetection,
Expand Down
6 changes: 1 addition & 5 deletions src/preamble.js
Original file line number Diff line number Diff line change
Expand Up @@ -360,11 +360,7 @@ function makeAbortWrapper(original) {
ABORT // rethrow exception if abort() was called in the original function call above
|| abortWrapperDepth > 1 // rethrow exceptions not caught at the top level if exception catching is enabled; rethrow from exceptions from within callMain
#if SUPPORT_LONGJMP == 'emscripten' // Rethrow longjmp if enabled
#if EXCEPTION_STACK_TRACES
|| e instanceof EmscriptenSjLj // EXCEPTION_STACK_TRACES=1 will throw an instance of EmscriptenSjLj
#else
|| e === Infinity // EXCEPTION_STACK_TRACES=0 will throw Infinity
#endif // EXCEPTION_STACK_TRACES
|| e instanceof EmscriptenSjLj
#endif
|| e === 'unwind'
) {
Expand Down
18 changes: 15 additions & 3 deletions src/runtime_exceptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,35 @@
* SPDX-License-Identifier: MIT
*/

#if EXCEPTION_STACK_TRACES && !WASM_EXCEPTIONS
#if !WASM_EXCEPTIONS

// Base Emscripten EH error class
#if EXCEPTION_STACK_TRACES
class EmscriptenEH extends Error {}
#else
class EmscriptenEH {}
#endif

#if SUPPORT_LONGJMP == 'emscripten'
class EmscriptenSjLj extends EmscriptenEH {}
#endif

#if !DISABLE_EXCEPTION_CATCHING
class CppException extends EmscriptenEH {
constructor(excPtr) {
#if EXCEPTION_STACK_TRACES
super(excPtr);
#else
super();
#endif
this.excPtr = excPtr;
#if !DISABLE_EXCEPTION_CATCHING
#if !DISABLE_EXCEPTION_CATCHING && EXCEPTION_STACK_TRACES
const excInfo = getExceptionMessage(excPtr);
this.name = excInfo[0];
this.message = excInfo[1];
#endif
}
}
#endif // EXCEPTION_STACK_TRACES && !WASM_EXCEPTIONS
#endif

#endif // !WASM_EXCEPTIONS
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": 19214,
"a.out.js.gz": 7981,
"a.out.js": 19193,
"a.out.js.gz": 7970,
"a.out.nodebug.wasm": 132638,
"a.out.nodebug.wasm.gz": 49927,
"total": 151852,
"total_gz": 57908,
"total": 151831,
"total_gz": 57897,
"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": 19191,
"a.out.js.gz": 7966,
"a.out.js": 19170,
"a.out.js.gz": 7957,
"a.out.nodebug.wasm": 132064,
"a.out.nodebug.wasm.gz": 49586,
"total": 151255,
"total_gz": 57552,
"total": 151234,
"total_gz": 57543,
"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": 22875,
"a.out.js.gz": 8956,
"a.out.js": 23195,
"a.out.js.gz": 8968,
"a.out.nodebug.wasm": 172516,
"a.out.nodebug.wasm.gz": 57438,
"total": 195391,
"total_gz": 66394,
"total": 195711,
"total_gz": 66406,
"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": 22925,
"a.out.js.gz": 8978,
"a.out.js": 23245,
"a.out.js.gz": 8990,
"a.out.nodebug.wasm": 238957,
"a.out.nodebug.wasm.gz": 79847,
"total": 261882,
"total_gz": 88825,
"total": 262202,
"total_gz": 88837,
"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": 19214,
"a.out.js.gz": 7981,
"a.out.js": 19193,
"a.out.js.gz": 7970,
"a.out.nodebug.wasm": 134661,
"a.out.nodebug.wasm.gz": 50777,
"total": 153875,
"total_gz": 58758,
"total": 153854,
"total_gz": 58747,
"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": 7053,
"a.out.js.gz": 3325,
"a.out.js": 7033,
"a.out.js.gz": 3310,
"a.out.nodebug.wasm": 172736,
"a.out.nodebug.wasm.gz": 63329,
"total": 179789,
"total_gz": 66654,
"total": 179769,
"total_gz": 66639,
"sent": [
"__cxa_throw",
"_abort_js",
Expand Down
Loading
Loading