Modified __cxa_end_catch to handle dependent exceptions.

llvm-svn: 146172
This commit is contained in:
Howard Hinnant 2011-12-08 19:35:18 +00:00
parent 0b9b9da6c8
commit 6ccae15ef0
3 changed files with 43 additions and 20 deletions

View File

@ -65,14 +65,14 @@ static bool isDependentException(_Unwind_Exception *unwind) throw() {
return (unwind->exception_class & 0xFF) == 0x01; return (unwind->exception_class & 0xFF) == 0x01;
} }
// TODO: This needs to be atomic // This does not need to be atomic
static int incrementHandlerCount(__cxa_exception *exception) throw() { static inline int incrementHandlerCount(__cxa_exception *exception) throw() {
return ++exception->handlerCount; return ++exception->handlerCount;
} }
// TODO: This needs to be atomic // This does not need to be atomic
static int decrementHandlerCount(__cxa_exception *exception) throw() { static inline int decrementHandlerCount(__cxa_exception *exception) throw() {
return --exception->handlerCount; return --exception->handlerCount;
} }
#include "fallback_malloc.cpp" #include "fallback_malloc.cpp"
@ -192,7 +192,7 @@ LIBCXXABI_NORETURN void
__cxa_throw(void * thrown_exception, std::type_info * tinfo, void (*dest)(void *)) { __cxa_throw(void * thrown_exception, std::type_info * tinfo, void (*dest)(void *)) {
__cxa_eh_globals *globals = __cxa_get_globals(); __cxa_eh_globals *globals = __cxa_get_globals();
__cxa_exception *exception = exception_from_thrown_object(thrown_exception); __cxa_exception *exception = exception_from_thrown_object(thrown_exception);
exception->unexpectedHandler = std::get_unexpected(); exception->unexpectedHandler = std::get_unexpected();
exception->terminateHandler = std::get_terminate(); exception->terminateHandler = std::get_terminate();
exception->exceptionType = tinfo; exception->exceptionType = tinfo;
@ -202,8 +202,11 @@ __cxa_throw(void * thrown_exception, std::type_info * tinfo, void (*dest)(void *
globals->uncaughtExceptions += 1; // Not atomically, since globals are thread-local globals->uncaughtExceptions += 1; // Not atomically, since globals are thread-local
exception->unwindHeader.exception_cleanup = exception_cleanup_func; exception->unwindHeader.exception_cleanup = exception_cleanup_func;
#if __arm__
_Unwind_SjLj_RaiseException(&exception->unwindHeader);
#else
_Unwind_RaiseException(&exception->unwindHeader); _Unwind_RaiseException(&exception->unwindHeader);
#endif
// If we get here, some kind of unwinding error has occurred. // If we get here, some kind of unwinding error has occurred.
failed_throw(exception); failed_throw(exception);
} }
@ -227,6 +230,8 @@ void * __cxa_begin_catch(void * exceptionObject) throw() {
__cxa_eh_globals *globals = __cxa_get_globals(); __cxa_eh_globals *globals = __cxa_get_globals();
__cxa_exception *exception = exception_from_exception_object(exceptionObject); __cxa_exception *exception = exception_from_exception_object(exceptionObject);
// TODO: Handle foreign exceptions? How?
// Increment the handler count, removing the flag about being rethrown // Increment the handler count, removing the flag about being rethrown
exception->handlerCount = exception->handlerCount < 0 ? exception->handlerCount = exception->handlerCount < 0 ?
-exception->handlerCount + 1 : exception->handlerCount + 1; -exception->handlerCount + 1 : exception->handlerCount + 1;
@ -249,28 +254,44 @@ Upon exit for any reason, a handler must call:
This routine: This routine:
* Locates the most recently caught exception and decrements its handler count. * 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. * Removes the exception from the caught exception stack, if the handler count goes to zero.
* Destroys the exception if the handler count goes to zero, and the exception was not re-thrown by throw. * 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.
*/ */
void __cxa_end_catch() { void __cxa_end_catch() {
__cxa_eh_globals *globals = __cxa_get_globals(); __cxa_eh_globals *globals = __cxa_get_globals_fast(); // __cxa_get_globals called in __cxa_begin_catch
__cxa_exception *current_exception = globals->caughtExceptions; __cxa_exception *current_exception = globals->caughtExceptions;
if (NULL != current_exception) { if (NULL != current_exception) {
if (current_exception->handlerCount < 0) { if (current_exception->handlerCount < 0) {
// The exception has been rethrown // The exception has been rethrown
if (0 == incrementHandlerCount(current_exception)) { if (0 == incrementHandlerCount(current_exception)) {
// Remove from the chain of uncaught exceptions
globals->caughtExceptions = current_exception->nextException; globals->caughtExceptions = current_exception->nextException;
// Howard says: If the exception has been rethrown, don't destroy. // but don't destroy
} }
} }
else { else { // The exception has not been rethrown
if (0 == decrementHandlerCount(current_exception)) { if (0 == decrementHandlerCount(current_exception)) {
// Remove from the chain of uncaught exceptions // Remove from the chain of uncaught exceptions
globals->caughtExceptions = current_exception->nextException; globals->caughtExceptions = current_exception->nextException;
if (!isDependentException(&current_exception->unwindHeader)) if (isDependentException(&current_exception->unwindHeader)) {
_Unwind_DeleteException(&current_exception->unwindHeader); // Reset current_exception to primaryException and deallocate the dependent exception
else { __cxa_dependent_exception* deh =
// TODO: deal with a dependent exception reinterpret_cast<__cxa_dependent_exception*>(current_exception + 1) - 1;
current_exception = static_cast<__cxa_exception*>(deh->primaryException) - 1;
__cxa_free_dependent_exception(deh);
}
// Destroy the primary exception only if its referenceCount goes to 0
// (this decrement must be atomic)
if (__sync_sub_and_fetch(&current_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);
} }
} }
} }
@ -306,7 +327,7 @@ extern LIBCXXABI_NORETURN void __cxa_rethrow() {
std::terminate (); std::terminate ();
// Mark the exception as being rethrown // Mark the exception as being rethrown
exception->handlerCount = -exception->handlerCount ; // TODO: Atomic exception->handlerCount = -exception->handlerCount ; // TODO: Atomic
#if __arm__ #if __arm__
(void) _Unwind_SjLj_Resume_or_Rethrow(&exception->unwindHeader); (void) _Unwind_SjLj_Resume_or_Rethrow(&exception->unwindHeader);

View File

@ -56,6 +56,8 @@ namespace __cxxabiv1 {
_Unwind_Exception unwindHeader; _Unwind_Exception unwindHeader;
}; };
// http://sourcery.mentor.com/archives/cxx-abi-dev/msg01924.html
struct __cxa_dependent_exception { struct __cxa_dependent_exception {
#if __LP64__ #if __LP64__

View File

@ -114,7 +114,7 @@ additional memory to hold private data. If memory can not be allocated, call
</td> </td>
<td>&#10003;</td> <td>&#10003;</td>
<td>&#10003;</td> <td>&#10003;</td>
<td></td> <td>&#10003;</td>
</tr> </tr>
<tr> <tr>