Skip to content

Commit d332adc

Browse files
committed
[libc++] Inline copy constructor & destructor for std::exception_ptr
1 parent f02b661 commit d332adc

File tree

5 files changed

+77
-40
lines changed

5 files changed

+77
-40
lines changed

libcxx/include/__exception/exception_ptr.h

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,28 @@ _LIBCPP_PUSH_MACROS
3030

3131
#ifndef _LIBCPP_ABI_MICROSOFT
3232

33+
// Previously, parts of exception_ptr were defined out-of-line, which prevented
34+
// useful compiler optimizations. Changing the out-of-line definitions to inline
35+
// definitions is an ABI break, however. To prevent this, we have to make sure
36+
// the symbols remain available in the libc++ library, in addition to being
37+
// defined inline here in this header.
38+
// To this end, we use _LIBCPP_EXPORTED_FROM_LIB_INLINEABLE macro:
39+
// The macro is defined as empty for src/exception.cpp, forcing the definitions of
40+
// the functions to be emitted and included in the library. When users of libc++
41+
// compile their code, the __gnu_inline__ attribute will suppress generation of
42+
// these functions while making their definitions available for inlining.
43+
# ifdef _LIBCPP_EMIT_CODE_FOR_EXCEPTION_PTR
44+
# define _LIBCPP_EXPORTED_FROM_LIB_INLINEABLE _LIBCPP_EXPORTED_FROM_ABI
45+
# else
46+
# if !__has_cpp_attribute(__gnu__::__gnu_inline__)
47+
# error "GNU inline attribute is not supported"
48+
# endif
49+
# define _LIBCPP_EXPORTED_FROM_LIB_INLINEABLE [[__gnu__::__gnu_inline__]] inline
50+
# endif
51+
52+
_LIBCPP_DIAGNOSTIC_PUSH
53+
_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wgnu-inline-cpp-without-extern")
54+
3355
# if _LIBCPP_AVAILABILITY_HAS_INIT_PRIMARY_EXCEPTION
3456

