blob: ff2afc3852e00390c2a4b516c2d316642e6d4fd1 [file] [log] [blame]
Marshall Clowe0252022011-07-20 15:04:39 +00001//===------------------------- cxa_exception.cpp --------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is dual licensed under the MIT and the University of Illinois Open
6// Source Licenses. See LICENSE.TXT for details.
7//
8//
9// This file implements the "Exception Handling APIs"
10// http://www.codesourcery.com/public/cxx-abi/abi-eh.html
11//
12//===----------------------------------------------------------------------===//
13
14#include "cxxabi.h"
15
16#include <exception> // for std::terminate
17#include <cstdlib> // for malloc, free
18#include <string> // for memset
19#include <pthread.h>
20
21#include "cxa_exception.hpp"
Howard Hinnantb80931e2011-12-07 21:16:40 +000022#include "cxa_handlers.hpp"
Marshall Clowe0252022011-07-20 15:04:39 +000023
24namespace __cxxabiv1 {
Marshall Clow3c54f1b2011-08-09 15:09:41 +000025static const uint64_t kOurExceptionClass = 0x434C4E47432B2B00; // CLNGC++\0
26static const uint64_t kOurDependentExceptionClass = 0x434C4E47432B2B01; // CLNGC++\1
27
Marshall Clowe0252022011-07-20 15:04:39 +000028// Utility routines
Howard Hinnantb80931e2011-12-07 21:16:40 +000029static inline __cxa_exception *exception_from_thrown_object(void *p) throw() {
Marshall Clowfb69a8b2011-08-15 18:06:47 +000030 return ((__cxa_exception *) p) - 1;
31}
Marshall Clowe0252022011-07-20 15:04:39 +000032
Howard Hinnantb80931e2011-12-07 21:16:40 +000033static inline void * thrown_object_from_exception(void *p) throw() {
Marshall Clowfb69a8b2011-08-15 18:06:47 +000034 return (void *) (((__cxa_exception *) p) + 1 );
35}
Marshall Clowe0252022011-07-20 15:04:39 +000036
Howard Hinnantb80931e2011-12-07 21:16:40 +000037static inline size_t object_size_from_exception_size(size_t size) throw() {
Marshall Clowe0252022011-07-20 15:04:39 +000038 return size + sizeof (__cxa_exception);
Marshall Clowfb69a8b2011-08-15 18:06:47 +000039}
Marshall Clowe0252022011-07-20 15:04:39 +000040
Marshall Clow3c54f1b2011-08-09 15:09:41 +000041// Get the exception object from the unwind pointer.
42// Relies on the structure layout, where the unwind pointer is right in
43// front of the user's exception object
44static __cxa_exception *
Marshall Clowfb69a8b2011-08-15 18:06:47 +000045exception_from_exception_object(void *ptr) throw() {
46 _Unwind_Exception *p = reinterpret_cast<_Unwind_Exception *>(ptr);
47 return exception_from_thrown_object(p + 1 );
48}
Marshall Clow3c54f1b2011-08-09 15:09:41 +000049
Marshall Clowfb69a8b2011-08-15 18:06:47 +000050static void setExceptionClass(_Unwind_Exception *unwind) throw() {
Marshall Clow3c54f1b2011-08-09 15:09:41 +000051 unwind->exception_class = kOurExceptionClass;
Marshall Clowfb69a8b2011-08-15 18:06:47 +000052}
Marshall Clow3c54f1b2011-08-09 15:09:41 +000053
Marshall Clowfb69a8b2011-08-15 18:06:47 +000054static void setDependentExceptionClass(_Unwind_Exception *unwind) throw() {
Marshall Clow3c54f1b2011-08-09 15:09:41 +000055 unwind->exception_class = kOurDependentExceptionClass;
Marshall Clowfb69a8b2011-08-15 18:06:47 +000056}
Marshall Clow3c54f1b2011-08-09 15:09:41 +000057
58// Is it one of ours?
Marshall Clowfb69a8b2011-08-15 18:06:47 +000059static bool isOurExceptionClass(_Unwind_Exception *unwind) throw() {
60 return(unwind->exception_class == kOurExceptionClass)||
61 (unwind->exception_class == kOurDependentExceptionClass);
62}
Marshall Clow3c54f1b2011-08-09 15:09:41 +000063
Marshall Clowfb69a8b2011-08-15 18:06:47 +000064static bool isDependentException(_Unwind_Exception *unwind) throw() {
65 return (unwind->exception_class & 0xFF) == 0x01;
66}
67
Howard Hinnanta6baba12011-12-08 19:35:18 +000068// This does not need to be atomic
69static inline int incrementHandlerCount(__cxa_exception *exception) throw() {
70 return ++exception->handlerCount;
Marshall Clowfb69a8b2011-08-15 18:06:47 +000071}
72
Howard Hinnanta6baba12011-12-08 19:35:18 +000073// This does not need to be atomic
74static inline int decrementHandlerCount(__cxa_exception *exception) throw() {
75 return --exception->handlerCount;
Marshall Clowfb69a8b2011-08-15 18:06:47 +000076}
Marshall Clow3c54f1b2011-08-09 15:09:41 +000077
Marshall Clowe0252022011-07-20 15:04:39 +000078#include "fallback_malloc.cpp"
79
80// Allocate some memory from _somewhere_
Marshall Clowfb69a8b2011-08-15 18:06:47 +000081static void *do_malloc(size_t size) throw() {
82 void *ptr = std::malloc(size);
83 if (NULL == ptr) // if malloc fails, fall back to emergency stash
84 ptr = fallback_malloc(size);
Marshall Clowe0252022011-07-20 15:04:39 +000085 return ptr;
Marshall Clowfb69a8b2011-08-15 18:06:47 +000086}
Marshall Clowe0252022011-07-20 15:04:39 +000087
88// Didn't know you could "return <expression>" from a void function, did you?
89// Well, you can, if the type of the expression is "void" also.
Marshall Clowfb69a8b2011-08-15 18:06:47 +000090static void do_free(void *ptr) throw() {
91 return is_fallback_ptr(ptr) ? fallback_free(ptr) : std::free(ptr);
92}
Marshall Clowe0252022011-07-20 15:04:39 +000093
Howard Hinnantb80931e2011-12-07 21:16:40 +000094/*
Marshall Clow3c54f1b2011-08-09 15:09:41 +000095 If reason isn't _URC_FOREIGN_EXCEPTION_CAUGHT, then the terminateHandler
96 stored in exc is called. Otherwise the exceptionDestructor stored in
97 exc is called, and then the memory for the exception is deallocated.
98*/
Marshall Clowfb69a8b2011-08-15 18:06:47 +000099static void exception_cleanup_func(_Unwind_Reason_Code reason, struct _Unwind_Exception* exc) {
100 __cxa_exception *exception = exception_from_exception_object(exc);
101 if (_URC_FOREIGN_EXCEPTION_CAUGHT != reason)
Howard Hinnantb80931e2011-12-07 21:16:40 +0000102 std::__terminate(exception->terminateHandler);
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000103
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000104 void * thrown_object = thrown_object_from_exception(exception);
105 if (NULL != exception->exceptionDestructor)
106 exception->exceptionDestructor(thrown_object);
107 __cxa_free_exception(thrown_object);
108}
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000109
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000110static LIBCXXABI_NORETURN void failed_throw(__cxa_exception *exception) throw() {
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000111// Section 2.5.3 says:
112// * For purposes of this ABI, several things are considered exception handlers:
113// ** A terminate() call due to a throw.
114// and
115// * Upon entry, Following initialization of the catch parameter,
116// a handler must call:
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000117// * void *__cxa_begin_catch(void *exceptionObject );
118 (void) __cxa_begin_catch(&exception->unwindHeader);
Howard Hinnantb80931e2011-12-07 21:16:40 +0000119 std::__terminate(exception->terminateHandler);
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000120}
Marshall Clowe0252022011-07-20 15:04:39 +0000121
122extern "C" {
123
124// Allocate a __cxa_exception object, and zero-fill it.
125// Reserve "thrown_size" bytes on the end for the user's exception
126// object. Zero-fill the object. If memory can't be allocated, call
127// std::terminate. Return a pointer to the memory to be used for the
128// user's exception object.
129void * __cxa_allocate_exception (size_t thrown_size) throw() {
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000130 size_t actual_size = object_size_from_exception_size(thrown_size);
131 void *ptr = do_malloc(actual_size);
132 if (NULL == ptr)
133 std::terminate();
134 std::memset(ptr, 0, actual_size);
135 return thrown_object_from_exception(ptr);
136}
Marshall Clowe0252022011-07-20 15:04:39 +0000137
138
139// Free a __cxa_exception object allocated with __cxa_allocate_exception.
140void __cxa_free_exception (void * thrown_exception) throw() {
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000141 do_free(exception_from_thrown_object(thrown_exception));
142}
Marshall Clowe0252022011-07-20 15:04:39 +0000143
144
145// This function shall allocate a __cxa_dependent_exception and
146// return a pointer to it. (Really to the object, not past its' end).
147// Otherwise, it will work like __cxa_allocate_exception.
148void * __cxa_allocate_dependent_exception () throw() {
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000149 size_t actual_size = sizeof(__cxa_dependent_exception);
150 void *ptr = do_malloc(actual_size);
151 if (NULL == ptr)
152 std::terminate();
153 std::memset(ptr, 0, actual_size);
Marshall Clowe0252022011-07-20 15:04:39 +0000154 return ptr;
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000155}
Marshall Clowe0252022011-07-20 15:04:39 +0000156
157
158// This function shall free a dependent_exception.
159// It does not affect the reference count of the primary exception.
160void __cxa_free_dependent_exception (void * dependent_exception) throw() {
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000161 do_free(dependent_exception);
162}
Marshall Clowe0252022011-07-20 15:04:39 +0000163
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000164
165// 2.4.3 Throwing the Exception Object
166/*
167After constructing the exception object with the throw argument value,
168the generated code calls the __cxa_throw runtime library routine. This
169routine never returns.
170
171The __cxa_throw routine will do the following:
172
173* Obtain the __cxa_exception header from the thrown exception object address,
174which can be computed as follows:
175 __cxa_exception *header = ((__cxa_exception *) thrown_exception - 1);
176* Save the current unexpected_handler and terminate_handler in the __cxa_exception header.
177* Save the tinfo and dest arguments in the __cxa_exception header.
178* Set the exception_class field in the unwind header. This is a 64-bit value
179representing the ASCII string "XXXXC++\0", where "XXXX" is a
180vendor-dependent string. That is, for implementations conforming to this
181ABI, the low-order 4 bytes of this 64-bit value will be "C++\0".
182* Increment the uncaught_exception flag.
183* Call _Unwind_RaiseException in the system unwind library, Its argument is the
184pointer to the thrown exception, which __cxa_throw itself received as an argument.
185__Unwind_RaiseException begins the process of stack unwinding, described
186in Section 2.5. In special cases, such as an inability to find a
187handler, _Unwind_RaiseException may return. In that case, __cxa_throw
188will call terminate, assuming that there was no handler for the
189exception.
190*/
191LIBCXXABI_NORETURN void
192__cxa_throw(void * thrown_exception, std::type_info * tinfo, void (*dest)(void *)) {
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000193 __cxa_eh_globals *globals = __cxa_get_globals();
194 __cxa_exception *exception = exception_from_thrown_object(thrown_exception);
Howard Hinnanta6baba12011-12-08 19:35:18 +0000195
Howard Hinnantd9ad30c2011-12-06 19:02:03 +0000196 exception->unexpectedHandler = std::get_unexpected();
197 exception->terminateHandler = std::get_terminate();
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000198 exception->exceptionType = tinfo;
199 exception->exceptionDestructor = dest;
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000200 setExceptionClass(&exception->unwindHeader);
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000201 exception->referenceCount = 1; // This is a newly allocated exception, no need for thread safety.
202 globals->uncaughtExceptions += 1; // Not atomically, since globals are thread-local
203
204 exception->unwindHeader.exception_cleanup = exception_cleanup_func;
Howard Hinnanta6baba12011-12-08 19:35:18 +0000205#if __arm__
206 _Unwind_SjLj_RaiseException(&exception->unwindHeader);
207#else
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000208 _Unwind_RaiseException(&exception->unwindHeader);
Howard Hinnanta6baba12011-12-08 19:35:18 +0000209#endif
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000210// If we get here, some kind of unwinding error has occurred.
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000211 failed_throw(exception);
212}
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000213
214
215// 2.5.3 Exception Handlers
216extern void * __cxa_get_exception_ptr(void * exceptionObject) throw() {
Howard Hinnant6556bdb2012-01-08 23:40:41 +0000217// TODO: This must return the *adjusted* pointer to the exception object.
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000218 return exception_from_exception_object(exceptionObject);
219}
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000220
221
222/*
223This routine:
224* Increment's the exception's handler count.
225* Places the exception on the stack of currently-caught exceptions if it is not
226 already there, linking the exception to the previous top of the stack.
227* Decrements the uncaught_exception count.
228* Returns the adjusted pointer to the exception object.
229*/
230void * __cxa_begin_catch(void * exceptionObject) throw() {
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000231 __cxa_eh_globals *globals = __cxa_get_globals();
232 __cxa_exception *exception = exception_from_exception_object(exceptionObject);
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000233
Howard Hinnanta6baba12011-12-08 19:35:18 +0000234// TODO: Handle foreign exceptions? How?
235
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000236// Increment the handler count, removing the flag about being rethrown
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000237 exception->handlerCount = exception->handlerCount < 0 ?
238 -exception->handlerCount + 1 : exception->handlerCount + 1;
239
240// place the exception on the top of the stack if it's not there.
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000241 if (exception != globals->caughtExceptions) {
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000242 exception->nextException = globals->caughtExceptions;
243 globals->caughtExceptions = exception;
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000244 }
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000245
246 globals->uncaughtExceptions -= 1; // Not atomically, since globals are thread-local
Howard Hinnant6556bdb2012-01-08 23:40:41 +0000247 return __cxa_get_exception_ptr(exceptionObject);
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000248}
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000249
250
251/*
252Upon exit for any reason, a handler must call:
253 void __cxa_end_catch ();
254
255This routine:
256* Locates the most recently caught exception and decrements its handler count.
257* Removes the exception from the caught exception stack, if the handler count goes to zero.
Howard Hinnanta6baba12011-12-08 19:35:18 +0000258* If the handler count goes down to zero, and the exception was not re-thrown
259 by throw, it locates the primary exception (which may be the same as the one
260 it's handling) and decrements its reference count. If that reference count
261 goes to zero, the function destroys the exception. In any case, if the current
262 exception is a dependent exception, it destroys that.
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000263*/
264void __cxa_end_catch() {
Howard Hinnanta6baba12011-12-08 19:35:18 +0000265 __cxa_eh_globals *globals = __cxa_get_globals_fast(); // __cxa_get_globals called in __cxa_begin_catch
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000266 __cxa_exception *current_exception = globals->caughtExceptions;
267
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000268 if (NULL != current_exception) {
Howard Hinnant939daa72011-12-12 19:11:42 +0000269 // TODO: Handle foreign exceptions? How?
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000270 if (current_exception->handlerCount < 0) {
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000271 // The exception has been rethrown
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000272 if (0 == incrementHandlerCount(current_exception)) {
Howard Hinnanta6baba12011-12-08 19:35:18 +0000273 // Remove from the chain of uncaught exceptions
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000274 globals->caughtExceptions = current_exception->nextException;
Howard Hinnanta6baba12011-12-08 19:35:18 +0000275 // but don't destroy
276 }
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000277 }
Howard Hinnanta6baba12011-12-08 19:35:18 +0000278 else { // The exception has not been rethrown
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000279 if (0 == decrementHandlerCount(current_exception)) {
Howard Hinnanta6baba12011-12-08 19:35:18 +0000280 // Remove from the chain of uncaught exceptions
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000281 globals->caughtExceptions = current_exception->nextException;
Howard Hinnanta6baba12011-12-08 19:35:18 +0000282 if (isDependentException(&current_exception->unwindHeader)) {
283 // Reset current_exception to primaryException and deallocate the dependent exception
284 __cxa_dependent_exception* deh =
285 reinterpret_cast<__cxa_dependent_exception*>(current_exception + 1) - 1;
286 current_exception = static_cast<__cxa_exception*>(deh->primaryException) - 1;
287 __cxa_free_dependent_exception(deh);
288 }
289 // Destroy the primary exception only if its referenceCount goes to 0
290 // (this decrement must be atomic)
Howard Hinnantf7b47f72011-12-21 23:32:11 +0000291 __cxa_decrement_exception_refcount(thrown_object_from_exception(current_exception));
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000292 }
293 }
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000294 }
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000295}
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000296
297
298std::type_info * __cxa_current_exception_type() {
Howard Hinnant6556bdb2012-01-08 23:40:41 +0000299// FIXME: I don't think we need to drill down into __cxa_dependent_exception
300// because the exceptionType is replicated in the __cxa_dependent_exception
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000301// get the current exception
Marshall Clow143cfb02011-12-22 15:45:05 +0000302 __cxa_eh_globals *globals = __cxa_get_globals_fast();
303 if (NULL == globals)
304 return NULL; // If there have never been any exceptions, there are none now.
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000305 __cxa_exception *current_exception = globals->caughtExceptions;
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000306 if (NULL == current_exception)
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000307 return NULL; // No current exception
Howard Hinnantc2cd2252011-12-12 18:16:10 +0000308 if (isDependentException(&current_exception->unwindHeader)) {
309 __cxa_dependent_exception* deh =
310 reinterpret_cast<__cxa_dependent_exception*>(current_exception + 1) - 1;
311 current_exception = static_cast<__cxa_exception*>(deh->primaryException) - 1;
312 }
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000313 return current_exception->exceptionType;
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000314}
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000315
316// 2.5.4 Rethrowing Exceptions
317/* This routine
318* marks the exception object on top of the caughtExceptions stack
319 (in an implementation-defined way) as being rethrown.
320* If the caughtExceptions stack is empty, it calls terminate()
321 (see [C++FDIS] [except.throw], 15.1.8).
Howard Hinnant939daa72011-12-12 19:11:42 +0000322* It then calls _Unwind_Resume_or_Rethrow which should not return
323 (terminate if it does).
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000324*/
325extern LIBCXXABI_NORETURN void __cxa_rethrow() {
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000326 __cxa_eh_globals *globals = __cxa_get_globals();
Howard Hinnant939daa72011-12-12 19:11:42 +0000327 __cxa_exception *exception = globals->caughtExceptions;
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000328
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000329 if (NULL == exception) // there's no current exception!
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000330 std::terminate ();
331
Howard Hinnant939daa72011-12-12 19:11:42 +0000332// TODO: Handle foreign exceptions? How?
333
334// Mark the exception as being rethrown (reverse the effects of __cxa_begin_catch)
335 exception->handlerCount = -exception->handlerCount;
336 globals->uncaughtExceptions += 1;
337// __cxa_end_catch will remove this exception from the caughtExceptions stack if necessary
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000338
339#if __arm__
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000340 (void) _Unwind_SjLj_Resume_or_Rethrow(&exception->unwindHeader);
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000341#else
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000342 (void) _Unwind_Resume_or_Rethrow (&exception->unwindHeader);
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000343#endif
344
345// If we get here, some kind of unwinding error has occurred.
Marshall Clowfb69a8b2011-08-15 18:06:47 +0000346 failed_throw(exception);
347}
Marshall Clow3c54f1b2011-08-09 15:09:41 +0000348
Howard Hinnantf7b47f72011-12-21 23:32:11 +0000349/*
350 If p is not null, atomically increment the referenceCount field of the
351 __cxa_exception header associated with the thrown object referred to by p.
352*/
353void
354__cxa_increment_exception_refcount(void* p) throw()
355{
356 if (p != NULL )
357 {
358 __cxa_exception* header = exception_from_thrown_object(p);
359 __sync_add_and_fetch(&header->referenceCount, 1);
360 }
361}
362
363/*
364 If p is not null, atomically decrement the referenceCount field of the
365 __cxa_exception header associated with the thrown object referred to by p.
366 If the referenceCount drops to zero, destroy and deallocate the exception.
367*/
368void
369__cxa_decrement_exception_refcount(void* thrown_object) throw()
370{
371 if (thrown_object != NULL )
372 {
373 __cxa_exception* header = exception_from_thrown_object(thrown_object);
374 if (__sync_sub_and_fetch(&header->referenceCount, size_t(1)) == 0)
375 {
376 if (NULL != header->exceptionDestructor)
377 header->exceptionDestructor(thrown_object);
378 __cxa_free_exception(thrown_object);
379 }
380 }
381}
382
383/*
384 Returns a pointer to the thrown object (if any) at the top of the
385 caughtExceptions stack. Atommically increment the exception's referenceCount.
386 If there is no such thrown object, returns null.
Marshall Clow15997562012-01-04 22:18:10 +0000387
388 We can use __cxa_get_globals_fast here to get the globals because if there have
389 been no exceptions thrown, ever, on this thread, we can return NULL without
390 the need to allocate the exception-handling globals.
Howard Hinnantf7b47f72011-12-21 23:32:11 +0000391*/
392void*
393__cxa_current_primary_exception() throw()
394{
395// get the current exception
Marshall Clowe80ed7d2012-01-03 23:26:09 +0000396 __cxa_eh_globals* globals = __cxa_get_globals_fast();
Marshall Clow57908522012-01-03 23:10:20 +0000397 if (NULL == globals)
Marshall Clow8989e4e2012-01-04 14:56:09 +0000398 return NULL; // If there are no globals, there is no exception
Howard Hinnantf7b47f72011-12-21 23:32:11 +0000399 __cxa_exception* current_exception = globals->caughtExceptions;
400 if (NULL == current_exception)
401 return NULL; // No current exception
402 if (isDependentException(&current_exception->unwindHeader)) {
403 __cxa_dependent_exception* deh =
404 reinterpret_cast<__cxa_dependent_exception*>(current_exception + 1) - 1;
405 current_exception = static_cast<__cxa_exception*>(deh->primaryException) - 1;
406 }
407 void* thrown_object = thrown_object_from_exception(current_exception);
408 __cxa_increment_exception_refcount(thrown_object);
409 return thrown_object;
410}
411
412/*
413 If reason isn't _URC_FOREIGN_EXCEPTION_CAUGHT, then the terminateHandler
414 stored in exc is called. Otherwise the referenceCount stored in the
415 primary exception is decremented, destroying the primary if necessary.
416 Finally the dependent exception is destroyed.
417*/
418static
419void
420dependent_exception_cleanup(_Unwind_Reason_Code reason, struct _Unwind_Exception* exc)
421{
422 __cxa_dependent_exception* deh =
423 reinterpret_cast<__cxa_dependent_exception*>(exc + 1) - 1;
424 if (_URC_FOREIGN_EXCEPTION_CAUGHT != reason)
425 std::__terminate(deh->terminateHandler);
426 __cxa_decrement_exception_refcount(deh->primaryException);
427 __cxa_free_dependent_exception(deh);
428}
429
430/*
431 If thrown_object is not null, allocate, initialize and thow a dependent
432 exception.
433*/
434void
435__cxa_rethrow_primary_exception(void* thrown_object)
436{
437 if ( thrown_object != NULL )
438 {
439 __cxa_exception* header = exception_from_thrown_object(thrown_object);
440 __cxa_dependent_exception* deh =
441 (__cxa_dependent_exception*)__cxa_allocate_dependent_exception();
442 deh->primaryException = thrown_object;
443 __cxa_increment_exception_refcount(thrown_object);
444 deh->exceptionType = header->exceptionType;
445 deh->unexpectedHandler = std::get_unexpected();
446 deh->terminateHandler = std::get_terminate();
447 setDependentExceptionClass(&deh->unwindHeader);
Howard Hinnantb9bf50b2011-12-21 23:48:05 +0000448 __cxa_get_globals()->uncaughtExceptions += 1;
Howard Hinnantf7b47f72011-12-21 23:32:11 +0000449 deh->unwindHeader.exception_cleanup = dependent_exception_cleanup;
450#if __arm__
451 _Unwind_SjLj_RaiseException(&deh->unwindHeader);
452#else
453 _Unwind_RaiseException(&deh->unwindHeader);
454#endif
455 // Some sort of unwinding error. Note that terminate is a handler.
456 __cxa_begin_catch(&deh->unwindHeader);
457 }
458 // If we return client will call terminate()
459}
460
Marshall Clowe0252022011-07-20 15:04:39 +0000461} // extern "C"
462
463} // abi