Skip to content

Commit b2f5377

Browse files
committed
[libc++] Optimize std::exception_ptr
This commit optimizes the performance for `std::exception_ptr` for an empty exception objects. To do so, we use 3 high-level approaches: 1. Moving the implementation from the libc++ library into the libc++ headers, thereby allowing the compiler to inline the function bodies. 2. Adding fast paths to the (now inlineable) bodies, checking for the empty case. 3. Adding move constuctor, assignment and `swap` Those optimizations were implemented for the libc++abi, libsupc++ and libstdc++ ABIs. Fixes #XXX Performance ----------- With this change, the compiler can now completely constant-fold https://godbolt.org/z/NaNKe5. Also in cases where the compiler cannot statically prove that exception_ptr is empty, it can at least generate a fast-path check if the exception_ptr is empty, without calling into the library. ABI compatibility ----------------- We use a new visibility macro `_LIBCPP_EXPORTED_FROM_ABI_INLINEABLE` to ensure that the functions which are now declared in the header are still exported by the library. See the description in `VisibilityMacros.rst` for details. This approach was originally proposed by Nikolas Klauser in https://reviews.llvm.org/D122536 Moving implementations to the header ------------------------------------ To move the implementation to the header, we must know the selected LIBCXX_CXX_ABI also in the headers. For that purpose, the LIBCXX_CXX_ABI configuration is now exposed via `__config_site`. While the Microsoft ABI and the "unimplemented" APIs do not benefit from this optimizations, I also moved their implementation to the headers for more uniformity. Mid-term, we probably have to expose all implementations in the header, anyway, because P3068R6 mandates all methods of `exception_ptr` to be constexpr. Unifying libc++abi, libsupc++ and `none` ----------------------------------------------- Both libc++abi and libsupc++ are reference-counted. The primary difference is the function called for ref-counting: * libc++api uses `__cxa_{in,de}crement_exception_refcount` * libsupc++ uses `__exception_ptr::_M_{addref,release}` This commit factors out the common reference-counting logic into a shared header. Our libsupc++ implementation so far did not take advantage of `_M_addref`/`_M_release`. For the performance benefits of this PR it was necessary to start using them. The same reference-counted approach is also reused for the `none`/`unimplemented` implementation. This has the side effect, that users can now use empty `exception_ptr`s even in the `none` ABI. The abort is only triggered for non-empty `exception_ptr`s. Given this simplifies the code, I think change is acceptable. Unifying nested_exception ------------------------- The implementation for `nested_exception` was effectively identical across all ABIs. For most ABIs, the source code was literally identical. There were only two deviations: * For libsupc++ or libstdc++, we did not use define the `~nested_exception` destructor. * The abort in `nested_exception::rethrow_nested` was unnecessary as the same abort is also present in the `rethrow_exception` implementation. As such, we were able to simply remove that special casing. The implementation is now unified directly in the `__nested_exception.h` header. Standard conformance -------------------- The available constructors, operators and methods of `exception_ptr` is not specified by the standard. As such, adding the move constructor and the assignment operator are standard conformant. libstdc++ made the same decision and also provides those headers.
1 parent a16477a commit b2f5377

25 files changed

+360
-292
lines changed

