OLD | NEW |
(Empty) | |
| 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>) |
| 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 |
OLD | NEW |