Skip to content

Commit

Permalink
.
Browse files Browse the repository at this point in the history
  • Loading branch information
sbc100 committed Aug 19, 2021
1 parent af8e829 commit 7fee243
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 97 deletions.
77 changes: 0 additions & 77 deletions src/library_exceptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@

var LibraryExceptions = {
$uncaughtExceptionCount: '0',
$exceptionLast: '0',
$exceptionCaught: ' []',

// This class is the exception metadata which is prepended to each thrown object (in WASM memory).
// It is allocated in one block among with a thrown object in __cxa_allocate_exception and freed
Expand Down Expand Up @@ -111,30 +109,6 @@ var LibraryExceptions = {
return type;
},

// 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', '__cxa_decrement_exception_refcount',
'$CatchInfo'],
__cxa_end_catch__sig: 'v',
__cxa_end_catch: function() {
// Clear state flag.
_setThrew(0);
#if ASSERTIONS
assert(exceptionCaught.length > 0);
#endif
// Call destructor if one is registered then clear it.
var catchInfo = exceptionCaught.pop();

#if EXCEPTION_DEBUG
err('cxa_end_catch popped ' + [catchInfo, exceptionLast, 'stack', exceptionCaught]);
#endif
___cxa_decrement_exception_refcount(catchInfo.get_base_ptr());
catchInfo.free();
exceptionLast = 0; // XXX in decRef?
},

