diff options
Diffstat (limited to 'r21/sources/cxx-stl/llvm-libc++abi/src/cxa_exception.cpp')
-rw-r--r-- | r21/sources/cxx-stl/llvm-libc++abi/src/cxa_exception.cpp | 756 |
1 files changed, 0 insertions, 756 deletions
diff --git a/r21/sources/cxx-stl/llvm-libc++abi/src/cxa_exception.cpp b/r21/sources/cxx-stl/llvm-libc++abi/src/cxa_exception.cpp deleted file mode 100644 index 688ba1ef7..000000000 --- a/r21/sources/cxx-stl/llvm-libc++abi/src/cxa_exception.cpp +++ /dev/null @@ -1,756 +0,0 @@ -//===------------------------- cxa_exception.cpp --------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -// -// This file implements the "Exception Handling APIs" -// https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html -// -//===----------------------------------------------------------------------===// - -#include "cxxabi.h" - -#include <exception> // for std::terminate -#include <cstring> // for memset -#include "cxa_exception.h" -#include "cxa_handlers.h" -#include "fallback_malloc.h" -#include "include/atomic_support.h" - -#if __has_feature(address_sanitizer) -extern "C" void __asan_handle_no_return(void); -#endif - -// +---------------------------+-----------------------------+---------------+ -// | __cxa_exception | _Unwind_Exception CLNGC++\0 | thrown object | -// +---------------------------+-----------------------------+---------------+ -// ^ -// | -// +-------------------------------------------------------+ -// | -// +---------------------------+-----------------------------+ -// | __cxa_dependent_exception | _Unwind_Exception CLNGC++\1 | -// +---------------------------+-----------------------------+ - -namespace __cxxabiv1 { - -// Utility routines -static -inline -__cxa_exception* -cxa_exception_from_thrown_object(void* thrown_object) -{ - return static_cast<__cxa_exception*>(thrown_object) - 1; -} - -// Note: This is never called when exception_header is masquerading as a -// __cxa_dependent_exception. -static -inline -void* -thrown_object_from_cxa_exception(__cxa_exception* exception_header) -{ - return static_cast<void*>(exception_header + 1); -} - -// Get the exception object from the unwind pointer. -// Relies on the structure layout, where the unwind pointer is right in -// front of the user's exception object -static -inline -__cxa_exception* -cxa_exception_from_exception_unwind_exception(_Unwind_Exception* unwind_exception) -{ - return cxa_exception_from_thrown_object(unwind_exception + 1 ); -} - -// Round s up to next multiple of a. -static inline -size_t aligned_allocation_size(size_t s, size_t a) { - return (s + a - 1) & ~(a - 1); -} - -static inline -size_t cxa_exception_size_from_exception_thrown_size(size_t size) { - return aligned_allocation_size(size + sizeof (__cxa_exception), - alignof(__cxa_exception)); -} - -void __setExceptionClass(_Unwind_Exception* unwind_exception, uint64_t newValue) { - ::memcpy(&unwind_exception->exception_class, &newValue, sizeof(newValue)); - } - - -static void setOurExceptionClass(_Unwind_Exception* unwind_exception) { - __setExceptionClass(unwind_exception, kOurExceptionClass); -} - -static void setDependentExceptionClass(_Unwind_Exception* unwind_exception) { - __setExceptionClass(unwind_exception, kOurDependentExceptionClass); -} - -// Is it one of ours? -uint64_t __getExceptionClass(const _Unwind_Exception* unwind_exception) { -// On x86 and some ARM unwinders, unwind_exception->exception_class is -// a uint64_t. On other ARM unwinders, it is a char[8] -// See: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf -// So we just copy it into a uint64_t to be sure. - uint64_t exClass; - ::memcpy(&exClass, &unwind_exception->exception_class, sizeof(exClass)); - return exClass; -} - -bool __isOurExceptionClass(const _Unwind_Exception* unwind_exception) { - return (__getExceptionClass(unwind_exception) & get_vendor_and_language) == - (kOurExceptionClass & get_vendor_and_language); -} - -static bool isDependentException(_Unwind_Exception* unwind_exception) { - return (__getExceptionClass(unwind_exception) & 0xFF) == 0x01; -} - -// This does not need to be atomic -static inline int incrementHandlerCount(__cxa_exception *exception) { - return ++exception->handlerCount; -} - -// This does not need to be atomic -static inline int decrementHandlerCount(__cxa_exception *exception) { - return --exception->handlerCount; -} - -/* - If reason isn't _URC_FOREIGN_EXCEPTION_CAUGHT, then the terminateHandler - stored in exc is called. Otherwise the exceptionDestructor stored in - exc is called, and then the memory for the exception is deallocated. - - This is never called for a __cxa_dependent_exception. -*/ -static -void -exception_cleanup_func(_Unwind_Reason_Code reason, _Unwind_Exception* unwind_exception) -{ - __cxa_exception* exception_header = cxa_exception_from_exception_unwind_exception(unwind_exception); - if (_URC_FOREIGN_EXCEPTION_CAUGHT != reason) - std::__terminate(exception_header->terminateHandler); - // Just in case there exists a dependent exception that is pointing to this, - // check the reference count and only destroy this if that count goes to zero. - __cxa_decrement_exception_refcount(unwind_exception + 1); -} - -static _LIBCXXABI_NORETURN void failed_throw(__cxa_exception* exception_header) { -// Section 2.5.3 says: -// * For purposes of this ABI, several things are considered exception handlers: -// ** A terminate() call due to a throw. -// and -// * Upon entry, Following initialization of the catch parameter, -// a handler must call: -// * void *__cxa_begin_catch(void *exceptionObject ); - (void) __cxa_begin_catch(&exception_header->unwindHeader); - std::__terminate(exception_header->terminateHandler); -} - -// Return the offset of the __cxa_exception header from the start of the -// allocated buffer. If __cxa_exception's alignment is smaller than the maximum -// useful alignment for the target machine, padding has to be inserted before -// the header to ensure the thrown object that follows the header is -// sufficiently aligned. This happens if _Unwind_exception isn't double-word -// aligned (on Darwin, for example). -static size_t get_cxa_exception_offset() { - struct S { - } __attribute__((aligned)); - - // Compute the maximum alignment for the target machine. - constexpr size_t alignment = std::alignment_of<S>::value; - constexpr size_t excp_size = sizeof(__cxa_exception); - constexpr size_t aligned_size = - (excp_size + alignment - 1) / alignment * alignment; - constexpr size_t offset = aligned_size - excp_size; - static_assert((offset == 0 || - std::alignment_of<_Unwind_Exception>::value < alignment), - "offset is non-zero only if _Unwind_Exception isn't aligned"); - return offset; -} - -extern "C" { - -// Allocate a __cxa_exception object, and zero-fill it. -// Reserve "thrown_size" bytes on the end for the user's exception -// object. Zero-fill the object. If memory can't be allocated, call -// std::terminate. Return a pointer to the memory to be used for the -// user's exception object. -void *__cxa_allocate_exception(size_t thrown_size) throw() { - size_t actual_size = cxa_exception_size_from_exception_thrown_size(thrown_size); - - // Allocate extra space before the __cxa_exception header to ensure the - // start of the thrown object is sufficiently aligned. - size_t header_offset = get_cxa_exception_offset(); - char *raw_buffer = - (char *)__aligned_malloc_with_fallback(header_offset + actual_size); - if (NULL == raw_buffer) - std::terminate(); - __cxa_exception *exception_header = - static_cast<__cxa_exception *>((void *)(raw_buffer + header_offset)); - std::memset(exception_header, 0, actual_size); - return thrown_object_from_cxa_exception(exception_header); -} - - -// Free a __cxa_exception object allocated with __cxa_allocate_exception. -void __cxa_free_exception(void *thrown_object) throw() { - // Compute the size of the padding before the header. - size_t header_offset = get_cxa_exception_offset(); - char *raw_buffer = - ((char *)cxa_exception_from_thrown_object(thrown_object)) - header_offset; - __aligned_free_with_fallback((void *)raw_buffer); -} - - -// This function shall allocate a __cxa_dependent_exception and -// return a pointer to it. (Really to the object, not past its' end). -// Otherwise, it will work like __cxa_allocate_exception. -void * __cxa_allocate_dependent_exception () { - size_t actual_size = sizeof(__cxa_dependent_exception); - void *ptr = __aligned_malloc_with_fallback(actual_size); - if (NULL == ptr) - std::terminate(); - std::memset(ptr, 0, actual_size); - return ptr; -} - - -// This function shall free a dependent_exception. -// It does not affect the reference count of the primary exception. -void __cxa_free_dependent_exception (void * dependent_exception) { - __aligned_free_with_fallback(dependent_exception); -} - - -// 2.4.3 Throwing the Exception Object -/* -After constructing the exception object with the throw argument value, -the generated code calls the __cxa_throw runtime library routine. This -routine never returns. - -The __cxa_throw routine will do the following: - -* Obtain the __cxa_exception header from the thrown exception object address, -which can be computed as follows: - __cxa_exception *header = ((__cxa_exception *) thrown_exception - 1); -* Save the current unexpected_handler and terminate_handler in the __cxa_exception header. -* Save the tinfo and dest arguments in the __cxa_exception header. -* Set the exception_class field in the unwind header. This is a 64-bit value -representing the ASCII string "XXXXC++\0", where "XXXX" is a -vendor-dependent string. That is, for implementations conforming to this -ABI, the low-order 4 bytes of this 64-bit value will be "C++\0". -* Increment the uncaught_exception flag. -* Call _Unwind_RaiseException in the system unwind library, Its argument is the -pointer to the thrown exception, which __cxa_throw itself received as an argument. -__Unwind_RaiseException begins the process of stack unwinding, described -in Section 2.5. In special cases, such as an inability to find a -handler, _Unwind_RaiseException may return. In that case, __cxa_throw -will call terminate, assuming that there was no handler for the -exception. -*/ -void -__cxa_throw(void *thrown_object, std::type_info *tinfo, void (*dest)(void *)) { - __cxa_eh_globals *globals = __cxa_get_globals(); - __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); - - exception_header->unexpectedHandler = std::get_unexpected(); - exception_header->terminateHandler = std::get_terminate(); - exception_header->exceptionType = tinfo; - exception_header->exceptionDestructor = dest; - setOurExceptionClass(&exception_header->unwindHeader); - exception_header->referenceCount = 1; // This is a newly allocated exception, no need for thread safety. - globals->uncaughtExceptions += 1; // Not atomically, since globals are thread-local - - exception_header->unwindHeader.exception_cleanup = exception_cleanup_func; - -#if __has_feature(address_sanitizer) - // Inform the ASan runtime that now might be a good time to clean stuff up. - __asan_handle_no_return(); -#endif - -#ifdef __USING_SJLJ_EXCEPTIONS__ - _Unwind_SjLj_RaiseException(&exception_header->unwindHeader); -#else - _Unwind_RaiseException(&exception_header->unwindHeader); -#endif - // This only happens when there is no handler, or some unexpected unwinding - // error happens. - failed_throw(exception_header); -} - - -// 2.5.3 Exception Handlers -/* -The adjusted pointer is computed by the personality routine during phase 1 - and saved in the exception header (either __cxa_exception or - __cxa_dependent_exception). - - Requires: exception is native -*/ -void *__cxa_get_exception_ptr(void *unwind_exception) throw() { -#if defined(_LIBCXXABI_ARM_EHABI) - return reinterpret_cast<void*>( - static_cast<_Unwind_Control_Block*>(unwind_exception)->barrier_cache.bitpattern[0]); -#else - return cxa_exception_from_exception_unwind_exception( - static_cast<_Unwind_Exception*>(unwind_exception))->adjustedPtr; -#endif -} - -#if defined(_LIBCXXABI_ARM_EHABI) -/* -The routine to be called before the cleanup. This will save __cxa_exception in -__cxa_eh_globals, so that __cxa_end_cleanup() can recover later. -*/ -bool __cxa_begin_cleanup(void *unwind_arg) throw() { - _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(unwind_arg); - __cxa_eh_globals* globals = __cxa_get_globals(); - __cxa_exception* exception_header = - cxa_exception_from_exception_unwind_exception(unwind_exception); - - if (__isOurExceptionClass(unwind_exception)) - { - if (0 == exception_header->propagationCount) - { - exception_header->nextPropagatingException = globals->propagatingExceptions; - globals->propagatingExceptions = exception_header; - } - ++exception_header->propagationCount; - } - else - { - // If the propagatingExceptions stack is not empty, since we can't - // chain the foreign exception, terminate it. - if (NULL != globals->propagatingExceptions) - std::terminate(); - globals->propagatingExceptions = exception_header; - } - return true; -} - -/* -The routine to be called after the cleanup has been performed. It will get the -propagating __cxa_exception from __cxa_eh_globals, and continue the stack -unwinding with _Unwind_Resume. - -According to ARM EHABI 8.4.1, __cxa_end_cleanup() should not clobber any -register, thus we have to write this function in assembly so that we can save -{r1, r2, r3}. We don't have to save r0 because it is the return value and the -first argument to _Unwind_Resume(). In addition, we are saving r4 in order to -align the stack to 16 bytes, even though it is a callee-save register. -*/ -__attribute__((used)) static _Unwind_Exception * -__cxa_end_cleanup_impl() -{ - __cxa_eh_globals* globals = __cxa_get_globals(); - __cxa_exception* exception_header = globals->propagatingExceptions; - if (NULL == exception_header) - { - // It seems that __cxa_begin_cleanup() is not called properly. - // We have no choice but terminate the program now. - std::terminate(); - } - - if (__isOurExceptionClass(&exception_header->unwindHeader)) - { - --exception_header->propagationCount; - if (0 == exception_header->propagationCount) - { - globals->propagatingExceptions = exception_header->nextPropagatingException; - exception_header->nextPropagatingException = NULL; - } - } - else - { - globals->propagatingExceptions = NULL; - } - return &exception_header->unwindHeader; -} - -asm ( - " .pushsection .text.__cxa_end_cleanup,\"ax\",%progbits\n" - " .globl __cxa_end_cleanup\n" - " .type __cxa_end_cleanup,%function\n" - "__cxa_end_cleanup:\n" - " push {r1, r2, r3, r4}\n" - " bl __cxa_end_cleanup_impl\n" - " pop {r1, r2, r3, r4}\n" - " bl _Unwind_Resume\n" - " bl abort\n" - " .popsection" -); -#endif // defined(_LIBCXXABI_ARM_EHABI) - -/* -This routine can catch foreign or native exceptions. If native, the exception -can be a primary or dependent variety. This routine may remain blissfully -ignorant of whether the native exception is primary or dependent. - -If the exception is native: -* Increment's the exception's handler count. -* Push the exception on the stack of currently-caught exceptions if it is not - already there (from a rethrow). -* Decrements the uncaught_exception count. -* Returns the adjusted pointer to the exception object, which is stored in - the __cxa_exception by the personality routine. - -If the exception is foreign, this means it did not originate from one of throw -routines. The foreign exception does not necessarily have a __cxa_exception -header. However we can catch it here with a catch (...), or with a call -to terminate or unexpected during unwinding. -* Do not try to increment the exception's handler count, we don't know where - it is. -* Push the exception on the stack of currently-caught exceptions only if the - stack is empty. The foreign exception has no way to link to the current - top of stack. If the stack is not empty, call terminate. Even with an - empty stack, this is hacked in by pushing a pointer to an imaginary - __cxa_exception block in front of the foreign exception. It would be better - if the __cxa_eh_globals structure had a stack of _Unwind_Exception, but it - doesn't. It has a stack of __cxa_exception (which has a next* in it). -* Do not decrement the uncaught_exception count because we didn't increment it - in __cxa_throw (or one of our rethrow functions). -* If we haven't terminated, assume the exception object is just past the - _Unwind_Exception and return a pointer to that. -*/ -void* -__cxa_begin_catch(void* unwind_arg) throw() -{ - _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(unwind_arg); - bool native_exception = __isOurExceptionClass(unwind_exception); - __cxa_eh_globals* globals = __cxa_get_globals(); - // exception_header is a hackish offset from a foreign exception, but it - // works as long as we're careful not to try to access any __cxa_exception - // parts. - __cxa_exception* exception_header = - cxa_exception_from_exception_unwind_exception - ( - static_cast<_Unwind_Exception*>(unwind_exception) - ); - if (native_exception) - { - // Increment the handler count, removing the flag about being rethrown - exception_header->handlerCount = exception_header->handlerCount < 0 ? - -exception_header->handlerCount + 1 : exception_header->handlerCount + 1; - // place the exception on the top of the stack if it's not already - // there by a previous rethrow - if (exception_header != globals->caughtExceptions) - { - exception_header->nextException = globals->caughtExceptions; - globals->caughtExceptions = exception_header; - } - globals->uncaughtExceptions -= 1; // Not atomically, since globals are thread-local -#if defined(_LIBCXXABI_ARM_EHABI) - return reinterpret_cast<void*>(exception_header->unwindHeader.barrier_cache.bitpattern[0]); -#else - return exception_header->adjustedPtr; -#endif - } - // Else this is a foreign exception - // If the caughtExceptions stack is not empty, terminate - if (globals->caughtExceptions != 0) - std::terminate(); - // Push the foreign exception on to the stack - globals->caughtExceptions = exception_header; - return unwind_exception + 1; -} - - -/* -Upon exit for any reason, a handler must call: - void __cxa_end_catch (); - -This routine can be called for either a native or foreign exception. -For a native exception: -* Locates the most recently caught exception and decrements its handler count. -* Removes the exception from the caught exception stack, if the handler count goes to zero. -* If the handler count goes down to zero, and the exception was not re-thrown - by throw, it locates the primary exception (which may be the same as the one - it's handling) and decrements its reference count. If that reference count - goes to zero, the function destroys the exception. In any case, if the current - exception is a dependent exception, it destroys that. - -For a foreign exception: -* If it has been rethrown, there is nothing to do. -* Otherwise delete the exception and pop the catch stack to empty. -*/ -void __cxa_end_catch() { - static_assert(sizeof(__cxa_exception) == sizeof(__cxa_dependent_exception), - "sizeof(__cxa_exception) must be equal to " - "sizeof(__cxa_dependent_exception)"); - static_assert(__builtin_offsetof(__cxa_exception, referenceCount) == - __builtin_offsetof(__cxa_dependent_exception, - primaryException), - "the layout of __cxa_exception must match the layout of " - "__cxa_dependent_exception"); - static_assert(__builtin_offsetof(__cxa_exception, handlerCount) == - __builtin_offsetof(__cxa_dependent_exception, handlerCount), - "the layout of __cxa_exception must match the layout of " - "__cxa_dependent_exception"); - __cxa_eh_globals* globals = __cxa_get_globals_fast(); // __cxa_get_globals called in __cxa_begin_catch - __cxa_exception* exception_header = globals->caughtExceptions; - // If we've rethrown a foreign exception, then globals->caughtExceptions - // will have been made an empty stack by __cxa_rethrow() and there is - // nothing more to be done. Do nothing! - if (NULL != exception_header) - { - bool native_exception = __isOurExceptionClass(&exception_header->unwindHeader); - if (native_exception) - { - // This is a native exception - if (exception_header->handlerCount < 0) - { - // The exception has been rethrown by __cxa_rethrow, so don't delete it - if (0 == incrementHandlerCount(exception_header)) - { - // Remove from the chain of uncaught exceptions - globals->caughtExceptions = exception_header->nextException; - // but don't destroy - } - // Keep handlerCount negative in case there are nested catch's - // that need to be told that this exception is rethrown. Don't - // erase this rethrow flag until the exception is recaught. - } - else - { - // The native exception has not been rethrown - if (0 == decrementHandlerCount(exception_header)) - { - // Remove from the chain of uncaught exceptions - globals->caughtExceptions = exception_header->nextException; - // Destroy this exception, being careful to distinguish - // between dependent and primary exceptions - if (isDependentException(&exception_header->unwindHeader)) - { - // Reset exception_header to primaryException and deallocate the dependent exception - __cxa_dependent_exception* dep_exception_header = - reinterpret_cast<__cxa_dependent_exception*>(exception_header); - exception_header = - cxa_exception_from_thrown_object(dep_exception_header->primaryException); - __cxa_free_dependent_exception(dep_exception_header); - } - // Destroy the primary exception only if its referenceCount goes to 0 - // (this decrement must be atomic) - __cxa_decrement_exception_refcount(thrown_object_from_cxa_exception(exception_header)); - } - } - } - else - { - // The foreign exception has not been rethrown. Pop the stack - // and delete it. If there are nested catch's and they try - // to touch a foreign exception in any way, that is undefined - // behavior. They likely can't since the only way to catch - // a foreign exception is with catch (...)! - _Unwind_DeleteException(&globals->caughtExceptions->unwindHeader); - globals->caughtExceptions = 0; - } - } -} - -// Note: exception_header may be masquerading as a __cxa_dependent_exception -// and that's ok. exceptionType is there too. -// However watch out for foreign exceptions. Return null for them. -std::type_info *__cxa_current_exception_type() { -// get the current exception - __cxa_eh_globals *globals = __cxa_get_globals_fast(); - if (NULL == globals) - return NULL; // If there have never been any exceptions, there are none now. - __cxa_exception *exception_header = globals->caughtExceptions; - if (NULL == exception_header) - return NULL; // No current exception - if (!__isOurExceptionClass(&exception_header->unwindHeader)) - return NULL; - return exception_header->exceptionType; -} - -// 2.5.4 Rethrowing Exceptions -/* This routine can rethrow native or foreign exceptions. -If the exception is native: -* marks the exception object on top of the caughtExceptions stack - (in an implementation-defined way) as being rethrown. -* If the caughtExceptions stack is empty, it calls terminate() - (see [C++FDIS] [except.throw], 15.1.8). -* It then calls _Unwind_RaiseException which should not return - (terminate if it does). - Note: exception_header may be masquerading as a __cxa_dependent_exception - and that's ok. -*/ -void __cxa_rethrow() { - __cxa_eh_globals* globals = __cxa_get_globals(); - __cxa_exception* exception_header = globals->caughtExceptions; - if (NULL == exception_header) - std::terminate(); // throw; called outside of a exception handler - bool native_exception = __isOurExceptionClass(&exception_header->unwindHeader); - if (native_exception) - { - // Mark the exception as being rethrown (reverse the effects of __cxa_begin_catch) - exception_header->handlerCount = -exception_header->handlerCount; - globals->uncaughtExceptions += 1; - // __cxa_end_catch will remove this exception from the caughtExceptions stack if necessary - } - else // this is a foreign exception - { - // The only way to communicate to __cxa_end_catch that we've rethrown - // a foreign exception, so don't delete us, is to pop the stack here - // which must be empty afterwards. Then __cxa_end_catch will do - // nothing - globals->caughtExceptions = 0; - } -#ifdef __USING_SJLJ_EXCEPTIONS__ - _Unwind_SjLj_RaiseException(&exception_header->unwindHeader); -#else - _Unwind_RaiseException(&exception_header->unwindHeader); -#endif - - // If we get here, some kind of unwinding error has occurred. - // There is some weird code generation bug happening with - // Apple clang version 4.0 (tags/Apple/clang-418.0.2) (based on LLVM 3.1svn) - // If we call failed_throw here. Turns up with -O2 or higher, and -Os. - __cxa_begin_catch(&exception_header->unwindHeader); - if (native_exception) - std::__terminate(exception_header->terminateHandler); - // Foreign exception: can't get exception_header->terminateHandler - std::terminate(); -} - -/* - If thrown_object is not null, atomically increment the referenceCount field - of the __cxa_exception header associated with the thrown object referred to - by thrown_object. - - Requires: If thrown_object is not NULL, it is a native exception. -*/ -void -__cxa_increment_exception_refcount(void *thrown_object) throw() { - if (thrown_object != NULL ) - { - __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); - std::__libcpp_atomic_add(&exception_header->referenceCount, size_t(1)); - } -} - -/* - If thrown_object is not null, atomically decrement the referenceCount field - of the __cxa_exception header associated with the thrown object referred to - by thrown_object. If the referenceCount drops to zero, destroy and - deallocate the exception. - - Requires: If thrown_object is not NULL, it is a native exception. -*/ -_LIBCXXABI_NO_CFI -void __cxa_decrement_exception_refcount(void *thrown_object) throw() { - if (thrown_object != NULL ) - { - __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); - if (std::__libcpp_atomic_add(&exception_header->referenceCount, size_t(-1)) == 0) - { - if (NULL != exception_header->exceptionDestructor) - exception_header->exceptionDestructor(thrown_object); - __cxa_free_exception(thrown_object); - } - } -} - -/* - Returns a pointer to the thrown object (if any) at the top of the - caughtExceptions stack. Atomically increment the exception's referenceCount. - If there is no such thrown object or if the thrown object is foreign, - returns null. - - We can use __cxa_get_globals_fast here to get the globals because if there have - been no exceptions thrown, ever, on this thread, we can return NULL without - the need to allocate the exception-handling globals. -*/ -void *__cxa_current_primary_exception() throw() { -// get the current exception - __cxa_eh_globals* globals = __cxa_get_globals_fast(); - if (NULL == globals) - return NULL; // If there are no globals, there is no exception - __cxa_exception* exception_header = globals->caughtExceptions; - if (NULL == exception_header) - return NULL; // No current exception - if (!__isOurExceptionClass(&exception_header->unwindHeader)) - return NULL; // Can't capture a foreign exception (no way to refcount it) - if (isDependentException(&exception_header->unwindHeader)) { - __cxa_dependent_exception* dep_exception_header = - reinterpret_cast<__cxa_dependent_exception*>(exception_header); - exception_header = cxa_exception_from_thrown_object(dep_exception_header->primaryException); - } - void* thrown_object = thrown_object_from_cxa_exception(exception_header); - __cxa_increment_exception_refcount(thrown_object); - return thrown_object; -} - -/* - If reason isn't _URC_FOREIGN_EXCEPTION_CAUGHT, then the terminateHandler - stored in exc is called. Otherwise the referenceCount stored in the - primary exception is decremented, destroying the primary if necessary. - Finally the dependent exception is destroyed. -*/ -static -void -dependent_exception_cleanup(_Unwind_Reason_Code reason, _Unwind_Exception* unwind_exception) -{ - __cxa_dependent_exception* dep_exception_header = - reinterpret_cast<__cxa_dependent_exception*>(unwind_exception + 1) - 1; - if (_URC_FOREIGN_EXCEPTION_CAUGHT != reason) - std::__terminate(dep_exception_header->terminateHandler); - __cxa_decrement_exception_refcount(dep_exception_header->primaryException); - __cxa_free_dependent_exception(dep_exception_header); -} - -/* - If thrown_object is not null, allocate, initialize and throw a dependent - exception. -*/ -void -__cxa_rethrow_primary_exception(void* thrown_object) -{ - if ( thrown_object != NULL ) - { - // thrown_object guaranteed to be native because - // __cxa_current_primary_exception returns NULL for foreign exceptions - __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); - __cxa_dependent_exception* dep_exception_header = - static_cast<__cxa_dependent_exception*>(__cxa_allocate_dependent_exception()); - dep_exception_header->primaryException = thrown_object; - __cxa_increment_exception_refcount(thrown_object); - dep_exception_header->exceptionType = exception_header->exceptionType; - dep_exception_header->unexpectedHandler = std::get_unexpected(); - dep_exception_header->terminateHandler = std::get_terminate(); - setDependentExceptionClass(&dep_exception_header->unwindHeader); - __cxa_get_globals()->uncaughtExceptions += 1; - dep_exception_header->unwindHeader.exception_cleanup = dependent_exception_cleanup; -#ifdef __USING_SJLJ_EXCEPTIONS__ - _Unwind_SjLj_RaiseException(&dep_exception_header->unwindHeader); -#else - _Unwind_RaiseException(&dep_exception_header->unwindHeader); -#endif - // Some sort of unwinding error. Note that terminate is a handler. - __cxa_begin_catch(&dep_exception_header->unwindHeader); - } - // If we return client will call terminate() -} - -bool -__cxa_uncaught_exception() throw() { return __cxa_uncaught_exceptions() != 0; } - -unsigned int -__cxa_uncaught_exceptions() throw() -{ - // This does not report foreign exceptions in flight - __cxa_eh_globals* globals = __cxa_get_globals_fast(); - if (globals == 0) - return 0; - return globals->uncaughtExceptions; -} - -} // extern "C" - -} // abi |