Skip to content

Move parts of emscripten exception handling to native code. NFC #16627

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Apr 11, 2023
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
7 changes: 7 additions & 0 deletions emcc.py
Original file line number Diff line number Diff line change
Expand Up @@ -2785,6 +2785,13 @@ def check_memory_setting(setting):
'__cxa_is_pointer_type',
'__cxa_can_catch',

# __cxa_begin_catch depends on this but we can't use deps info in this
# case because that only works for user-level code, and __cxa_begin_catch
# can be used by the standard library.
'__cxa_increment_exception_refcount',
# Same for __cxa_end_catch
Copy link
Collaborator

Choose a reason for hiding this comment

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

Also had to add __cxa_decrement_exception_refcount here to make some tests pass; I'm not sure why it wasn't necessary for the original PR but became now - maybe I'm missing a better place where it should be added, or maybe something changed in tests.

'__cxa_decrement_exception_refcount',

# Emscripten exception handling can generate invoke calls, and they call
# setThrew(). We cannot handle this using deps_info as the invokes are not
# emitted because of library function usage, but by codegen itself.
Expand Down
98 changes: 11 additions & 87 deletions src/library_exceptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,9 @@ var LibraryExceptions = {
//
// excPtr - Thrown object pointer to wrap. Metadata pointer is calculated from it.
$ExceptionInfo__docs: '/** @constructor */',
$ExceptionInfo__deps: ['__cxa_is_pointer_type',
#if EXCEPTION_DEBUG
'$ptrToString',
$ExceptionInfo__deps: ['$ptrToString'],
#endif
],
$ExceptionInfo: function(excPtr) {
this.excPtr = excPtr;
this.ptr = excPtr - {{{ C_STRUCTS.__cxa_exception.__size__ }}};
Expand All @@ -48,10 +46,6 @@ var LibraryExceptions = {
return {{{ makeGetValue('this.ptr', C_STRUCTS.__cxa_exception.exceptionDestructor, '*') }}};
};

this.set_refcount = function(refcount) {
{{{ makeSetValue('this.ptr', C_STRUCTS.__cxa_exception.referenceCount, 'refcount', 'i32') }}};
};

this.set_caught = function (caught) {
caught = caught ? 1 : 0;
{{{ makeSetValue('this.ptr', C_STRUCTS.__cxa_exception.caught, 'caught', 'i8') }}};
Expand All @@ -78,34 +72,8 @@ var LibraryExceptions = {
this.set_adjusted_ptr(0);
this.set_type(type);
this.set_destructor(destructor);
this.set_refcount(0);
this.set_caught(false);
this.set_rethrown(false);
}

this.add_ref = function() {
#if SHARED_MEMORY
Atomics.add(HEAP32, (this.ptr + {{{ C_STRUCTS.__cxa_exception.referenceCount }}}) >> 2, 1);
#else
var value = {{{ makeGetValue('this.ptr', C_STRUCTS.__cxa_exception.referenceCount, 'i32') }}};
{{{ makeSetValue('this.ptr', C_STRUCTS.__cxa_exception.referenceCount, 'value + 1', 'i32') }}};
#endif
};

// Returns true if last reference released.
this.release_ref = function() {
#if SHARED_MEMORY
var prev = Atomics.sub(HEAP32, (this.ptr + {{{ C_STRUCTS.__cxa_exception.referenceCount }}}) >> 2, 1);
#else
var prev = {{{ makeGetValue('this.ptr', C_STRUCTS.__cxa_exception.referenceCount, 'i32') }}};
{{{ makeSetValue('this.ptr', C_STRUCTS.__cxa_exception.referenceCount, 'prev - 1', 'i32') }}};
#endif
#if ASSERTIONS
assert(prev > 0);
#endif
return prev === 1;
};

this.set_adjusted_ptr = function(adjustedPtr) {
{{{ makeSetValue('this.ptr', C_STRUCTS.__cxa_exception.adjustedPtr, 'adjustedPtr', '*') }}};
};
Expand All @@ -131,52 +99,6 @@ var LibraryExceptions = {
};
},

$exception_addRef: function (info) {
#if EXCEPTION_DEBUG
dbg('exception_addRef ' + ptrToString(info.excPtr));
#endif
info.add_ref();
},

$exception_decRef__deps: ['__cxa_free_exception'
#if EXCEPTION_DEBUG
, '$exceptionLast', '$exceptionCaught'
#endif
],
$exception_decRef: function(info) {
#if EXCEPTION_DEBUG
dbg('exception_decRef ' + ptrToString(info.excPtr));
#endif
// A rethrown exception can reach refcount 0; it must not be discarded
// Its next handler will clear the rethrown flag and addRef it, prior to
// final decRef and destruction here
if (info.release_ref() && !info.get_rethrown()) {
var destructor = info.get_destructor();
if (destructor) {
// In Wasm, destructors return 'this' as in ARM
{{{ makeDynCall('pp', 'destructor') }}}(info.excPtr);
}
___cxa_free_exception(info.excPtr);
#if EXCEPTION_DEBUG
dbg('decref freeing exception ' + [ptrToString(info.excPtr), exceptionLast, 'stack', exceptionCaught]);
#endif
}
},

__cxa_increment_exception_refcount__deps: ['$exception_addRef', '$ExceptionInfo'],
__cxa_increment_exception_refcount__sig: 'vp',
__cxa_increment_exception_refcount: function(ptr) {
if (!ptr) return;
exception_addRef(new ExceptionInfo(ptr));
},

__cxa_decrement_exception_refcount__deps: ['$exception_decRef', '$ExceptionInfo'],
__cxa_decrement_exception_refcount__sig: 'vp',
__cxa_decrement_exception_refcount: function(ptr) {
if (!ptr) return;
exception_decRef(new ExceptionInfo(ptr));
},

// 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__sig: 'vppp',
Expand Down Expand Up @@ -224,7 +146,8 @@ var LibraryExceptions = {
return type;
},

__cxa_begin_catch__deps: ['$exceptionCaught', '$exception_addRef', '$uncaughtExceptionCount'],
__cxa_begin_catch__deps: ['$exceptionCaught', '__cxa_increment_exception_refcount',
'$uncaughtExceptionCount'],
__cxa_begin_catch__sig: 'pp',
__cxa_begin_catch: function(ptr) {
var info = new ExceptionInfo(ptr);
Expand All @@ -237,15 +160,15 @@ var LibraryExceptions = {
#if EXCEPTION_DEBUG
dbg('__cxa_begin_catch ' + [ptrToString(ptr), 'stack', exceptionCaught]);
#endif
exception_addRef(info);
___cxa_increment_exception_refcount(info.excPtr);
return info.get_exception_ptr();
},

// We're done with a catch. Now, we can run the destructor if there is one
// 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', '$exception_decRef'],
__cxa_end_catch__deps: ['$exceptionCaught', '$exceptionLast', '__cxa_decrement_exception_refcount', 'setThrew'],
__cxa_end_catch__sig: 'v',
__cxa_end_catch: function() {
// Clear state flag.
Expand All @@ -259,17 +182,18 @@ var LibraryExceptions = {
#if EXCEPTION_DEBUG
dbg('__cxa_end_catch popped ' + [info, exceptionLast, 'stack', exceptionCaught]);
#endif
exception_decRef(info);
___cxa_decrement_exception_refcount(info.excPtr);
exceptionLast = 0; // XXX in decRef?
},

__cxa_get_exception_ptr__deps: ['$ExceptionInfo'],
__cxa_get_exception_ptr__sig: 'pp',
__cxa_get_exception_ptr: function(ptr) {
var rtn = new ExceptionInfo(ptr).get_exception_ptr();
#if EXCEPTION_DEBUG
dbg('__cxa_get_exception_ptr ' + ptrToString(ptr));
err('__cxa_get_exception_ptr ' + ptrToString(ptr) + ' -> ' + ptrToString(rtn));
#endif
return new ExceptionInfo(ptr).get_exception_ptr();
return rtn;
},

__cxa_uncaught_exceptions__deps: ['$uncaughtExceptionCount'],
Expand All @@ -285,13 +209,13 @@ var LibraryExceptions = {
throw exception;
},

__cxa_current_primary_exception__deps: ['$exceptionCaught', '$exception_addRef'],
__cxa_current_primary_exception__deps: ['$exceptionCaught', '__cxa_increment_exception_refcount'],
__cxa_current_primary_exception: function() {
if (!exceptionCaught.length) {
return 0;
}
var info = exceptionCaught[exceptionCaught.length - 1];
exception_addRef(info);
___cxa_increment_exception_refcount(info.excPtr);
return info.excPtr;
},

Expand Down
4 changes: 0 additions & 4 deletions src/library_exceptions_stub.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@
var LibraryExceptions = {};

[
'__cxa_allocate_exception',
'__cxa_free_exception',
'__cxa_increment_exception_refcount',
'__cxa_decrement_exception_refcount',
'__cxa_throw',
'__cxa_rethrow',
'llvm_eh_typeid_for',
Expand Down
Loading