__cxa_get_exception_ptr__deps: ['$CatchInfo'],
__cxa_get_exception_ptr: function(ptr) {
#if EXCEPTION_DEBUG
Expand Down Expand Up @@ -179,57 +153,6 @@ var LibraryExceptions = {
___cxa_rethrow();
},

// Finds a suitable catch clause for when an exception is thrown.
// In normal compilers, this functionality is handled by the C++
// 'personality' routine. This is passed a fairly complex structure
// relating to the context of the exception and makes judgements
// about how to handle it. Some of it is about matching a suitable
// catch clause, and some of it is about unwinding. We already handle
// 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.
__cxa_find_matching_catch__deps: ['$exceptionLast', '$ExceptionInfo', '$CatchInfo', '__resumeException', '__cxa_can_catch'],
__cxa_find_matching_catch: function() {
var thrown = exceptionLast;
if (!thrown) {
// just pass through the null ptr
{{{ makeStructuralReturn([0, 0]) }}};
}
var info = new ExceptionInfo(thrown);
var thrownType = info.get_type();
var catchInfo = new CatchInfo();
catchInfo.set_base_ptr(thrown);
catchInfo.set_adjusted_ptr(thrown);
if (!thrownType) {
// just pass through the thrown ptr
{{{ makeStructuralReturn(['catchInfo.ptr', 0]) }}};
}
var typeArray = Array.prototype.slice.call(arguments);

// can_catch receives a **, add indirection
#if EXCEPTION_DEBUG
out("can_catch on " + [thrown]);
#endif
// The different catch blocks are denoted by different types.
// Due to inheritance, those types may not precisely match the
// type of the thrown object. Find one which matches, and
// return the type of the catch block which should be called.
for (var i = 0; i < typeArray.length; i++) {
var caughtType = typeArray[i];
if (caughtType === 0 || caughtType === thrownType) {
// Catch all clause matched or exactly the same type is caught
break;
}
if ({{{ exportedAsmFunc('___cxa_can_catch') }}}(caughtType, thrownType, catchInfo.get_adjusted_ptr_addr())) {
#if EXCEPTION_DEBUG
out(" can_catch found " + [catchInfo.get_adjusted_ptr(), caughtType]);
#endif
{{{ makeStructuralReturn(['catchInfo.ptr', 'caughtType']) }}};
}
}
{{{ makeStructuralReturn(['catchInfo.ptr', 'thrownType']) }}};
},

__resumeException__deps: ['$exceptionLast', '$CatchInfo'],
__resumeException: function(catchInfoPtr) {
var catchInfo = new CatchInfo(catchInfoPtr);
Expand Down
117 changes: 101 additions & 16 deletions system/lib/libcxxabi/src/cxa_exception_emscripten.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
#include <cassert>
#include <cstring>
#include <cstdio>
#include <vector>

#include "cxxabi.h"

#include "private_typeinfo.h"
#include "cxa_exception.h"
#include "include/atomic_support.h"

extern "C" void setThrew(uintptr_t threw, int value);
extern "C" void setTempRet0(uint32_t value);

namespace __cxxabiv1 {

extern "C" {
Expand Down Expand Up @@ -67,46 +72,126 @@ struct __catch_info {
void* adjustedPtr;
};

static __cxa_exception* get_exception_info(__catch_info* info) {
return (__cxa_exception*)info->basePtr;
static __cxa_exception* get_cxa_exception(__catch_info* info) {
return cxa_exception_from_thrown_object(info->basePtr);
}

static int is_pointer_type(std::type_info* type) {
return !!dynamic_cast<__pointer_type_info*>(type);
}

// Get pointer which is expected to be received by catch clause in C++ code. It may be adjusted
// when the pointer is casted to some of the exception object base classes (e.g. when virtual
// inheritance is used). When a pointer is thrown this method should return the thrown pointer
// itself.
static void* get_thrown_object(__catch_info* info) {
bool isPointer = ___cxa_is_pointer_type(get_exception_info(info)->exceptionType);
static void* get_exception_ptr(__catch_info* info) {
bool isPointer = is_pointer_type(get_cxa_exception(info)->exceptionType);
if (isPointer) {
return *this.basePtr;
return info->basePtr;
}
void* adjusted = get_adjusted_ptr(info);
if (adjusted) {
return adjusted;
if (info->adjustedPtr) {
return &info->adjustedPtr;
}
return info.basePtr;
return &info->basePtr;
}

static int uncaughtExceptionCount;
static std::vector<__catch_info*> exceptionCaught;

void* __cxa_begin_catch(void* unwind_arg) _NOEXCEPT
void* __cxa_begin_catch(void* unwind_arg) _NOEXCEPT {
__catch_info* info = (__catch_info*)unwind_arg;
__cxa_exception* ex = get_exception_info(info);
if (!ex->caught()) {
__cxa_exception* ex = get_cxa_exception(info);
if (!ex->caught) {
ex->caught = true;
uncaughtExceptionCount--;
}
info->rethrown = false;
ex->rethrown = false;
exceptionCaught.push_back(info);
#if 0
err('cxa_begin_catch ' + [ptr, 'stack', exceptionCaught]);
#endif
__cxa_increment_exception_refcount(info->basePtr);
return get_thrown_object(info);
return get_exception_ptr(info);
}
#endif

static void* exceptionLast;

// 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.
void __cxa_end_catch() {
// Clear state flag.
setThrew(0, 0);
assert(exceptionCaught.size() > 0);
// Call destructor if one is registered then clear it.
__catch_info* catchInfo = exceptionCaught.back();
exceptionCaught.pop_back();

//err('cxa_end_catch popped ' + [catchInfo, exceptionLast, 'stack', exceptionCaught]);
__cxa_decrement_exception_refcount(catchInfo->basePtr);
::free(catchInfo);
exceptionLast = 0; // XXX in decRef?
}

int __cxa_can_catch(std::type_info* catchType, std::type_info* excpType, void **thrown);

// Finds a suitable catch clause for when an exception is thrown.
// In normal compilers, this functionality is handled by the C++
// 'personality' routine. This is passed a fairly complex structure
// relating to the context of the exception and makes judgements
// about how to handle it. Some of it is about matching a suitable
// catch clause, and some of it is about unwinding. We already handle
// 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.
void* __cxa_find_matching_catch_v(int count, ...) {
void* thrown = exceptionLast;
if (!thrown) {
// just pass through the null ptr
setTempRet0(0);
return 0;
}
__cxa_exception* info = cxa_exception_from_thrown_object(thrown);
std::type_info* thrownType = info->exceptionType;
__catch_info CatchInfo{thrown, 0}
if (!thrownType) {
// just pass through the thrown ptr
setTempRet0(0);
return catchInfo.basePtr;
}

// can_catch receives a **, add indirection
//out("can_catch on " + [thrown]);
void* exceptionThrown = 0;
// The different catch blocks are denoted by different types.
// Due to inheritance, those types may not precisely match the
// type of the thrown object. Find one which matches, and
// return the type of the catch block which should be called.
va_list ap;
va_start(ap, count);
for (int i = 0; i < count; i++) {
std::type_info* caughtType = va_arg(va_list ap, std::type_info*);
if (caughtType === 0 || caughtType === thrownType) {
// Catch all clause matched or exactly the same type is caught
break;
}
if (__cxa_can_catch(caughtType, thrownType, &exceptionThrown) {
if (thrown !== exceptionThrown) {
catchInfo.set_adjusted_ptr(exceptionThrown);
}
//out(" can_catch found " + [adjusted, caughtType]);
setTempRet0(caughtType);
return makeStructuralReturn(catchInfo.basePtr);
}
}
va_end(ap);
setTempRet0(thrownType);
return catchInfo.basePtr;
},

#endif // __USING_EMSCRIPTEN_EXCEPTIONS__

} // extern "C"

} // abi
4 changes: 0 additions & 4 deletions system/lib/libcxxabi/src/private_typeinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1350,10 +1350,6 @@ int __cxa_can_catch(__shim_type_info* catchType, __shim_type_info* excpType, voi
return ret;
}

int __cxa_is_pointer_type(__shim_type_info* type) {
return !!dynamic_cast<__pointer_type_info*>(type);
}

}
#endif // !__USING_WASM_EXCEPTIONS__

Expand Down

0 comments on commit 7fee243

Please sign in to comment.