libcxx/CMakeLists.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,7 @@ config_define(${LIBCXX_ABI_VERSION} _LIBCPP_ABI_VERSION)
731731
config_define(${LIBCXX_ABI_NAMESPACE} _LIBCPP_ABI_NAMESPACE)
732732
config_define(${LIBCXX_ABI_FORCE_ITANIUM} _LIBCPP_ABI_FORCE_ITANIUM)
733733
config_define(${LIBCXX_ABI_FORCE_MICROSOFT} _LIBCPP_ABI_FORCE_MICROSOFT)
734+
config_define(${LIBCXX_CXX_ABI} _LIBCXX_CXX_ABI)
734735
config_define(${LIBCXX_ENABLE_THREADS} _LIBCPP_HAS_THREADS)
735736
config_define(${LIBCXX_ENABLE_MONOTONIC_CLOCK} _LIBCPP_HAS_MONOTONIC_CLOCK)
736737
config_define(${LIBCXX_HAS_TERMINAL_AVAILABLE} _LIBCPP_HAS_TERMINAL)
@@ -750,6 +751,20 @@ config_define(${LIBCXX_ENABLE_WIDE_CHARACTERS} _LIBCPP_HAS_WIDE_CHARACTERS)
750751
config_define(${LIBCXX_ENABLE_TIME_ZONE_DATABASE} _LIBCPP_HAS_TIME_ZONE_DATABASE)
751752
config_define(${LIBCXX_ENABLE_VENDOR_AVAILABILITY_ANNOTATIONS} _LIBCPP_HAS_VENDOR_AVAILABILITY_ANNOTATIONS)
752753

754+
if (LIBCXX_CXX_ABI STREQUAL "none")
755+
config_define(1 _LIBCPP_CXX_ABI_NONE)
756+
elseif (LIBCXX_CXX_ABI STREQUAL "libcxxabi" OR LIBCXX_CXX_ABI STREQUAL "system-libcxxabi")
757+
config_define(1 _LIBCPP_CXX_ABI_LIBCXXABI)
758+
elseif (LIBCXX_CXX_ABI STREQUAL "libcxxrt")
759+
config_define(1 _LIBCPP_CXX_ABI_LIBCXXRT)
760+
elseif (LIBCXX_CXX_ABI STREQUAL "libstdc++")
761+
config_define(1 _LIBCPP_CXX_ABI_LIBSTDCXX)
762+
elseif (LIBCXX_CXX_ABI STREQUAL "libsupc++")
763+
config_define(1 _LIBCPP_CXX_ABI_LIBSUPCXX)
764+
elseif (LIBCXX_CXX_ABI STREQUAL "vcruntime")
765+
config_define(1 _LIBCPP_CXX_ABI_VCRUNTIME)
766+
endif()
767+
753768
# TODO: Remove in LLVM 21. We're leaving an error to make this fail explicitly.
754769
if (LIBCXX_ENABLE_ASSERTIONS)
755770
message(FATAL_ERROR "LIBCXX_ENABLE_ASSERTIONS has been removed. Please use LIBCXX_HARDENING_MODE instead.")

libcxx/cmake/Modules/HandleLibCXXABI.cmake

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,6 @@ elseif ("${LIBCXX_CXX_ABI}" STREQUAL "libsupc++")
119119
elseif ("${LIBCXX_CXX_ABI}" STREQUAL "libcxxabi")
120120
add_library(libcxx-abi-headers INTERFACE)
121121
target_link_libraries(libcxx-abi-headers INTERFACE cxxabi-headers)
122-
target_compile_definitions(libcxx-abi-headers INTERFACE "-DLIBCXX_BUILDING_LIBCXXABI")
123122

124123
if (TARGET cxxabi_shared)
125124
add_library(libcxx-abi-shared INTERFACE)
@@ -156,7 +155,6 @@ elseif ("${LIBCXX_CXX_ABI}" STREQUAL "system-libcxxabi")
156155

157156
add_library(libcxx-abi-headers INTERFACE)
158157
import_private_headers(libcxx-abi-headers "${LIBCXX_CXX_ABI_INCLUDE_PATHS}" "cxxabi.h;__cxxabi_config.h")
159-
target_compile_definitions(libcxx-abi-headers INTERFACE "-DLIBCXX_BUILDING_LIBCXXABI")
160158

