diff options
author | Howard Hinnant <hhinnant@apple.com> | 2011-12-21 23:32:11 +0000 |
---|---|---|
committer | Howard Hinnant <hhinnant@apple.com> | 2011-12-21 23:32:11 +0000 |
commit | 1b0aed9312dca7ffd27522864b9101ca816112b1 (patch) | |
tree | 618fd96db96d4d837a086926a1e25ed86a576ebf | |
parent | 4a6e1033ec6cb5648593424fa9e19689668f15a8 (diff) |
Added __cxa_increment_exception_refcount, __cxa_decrement_exception_refcount, __cxa_current_primary_exception, __cxa_rethrow_primary_exception
git-svn-id: https://llvm.org/svn/llvm-project/libcxxabi/trunk@147106 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/cxxabi.h | 19 | ||||
-rw-r--r-- | src/cxa_exception.cpp | 113 | ||||
-rw-r--r-- | www/spec.html | 42 |
3 files changed, 128 insertions, 46 deletions
diff --git a/include/cxxabi.h b/include/cxxabi.h index 933ff21..6d04555 100644 --- a/include/cxxabi.h +++ b/include/cxxabi.h @@ -155,24 +155,6 @@ extern char* __cxa_demangle(const char* mangled_name, size_t* length, int* status); - } // extern "C" -} // namespace __cxxabiv1 -namespace abi = __cxxabiv1; - - - - - -// Below are Apple extensions to support implementing C++ ABI in a seperate dylib -namespace __cxxabiapple { - extern "C" { - -// Apple additions to support multiple STL stacks that share common -// terminate, unexpected, and new handlers -extern void (*__cxa_terminate_handler)(); -extern void (*__cxa_unexpected_handler)(); -extern void (*__cxa_new_handler)(); - // Apple additions to support C++ 0x exception_ptr class // These are primitives to wrap a smart pointer around an exception object extern void * __cxa_current_primary_exception() throw(); @@ -185,6 +167,7 @@ extern bool __cxa_uncaught_exception() throw(); } // extern "C" } // namespace __cxxabiv1 +namespace abi = __cxxabiv1; #endif // __cplusplus diff --git a/src/cxa_exception.cpp b/src/cxa_exception.cpp index e717bc7..9df0564 100644 --- a/src/cxa_exception.cpp +++ b/src/cxa_exception.cpp @@ -287,13 +287,7 @@ void __cxa_end_catch() { } // Destroy the primary exception only if its referenceCount goes to 0 // (this decrement must be atomic) - if (__sync_sub_and_fetch(¤t_exception->referenceCount, size_t(1)) == 0) - { - void* thrown_object = thrown_object_from_exception(current_exception); - if (NULL != current_exception->exceptionDestructor) - current_exception->exceptionDestructor(thrown_object); - __cxa_free_exception(thrown_object); - } + __cxa_decrement_exception_refcount(thrown_object_from_exception(current_exception)); } } } @@ -347,6 +341,111 @@ extern LIBCXXABI_NORETURN void __cxa_rethrow() { failed_throw(exception); } +/* + If p is not null, atomically increment the referenceCount field of the + __cxa_exception header associated with the thrown object referred to by p. +*/ +void +__cxa_increment_exception_refcount(void* p) throw() +{ + if (p != NULL ) + { + __cxa_exception* header = exception_from_thrown_object(p); + __sync_add_and_fetch(&header->referenceCount, 1); + } +} + +/* + If p is not null, atomically decrement the referenceCount field of the + __cxa_exception header associated with the thrown object referred to by p. + If the referenceCount drops to zero, destroy and deallocate the exception. +*/ +void +__cxa_decrement_exception_refcount(void* thrown_object) throw() +{ + if (thrown_object != NULL ) + { + __cxa_exception* header = exception_from_thrown_object(thrown_object); + if (__sync_sub_and_fetch(&header->referenceCount, size_t(1)) == 0) + { + if (NULL != header->exceptionDestructor) + 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. Atommically increment the exception's referenceCount. + If there is no such thrown object, returns null. +*/ +void* +__cxa_current_primary_exception() throw() +{ +// get the current exception + __cxa_eh_globals* globals = __cxa_get_globals(); + __cxa_exception* current_exception = globals->caughtExceptions; + if (NULL == current_exception) + return NULL; // No current exception + if (isDependentException(¤t_exception->unwindHeader)) { + __cxa_dependent_exception* deh = + reinterpret_cast<__cxa_dependent_exception*>(current_exception + 1) - 1; + current_exception = static_cast<__cxa_exception*>(deh->primaryException) - 1; + } + void* thrown_object = thrown_object_from_exception(current_exception); + __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, struct _Unwind_Exception* exc) +{ + __cxa_dependent_exception* deh = + reinterpret_cast<__cxa_dependent_exception*>(exc + 1) - 1; + if (_URC_FOREIGN_EXCEPTION_CAUGHT != reason) + std::__terminate(deh->terminateHandler); + __cxa_decrement_exception_refcount(deh->primaryException); + __cxa_free_dependent_exception(deh); +} + +/* + If thrown_object is not null, allocate, initialize and thow a dependent + exception. +*/ +void +__cxa_rethrow_primary_exception(void* thrown_object) +{ + if ( thrown_object != NULL ) + { + __cxa_exception* header = exception_from_thrown_object(thrown_object); + __cxa_dependent_exception* deh = + (__cxa_dependent_exception*)__cxa_allocate_dependent_exception(); + deh->primaryException = thrown_object; + __cxa_increment_exception_refcount(thrown_object); + deh->exceptionType = header->exceptionType; + deh->unexpectedHandler = std::get_unexpected(); + deh->terminateHandler = std::get_terminate(); + setDependentExceptionClass(&deh->unwindHeader); + deh->unwindHeader.exception_cleanup = dependent_exception_cleanup; +#if __arm__ + _Unwind_SjLj_RaiseException(&deh->unwindHeader); +#else + _Unwind_RaiseException(&deh->unwindHeader); +#endif + // Some sort of unwinding error. Note that terminate is a handler. + __cxa_begin_catch(&deh->unwindHeader); + } + // If we return client will call terminate() +} + } // extern "C" } // abi diff --git a/www/spec.html b/www/spec.html index 8d7a127..f0a10dc 100644 --- a/www/spec.html +++ b/www/spec.html @@ -248,9 +248,9 @@ are no caught exceptions. </p> </blockquote> </td> -<td></td> -<td></td> -<td></td> +<td>✓</td> +<td>✓</td> +<td>✓</td> </tr> <tr> @@ -265,9 +265,9 @@ zero calls <tt>_Unwind_DeleteException</tt> with the exception object. </p> </blockquote> </td> -<td></td> -<td></td> -<td></td> +<td>✓</td> +<td>✓</td> +<td>✓</td> </tr> <tr> @@ -319,9 +319,9 @@ thread. </p> </blockquote> </td> -<td></td> -<td></td> -<td></td> +<td>✓</td> +<td>✓</td> +<td>✓</td> </tr> <tr> @@ -335,9 +335,9 @@ thread. </p> </blockquote> </td> -<td></td> -<td></td> -<td></td> +<td>✓</td> +<td>✓</td> +<td>✓</td> </tr> <tr> @@ -675,9 +675,9 @@ The currently installed new handler. </p> </blockquote> </td> -<td></td> -<td></td> -<td></td> +<td>✓</td> +<td>✓</td> +<td>✓</td> </tr> <tr> @@ -691,9 +691,9 @@ The currently installed terminate handler. </p> </blockquote> </td> -<td></td> -<td></td> -<td></td> +<td>✓</td> +<td>✓</td> +<td>✓</td> </tr> <tr> @@ -707,9 +707,9 @@ The currently installed terminate handler. </p> </blockquote> </td> -<td></td> -<td></td> -<td></td> +<td>✓</td> +<td>✓</td> +<td>✓</td> </tr> |