3557
namespace __cxxabiv1 {
@@ -67,6 +89,17 @@ inline _LIBCPP_HIDE_FROM_ABI void swap(exception_ptr& __x, exception_ptr& __y) _
6789
class _LIBCPP_EXPORTED_FROM_ABI exception_ptr {
6890
void* __ptr_;
6991

92+
static void __do_increment_refcount(void* __ptr) _NOEXCEPT;
93+
static void __do_decrement_refcount(void* __ptr) _NOEXCEPT;
94+
_LIBCPP_HIDE_FROM_ABI static void __increment_refcount(void* __ptr) _NOEXCEPT {
95+
if (__ptr)
96+
__do_increment_refcount(__ptr);
97+
}
98+
_LIBCPP_HIDE_FROM_ABI static void __decrement_refcount(void* __ptr) _NOEXCEPT {
99+
if (__ptr)
100+
__do_decrement_refcount(__ptr);
101+
}
102+
70103
static exception_ptr __from_native_exception_pointer(void*) _NOEXCEPT;
71104

72105
template <class _Ep>
@@ -81,17 +114,18 @@ class _LIBCPP_EXPORTED_FROM_ABI exception_ptr {
81114
_LIBCPP_HIDE_FROM_ABI exception_ptr() _NOEXCEPT : __ptr_() {}
82115
_LIBCPP_HIDE_FROM_ABI exception_ptr(nullptr_t) _NOEXCEPT : __ptr_() {}
83116

84-
exception_ptr(const exception_ptr&) _NOEXCEPT;
117+
_LIBCPP_EXPORTED_FROM_LIB_INLINEABLE exception_ptr(const exception_ptr&) _NOEXCEPT;
85118
_LIBCPP_HIDE_FROM_ABI exception_ptr(exception_ptr&& __other) _NOEXCEPT : __ptr_(__other.__ptr_) {
86119
__other.__ptr_ = nullptr;
87120
}
88-
exception_ptr& operator=(const exception_ptr&) _NOEXCEPT;
121+
_LIBCPP_EXPORTED_FROM_LIB_INLINEABLE exception_ptr& operator=(const exception_ptr&) _NOEXCEPT;
89122
_LIBCPP_HIDE_FROM_ABI exception_ptr& operator=(exception_ptr&& __other) _NOEXCEPT {
90-
exception_ptr __tmp(std::move(__other));
91-
std::swap(__tmp, *this);
123+
__decrement_refcount(__ptr_);
124+
__ptr_ = __other.__ptr_;
125+
__other.__ptr_ = nullptr;
92126
return *this;
93127
}
94-
~exception_ptr() _NOEXCEPT;
128+
_LIBCPP_EXPORTED_FROM_LIB_INLINEABLE ~exception_ptr() _NOEXCEPT;
95129

96130
_LIBCPP_HIDE_FROM_ABI explicit operator bool() const _NOEXCEPT { return __ptr_ != nullptr; }
97131

@@ -109,6 +143,25 @@ class _LIBCPP_EXPORTED_FROM_ABI exception_ptr {
109143
friend _LIBCPP_EXPORTED_FROM_ABI void rethrow_exception(exception_ptr);
110144
};
111145

146+
// Must be defined outside the class definition due to _LIBCPP_EXPORTED_FROM_LIB_INLINEABLE
147+
_LIBCPP_EXPORTED_FROM_LIB_INLINEABLE exception_ptr::exception_ptr(const exception_ptr& __other) _NOEXCEPT
148+
: __ptr_(__other.__ptr_) {
149+
__increment_refcount(__ptr_);
150+
}
151+
152+
// Must be defined outside the class definition due to _LIBCPP_EXPORTED_FROM_LIB_INLINEABLE
153+
_LIBCPP_EXPORTED_FROM_LIB_INLINEABLE exception_ptr& exception_ptr::operator=(const exception_ptr& __other) _NOEXCEPT {
154+
if (__ptr_ != __other.__ptr_) {
155+
__increment_refcount(__other.__ptr_);
156+
__decrement_refcount(__ptr_);
157+
__ptr_ = __other.__ptr_;
158+
}
159+
return *this;
160+
}
161+
162+
// Must be defined outside the class definition due to _LIBCPP_EXPORTED_FROM_LIB_INLINEABLE
163+
_LIBCPP_EXPORTED_FROM_LIB_INLINEABLE exception_ptr::~exception_ptr() _NOEXCEPT { __decrement_refcount(__ptr_); }
164+
112165
inline _LIBCPP_HIDE_FROM_ABI void swap(exception_ptr& __x, exception_ptr& __y) _NOEXCEPT {
113166
std::swap(__x.__ptr_, __y.__ptr_);
114167
}
@@ -222,6 +275,8 @@ _LIBCPP_HIDE_FROM_ABI exception_ptr make_exception_ptr(_Ep __e) _NOEXCEPT {
222275
#endif // _LIBCPP_ABI_MICROSOFT
223276
_LIBCPP_END_UNVERSIONED_NAMESPACE_STD
224277

278+
_LIBCPP_DIAGNOSTIC_POP
279+
225280
_LIBCPP_POP_MACROS
226281

227282
#endif // _LIBCPP___EXCEPTION_EXCEPTION_PTR_H

libcxx/src/exception.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#define _LIBCPP_ENABLE_CXX20_REMOVED_UNCAUGHT_EXCEPTION
1010
#define _LIBCPP_DISABLE_DEPRECATION_WARNINGS
11+
#define _LIBCPP_EMIT_CODE_FOR_EXCEPTION_PTR
1112

1213
#include <exception>
1314
#include <new>

libcxx/src/support/runtime/exception_pointer_cxxabi.ipp

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,12 @@
1313

1414
namespace std {
1515

16-
exception_ptr::~exception_ptr() noexcept { __cxa_decrement_exception_refcount(__ptr_); }
17-
18-
exception_ptr::exception_ptr(const exception_ptr& other) noexcept : __ptr_(other.__ptr_) {
19-
__cxa_increment_exception_refcount(__ptr_);
16+
void exception_ptr::__do_increment_refcount(void* __ptr) noexcept {
17+
__cxa_increment_exception_refcount(__ptr);
2018
}
2119

22-
exception_ptr& exception_ptr::operator=(const exception_ptr& other) noexcept {
23-
if (__ptr_ != other.__ptr_) {
24-
__cxa_increment_exception_refcount(other.__ptr_);
25-
__cxa_decrement_exception_refcount(__ptr_);
26-
__ptr_ = other.__ptr_;
27-
}
28-
return *this;
20+
void exception_ptr::__do_decrement_refcount(void* __ptr) noexcept {
21+
__cxa_decrement_exception_refcount(__ptr);
2922
}
3023

3124
exception_ptr exception_ptr::__from_native_exception_pointer(void* __e) noexcept {

libcxx/src/support/runtime/exception_pointer_glibcxx.ipp

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@
77
//
88
//===----------------------------------------------------------------------===//
99

10+
1011
// libsupc++ does not implement the dependent EH ABI and the functionality
1112
// it uses to implement std::exception_ptr (which it declares as an alias of
1213
// std::__exception_ptr::exception_ptr) is not directly exported to clients. So
1314
// we have little choice but to hijack std::__exception_ptr::exception_ptr's
14-
// (which fortunately has the same layout as our std::exception_ptr) copy
15-
// constructor, assignment operator and destructor (which are part of its
16-
// stable ABI), and its rethrow_exception(std::__exception_ptr::exception_ptr)
17-
// function.
15+
// _M_addref and _M_release and its rethrow_exception function. Fortunately,
16+
// glibcxx's exception_ptr has the same layout as our exception_ptr and we can
17+
// reinterpret_cast between the two.
1818

1919
namespace std {
2020

@@ -23,27 +23,20 @@ namespace __exception_ptr {
2323
struct exception_ptr {
2424
void* __ptr_;
2525

26-
explicit exception_ptr(void*) noexcept;
27-
exception_ptr(const exception_ptr&) noexcept;
28-
exception_ptr& operator=(const exception_ptr&) noexcept;
29-
~exception_ptr() noexcept;
26+
void _M_addref() noexcept;
27+
void _M_release() noexcept;
3028
};
3129

3230
} // namespace __exception_ptr
3331

3432
[[noreturn]] void rethrow_exception(__exception_ptr::exception_ptr);
3533

36-
exception_ptr::~exception_ptr() noexcept { reinterpret_cast<__exception_ptr::exception_ptr*>(this)->~exception_ptr(); }
37-
38-
exception_ptr::exception_ptr(const exception_ptr& other) noexcept : __ptr_(other.__ptr_) {
39-
new (reinterpret_cast<void*>(this))
40-
__exception_ptr::exception_ptr(reinterpret_cast<const __exception_ptr::exception_ptr&>(other));
34+
void exception_ptr::__do_increment_refcount(void* __ptr) noexcept {
35+
reinterpret_cast<__exception_ptr::exception_ptr*>(this)->_M_addref();
4136
}
4237

43-
exception_ptr& exception_ptr::operator=(const exception_ptr& other) noexcept {
44-
*reinterpret_cast<__exception_ptr::exception_ptr*>(this) =
45-
reinterpret_cast<const __exception_ptr::exception_ptr&>(other);
46-
return *this;
38+
void exception_ptr::__do_decrement_refcount(void* __ptr) noexcept {
39+
reinterpret_cast<__exception_ptr::exception_ptr*>(this)->_M_release();
4740
}
4841

4942
exception_ptr exception_ptr::__from_native_exception_pointer(void* __e) noexcept {

libcxx/src/support/runtime/exception_pointer_unimplemented.ipp

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,12 @@
1111

1212
namespace std {
1313

14-
exception_ptr::~exception_ptr() noexcept {
14+
void exception_ptr::__do_increment_refcount(void* __ptr) noexcept {
1515
#warning exception_ptr not yet implemented
1616
__libcpp_verbose_abort("exception_ptr not yet implemented\n");
1717
}
1818

19-
exception_ptr::exception_ptr(const exception_ptr& other) noexcept : __ptr_(other.__ptr_) {
20-
#warning exception_ptr not yet implemented
21-
__libcpp_verbose_abort("exception_ptr not yet implemented\n");
22-
}
23-
24-
exception_ptr& exception_ptr::operator=(const exception_ptr& other) noexcept {
19+
void exception_ptr::__do_decrement_refcount(void* __ptr) noexcept {
2520
#warning exception_ptr not yet implemented
2621
__libcpp_verbose_abort("exception_ptr not yet implemented\n");
2722
}

0 commit comments

Comments
 (0)