1227825Stheraven//===------------------------ exception.cpp -------------------------------===// 2227825Stheraven// 3227825Stheraven// The LLVM Compiler Infrastructure 4227825Stheraven// 5227825Stheraven// This file is dual licensed under the MIT and the University of Illinois Open 6227825Stheraven// Source Licenses. See LICENSE.TXT for details. 7227825Stheraven// 8227825Stheraven//===----------------------------------------------------------------------===// 9227825Stheraven#include <stdlib.h> 10262801Sdim#include <stdio.h> 11227825Stheraven 12227825Stheraven#include "exception" 13262801Sdim#include "new" 14227825Stheraven 15241903Sdim#ifndef __has_include 16241903Sdim#define __has_include(inc) 0 17241903Sdim#endif 18241903Sdim 19278724Sdim#if defined(__APPLE__) && !defined(LIBCXXRT) 20227825Stheraven #include <cxxabi.h> 21232950Stheraven 22227825Stheraven using namespace __cxxabiv1; 23227825Stheraven #define HAVE_DEPENDENT_EH_ABI 1 24232950Stheraven #ifndef _LIBCPPABI_VERSION 25232950Stheraven using namespace __cxxabiapple; 26232950Stheraven // On Darwin, there are two STL shared libraries and a lower level ABI 27262801Sdim // shared library. The globals holding the current terminate handler and 28232950Stheraven // current unexpected handler are in the ABI library. 29232950Stheraven #define __terminate_handler __cxxabiapple::__cxa_terminate_handler 30232950Stheraven #define __unexpected_handler __cxxabiapple::__cxa_unexpected_handler 31232950Stheraven #endif // _LIBCPPABI_VERSION 32241903Sdim#elif defined(LIBCXXRT) || __has_include(<cxxabi.h>) 33227825Stheraven #include <cxxabi.h> 34227825Stheraven using namespace __cxxabiv1; 35241903Sdim #if defined(LIBCXXRT) || defined(_LIBCPPABI_VERSION) 36241903Sdim #define HAVE_DEPENDENT_EH_ABI 1 37241903Sdim #endif 38246487Stheraven#elif !defined(__GLIBCXX__) // __has_include(<cxxabi.h>) 39227825Stheraven static std::terminate_handler __terminate_handler; 40227825Stheraven static std::unexpected_handler __unexpected_handler; 41241903Sdim#endif // __has_include(<cxxabi.h>) 42227825Stheraven 43232950Stheravennamespace std 44232950Stheraven{ 45232950Stheraven 46246487Stheraven#if !defined(LIBCXXRT) && !defined(_LIBCPPABI_VERSION) && !defined(__GLIBCXX__) 47232950Stheraven 48227825Stheraven// libcxxrt provides implementations of these functions itself. 49232950Stheravenunexpected_handler 50232950Stheravenset_unexpected(unexpected_handler func) _NOEXCEPT 51227825Stheraven{ 52227825Stheraven return __sync_lock_test_and_set(&__unexpected_handler, func); 53227825Stheraven} 54227825Stheraven 55232950Stheravenunexpected_handler 56232950Stheravenget_unexpected() _NOEXCEPT 57227825Stheraven{ 58232950Stheraven return __sync_fetch_and_add(&__unexpected_handler, (unexpected_handler)0); 59227825Stheraven} 60227825Stheraven 61241903Sdim_LIBCPP_NORETURN 62227825Stheravenvoid 63232950Stheravenunexpected() 64227825Stheraven{ 65232950Stheraven (*get_unexpected())(); 66227825Stheraven // unexpected handler should not return 67232950Stheraven terminate(); 68227825Stheraven} 69227825Stheraven 70232950Stheraventerminate_handler 71232950Stheravenset_terminate(terminate_handler func) _NOEXCEPT 72227825Stheraven{ 73227825Stheraven return __sync_lock_test_and_set(&__terminate_handler, func); 74227825Stheraven} 75227825Stheraven 76232950Stheraventerminate_handler 77232950Stheravenget_terminate() _NOEXCEPT 78227825Stheraven{ 79232950Stheraven return __sync_fetch_and_add(&__terminate_handler, (terminate_handler)0); 80227825Stheraven} 81227825Stheraven 82262801Sdim#ifndef __EMSCRIPTEN__ // We provide this in JS 83241903Sdim_LIBCPP_NORETURN 84227825Stheravenvoid 85232950Stheraventerminate() _NOEXCEPT 86227825Stheraven{ 87227825Stheraven#ifndef _LIBCPP_NO_EXCEPTIONS 88227825Stheraven try 89227825Stheraven { 90227825Stheraven#endif // _LIBCPP_NO_EXCEPTIONS 91232950Stheraven (*get_terminate())(); 92227825Stheraven // handler should not return 93262801Sdim printf("terminate_handler unexpectedly returned\n"); 94262801Sdim ::abort(); 95227825Stheraven#ifndef _LIBCPP_NO_EXCEPTIONS 96227825Stheraven } 97227825Stheraven catch (...) 98227825Stheraven { 99227825Stheraven // handler should not throw exception 100262801Sdim printf("terminate_handler unexpectedly threw an exception\n"); 101262801Sdim ::abort(); 102227825Stheraven } 103227825Stheraven#endif // _LIBCPP_NO_EXCEPTIONS 104227825Stheraven} 105262801Sdim#endif // !__EMSCRIPTEN__ 106232950Stheraven#endif // !defined(LIBCXXRT) && !defined(_LIBCPPABI_VERSION) 107227825Stheraven 108262801Sdim#if !defined(LIBCXXRT) && !defined(__GLIBCXX__) && !defined(__EMSCRIPTEN__) 109232950Stheravenbool uncaught_exception() _NOEXCEPT 110227825Stheraven{ 111249998Sdim#if defined(__APPLE__) || defined(_LIBCPPABI_VERSION) 112227825Stheraven // on Darwin, there is a helper function so __cxa_get_globals is private 113232950Stheraven return __cxa_uncaught_exception(); 114227825Stheraven#else // __APPLE__ 115262801Sdim# if defined(_MSC_VER) && ! defined(__clang__) 116262801Sdim _LIBCPP_WARNING("uncaught_exception not yet implemented") 117262801Sdim# else 118262801Sdim# warning uncaught_exception not yet implemented 119262801Sdim# endif 120262801Sdim printf("uncaught_exception not yet implemented\n"); 121227825Stheraven ::abort(); 122227825Stheraven#endif // __APPLE__ 123227825Stheraven} 124227825Stheraven 125262801Sdim 126232950Stheraven#ifndef _LIBCPPABI_VERSION 127227825Stheraven 128227825Stheravenexception::~exception() _NOEXCEPT 129227825Stheraven{ 130227825Stheraven} 131227825Stheraven 132232972Stheravenconst char* exception::what() const _NOEXCEPT 133227825Stheraven{ 134232972Stheraven return "std::exception"; 135227825Stheraven} 136227825Stheraven 137232972Stheraven#endif // _LIBCPPABI_VERSION 138232972Stheraven#endif //LIBCXXRT 139246487Stheraven#if !defined(_LIBCPPABI_VERSION) && !defined(__GLIBCXX__) 140232972Stheraven 141232972Stheravenbad_exception::~bad_exception() _NOEXCEPT 142227825Stheraven{ 143227825Stheraven} 144227825Stheraven 145227825Stheravenconst char* bad_exception::what() const _NOEXCEPT 146227825Stheraven{ 147227825Stheraven return "std::bad_exception"; 148227825Stheraven} 149227825Stheraven 150232972Stheraven#endif 151232950Stheraven 152262801Sdim#if defined(__GLIBCXX__) 153232972Stheraven 154262801Sdim// libsupc++ does not implement the dependent EH ABI and the functionality 155262801Sdim// it uses to implement std::exception_ptr (which it declares as an alias of 156262801Sdim// std::__exception_ptr::exception_ptr) is not directly exported to clients. So 157262801Sdim// we have little choice but to hijack std::__exception_ptr::exception_ptr's 158262801Sdim// (which fortunately has the same layout as our std::exception_ptr) copy 159262801Sdim// constructor, assignment operator and destructor (which are part of its 160262801Sdim// stable ABI), and its rethrow_exception(std::__exception_ptr::exception_ptr) 161262801Sdim// function. 162262801Sdim 163262801Sdimnamespace __exception_ptr 164262801Sdim{ 165262801Sdim 166262801Sdimstruct exception_ptr 167262801Sdim{ 168262801Sdim void* __ptr_; 169262801Sdim 170262801Sdim exception_ptr(const exception_ptr&) _NOEXCEPT; 171262801Sdim exception_ptr& operator=(const exception_ptr&) _NOEXCEPT; 172262801Sdim ~exception_ptr() _NOEXCEPT; 173262801Sdim}; 174262801Sdim 175262801Sdim} 176262801Sdim 177262801Sdim_LIBCPP_NORETURN void rethrow_exception(__exception_ptr::exception_ptr); 178262801Sdim 179262801Sdim#endif 180262801Sdim 181227825Stheravenexception_ptr::~exception_ptr() _NOEXCEPT 182227825Stheraven{ 183227825Stheraven#if HAVE_DEPENDENT_EH_ABI 184227825Stheraven __cxa_decrement_exception_refcount(__ptr_); 185262801Sdim#elif defined(__GLIBCXX__) 186262801Sdim reinterpret_cast<__exception_ptr::exception_ptr*>(this)->~exception_ptr(); 187227825Stheraven#else 188262801Sdim# if defined(_MSC_VER) && ! defined(__clang__) 189262801Sdim _LIBCPP_WARNING("exception_ptr not yet implemented") 190262801Sdim# else 191262801Sdim# warning exception_ptr not yet implemented 192262801Sdim# endif 193262801Sdim printf("exception_ptr not yet implemented\n"); 194227825Stheraven ::abort(); 195262801Sdim#endif 196227825Stheraven} 197227825Stheraven 198227825Stheravenexception_ptr::exception_ptr(const exception_ptr& other) _NOEXCEPT 199227825Stheraven : __ptr_(other.__ptr_) 200227825Stheraven{ 201227825Stheraven#if HAVE_DEPENDENT_EH_ABI 202227825Stheraven __cxa_increment_exception_refcount(__ptr_); 203262801Sdim#elif defined(__GLIBCXX__) 204262801Sdim new (reinterpret_cast<void*>(this)) __exception_ptr::exception_ptr( 205262801Sdim reinterpret_cast<const __exception_ptr::exception_ptr&>(other)); 206227825Stheraven#else 207262801Sdim# if defined(_MSC_VER) && ! defined(__clang__) 208262801Sdim _LIBCPP_WARNING("exception_ptr not yet implemented") 209262801Sdim# else 210262801Sdim# warning exception_ptr not yet implemented 211262801Sdim# endif 212262801Sdim printf("exception_ptr not yet implemented\n"); 213227825Stheraven ::abort(); 214262801Sdim#endif 215227825Stheraven} 216227825Stheraven 217227825Stheravenexception_ptr& exception_ptr::operator=(const exception_ptr& other) _NOEXCEPT 218227825Stheraven{ 219227825Stheraven#if HAVE_DEPENDENT_EH_ABI 220227825Stheraven if (__ptr_ != other.__ptr_) 221227825Stheraven { 222227825Stheraven __cxa_increment_exception_refcount(other.__ptr_); 223227825Stheraven __cxa_decrement_exception_refcount(__ptr_); 224227825Stheraven __ptr_ = other.__ptr_; 225227825Stheraven } 226227825Stheraven return *this; 227262801Sdim#elif defined(__GLIBCXX__) 228262801Sdim *reinterpret_cast<__exception_ptr::exception_ptr*>(this) = 229262801Sdim reinterpret_cast<const __exception_ptr::exception_ptr&>(other); 230262801Sdim return *this; 231262801Sdim#else 232262801Sdim# if defined(_MSC_VER) && ! defined(__clang__) 233262801Sdim _LIBCPP_WARNING("exception_ptr not yet implemented") 234262801Sdim# else 235262801Sdim# warning exception_ptr not yet implemented 236262801Sdim# endif 237262801Sdim printf("exception_ptr not yet implemented\n"); 238227825Stheraven ::abort(); 239262801Sdim#endif 240227825Stheraven} 241227825Stheraven 242227825Stheravennested_exception::nested_exception() _NOEXCEPT 243227825Stheraven : __ptr_(current_exception()) 244227825Stheraven{ 245227825Stheraven} 246227825Stheraven 247262801Sdim#if !defined(__GLIBCXX__) 248262801Sdim 249227825Stheravennested_exception::~nested_exception() _NOEXCEPT 250227825Stheraven{ 251227825Stheraven} 252227825Stheraven 253262801Sdim#endif 254262801Sdim 255241903Sdim_LIBCPP_NORETURN 256227825Stheravenvoid 257227825Stheravennested_exception::rethrow_nested() const 258227825Stheraven{ 259227825Stheraven if (__ptr_ == nullptr) 260227825Stheraven terminate(); 261227825Stheraven rethrow_exception(__ptr_); 262227825Stheraven} 263227825Stheraven 264262801Sdim#if !defined(__GLIBCXX__) 265227825Stheraven 266232950Stheravenexception_ptr current_exception() _NOEXCEPT 267227825Stheraven{ 268227825Stheraven#if HAVE_DEPENDENT_EH_ABI 269227825Stheraven // be nicer if there was a constructor that took a ptr, then 270227825Stheraven // this whole function would be just: 271227825Stheraven // return exception_ptr(__cxa_current_primary_exception()); 272232950Stheraven exception_ptr ptr; 273227825Stheraven ptr.__ptr_ = __cxa_current_primary_exception(); 274227825Stheraven return ptr; 275262801Sdim#else 276262801Sdim# if defined(_MSC_VER) && ! defined(__clang__) 277262801Sdim _LIBCPP_WARNING( "exception_ptr not yet implemented" ) 278262801Sdim# else 279262801Sdim# warning exception_ptr not yet implemented 280262801Sdim# endif 281262801Sdim printf("exception_ptr not yet implemented\n"); 282227825Stheraven ::abort(); 283262801Sdim#endif 284227825Stheraven} 285227825Stheraven 286262801Sdim#endif // !__GLIBCXX__ 287262801Sdim 288241903Sdim_LIBCPP_NORETURN 289232950Stheravenvoid rethrow_exception(exception_ptr p) 290227825Stheraven{ 291227825Stheraven#if HAVE_DEPENDENT_EH_ABI 292227825Stheraven __cxa_rethrow_primary_exception(p.__ptr_); 293227825Stheraven // if p.__ptr_ is NULL, above returns so we terminate 294227825Stheraven terminate(); 295262801Sdim#elif defined(__GLIBCXX__) 296262801Sdim rethrow_exception(reinterpret_cast<__exception_ptr::exception_ptr&>(p)); 297262801Sdim#else 298262801Sdim# if defined(_MSC_VER) && ! defined(__clang__) 299262801Sdim _LIBCPP_WARNING("exception_ptr not yet implemented") 300262801Sdim# else 301262801Sdim# warning exception_ptr not yet implemented 302262801Sdim# endif 303262801Sdim printf("exception_ptr not yet implemented\n"); 304227825Stheraven ::abort(); 305262801Sdim#endif 306227825Stheraven} 307232950Stheraven} // std 308