diff --git a/src/library_exceptions.js b/src/library_exceptions.js index f36a825acad28..d38b6f49cab46 100644 --- a/src/library_exceptions.js +++ b/src/library_exceptions.js @@ -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 @@ -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 @@ -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); diff --git a/system/lib/libcxxabi/src/cxa_exception_emscripten.cpp b/system/lib/libcxxabi/src/cxa_exception_emscripten.cpp index 5750ad36c7f86..31bc70f2f5804 100644 --- a/system/lib/libcxxabi/src/cxa_exception_emscripten.cpp +++ b/system/lib/libcxxabi/src/cxa_exception_emscripten.cpp @@ -1,11 +1,16 @@ +#include #include #include +#include #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" { @@ -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 diff --git a/system/lib/libcxxabi/src/private_typeinfo.cpp b/system/lib/libcxxabi/src/private_typeinfo.cpp index d65903a794281..bd48d9e783cea 100644 --- a/system/lib/libcxxabi/src/private_typeinfo.cpp +++ b/system/lib/libcxxabi/src/private_typeinfo.cpp @@ -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__