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 
11 #include "exception"
12 
13 #if __APPLE__
14   #include <cxxabi.h>
15 
16   using namespace __cxxabiv1;
17   #define HAVE_DEPENDENT_EH_ABI 1
18   #ifndef _LIBCPPABI_VERSION
19     using namespace __cxxabiapple;
20     // On Darwin, there are two STL shared libraries and a lower level ABI
21     // shared libray.  The globals holding the current terminate handler and
22     // current unexpected handler are in the ABI library.
23     #define __terminate_handler  __cxxabiapple::__cxa_terminate_handler
24     #define __unexpected_handler __cxxabiapple::__cxa_unexpected_handler
25   #endif  // _LIBCPPABI_VERSION
26 #elif defined(LIBCXXRT)
27   #include <cxxabi.h>
28   using namespace __cxxabiv1;
29   #define HAVE_DEPENDENT_EH_ABI 1
30 #else  // __APPLE__
31   static std::terminate_handler  __terminate_handler;
32   static std::unexpected_handler __unexpected_handler;
33 #endif  // __APPLE__
34 
35 namespace std
36 {
37 
38 #if !defined(LIBCXXRT) && !defined(_LIBCPPABI_VERSION)
39 
40 // libcxxrt provides implementations of these functions itself.
41 unexpected_handler
42 set_unexpected(unexpected_handler func) _NOEXCEPT
43 {
44     return __sync_lock_test_and_set(&__unexpected_handler, func);
45 }
46 
47 unexpected_handler
48 get_unexpected() _NOEXCEPT
49 {
50     return __sync_fetch_and_add(&__unexpected_handler, (unexpected_handler)0);
51 }
52 
53 _ATTRIBUTE(noreturn)
54 void
55 unexpected()
56 {
57     (*get_unexpected())();
58     // unexpected handler should not return
59     terminate();
60 }
61 
62 terminate_handler
63 set_terminate(terminate_handler func) _NOEXCEPT
64 {
65     return __sync_lock_test_and_set(&__terminate_handler, func);
66 }
67 
68 terminate_handler
69 get_terminate() _NOEXCEPT
70 {
71     return __sync_fetch_and_add(&__terminate_handler, (terminate_handler)0);
72 }
73 
74 _ATTRIBUTE(noreturn)
75 void
76 terminate() _NOEXCEPT
77 {
78 #ifndef _LIBCPP_NO_EXCEPTIONS
79     try
80     {
81 #endif  // _LIBCPP_NO_EXCEPTIONS
82         (*get_terminate())();
83         // handler should not return
84         ::abort ();
85 #ifndef _LIBCPP_NO_EXCEPTIONS
86     }
87     catch (...)
88     {
89         // handler should not throw exception
90         ::abort ();
91     }
92 #endif  // _LIBCPP_NO_EXCEPTIONS
93 }
94 #endif // !defined(LIBCXXRT) && !defined(_LIBCPPABI_VERSION)
95 
96 #ifndef LIBCXXRT
97 bool uncaught_exception() _NOEXCEPT
98 {
99 #if __APPLE__
100     // on Darwin, there is a helper function so __cxa_get_globals is private
101     return __cxa_uncaught_exception();
102 #elif LIBCXXRT
103     __cxa_eh_globals * globals = __cxa_get_globals();
104     return (globals->uncaughtExceptions != 0);
105 #else  // __APPLE__
106     #warning uncaught_exception not yet implemented
107     ::abort();
108 #endif  // __APPLE__
109 }
110 
111 #ifndef _LIBCPPABI_VERSION
112 
113 exception::~exception() _NOEXCEPT
114 {
115 }
116 
117 bad_exception::~bad_exception() _NOEXCEPT
118 {
119 }
120 
121 const char* exception::what() const _NOEXCEPT
122 {
123   return "std::exception";
124 }
125 
126 const char* bad_exception::what() const _NOEXCEPT
127 {
128   return "std::bad_exception";
129 }
130 
131 #endif  // _LIBCPPABI_VERSION
132 #endif //LIBCXXRT
133 
134 exception_ptr::~exception_ptr() _NOEXCEPT
135 {
136 #if HAVE_DEPENDENT_EH_ABI
137     __cxa_decrement_exception_refcount(__ptr_);
138 #else
139     #warning exception_ptr not yet implemented
140     ::abort();
141 #endif  // __APPLE__
142 }
143 
144 exception_ptr::exception_ptr(const exception_ptr& other) _NOEXCEPT
145     : __ptr_(other.__ptr_)
146 {
147 #if HAVE_DEPENDENT_EH_ABI
148     __cxa_increment_exception_refcount(__ptr_);
149 #else
150     #warning exception_ptr not yet implemented
151     ::abort();
152 #endif  // __APPLE__
153 }
154 
155 exception_ptr& exception_ptr::operator=(const exception_ptr& other) _NOEXCEPT
156 {
157 #if HAVE_DEPENDENT_EH_ABI
158     if (__ptr_ != other.__ptr_)
159     {
160         __cxa_increment_exception_refcount(other.__ptr_);
161         __cxa_decrement_exception_refcount(__ptr_);
162         __ptr_ = other.__ptr_;
163     }
164     return *this;
165 #else  // __APPLE__
166     #warning exception_ptr not yet implemented
167     ::abort();
168 #endif  // __APPLE__
169 }
170 
171 nested_exception::nested_exception() _NOEXCEPT
172     : __ptr_(current_exception())
173 {
174 }
175 
176 nested_exception::~nested_exception() _NOEXCEPT
177 {
178 }
179 
180 _ATTRIBUTE(noreturn)
181 void
182 nested_exception::rethrow_nested() const
183 {
184     if (__ptr_ == nullptr)
185         terminate();
186     rethrow_exception(__ptr_);
187 }
188 
189 
190 exception_ptr current_exception() _NOEXCEPT
191 {
192 #if HAVE_DEPENDENT_EH_ABI
193     // be nicer if there was a constructor that took a ptr, then
194     // this whole function would be just:
195     //    return exception_ptr(__cxa_current_primary_exception());
196     exception_ptr ptr;
197     ptr.__ptr_ = __cxa_current_primary_exception();
198     return ptr;
199 #else  // __APPLE__
200     #warning exception_ptr not yet implemented
201     ::abort();
202 #endif  // __APPLE__
203 }
204 
205 _ATTRIBUTE(noreturn)
206 void rethrow_exception(exception_ptr p)
207 {
208 #if HAVE_DEPENDENT_EH_ABI
209     __cxa_rethrow_primary_exception(p.__ptr_);
210     // if p.__ptr_ is NULL, above returns so we terminate
211     terminate();
212 #else  // __APPLE__
213     #warning exception_ptr not yet implemented
214     ::abort();
215 #endif  // __APPLE__
216 }
217 } // std
218