Modified __cxa_end_catch to handle dependent exceptions.

llvm-svn: 146172
Cr-Mirrored-From: sso://chromium.googlesource.com/_direct/external/github.com/llvm/llvm-project
Cr-Mirrored-Commit: 6ccae15ef0b96b1b4db642020a249bb9cff204df
diff --git a/src/cxa_exception.cpp b/src/cxa_exception.cpp
index 90e9032..6022740 100644
--- a/src/cxa_exception.cpp
+++ b/src/cxa_exception.cpp
@@ -65,14 +65,14 @@
     return (unwind->exception_class & 0xFF) == 0x01;
 }
 
-//	TODO: This needs to be atomic
-static int incrementHandlerCount(__cxa_exception *exception) throw() {
-	return ++exception->handlerCount;
+//  This does not need to be atomic
+static inline int incrementHandlerCount(__cxa_exception *exception) throw() {
+    return ++exception->handlerCount;
 }
 
-//	TODO: This needs to be atomic
-static int decrementHandlerCount(__cxa_exception *exception) throw() {
-	return --exception->handlerCount;
+//  This does not need to be atomic
+static inline  int decrementHandlerCount(__cxa_exception *exception) throw() {
+    return --exception->handlerCount;
 }
 
 #include "fallback_malloc.cpp"
@@ -192,7 +192,7 @@
 __cxa_throw(void * thrown_exception, std::type_info * tinfo, void (*dest)(void *)) {
     __cxa_eh_globals *globals = __cxa_get_globals();
     __cxa_exception *exception = exception_from_thrown_object(thrown_exception);
-    
+
     exception->unexpectedHandler = std::get_unexpected();
     exception->terminateHandler  = std::get_terminate();
     exception->exceptionType = tinfo;
@@ -202,8 +202,11 @@
     globals->uncaughtExceptions += 1;   // Not atomically, since globals are thread-local
 
     exception->unwindHeader.exception_cleanup = exception_cleanup_func;
+#if __arm__
+    _Unwind_SjLj_RaiseException(&exception->unwindHeader);
+#else
     _Unwind_RaiseException(&exception->unwindHeader);
-    
+#endif
 //  If we get here, some kind of unwinding error has occurred.
     failed_throw(exception);
 }
@@ -227,6 +230,8 @@
     __cxa_eh_globals *globals = __cxa_get_globals();
     __cxa_exception *exception = exception_from_exception_object(exceptionObject);
 
+// TODO:  Handle foreign exceptions?  How?
+
 //  Increment the handler count, removing the flag about being rethrown
     exception->handlerCount = exception->handlerCount < 0 ?
         -exception->handlerCount + 1 : exception->handlerCount + 1;
@@ -249,28 +254,44 @@
 This routine:
 * 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.
-* 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() {
-    __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;
     
     if (NULL != current_exception) {
         if (current_exception->handlerCount < 0) {
         //  The exception has been rethrown
             if (0 == incrementHandlerCount(current_exception)) {
+                //  Remove from the chain of uncaught exceptions
                 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)) {
-            //  Remove from the chain of uncaught exceptions
+                //  Remove from the chain of uncaught exceptions
                 globals->caughtExceptions = current_exception->nextException;
-                if (!isDependentException(&current_exception->unwindHeader))
-                    _Unwind_DeleteException(&current_exception->unwindHeader);
-                else {
-                //  TODO: deal with a dependent exception
+                if (isDependentException(&current_exception->unwindHeader)) {
+                    // Reset current_exception to primaryException and deallocate the dependent exception
+                    __cxa_dependent_exception* deh =
+                        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 @@
         std::terminate ();
 
 //  Mark the exception as being rethrown
-    exception->handlerCount = -exception->handlerCount ;	// TODO: Atomic
+    exception->handlerCount = -exception->handlerCount ;  // TODO: Atomic
     
 #if __arm__
     (void) _Unwind_SjLj_Resume_or_Rethrow(&exception->unwindHeader);
diff --git a/src/cxa_exception.hpp b/src/cxa_exception.hpp
index 9681298..8f795f0 100644
--- a/src/cxa_exception.hpp
+++ b/src/cxa_exception.hpp
@@ -56,6 +56,8 @@
     
         _Unwind_Exception unwindHeader;
         };
+
+// http://sourcery.mentor.com/archives/cxx-abi-dev/msg01924.html
     
     struct __cxa_dependent_exception {
 #if __LP64__