161159
import_shared_library(libcxx-abi-shared c++abi)
162160
target_link_libraries(libcxx-abi-shared INTERFACE libcxx-abi-headers)
@@ -173,7 +171,6 @@ elseif ("${LIBCXX_CXX_ABI}" STREQUAL "libcxxrt")
173171
add_library(libcxx-abi-headers INTERFACE)
174172
import_private_headers(libcxx-abi-headers "${LIBCXX_CXX_ABI_INCLUDE_PATHS}"
175173
"cxxabi.h;unwind.h;unwind-arm.h;unwind-itanium.h")
176-
target_compile_definitions(libcxx-abi-headers INTERFACE "-DLIBCXXRT")
177174

178175
import_shared_library(libcxx-abi-shared cxxrt)
179176
target_link_libraries(libcxx-abi-shared INTERFACE libcxx-abi-headers)
@@ -191,7 +188,6 @@ elseif ("${LIBCXX_CXX_ABI}" STREQUAL "vcruntime")
191188
# Don't link against any ABI library
192189
elseif ("${LIBCXX_CXX_ABI}" STREQUAL "none")
193190
add_library(libcxx-abi-headers INTERFACE)
194-
target_compile_definitions(libcxx-abi-headers INTERFACE "-D_LIBCPP_BUILDING_HAS_NO_ABI_LIBRARY")
195191

196192
add_library(libcxx-abi-shared INTERFACE)
197193
target_link_libraries(libcxx-abi-shared INTERFACE libcxx-abi-headers)

libcxx/docs/DesignDocs/VisibilityMacros.rst

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,25 @@ Visibility Macros
3535
used on class templates. On classes it should only be used if the vtable
3636
lives in the built library.
3737

38+
**_LIBCPP_EXPORTED_FROM_LIB_INLINEABLE**
39+
Mark a symbol as exported from the libc++ library, while still providing an
40+
inlineable definition that can be used by the compiler for optimization
41+
purposes.
42+
43+
To use this macro on a class method, define the method body
44+
*outside* of the class definition and annotate that definition with
45+
`_LIBCPP_EXPORTED_FROM_LIB_INLINEABLE`. Make sure to include the
46+
header in at least one translation unit linked into the libc++ library.
47+
48+
This macro works by applying `[[gnu::gnu_inline]] inline` to the funciton
49+
in the header, thereby suppressing code generation while still allowing the
50+
compiler to use the function for optimization purposes.
51+
During the build of libc++, we trigger code generation by not expanding the
52+
macro to `_LIBCPP_EXPORTED_FROM_ABI`. Since the function is no longer marked
53+
as `inline`, it will be emitted even if not called. (For this reason its
54+
paramount to not define methods in the class definition, since those definitions
55+
would be implicitly `inline`.)
56+
3857
**_LIBCPP_OVERRIDABLE_FUNC_VIS**
3958
Mark a symbol as being exported by the libc++ library, but allow it to be
4059
overridden locally. On non-Windows, this is equivalent to `_LIBCPP_FUNC_VIS`.

