Skip to content

Commit 38269ec

Browse files
committed
[libc++] Inline copy constructor & destructor for std::exception_ptr
1 parent 32a85dd commit 38269ec

File tree

5 files changed

+71
-40
lines changed

5 files changed

+71
-40
lines changed

libcxx/include/__exception/exception_ptr.h

Lines changed: 54 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,11 @@ 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 { if (__ptr) __do_increment_refcount(__ptr); }
95+
_LIBCPP_HIDE_FROM_ABI static void __decrement_refcount(void* __ptr) _NOEXCEPT { if (__ptr) __do_decrement_refcount(__ptr); }
96+
7097
static exception_ptr __from_native_exception_pointer(void*) _NOEXCEPT;
7198

7299
template <class _Ep>
@@ -81,17 +108,18 @@ class _LIBCPP_EXPORTED_FROM_ABI exception_ptr {
81108
_LIBCPP_HIDE_FROM_ABI exception_ptr() _NOEXCEPT : __ptr_() {}
82109
_LIBCPP_HIDE_FROM_ABI exception_ptr(nullptr_t) _NOEXCEPT : __ptr_() {}
83110

84-
exception_ptr(const exception_ptr&) _NOEXCEPT;
111+
_LIBCPP_EXPORTED_FROM_LIB_INLINEABLE exception_ptr(const exception_ptr&) _NOEXCEPT;
85112
_LIBCPP_HIDE_FROM_ABI exception_ptr(exception_ptr&& __other) _NOEXCEPT : __ptr_(__other.__ptr_) {
86113
__other.__ptr_ = nullptr;
87114
}
88-
exception_ptr& operator=(const exception_ptr&) _NOEXCEPT;
115+
_LIBCPP_EXPORTED_FROM_LIB_INLINEABLE exception_ptr& operator=(const exception_ptr&) _NOEXCEPT;
89116
_LIBCPP_HIDE_FROM_ABI exception_ptr& operator=(exception_ptr&& __other) _NOEXCEPT {
90-
exception_ptr __tmp(std::move(__other));
91-
std::swap(__tmp, *this);
117+
__decrement_refcount(__ptr_);
118+
__ptr_ = __other.__ptr_;
119+
__other.__ptr_ = nullptr;
92120
return *this;
93121
}
94-
~exception_ptr() _NOEXCEPT;
122+
_LIBCPP_EXPORTED_FROM_LIB_INLINEABLE ~exception_ptr() _NOEXCEPT;
95123

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

@@ -109,6 +137,25 @@ class _LIBCPP_EXPORTED_FROM_ABI exception_ptr {
109137
friend _LIBCPP_EXPORTED_FROM_ABI void rethrow_exception(exception_ptr);
110138
};
111139

140+
// Must be defined outside the class definition due to _LIBCPP_EXPORTED_FROM_LIB_INLINEABLE
141+
_LIBCPP_EXPORTED_FROM_LIB_INLINEABLE exception_ptr::exception_ptr(const exception_ptr& __other) _NOEXCEPT
142+
: __ptr_(__other.__ptr_) {
143+
__increment_refcount(__ptr_);
144+
}
145+
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::operator=(const exception_ptr& __other) _NOEXCEPT {
148+
if (__ptr_ != __other.__ptr_) {
149+
__increment_refcount(__other.__ptr_);
150+
__decrement_refcount(__ptr_);
151+
__ptr_ = __other.__ptr_;
152+
}
153+
return *this;
154+
}
155+
156+
// Must be defined outside the class definition due to _LIBCPP_EXPORTED_FROM_LIB_INLINEABLE
157+
_LIBCPP_EXPORTED_FROM_LIB_INLINEABLE exception_ptr::~exception_ptr() _NOEXCEPT { __decrement_refcount(__ptr_); }
158+
112159
inline _LIBCPP_HIDE_FROM_ABI void swap(exception_ptr& __x, exception_ptr& __y) _NOEXCEPT {
113160
std::swap(__x.__ptr_, __y.__ptr_);
114161
}
@@ -222,6 +269,8 @@ _LIBCPP_HIDE_FROM_ABI exception_ptr make_exception_ptr(_Ep __e) _NOEXCEPT {
222269
#endif // _LIBCPP_ABI_MICROSOFT
223270
_LIBCPP_END_UNVERSIONED_NAMESPACE_STD
224271

272+
_LIBCPP_DIAGNOSTIC_POP
273+
225274
_LIBCPP_POP_MACROS
226275

227276
#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)