diff options
author | Chris Lattner <sabre@nondot.org> | 2003-08-25 22:35:36 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2003-08-25 22:35:36 +0000 |
commit | 5337521c2b04f5dce02b3ce9a8d231c4273ab3fd (patch) | |
tree | 4c3386537caff6a2ae64eeba7dd081b5435d1592 /runtime/GCCLibraries/libexception/C++-Exception.cpp | |
parent | bfa964699f2ee6390a713bd1f77953d61e38e93d (diff) |
Initial checking of C++ exception handling library
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@8146 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'runtime/GCCLibraries/libexception/C++-Exception.cpp')
-rw-r--r-- | runtime/GCCLibraries/libexception/C++-Exception.cpp | 223 |
1 files changed, 223 insertions, 0 deletions
diff --git a/runtime/GCCLibraries/libexception/C++-Exception.cpp b/runtime/GCCLibraries/libexception/C++-Exception.cpp new file mode 100644 index 0000000000..7ed78688ea --- /dev/null +++ b/runtime/GCCLibraries/libexception/C++-Exception.cpp @@ -0,0 +1,223 @@ +//===- c++-exception.cpp - Exception handling support for C++ exceptions --===// +// +// This file defines the methods used to implement C++ exception handling in +// terms of the invoke and %llvm.unwind intrinsic. These primitives implement +// an exception handling ABI similar (but simpler and more efficient than) the +// Itanium C++ ABI exception handling standard. +// +//===----------------------------------------------------------------------===// + +#include "c++-exception.h" +#include <cstdlib> +#include <cassert> + +//===----------------------------------------------------------------------===// +// Generic exception support +// + +// Thread local state for exception handling. +// FIXME: This should really be made thread-local! +// +static llvm_exception *CaughtExceptionStack = 0; + +// UncaughtExceptionStack - The stack of exceptions currently being thrown. +static llvm_exception *UncaughtExceptionStack = 0; + +// __llvm_eh_has_uncaught_exception - This is used to implement +// std::uncaught_exception. +// +bool __llvm_eh_has_uncaught_exception(void) { + return UncaughtExceptionStack != 0; +} + +// __llvm_eh_current_uncaught_exception - This function checks to see if the +// current uncaught exception is of the specified language type. If so, it +// returns a pointer to the exception area data. +// +void *__llvm_eh_current_uncaught_exception_type(unsigned HandlerType) { + assert(UncaughtExceptionStack && "No uncaught exception!"); + if (UncaughtExceptionStack->ExceptionType == HandlerType) + return UncaughtExceptionStack+1; + return 0; +} + + +/*===----------------------------------------------------------------------===** + * C++ Specific exception handling support... + */ + +// __llvm_cxxeh_allocate_exception - This function allocates space for the +// specified number of bytes, plus a C++ exception object header. +// +void *__llvm_cxxeh_allocate_exception(unsigned NumBytes) { + // FIXME: This should eventually have back-up buffers for out-of-memory + // situations. + // + llvm_cxx_exception *E = + (llvm_cxx_exception *)malloc(NumBytes+sizeof(llvm_cxx_exception)); + E->BaseException.ExceptionType = 0; // intialize to invalid + + return E+1; // return the pointer after the header +} + +// __llvm_cxxeh_free_exception - Low-level function to free an exception. This +// is called directly from generated C++ code if evaluating the exception value +// into the exception location throws. Otherwise it is called from the C++ +// exception object destructor. +// +void __llvm_cxxeh_free_exception(void *ObjectPtr) { + llvm_cxx_exception *E = (llvm_cxx_exception *)ObjectPtr - 1; + free(E); +} + +// cxx_destructor - This function is called through the generic +// exception->ExceptionDestructor function pointer to destroy a caught +// exception. +// +static void cxx_destructor(llvm_exception *LE) { + void *ObjectPtr = LE+1; + llvm_cxx_exception *E = (llvm_cxx_exception *)ObjectPtr - 1; + + // The exception is no longer caught. + assert(CaughtExceptionStack == LE && + "Destroying an exception which is not the current caught exception?"); + CaughtExceptionStack = LE->Next; + + struct ExceptionFreer { + void *Ptr; + ExceptionFreer(void *P) : Ptr(P) {} + ~ExceptionFreer() { + // Free the memory for the exception, when the function is left, even if + // the exception object dtor throws its own exception! + __llvm_cxxeh_free_exception(Ptr); + } + } EF(E+1); + + // Run the exception object dtor if it exists. */ + if (E->ExceptionObjectDestructor) + E->ExceptionObjectDestructor(E); +} + +// __llvm_cxxeh_throw - Given a pointer to memory which has an exception object +// evaluated into it, this sets up all of the fields of the exception allowing +// it to be thrown. After calling this, the code should call %llvm.unwind +// +void __llvm_cxxeh_throw(void *ObjectPtr, const std::type_info *TypeInfoPtr, + void (*DtorPtr)(void*)) { + llvm_cxx_exception *E = (llvm_cxx_exception *)ObjectPtr - 1; + E->BaseException.ExceptionDestructor = cxx_destructor; + E->BaseException.ExceptionType = CXXException; + E->BaseException.Next = UncaughtExceptionStack; + UncaughtExceptionStack = &E->BaseException; + E->BaseException.HandlerCount = 0; + + E->TypeInfo = TypeInfoPtr; + E->ExceptionObjectDestructor = DtorPtr; + E->UnexpectedHandler = 0; /* FIXME */ + E->TerminateHandler = 0; /* FIXME */ +} + +// __llvm_cxxeh_current_uncaught_exception_isa - This function checks to see if +// the current uncaught exception is a C++ exception, and if it is of the +// specified type id. If so, it returns a pointer to the object adjusted as +// appropriate, otherwise it returns null. +// +void *__llvm_cxxeh_current_uncaught_exception_isa( + const std::type_info *CatchType) { + assert(UncaughtExceptionStack && "No uncaught exception!"); + if (UncaughtExceptionStack->ExceptionType != CXXException) + return 0; /* If it's not a c++ exception, it doesn't match! */ + + // If it is a C++ exception, use the type info object stored in the exception + // to see if TypeID matches and, if so, to adjust the exception object + // pointer. + // + llvm_cxx_exception *E = (llvm_cxx_exception*)UncaughtExceptionStack; + + // ThrownPtr is a pointer to the object being thrown... + void *ThrownPtr = E+1; + const std::type_info *ThrownType = E->TypeInfo; + + // FIXME: this code exists in the GCC exception handling library: I haven't + // thought about this yet, so it should be verified at some point! +#if 1 + // Pointer types need to adjust the actual pointer, not + // the pointer to pointer that is the exception object. + // This also has the effect of passing pointer types + // "by value" through the __cxa_begin_catch return value. + if (ThrownType->__is_pointer_p()) + ThrownPtr = *(void **)ThrownPtr; +#endif + + if (CatchType->__do_catch(ThrownType, &ThrownPtr, 1)) + return ThrownPtr; + + return 0; +} + + +/* __llvm_cxxeh_begin_catch - This function is called by "exception handlers", + * which transition an exception from being uncaught to being caught. It + * returns a pointer to the exception object portion of the exception. This + * function must work with foreign exceptions. + */ +void *__llvm_cxxeh_begin_catch(void) { + llvm_exception *E = UncaughtExceptionStack; + assert(UncaughtExceptionStack && "There are no uncaught exceptions!?!?"); + + /* The exception is now no longer uncaught... */ + UncaughtExceptionStack = E->Next; + + /* The exception is now caught... */ + E->Next = CaughtExceptionStack; + CaughtExceptionStack = E->Next; + + /* Increment the handler count for this exception. */ + E->HandlerCount++; + + /* Return a pointer to the exception object */ + return E+1; +} + +/* __llvm_cxxeh_end_catch - This function decrements the HandlerCount of the + * top-level caught exception, destroying it if this is the last handler for the + * exception. + */ +void __llvm_cxxeh_end_catch(void) { + llvm_exception *E = CaughtExceptionStack; + assert(E && "There are no caught exceptions!"); + + /* If this is the last handler using the exception, destroy it now! */ + if (--E->HandlerCount == 0) { + CaughtExceptionStack = E->Next; /* Unlink from the stack */ + E->ExceptionDestructor(E); /* Release memory for the exception */ + } +} + +/* __llvm_cxxeh_rethrow - This function turns the top-level caught exception + * into an uncaught exception, in preparation for an llvm.unwind, which should + * follow immediately after the call to this function. This function must be + * prepared to deal with foreign exceptions. + */ +void __llvm_cxxeh_rethrow(void) { + llvm_exception *E = CaughtExceptionStack; + if (E == 0) { + /* 15.1.8 - If there are no uncaught exceptions being thrown, 'throw;' + * should call terminate. + */ + /* FIXME */assert(0 && "FIXME: this should call E->Terminate!"); + } + + /* Otherwise we have an exception to rethrow. Move it back to the uncaught + * stack. + */ + CaughtExceptionStack = E->Next; + E->Next = UncaughtExceptionStack; + UncaughtExceptionStack = E; + + /* Decrement the number of handlers which are using the exception. */ + --E->HandlerCount; + + /* Return to the caller, which should perform the unwind now. */ +} + |