libcxx/include/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,10 @@ set(files
343343
__debug_utils/strict_weak_ordering_check.h
344344
__exception/exception.h
345345
__exception/exception_ptr.h
346+
__exception/exception_ptr_cxxabi.ipp
347+
__exception/exception_ptr_glibcxx.ipp
348+
__exception/exception_ptr_msvc.ipp
349+
__exception/exception_ptr_unimplemented.ipp
346350
__exception/nested_exception.h
347351
__exception/operations.h
348352
__exception/terminate.h

libcxx/include/__config_site.in

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@
3333
#cmakedefine01 _LIBCPP_HAS_TIME_ZONE_DATABASE
3434
#cmakedefine01 _LIBCPP_INSTRUMENTED_WITH_ASAN
3535

36+
// LIBCXX_CXX_ABI backends
37+
#cmakedefine _LIBCPP_CXX_ABI_NONE
38+
#cmakedefine _LIBCPP_CXX_ABI_LIBCXXABI
39+
#cmakedefine _LIBCPP_CXX_ABI_LIBCXXRT
40+
#cmakedefine _LIBCPP_CXX_ABI_LIBSTDCXX
41+
#cmakedefine _LIBCPP_CXX_ABI_LIBSUPCXX
42+
#cmakedefine _LIBCPP_CXX_ABI_VCRUNTIME
43+
3644
// PSTL backends
3745
#cmakedefine _LIBCPP_PSTL_BACKEND_SERIAL
3846
#cmakedefine _LIBCPP_PSTL_BACKEND_STD_THREAD

libcxx/include/__exception/exception_ptr.h

Lines changed: 108 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,29 @@
2323
# pragma GCC system_header
2424
#endif
2525

26-
#ifndef _LIBCPP_ABI_MICROSOFT
26+
// Previously, parts of exception_ptr were defined out-of-line, which prevented
27+
// useful compiler optimizations. Changing the out-of-line definitions to inline
28+
// definitions is an ABI break, however. To prevent this, we have to make sure
29+
// the symbols remain available in the libc++ library, in addition to being
30+
// defined inline here in this header.
31+
// To this end, we use _LIBCPP_EXPORTED_FROM_LIB_INLINEABLE macro:
32+
// The macro is defined as empty for src/exception.cpp, forcing the definitions of
33+
// the functions to be emitted and included in the library. When users of libc++
34+
// compile their code, the __gnu_inline__ attribute will suppress generation of
35+
// these functions while making their definitions available for inlining.
36+
# ifdef _LIBCPP_EMIT_CODE_FOR_EXCEPTION_PTR
37+
# define _LIBCPP_EXPORTED_FROM_LIB_INLINEABLE _LIBCPP_EXPORTED_FROM_ABI
38+
# else
39+
# if !__has_cpp_attribute(gnu::gnu_inline)
40+
# error "GNU inline attribute is not supported"
41+
# endif
42+
# define _LIBCPP_EXPORTED_FROM_LIB_INLINEABLE [[gnu::gnu_inline]] inline
43+
# endif
2744

28-
# if _LIBCPP_AVAILABILITY_HAS_INIT_PRIMARY_EXCEPTION
45+
_LIBCPP_DIAGNOSTIC_PUSH
46+
_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wgnu-inline-cpp-without-extern")
47+
48+
#ifdef _LIBCPP_AVAILABILITY_HAS_INIT_PRIMARY_EXCEPTION
2949

3050
namespace __cxxabiv1 {
3151

@@ -49,18 +69,25 @@ _LIBCPP_OVERRIDABLE_FUNC_VIS __cxa_exception* __cxa_init_primary_exception(
4969

5070
} // namespace __cxxabiv1
5171

52-
# endif
53-
5472
#endif
5573

5674
_LIBCPP_BEGIN_UNVERSIONED_NAMESPACE_STD
5775

58-
#ifndef _LIBCPP_ABI_MICROSOFT
76+
class _LIBCPP_EXPORTED_FROM_ABI exception_ptr;
77+
_LIBCPP_EXPORTED_FROM_LIB_INLINEABLE exception_ptr current_exception() _NOEXCEPT;
78+
[[__noreturn__]] _LIBCPP_EXPORTED_FROM_LIB_INLINEABLE void rethrow_exception(exception_ptr);
79+
80+
#ifndef _LIBCPP_CXX_ABI_VCRUNTIME
5981

6082
class _LIBCPP_EXPORTED_FROM_ABI exception_ptr {
6183
void* __ptr_;
6284

63-
static exception_ptr __from_native_exception_pointer(void*) _NOEXCEPT;
85+
// Customization points to adjust the reference counting for cxxabi or
86+
// libsupc++/libstdc++
87+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE static void __increment_refcount(void* __ptr) _NOEXCEPT;
88+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE static void __decrement_refcount(void* __ptr) _NOEXCEPT;
89+
90+
_LIBCPP_EXPORTED_FROM_LIB_INLINEABLE static exception_ptr __from_native_exception_pointer(void*) _NOEXCEPT;
6491

6592
template <class _Ep>
6693
friend _LIBCPP_HIDE_FROM_ABI exception_ptr __make_exception_ptr_explicit(_Ep&) _NOEXCEPT;
@@ -74,9 +101,11 @@ class _LIBCPP_EXPORTED_FROM_ABI exception_ptr {
74101
_LIBCPP_HIDE_FROM_ABI exception_ptr() _NOEXCEPT : __ptr_() {}
75102
_LIBCPP_HIDE_FROM_ABI exception_ptr(nullptr_t) _NOEXCEPT : __ptr_() {}
76103

77-
exception_ptr(const exception_ptr&) _NOEXCEPT;
78-
exception_ptr& operator=(const exception_ptr&) _NOEXCEPT;
79-
~exception_ptr() _NOEXCEPT;
104+
_LIBCPP_EXPORTED_FROM_LIB_INLINEABLE exception_ptr(const exception_ptr&) _NOEXCEPT;
105+
_LIBCPP_HIDE_FROM_ABI exception_ptr(exception_ptr&&) _NOEXCEPT;
106+
_LIBCPP_EXPORTED_FROM_LIB_INLINEABLE exception_ptr& operator=(const exception_ptr&) _NOEXCEPT;
107+
_LIBCPP_HIDE_FROM_ABI exception_ptr& operator=(exception_ptr&&) _NOEXCEPT;
108+
_LIBCPP_EXPORTED_FROM_LIB_INLINEABLE ~exception_ptr() _NOEXCEPT;
80109

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

@@ -88,10 +117,53 @@ class _LIBCPP_EXPORTED_FROM_ABI exception_ptr {
88117
return !(__x == __y);
89118
}
90119

120+
friend _LIBCPP_HIDE_FROM_ABI void swap(exception_ptr& __x, exception_ptr& __y) {
121+
void* __tmp = __x.__ptr_;
122+
__x.__ptr_ = __y.__ptr_;
123+
__y.__ptr_ = __tmp;
124+
}
125+
91126
friend _LIBCPP_EXPORTED_FROM_ABI exception_ptr current_exception() _NOEXCEPT;
92127
friend _LIBCPP_EXPORTED_FROM_ABI void rethrow_exception(exception_ptr);
93128
};
94129

130+
// Must be defined outside the class definition due to _LIBCPP_EXPORTED_FROM_LIB_INLINEABLE
131+
_LIBCPP_EXPORTED_FROM_LIB_INLINEABLE exception_ptr exception_ptr::__from_native_exception_pointer(void* __e) noexcept {
132+
__increment_refcount(__e);
133+
exception_ptr __ptr;
134+
__ptr.__ptr_ = __e;
135+
return __ptr;
136+
}
137+
138+
// Must be defined outside the class definition due to _LIBCPP_EXPORTED_FROM_LIB_INLINEABLE
139+
_LIBCPP_EXPORTED_FROM_LIB_INLINEABLE exception_ptr::exception_ptr(const exception_ptr& __other) noexcept : __ptr_(__other.__ptr_) {
140+
__increment_refcount(__ptr_);
141+
}
142+
143+
_LIBCPP_HIDE_FROM_ABI inline exception_ptr::exception_ptr(exception_ptr&& __other) _NOEXCEPT : __ptr_(__other.__ptr_) {
144+
__other.__ptr_ = nullptr;
145+
}
146+
147+
// Must be defined outside the class definition due to _LIBCPP_EXPORTED_FROM_LIB_INLINEABLE
148+
_LIBCPP_EXPORTED_FROM_LIB_INLINEABLE exception_ptr& exception_ptr::operator=(const exception_ptr& __other) noexcept {
149+
if (__ptr_ != __other.__ptr_) {
150+
__increment_refcount(__other.__ptr_);
151+
__decrement_refcount(__ptr_);
152+
__ptr_ = __other.__ptr_;
153+
}
154+
return *this;
155+
}
156+
157+
_LIBCPP_HIDE_FROM_ABI inline exception_ptr& exception_ptr::operator=(exception_ptr&& __other) noexcept {
158+
__decrement_refcount(__ptr_);
159+
__ptr_ = __other.__ptr_;
160+
__other.__ptr_ = nullptr;
161+
return *this;
162+
}
163+
164+
// Must be defined outside the class definition due to _LIBCPP_EXPORTED_FROM_LIB_INLINEABLE
165+
_LIBCPP_EXPORTED_FROM_LIB_INLINEABLE exception_ptr::~exception_ptr() noexcept { __decrement_refcount(__ptr_); }
166+
95167
# if _LIBCPP_HAS_EXCEPTIONS
96168
# if _LIBCPP_AVAILABILITY_HAS_INIT_PRIMARY_EXCEPTION
97169
template <class _Ep>
@@ -167,26 +239,26 @@ class _LIBCPP_EXPORTED_FROM_ABI exception_ptr {
167239
_LIBCPP_DIAGNOSTIC_POP
168240

169241
public:
170-
exception_ptr() _NOEXCEPT;
171-
exception_ptr(nullptr_t) _NOEXCEPT;
172-
exception_ptr(const exception_ptr& __other) _NOEXCEPT;
173-
exception_ptr& operator=(const exception_ptr& __other) _NOEXCEPT;
174-
exception_ptr& operator=(nullptr_t) _NOEXCEPT;
175-
~exception_ptr() _NOEXCEPT;
176-
explicit operator bool() const _NOEXCEPT;
242+
_LIBCPP_EXPORTED_FROM_LIB_INLINEABLE exception_ptr() _NOEXCEPT;
243+
_LIBCPP_EXPORTED_FROM_LIB_INLINEABLE exception_ptr(nullptr_t) _NOEXCEPT;
244+
_LIBCPP_EXPORTED_FROM_LIB_INLINEABLE exception_ptr(const exception_ptr& __other) _NOEXCEPT;
245+
_LIBCPP_EXPORTED_FROM_LIB_INLINEABLE exception_ptr& operator=(const exception_ptr& __other) _NOEXCEPT;
246+
_LIBCPP_EXPORTED_FROM_LIB_INLINEABLE exception_ptr& operator=(nullptr_t) _NOEXCEPT;
247+
_LIBCPP_EXPORTED_FROM_LIB_INLINEABLE ~exception_ptr() _NOEXCEPT;
248+
_LIBCPP_EXPORTED_FROM_LIB_INLINEABLE explicit operator bool() const _NOEXCEPT;
177249
};
178250

179-
_LIBCPP_EXPORTED_FROM_ABI bool operator==(const exception_ptr& __x, const exception_ptr& __y) _NOEXCEPT;
251+
_LIBCPP_EXPORTED_FROM_LIB_INLINEABLE bool operator==(const exception_ptr& __x, const exception_ptr& __y) _NOEXCEPT;
180252

181253
inline _LIBCPP_HIDE_FROM_ABI bool operator!=(const exception_ptr& __x, const exception_ptr& __y) _NOEXCEPT {
182254
return !(__x == __y);
183255
}
184256

185-
_LIBCPP_EXPORTED_FROM_ABI void swap(exception_ptr&, exception_ptr&) _NOEXCEPT;
257+
_LIBCPP_EXPORTED_FROM_LIB_INLINEABLE void swap(exception_ptr&, exception_ptr&) _NOEXCEPT;
186258

187-
_LIBCPP_EXPORTED_FROM_ABI exception_ptr __copy_exception_ptr(void* __except, const void* __ptr);
188-
_LIBCPP_EXPORTED_FROM_ABI exception_ptr current_exception() _NOEXCEPT;
189-
[[__noreturn__]] _LIBCPP_EXPORTED_FROM_ABI void rethrow_exception(exception_ptr);
259+
_LIBCPP_EXPORTED_FROM_LIB_INLINEABLE exception_ptr __copy_exception_ptr(void* __except, const void* __ptr);
260+
_LIBCPP_EXPORTED_FROM_LIB_INLINEABLE exception_ptr current_exception() _NOEXCEPT;
261+
[[__noreturn__]] _LIBCPP_EXPORTED_FROM_LIB_INLINEABLE void rethrow_exception(exception_ptr);
190262

191263
// This is a built-in template function which automagically extracts the required
192264
// information.
@@ -199,6 +271,21 @@ _LIBCPP_HIDE_FROM_ABI exception_ptr make_exception_ptr(_Ep __e) _NOEXCEPT {
199271
}
200272

201273
#endif // _LIBCPP_ABI_MICROSOFT
274+
202275
_LIBCPP_END_UNVERSIONED_NAMESPACE_STD
203276

277+
# if defined(_LIBCPP_CXX_ABI_NONE)
278+
# include <__exception/exception_ptr_unimplemented.ipp>
279+
# elif defined(_LIBCPP_CXX_ABI_LIBCXXABI) || defined(_LIBCPP_CXX_ABI_LIBCXXRT)
280+
# include <__exception/exception_ptr_cxxabi.ipp>
281+
# elif defined(_LIBCPP_CXX_ABI_LIBSTDCXX) || defined(_LIBCPP_CXX_ABI_LIBSUPCXX)
282+
# include <__exception/exception_ptr_glibcxx.ipp>
283+
# elif defined(_LIBCPP_CXX_ABI_VCRUNTIME)
284+
# include <__exception/exception_ptr_msvc.ipp>
285+
# else
286+
# error "Unsupported C++ ABI library"
287+
# endif
288+
289+
_LIBCPP_DIAGNOSTIC_POP
290+
204291
#endif // _LIBCPP___EXCEPTION_EXCEPTION_PTR_H
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// -*- C++ -*-
2+
//===----------------------------------------------------------------------===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#include <__exception/terminate.h>
11+
12+
namespace __cxxabiv1 {
13+
14+
extern "C" {
15+
_LIBCPP_OVERRIDABLE_FUNC_VIS void __cxa_increment_exception_refcount(void*) noexcept;
16+
_LIBCPP_OVERRIDABLE_FUNC_VIS void __cxa_decrement_exception_refcount(void*) noexcept;
17+
_LIBCPP_OVERRIDABLE_FUNC_VIS void* __cxa_current_primary_exception() noexcept;
18+
_LIBCPP_OVERRIDABLE_FUNC_VIS void __cxa_rethrow_primary_exception(void*);
19+
}
20+
21+
} // namespace __cxxabiv1
22+
23+
namespace std {
24+
25+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE inline void exception_ptr::__increment_refcount(void* __ptr) _NOEXCEPT {
26+
if (__ptr)
27+
__cxxabiv1::__cxa_increment_exception_refcount(__ptr);
28+
}
29+
30+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE inline void exception_ptr::__decrement_refcount(void* __ptr) _NOEXCEPT {
31+
if (__ptr)
32+
__cxxabiv1::__cxa_decrement_exception_refcount(__ptr);
33+
}
34+
35+
_LIBCPP_EXPORTED_FROM_LIB_INLINEABLE exception_ptr current_exception() _NOEXCEPT {
36+
// It would be nicer if there was a constructor that took a ptr, then
37+
// this whole function would be just:
38+
// return exception_ptr(__cxa_current_primary_exception());
39+
exception_ptr __ptr;
40+
__ptr.__ptr_ = __cxxabiv1::__cxa_current_primary_exception();
41+
return __ptr;
42+
}
43+
44+
_LIBCPP_EXPORTED_FROM_LIB_INLINEABLE void rethrow_exception(exception_ptr __ptr) {
45+
__cxxabiv1::__cxa_rethrow_primary_exception(__ptr.__ptr_);
46+
// if __ptr.__ptr_ is NULL, above returns so we terminate.
47+
terminate();
48+
}
49+
50+
} // namespace std

0 commit comments

Comments
 (0)