|
15 | 15 | #include <cstring> |
16 | 16 | #include <stdexcept> |
17 | 17 |
|
18 | | -// MacOS and iOS used to ship with libstdc++, and still support old applications |
19 | | -// linking against libstdc++. The libc++ and libstdc++ exceptions are supposed |
20 | | -// to be ABI compatible, such that they can be thrown from one library and caught |
21 | | -// in the other. |
22 | | -// |
23 | | -// For that reason, we must look for libstdc++ in the same process and if found, |
24 | | -// check the string stored in the exception object to see if it is the GCC empty |
25 | | -// string singleton before manipulating the reference count. This is done so that |
26 | | -// if an exception is created with a zero-length string in libstdc++, libc++abi |
27 | | -// won't try to delete the memory. |
28 | | -#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) || defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) |
29 | | -# define _LIBCPP_CHECK_FOR_GCC_EMPTY_STRING_STORAGE |
30 | | -# include <dlfcn.h> |
31 | | -# include <mach-o/dyld.h> |
32 | | -#endif |
33 | | - |
34 | 18 | _LIBCPP_BEGIN_NAMESPACE_STD |
35 | 19 |
|
36 | | -namespace __refstring_imp { |
37 | | -namespace { |
38 | | -typedef int count_t; |
| 20 | +_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wc99-extensions") |
39 | 21 |
|
40 | | -struct _Rep_base { |
41 | | - std::size_t len; |
42 | | - std::size_t cap; |
43 | | - count_t count; |
| 22 | +struct __libcpp_refstring::__rep { |
| 23 | + ptrdiff_t refcount; |
| 24 | + char data[]; |
44 | 25 | }; |
45 | 26 |
|
46 | | -inline _Rep_base* rep_from_data(const char* data_) noexcept { |
47 | | - char* data = const_cast<char*>(data_); |
48 | | - return reinterpret_cast<_Rep_base*>(data - sizeof(_Rep_base)); |
49 | | -} |
50 | | - |
51 | | -inline char* data_from_rep(_Rep_base* rep) noexcept { |
52 | | - char* data = reinterpret_cast<char*>(rep); |
53 | | - return data + sizeof(*rep); |
54 | | -} |
55 | | - |
56 | | -#if defined(_LIBCPP_CHECK_FOR_GCC_EMPTY_STRING_STORAGE) |
57 | | -inline const char* compute_gcc_empty_string_storage() noexcept { |
58 | | - void* handle = dlopen("/usr/lib/libstdc++.6.dylib", RTLD_NOLOAD); |
59 | | - if (handle == nullptr) |
60 | | - return nullptr; |
61 | | - void* sym = dlsym(handle, "_ZNSs4_Rep20_S_empty_rep_storageE"); |
62 | | - if (sym == nullptr) |
63 | | - return nullptr; |
64 | | - return data_from_rep(reinterpret_cast<_Rep_base*>(sym)); |
65 | | -} |
66 | | - |
67 | | -inline const char* get_gcc_empty_string_storage() noexcept { |
68 | | - static const char* p = compute_gcc_empty_string_storage(); |
69 | | - return p; |
70 | | -} |
71 | | -#endif |
72 | | - |
73 | | -} // namespace |
74 | | -} // namespace __refstring_imp |
75 | | - |
76 | | -using namespace __refstring_imp; |
77 | | - |
78 | 27 | inline __libcpp_refstring::__libcpp_refstring(const char* msg) { |
79 | 28 | std::size_t len = strlen(msg); |
80 | | - _Rep_base* rep = static_cast<_Rep_base*>(::operator new(sizeof(*rep) + len + 1)); |
81 | | - rep->len = len; |
82 | | - rep->cap = len; |
83 | | - rep->count = 0; |
84 | | - char* data = data_from_rep(rep); |
85 | | - std::memcpy(data, msg, len + 1); |
86 | | - __imp_ = data; |
| 29 | + auto* rep = static_cast<__rep*>(::operator new(sizeof(__rep) + len + 1)); |
| 30 | + rep->refcount = 0; |
| 31 | + std::memcpy(rep->data, msg, len + 1); |
| 32 | + __imp_ = rep; |
87 | 33 | } |
88 | 34 |
|
89 | 35 | inline __libcpp_refstring::__libcpp_refstring(const __libcpp_refstring& s) noexcept : __imp_(s.__imp_) { |
90 | | - if (__uses_refcount()) |
91 | | - __libcpp_atomic_add(&rep_from_data(__imp_)->count, 1); |
| 36 | + __libcpp_atomic_add(&__imp_->refcount, 1); |
92 | 37 | } |
93 | 38 |
|
94 | 39 | inline __libcpp_refstring& __libcpp_refstring::operator=(__libcpp_refstring const& s) noexcept { |
95 | | - bool adjust_old_count = __uses_refcount(); |
96 | | - struct _Rep_base* old_rep = rep_from_data(__imp_); |
97 | | - __imp_ = s.__imp_; |
98 | | - if (__uses_refcount()) |
99 | | - __libcpp_atomic_add(&rep_from_data(__imp_)->count, 1); |
100 | | - if (adjust_old_count) { |
101 | | - if (__libcpp_atomic_add(&old_rep->count, count_t(-1)) < 0) { |
102 | | - ::operator delete(old_rep); |
103 | | - } |
104 | | - } |
| 40 | + __rep* old_rep = __imp_; |
| 41 | + __imp_ = s.__imp_; |
| 42 | + __libcpp_atomic_add(&__imp_->refcount, 1); |
| 43 | + |
| 44 | + if (__libcpp_atomic_add(&old_rep->refcount, ptrdiff_t(-1)) < 0) |
| 45 | + ::operator delete(old_rep); |
105 | 46 | return *this; |
106 | 47 | } |
107 | 48 |
|
108 | 49 | inline __libcpp_refstring::~__libcpp_refstring() { |
109 | | - if (__uses_refcount()) { |
110 | | - _Rep_base* rep = rep_from_data(__imp_); |
111 | | - if (__libcpp_atomic_add(&rep->count, count_t(-1)) < 0) { |
112 | | - ::operator delete(rep); |
113 | | - } |
114 | | - } |
| 50 | + if (__libcpp_atomic_add(&__imp_->refcount, ptrdiff_t(-1)) < 0) |
| 51 | + ::operator delete(__imp_); |
115 | 52 | } |
116 | 53 |
|
117 | | -inline bool __libcpp_refstring::__uses_refcount() const { |
118 | | -#if defined(_LIBCPP_CHECK_FOR_GCC_EMPTY_STRING_STORAGE) |
119 | | - return __imp_ != get_gcc_empty_string_storage(); |
120 | | -#else |
121 | | - return true; |
122 | | -#endif |
123 | | -} |
| 54 | +inline const char* __libcpp_refstring::c_str() const noexcept { return __imp_->data; } |
124 | 55 |
|
125 | 56 | _LIBCPP_END_NAMESPACE_STD |
126 | 57 |
|
|
0 commit comments