Home | History | Annotate | Download | only in src
      1 //===------------------------ 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 #include <stdlib.h>
     10 #include <stdio.h>
     11 
     12 #include "exception"
     13 #include "new"
     14 
     15 #ifndef __has_include
     16 #define __has_include(inc) 0
     17 #endif
     18 
     19 #ifdef __APPLE__
     20   #include <cxxabi.h>
     21 
     22   using namespace __cxxabiv1;
     23   #define HAVE_DEPENDENT_EH_ABI 1
     24   #ifndef _LIBCPPABI_VERSION
     25     using namespace __cxxabiapple;
     26     // On Darwin, there are two STL shared libraries and a lower level ABI
     27     // shared library.  The globals holding the current terminate handler and
     28     // current unexpected handler are in the ABI library.
     29     #define __terminate_handler  __cxxabiapple::__cxa_terminate_handler
     30     #define __unexpected_handler __cxxabiapple::__cxa_unexpected_handler
     31   #endif  // _LIBCPPABI_VERSION
     32 #elif defined(LIBCXXRT) || __has_include(<cxxabi.h>) || defined(__ANDROID__)
     33   #include <cxxabi.h>
     34   using namespace __cxxabiv1;
     35   #if defined(LIBCXXRT) || defined(_LIBCPPABI_VERSION)
     36     #define HAVE_DEPENDENT_EH_ABI 1
     37   #endif
     38 #elif !defined(__GLIBCXX__) // __has_include(<cxxabi.h>)
     39   static std::terminate_handler  __terminate_handler;
     40   static std::unexpected_handler __unexpected_handler;
     41 #endif // __has_include(<cxxabi.h>)
     42 
     43 namespace std
     44 {
     45 
     46 #if !defined(LIBCXXRT) && !defined(_LIBCPPABI_VERSION) && !defined(__GLIBCXX__)
     47 
     48 // libcxxrt provides implementations of these functions itself.
     49 unexpected_handler
     50 set_unexpected(unexpected_handler func) _NOEXCEPT
     51 {
     52     return __sync_lock_test_and_set(&__unexpected_handler, func);
     53 }
     54 
     55 unexpected_handler
     56 get_unexpected() _NOEXCEPT
     57 {
     58     return __sync_fetch_and_add(&__unexpected_handler, (unexpected_handler)0);
     59 }
     60 
     61 _LIBCPP_NORETURN
     62 void
     63 unexpected()
     64 {
     65     (*get_unexpected())();
     66     // unexpected handler should not return
     67     terminate();
     68 }
     69 
     70 terminate_handler
     71 set_terminate(terminate_handler func) _NOEXCEPT
     72 {
     73     return __sync_lock_test_and_set(&__terminate_handler, func);
     74 }
     75 
     76 terminate_handler
     77 get_terminate() _NOEXCEPT
     78 {
     79     return __sync_fetch_and_add(&__terminate_handler, (terminate_handler)0);
     80 }
     81 
     82 #ifndef __EMSCRIPTEN__ // We provide this in JS
     83 _LIBCPP_NORETURN
     84 void
     85 terminate() _NOEXCEPT
     86 {
     87 #ifndef _LIBCPP_NO_EXCEPTIONS
     88     try
     89     {
     90 #endif  // _LIBCPP_NO_EXCEPTIONS
     91         (*get_terminate())();
     92         // handler should not return
     93         printf("terminate_handler unexpectedly returned\n");
     94         ::abort();
     95 #ifndef _LIBCPP_NO_EXCEPTIONS
     96     }
     97     catch (...)
     98     {
     99         // handler should not throw exception
    100         printf("terminate_handler unexpectedly threw an exception\n");
    101         ::abort();
    102     }
    103 #endif  // _LIBCPP_NO_EXCEPTIONS
    104 }
    105 #endif // !__EMSCRIPTEN__
    106 #endif // !defined(LIBCXXRT) && !defined(_LIBCPPABI_VERSION)
    107 
    108 #if !defined(LIBCXXRT) && !defined(__GLIBCXX__) && !defined(__EMSCRIPTEN__)
    109 bool uncaught_exception() _NOEXCEPT
    110 {
    111 #if defined(__APPLE__) || defined(_LIBCPPABI_VERSION)
    112     // on Darwin, there is a helper function so __cxa_get_globals is private
    113     return __cxa_uncaught_exception();
    114 #else  // __APPLE__
    115 #   if defined(_MSC_VER) && ! defined(__clang__)
    116         _LIBCPP_WARNING("uncaught_exception not yet implemented")
    117 #   else
    118 #       warning uncaught_exception not yet implemented
    119 #   endif
    120     printf("uncaught_exception not yet implemented\n");
    121     ::abort();
    122 #endif  // __APPLE__
    123 }
    124 
    125 
    126 #ifndef _LIBCPPABI_VERSION
    127 
    128 exception::~exception() _NOEXCEPT
    129 {
    130 }
    131 
    132 const char* exception::what() const _NOEXCEPT
    133 {
    134   return "std::exception";
    135 }
    136 
    137 #endif  // _LIBCPPABI_VERSION
    138 #endif //LIBCXXRT
    139 #if !defined(_LIBCPPABI_VERSION) && !defined(__GLIBCXX__)
    140 
    141 bad_exception::~bad_exception() _NOEXCEPT
    142 {
    143 }
    144 
    145 const char* bad_exception::what() const _NOEXCEPT
    146 {
    147   return "std::bad_exception";
    148 }
    149 
    150 #endif
    151 
    152 #if defined(__GLIBCXX__)
    153 
    154 // libsupc++ does not implement the dependent EH ABI and the functionality
    155 // it uses to implement std::exception_ptr (which it declares as an alias of
    156 // std::__exception_ptr::exception_ptr) is not directly exported to clients. So
    157 // we have little choice but to hijack std::__exception_ptr::exception_ptr's
    158 // (which fortunately has the same layout as our std::exception_ptr) copy
    159 // constructor, assignment operator and destructor (which are part of its
    160 // stable ABI), and its rethrow_exception(std::__exception_ptr::exception_ptr)
    161 // function.
    162 
    163 namespace __exception_ptr
    164 {
    165 
    166 struct exception_ptr
    167 {
    168     void* __ptr_;
    169 
    170     exception_ptr(const exception_ptr&) _NOEXCEPT;
    171     exception_ptr& operator=(const exception_ptr&) _NOEXCEPT;
    172     ~exception_ptr() _NOEXCEPT;
    173 };
    174 
    175 }
    176 
    177 _LIBCPP_NORETURN void rethrow_exception(__exception_ptr::exception_ptr);
    178 
    179 #endif
    180 
    181 exception_ptr::~exception_ptr() _NOEXCEPT
    182 {
    183 #if HAVE_DEPENDENT_EH_ABI
    184     __cxa_decrement_exception_refcount(__ptr_);
    185 #elif defined(__GLIBCXX__)
    186     reinterpret_cast<__exception_ptr::exception_ptr*>(this)->~exception_ptr();
    187 #else
    188 #   if defined(_MSC_VER) && ! defined(__clang__)
    189         _LIBCPP_WARNING("exception_ptr not yet implemented")
    190 #   else
    191 #       warning exception_ptr not yet implemented
    192 #   endif
    193     printf("exception_ptr not yet implemented\n");
    194     ::abort();
    195 #endif
    196 }
    197 
    198 exception_ptr::exception_ptr(const exception_ptr& other) _NOEXCEPT
    199     : __ptr_(other.__ptr_)
    200 {
    201 #if HAVE_DEPENDENT_EH_ABI
    202     __cxa_increment_exception_refcount(__ptr_);
    203 #elif defined(__GLIBCXX__)
    204     new (reinterpret_cast<void*>(this)) __exception_ptr::exception_ptr(
    205         reinterpret_cast<const __exception_ptr::exception_ptr&>(other));
    206 #else
    207 #   if defined(_MSC_VER) && ! defined(__clang__)
    208         _LIBCPP_WARNING("exception_ptr not yet implemented")
    209 #   else
    210 #       warning exception_ptr not yet implemented
    211 #   endif
    212     printf("exception_ptr not yet implemented\n");
    213     ::abort();
    214 #endif
    215 }
    216 
    217 exception_ptr& exception_ptr::operator=(const exception_ptr& other) _NOEXCEPT
    218 {
    219 #if HAVE_DEPENDENT_EH_ABI
    220     if (__ptr_ != other.__ptr_)
    221     {
    222         __cxa_increment_exception_refcount(other.__ptr_);
    223         __cxa_decrement_exception_refcount(__ptr_);
    224         __ptr_ = other.__ptr_;
    225     }
    226     return *this;
    227 #elif defined(__GLIBCXX__)
    228     *reinterpret_cast<__exception_ptr::exception_ptr*>(this) =
    229         reinterpret_cast<const __exception_ptr::exception_ptr&>(other);
    230     return *this;
    231 #else
    232 #   if defined(_MSC_VER) && ! defined(__clang__)
    233         _LIBCPP_WARNING("exception_ptr not yet implemented")
    234 #   else
    235 #       warning exception_ptr not yet implemented
    236 #   endif
    237     printf("exception_ptr not yet implemented\n");
    238     ::abort();
    239 #endif
    240 }
    241 
    242 nested_exception::nested_exception() _NOEXCEPT
    243     : __ptr_(current_exception())
    244 {
    245 }
    246 
    247 #if !defined(__GLIBCXX__)
    248 
    249 nested_exception::~nested_exception() _NOEXCEPT
    250 {
    251 }
    252 
    253 #endif
    254 
    255 _LIBCPP_NORETURN
    256 void
    257 nested_exception::rethrow_nested() const
    258 {
    259     if (__ptr_ == nullptr)
    260         terminate();
    261     rethrow_exception(__ptr_);
    262 }
    263 
    264 #if !defined(__GLIBCXX__)
    265 
    266 exception_ptr current_exception() _NOEXCEPT
    267 {
    268 #if HAVE_DEPENDENT_EH_ABI
    269     // be nicer if there was a constructor that took a ptr, then
    270     // this whole function would be just:
    271     //    return exception_ptr(__cxa_current_primary_exception());
    272     exception_ptr ptr;
    273     ptr.__ptr_ = __cxa_current_primary_exception();
    274     return ptr;
    275 #else
    276 #   if defined(_MSC_VER) && ! defined(__clang__)
    277         _LIBCPP_WARNING( "exception_ptr not yet implemented" )
    278 #   else
    279 #       warning exception_ptr not yet implemented
    280 #   endif
    281     printf("exception_ptr not yet implemented\n");
    282     ::abort();
    283 #endif
    284 }
    285 
    286 #endif  // !__GLIBCXX__
    287 
    288 _LIBCPP_NORETURN
    289 void rethrow_exception(exception_ptr p)
    290 {
    291 #if HAVE_DEPENDENT_EH_ABI
    292     __cxa_rethrow_primary_exception(p.__ptr_);
    293     // if p.__ptr_ is NULL, above returns so we terminate
    294     terminate();
    295 #elif defined(__GLIBCXX__)
    296     rethrow_exception(reinterpret_cast<__exception_ptr::exception_ptr&>(p));
    297 #else
    298 #   if defined(_MSC_VER) && ! defined(__clang__)
    299         _LIBCPP_WARNING("exception_ptr not yet implemented")
    300 #   else
    301 #       warning exception_ptr not yet implemented
    302 #   endif
    303     printf("exception_ptr not yet implemented\n");
    304     ::abort();
    305 #endif
    306 }
    307 } // std
    308