YSTest: exception.cpp 源文件

YSTest PreAlpha_b700_20160611 The YSLib Test Project

- 首页
- 相关页面
- 模块
- 命名空间
- 类
- 文件

- 文件列表
- 文件成员

libdefect/exception.cpp
浏览该文件的文档.
1 /*
2 © 2014-2015 FrankHB.
3
4 This file is part of the YSLib project, and may only be used,
5 modified, and distributed under the terms of the YSLib project
6 license, LICENSE.TXT. By continuing to use, modify, or distribute
7 this file you indicate that you have read the license and
8 understand and accept it fully.
9 */
10
28 #include <cstddef> // for std::size_t and <bits/c++config.h> if using libstdc++.
29 #include <atomic> // for <bits/atomic_lockfree_defines.h> if using libstdc++.
30
31 #if defined(__GLIBCXX__) \
32 && (defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L) \
33 && ATOMIC_INT_LOCK_FREE < 2
34
35 # include "libdefect/exception.h"
36 # include <cxxabi.h> // for __cxxabiv1 and std::type_info;
37 # include <bits/atomic_word.h> // for ::_Atomic_word;
38 # include <unwind.h> // from libgcc, for __ARM_EABI_UNWINDER__, _Unwind_Ptr, etc;
39
40 # pragma GCC visibility push(default)
41
42 namespace __cxxabiv1
43 {
44
45 struct __cxa_exception
46 {
47 std::type_info* exceptionType;
48 void(_GLIBCXX_CDTOR_CALLABI*exceptionDestructor)(void*);
49 std::unexpected_handler unexpectedHandler;
50 std::terminate_handler terminateHandler;
51 __cxa_exception* nextException;
52 int handlerCount;
53 # ifdef __ARM_EABI_UNWINDER__
54 __cxa_exception* nextPropagatingException;
55 int propagationCount;
56 # else
57 int handlerSwitchValue;
58 const unsigned char* actionRecord;
59 const unsigned char* languageSpecificData;
60 _Unwind_Ptr catchTemp;
61 void* adjustedPtr;
62 # endif
63 _Unwind_Exception unwindHeader;
64 };
65
66 struct __cxa_refcounted_exception
67 {
68 ::_Atomic_word referenceCount;
69 __cxa_exception exc;
70 };
71
72 struct __cxa_dependent_exception
73 {
74 void* primaryException;
75 # if __GNUC__ * 100 + __GNUC_MINOR__ >= 409
76 void(_GLIBCXX_CDTOR_CALLABI*__padding)(void*);
77 # endif
78 std::unexpected_handler unexpectedHandler;
79 std::terminate_handler terminateHandler;
80 __cxa_exception* nextException;
81 int handlerCount;
82 # ifdef __ARM_EABI_UNWINDER__
83 __cxa_exception* nextPropagatingException;
84 int propagationCount;
85 # else
86 int handlerSwitchValue;
87 const unsigned char* actionRecord;
88 const unsigned char* languageSpecificData;
89 _Unwind_Ptr catchTemp;
90 void* adjustedPtr;
91 # endif
92 _Unwind_Exception unwindHeader;
93 };
94
95 struct __cxa_eh_globals
96 {
97 __cxa_exception* caughtExceptions;
98 unsigned int uncaughtExceptions;
99 # ifdef __ARM_EABI_UNWINDER__
100 __cxa_exception* propagatingExceptions;
101 # endif
102 };
103
104 extern void
105 __terminate(std::terminate_handler) throw() __attribute__((__noreturn__));
106
107 } // namespace __cxxabiv1;
108
109 using namespace __cxxabiv1;
110
111 namespace
112 {
113
114 inline __cxa_exception*
115 __get_exception_header_from_obj(void *ptr)
116 {
117 return reinterpret_cast<__cxa_exception*>(ptr) - 1;
118 }
119
120 inline __cxa_refcounted_exception*
121 __get_refcounted_exception_header_from_obj(void* ptr)
122 {
123 return reinterpret_cast<__cxa_refcounted_exception*>(ptr) - 1;
124 }
125
126 inline __cxa_dependent_exception*
127 __get_dependent_exception_from_ue(_Unwind_Exception *exc)
128 {
129 return reinterpret_cast<__cxa_dependent_exception*>(exc + 1) - 1;
130 }
131
132 # ifdef __ARM_EABI_UNWINDER__
133 inline bool
134 __is_gxx_exception_class(_Unwind_Exception_Class c)
135 {
136 // TODO: Take advantage of the fact that c will always be word aligned.
137 return c[0] == 'G' && c[1] == 'N' && c[2] == 'U' && c[3] == 'C'
138 && c[4] == 'C' && c[5] == '+' && c[6] == '+'
139 && (c[7] == '\0' || c[7] == '\x01');
140 }
141
142 inline bool
143 __is_dependent_exception(_Unwind_Exception_Class c)
144 {
145 return c[7] == '\x01';
146 }
147
148 inline void
149 __GXX_INIT_DEPENDENT_EXCEPTION_CLASS(_Unwind_Exception_Class c)
150 {
151 c[0] = 'G';
152 c[1] = 'N';
153 c[2] = 'U';
154 c[3] = 'C';
155 c[4] = 'C';
156 c[5] = '+';
157 c[6] = '+';
158 c[7] = '\x01';
159 }
160 # else
161 const _Unwind_Exception_Class __gxx_primary_exception_class
162 = (((((((_Unwind_Exception_Class('G')
163 << 8 | _Unwind_Exception_Class('N'))
164 << 8 | _Unwind_Exception_Class('U'))
165 << 8 | _Unwind_Exception_Class('C'))
166 << 8 | _Unwind_Exception_Class('C'))
167 << 8 | _Unwind_Exception_Class('+'))
168 << 8 | _Unwind_Exception_Class('+'))
169 << 8 | _Unwind_Exception_Class('\0'));
170
171 const _Unwind_Exception_Class __gxx_dependent_exception_class
172 = (((((((_Unwind_Exception_Class('G')
173 << 8 | _Unwind_Exception_Class('N'))
174 << 8 | _Unwind_Exception_Class('U'))
175 << 8 | _Unwind_Exception_Class('C'))
176 << 8 | _Unwind_Exception_Class('C'))
177 << 8 | _Unwind_Exception_Class('+'))
178 << 8 | _Unwind_Exception_Class('+'))
179 << 8 | _Unwind_Exception_Class('\x01'));
180
181 inline bool
182 __is_gxx_exception_class(_Unwind_Exception_Class c)
183 {
184 return c == __gxx_primary_exception_class
185 || c == __gxx_dependent_exception_class;
186 }
187
188 inline bool
189 __is_dependent_exception(_Unwind_Exception_Class c)
190 {
191 return c & 1;
192 }
193
194 # define __GXX_INIT_DEPENDENT_EXCEPTION_CLASS(c) \
195 c = __gxx_dependent_exception_class
196 # endif
197
198 inline void*
199 __get_object_from_ue(_Unwind_Exception* eo) throw()
200 {
201 return __is_dependent_exception(eo->exception_class) ?
202 __get_dependent_exception_from_ue(eo)->primaryException : eo + 1;
203 }
204
205 inline void*
206 __get_object_from_ambiguous_exception(__cxa_exception* p_or_d) throw()
207 {
208 return __get_object_from_ue(&p_or_d->unwindHeader);
209 }
210
211 template<typename Ex>
212 constexpr
213 std::size_t unwindhdr()
214 {
215 return offsetof(Ex, unwindHeader);
216 }
217
218 # if __GNUC__ * 100 + __GNUC_MINOR__ >= 409
219 template<typename Ex>
220 constexpr
221 std::size_t termHandler()
222 {
223 return unwindhdr<Ex>() - offsetof(Ex, terminateHandler);
224 }
225
226 static_assert(termHandler<__cxa_exception>()
227 == termHandler<__cxa_dependent_exception>(),
228 "__cxa_dependent_exception::termHandler layout must be"
229 " consistent with __cxa_exception::termHandler");
230 # endif
231
232 # ifndef __ARM_EABI_UNWINDER__
233 template<typename Ex>
234 constexpr std::ptrdiff_t adjptr()
235 {
236 return unwindhdr<Ex>() - offsetof(Ex, adjustedPtr);
237 }
238
239 static_assert(adjptr<__cxa_exception>()
240 == adjptr<__cxa_dependent_exception>(),
241 "__cxa_dependent_exception::adjustedPtr layout must be"
242 " consistent with __cxa_exception::adjustedPtr");
243 # endif
244
245 // FIXME: For platforms with threading but no atomic builtins, e.g. Android
246 // ARMv5.
247 # if !_GLIBCXX_HAS_GTHREADS
248 template<typename _type>
249 inline _type
250 __atomic_add_fetch(_type* ptr, _type val, int)
251 {
252 *ptr += val;
253 return *ptr;
254 }
255
256 template<typename _type>
257 inline _type
258 __atomic_sub_fetch(_type* ptr, _type val, int)
259 {
260 *ptr -= val;
261 return *ptr;
262 }
263 # endif
264
265 void
266 __gxx_dependent_exception_cleanup(_Unwind_Reason_Code code,
267 _Unwind_Exception* exc)
268 {
269 const auto dep(__get_dependent_exception_from_ue(exc));
270 const auto header(
271 __get_refcounted_exception_header_from_obj(dep->primaryException));
272
273 if(code != _URC_FOREIGN_EXCEPTION_CAUGHT && code != _URC_NO_REASON)
274 __terminate(header->exc.terminateHandler);
275 __cxa_free_dependent_exception(dep);
276 if(__atomic_sub_fetch(&header->referenceCount, 1, __ATOMIC_ACQ_REL) == 0)
277 {
278 if(header->exc.exceptionDestructor)
279 header->exc.exceptionDestructor(header + 1);
280 __cxa_free_exception(header + 1);
281 }
282 }
283
284 } // unnamed namespace;
285
286 # pragma GCC visibility pop
287
288 namespace std
289 {
290
291 namespace __exception_ptr
292 {
293
294 exception_ptr::exception_ptr() noexcept
295 : _M_exception_object()
296 {}
297 exception_ptr::exception_ptr(void* obj) noexcept
298 : _M_exception_object(obj)
299 {
300 _M_addref();
301 }
302 # ifdef _GLIBCXX_EH_PTR_COMPAT
303 exception_ptr::exception_ptr(__safe_bool) noexcept
304 : _M_exception_object()
305 {}
306 # endif
307 exception_ptr::exception_ptr(const exception_ptr& other) noexcept
308 : _M_exception_object(other._M_exception_object)
309 {
310 _M_addref();
311 }
312 exception_ptr::~exception_ptr() noexcept
313 {
314 _M_release();
315 }
316
317 exception_ptr&
318 exception_ptr::operator=(const exception_ptr& other) noexcept
319 {
320 exception_ptr(other).swap(*this);
321 return *this;
322 }
323
324 void
325 exception_ptr::_M_addref() noexcept
326 {
327 if(_M_exception_object)
328 {
329 const auto
330 eh(__get_refcounted_exception_header_from_obj(_M_exception_object));
331
332 __atomic_add_fetch(&eh->referenceCount, 1, __ATOMIC_ACQ_REL);
333 }
334 }
335
336 void
337 exception_ptr::_M_release() noexcept
338 {
339 if(_M_exception_object)
340 {
341 const auto eh(
342 __get_refcounted_exception_header_from_obj(_M_exception_object));
343
344 if(__atomic_sub_fetch(&eh->referenceCount, 1, __ATOMIC_ACQ_REL) == 0)
345 {
346 if(eh->exc.exceptionDestructor)
347 eh->exc.exceptionDestructor(_M_exception_object);
348 __cxa_free_exception(_M_exception_object);
349 _M_exception_object = {};
350 }
351 }
352 }
353
354 void*
355 exception_ptr::_M_get() const noexcept
356 {
357 return _M_exception_object;
358 }
359
360 void
361 exception_ptr::swap(exception_ptr& other) noexcept
362 {
363 const auto tmp(_M_exception_object);
364
365 _M_exception_object = other._M_exception_object;
366 other._M_exception_object = tmp;
367 }
368
369
370 # ifdef _GLIBCXX_EH_PTR_COMPAT
371 void
372 exception_ptr::_M_safe_bool_dummy() noexcept
373 {}
374
375 bool
376 exception_ptr::operator!() const noexcept
377 {
378 return !_M_exception_object;
379 }
380
381 exception_ptr::operator __safe_bool() const noexcept
382 {
383 return _M_exception_object ? &exception_ptr::_M_safe_bool_dummy : nullptr;
384 }
385 # endif
386
387 const type_info*
388 exception_ptr::__cxa_exception_type() const noexcept
389 {
390 return __get_exception_header_from_obj(_M_exception_object)->exceptionType;
391 }
392
393 bool
394 operator==(const exception_ptr& lhs, const exception_ptr& rhs) noexcept
395 {
396 return lhs._M_exception_object == rhs._M_exception_object;
397 }
398
399 bool
400 operator!=(const exception_ptr& lhs, const exception_ptr& rhs) noexcept
401 {
402 return !(lhs == rhs);
403 }
404
405 } // namespace __exception_ptr;
406
407 exception_ptr
408 current_exception() noexcept
409 {
410 const auto header(__cxa_get_globals()->caughtExceptions);
411
412 return !header || !__is_gxx_exception_class(
413 header->unwindHeader.exception_class) ? exception_ptr()
414 : exception_ptr(__get_object_from_ambiguous_exception (header));
415 }
416
417 void
418 rethrow_exception(exception_ptr ep)
419 {
420 void* obj(ep._M_get());
421 const auto eh(__get_refcounted_exception_header_from_obj(obj));
422 const auto dep(__cxa_allocate_dependent_exception());
423
424 dep->primaryException = obj;
425 __atomic_add_fetch(&eh->referenceCount, 1, __ATOMIC_ACQ_REL);
426 dep->unexpectedHandler = get_unexpected();
427 dep->terminateHandler = get_terminate();
428 __GXX_INIT_DEPENDENT_EXCEPTION_CLASS(dep->unwindHeader.exception_class);
429 dep->unwindHeader.exception_cleanup = __gxx_dependent_exception_cleanup;
430 #ifdef _GLIBCXX_SJLJ_EXCEPTIONS
431 _Unwind_SjLj_RaiseException(&dep->unwindHeader);
432 #else
433 _Unwind_RaiseException(&dep->unwindHeader);
434 #endif
435 __cxa_begin_catch(&dep->unwindHeader);
436 std::terminate();
437 }
438
439 } // namespace std;
440
441 #endif
442
443 #if defined(__GLIBCXX__) \
444 && (defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L) \
445 && __GNUC__ * 100 + __GNUC_MINOR__ < 409
446
447 # include <exception>
448 # if ATOMIC_POINTER_LOCK_FREE < 2
449 // XXX: Reordered to avoid include <exception> too early.
450 # include <ext/concurrence.h>
451 namespace
452 {
453 __gnu_cxx::__mutex mx;
454 } // unnamed namespace;
455 # endif
456
457 namespace __cxxabiv1
458 {
459
460 extern std::terminate_handler __terminate_handler;
461 extern std::unexpected_handler __unexpected_handler;
462
463 } // namespace __cxxabiv1;
464
465 using namespace __cxxabiv1;
466
467 namespace std
468 {
469
470 terminate_handler
471 get_terminate() noexcept
472 {
473 terminate_handler func;
474
475 # if ATOMIC_POINTER_LOCK_FREE > 1
476 __atomic_load(&__terminate_handler, &func, __ATOMIC_ACQUIRE);
477 # else
478 __gnu_cxx::__scoped_lock l(mx);
479
480 func = __terminate_handler;
481 # endif
482 return func;
483 }
484
485 unexpected_handler
486 get_unexpected() noexcept
487 {
488 unexpected_handler func;
489
490 # if ATOMIC_POINTER_LOCK_FREE > 1
491 __atomic_load(&__unexpected_handler, &func, __ATOMIC_ACQUIRE);
492 # else
493 __gnu_cxx::__scoped_lock l(mx);
494
495 func = __unexpected_handler;
496 # endif
497 return func;
498 }
499
500 } // namespace std;
501
502 #endif
503
ystdex::swap
void swap(container_adaptor< _tSeqCon > &x, container_adaptor< _tSeqCon > &y)
Definition: container.hpp:179
ystdex::operator!=
bool operator!=(nullptr_t lhs, const _type &rhs)
Definition: ydef.h:882
exception.h
platform::size_t
YF_API size_t
Definition: FileIO.h:1262
CHRLib::c
c
Definition: CharacterProcessing.h:81
std
Definition: memory.hpp:1100
platform_ex::operator==
PDefH(void, EnsureNonNull, void *p) ImplExpr(p?void() boo operator==)(const COMPtr< _iCOM1 > &x, const COMPtr< _iCOM2 > &y) ynothrow
检查指针值，若为空则抛出 COMException 。
Definition: COM.h:330
CHRLib::CharSet::other
Definition: Encoding.h:65
platform::terminate
YB_NORETURN YF_API void terminate() ynothrow
异常终止函数。
Definition: YCommon.cpp:42