1 | /* |
2 | * Copyright (C) 2013-2019 Apple Inc. All rights reserved. |
3 | * |
4 | * Redistribution and use in source and binary forms, with or without |
5 | * modification, are permitted provided that the following conditions |
6 | * are met: |
7 | * 1. Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. |
9 | * 2. Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. |
12 | * |
13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
14 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
15 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
17 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
18 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
19 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
20 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
21 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
22 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
23 | * THE POSSIBILITY OF SUCH DAMAGE. |
24 | */ |
25 | |
26 | #pragma once |
27 | |
28 | #include <wtf/Assertions.h> |
29 | #include <wtf/DumbPtrTraits.h> |
30 | #include <wtf/Forward.h> |
31 | #include <wtf/GetPtr.h> |
32 | #include <wtf/StdLibExtras.h> |
33 | #include <wtf/TypeCasts.h> |
34 | |
35 | #if ASAN_ENABLED |
36 | extern "C" void __asan_poison_memory_region(void const volatile *addr, size_t size); |
37 | extern "C" void __asan_unpoison_memory_region(void const volatile *addr, size_t size); |
38 | extern "C" int __asan_address_is_poisoned(void const volatile *addr); |
39 | #endif |
40 | |
41 | namespace WTF { |
42 | |
43 | inline void adopted(const void*) { } |
44 | |
45 | template<typename T, typename PtrTraits> class Ref; |
46 | template<typename T, typename PtrTraits = DumbPtrTraits<T>> Ref<T, PtrTraits> adoptRef(T&); |
47 | |
48 | template<typename T, typename PtrTraits> |
49 | class Ref { |
50 | public: |
51 | static constexpr bool isRef = true; |
52 | |
53 | ~Ref() |
54 | { |
55 | #if ASAN_ENABLED |
56 | if (__asan_address_is_poisoned(this)) |
57 | __asan_unpoison_memory_region(this, sizeof(*this)); |
58 | #endif |
59 | if (m_ptr) |
60 | PtrTraits::unwrap(m_ptr)->deref(); |
61 | } |
62 | |
63 | Ref(T& object) |
64 | : m_ptr(&object) |
65 | { |
66 | object.ref(); |
67 | } |
68 | |
69 | // Use copyRef() instead. |
70 | Ref(const Ref& other) = delete; |
71 | template<typename X, typename Y> Ref(const Ref<X, Y>& other) = delete; |
72 | |
73 | Ref(Ref&& other) |
74 | : m_ptr(&other.leakRef()) |
75 | { |
76 | ASSERT(m_ptr); |
77 | } |
78 | |
79 | template<typename X, typename Y> |
80 | Ref(Ref<X, Y>&& other) |
81 | : m_ptr(&other.leakRef()) |
82 | { |
83 | ASSERT(m_ptr); |
84 | } |
85 | |
86 | Ref& operator=(T&); |
87 | Ref& operator=(Ref&&); |
88 | template<typename X, typename Y> Ref& operator=(Ref<X, Y>&&); |
89 | |
90 | // Use copyRef() and the move assignment operators instead. |
91 | Ref& operator=(const Ref&) = delete; |
92 | template<typename X, typename Y> Ref& operator=(const Ref<X, Y>&) = delete; |
93 | |
94 | template<typename X, typename Y> void swap(Ref<X, Y>&); |
95 | |
96 | // Hash table deleted values, which are only constructed and never copied or destroyed. |
97 | Ref(HashTableDeletedValueType) : m_ptr(hashTableDeletedValue()) { } |
98 | bool isHashTableDeletedValue() const { return m_ptr == hashTableDeletedValue(); } |
99 | static T* hashTableDeletedValue() { return reinterpret_cast<T*>(-1); } |
100 | |
101 | Ref(HashTableEmptyValueType) : m_ptr(hashTableEmptyValue()) { } |
102 | bool isHashTableEmptyValue() const { return m_ptr == hashTableEmptyValue(); } |
103 | static T* hashTableEmptyValue() { return nullptr; } |
104 | |
105 | const T* ptrAllowingHashTableEmptyValue() const { ASSERT(m_ptr || isHashTableEmptyValue()); return PtrTraits::unwrap(m_ptr); } |
106 | T* ptrAllowingHashTableEmptyValue() { ASSERT(m_ptr || isHashTableEmptyValue()); return PtrTraits::unwrap(m_ptr); } |
107 | |
108 | void assignToHashTableEmptyValue(Ref&& reference) |
109 | { |
110 | #if ASAN_ENABLED |
111 | if (__asan_address_is_poisoned(this)) |
112 | __asan_unpoison_memory_region(this, sizeof(*this)); |
113 | #endif |
114 | ASSERT(m_ptr == hashTableEmptyValue()); |
115 | m_ptr = &reference.leakRef(); |
116 | ASSERT(m_ptr); |
117 | } |
118 | |
119 | T* operator->() const { ASSERT(m_ptr); return PtrTraits::unwrap(m_ptr); } |
120 | T* ptr() const RETURNS_NONNULL { ASSERT(m_ptr); return PtrTraits::unwrap(m_ptr); } |
121 | T& get() const { ASSERT(m_ptr); return *PtrTraits::unwrap(m_ptr); } |
122 | operator T&() const { ASSERT(m_ptr); return *PtrTraits::unwrap(m_ptr); } |
123 | bool operator!() const { ASSERT(m_ptr); return !*m_ptr; } |
124 | |
125 | template<typename X, typename Y> Ref<T, PtrTraits> replace(Ref<X, Y>&&) WARN_UNUSED_RETURN; |
126 | |
127 | Ref copyRef() && = delete; |
128 | Ref copyRef() const & WARN_UNUSED_RETURN { return Ref(*m_ptr); } |
129 | |
130 | T& leakRef() WARN_UNUSED_RETURN |
131 | { |
132 | ASSERT(m_ptr); |
133 | |
134 | T& result = *PtrTraits::exchange(m_ptr, nullptr); |
135 | #if ASAN_ENABLED |
136 | __asan_poison_memory_region(this, sizeof(*this)); |
137 | #endif |
138 | return result; |
139 | } |
140 | |
141 | private: |
142 | friend Ref adoptRef<T>(T&); |
143 | template<typename X, typename Y> friend class Ref; |
144 | |
145 | enum AdoptTag { Adopt }; |
146 | Ref(T& object, AdoptTag) |
147 | : m_ptr(&object) |
148 | { |
149 | } |
150 | |
151 | typename PtrTraits::StorageType m_ptr; |
152 | }; |
153 | |
154 | template<typename T, typename U> Ref<T, U> adoptRef(T&); |
155 | template<typename T> Ref<T> makeRef(T&); |
156 | |
157 | template<typename T, typename U> |
158 | inline Ref<T, U>& Ref<T, U>::operator=(T& reference) |
159 | { |
160 | Ref copiedReference = reference; |
161 | swap(copiedReference); |
162 | return *this; |
163 | } |
164 | |
165 | template<typename T, typename U> |
166 | inline Ref<T, U>& Ref<T, U>::operator=(Ref&& reference) |
167 | { |
168 | #if ASAN_ENABLED |
169 | if (__asan_address_is_poisoned(this)) |
170 | __asan_unpoison_memory_region(this, sizeof(*this)); |
171 | #endif |
172 | Ref movedReference = WTFMove(reference); |
173 | swap(movedReference); |
174 | return *this; |
175 | } |
176 | |
177 | template<typename T, typename U> |
178 | template<typename X, typename Y> |
179 | inline Ref<T, U>& Ref<T, U>::operator=(Ref<X, Y>&& reference) |
180 | { |
181 | #if ASAN_ENABLED |
182 | if (__asan_address_is_poisoned(this)) |
183 | __asan_unpoison_memory_region(this, sizeof(*this)); |
184 | #endif |
185 | Ref movedReference = WTFMove(reference); |
186 | swap(movedReference); |
187 | return *this; |
188 | } |
189 | |
190 | template<typename T, typename U> |
191 | template<typename X, typename Y> |
192 | inline void Ref<T, U>::swap(Ref<X, Y>& other) |
193 | { |
194 | U::swap(m_ptr, other.m_ptr); |
195 | } |
196 | |
197 | template<typename T, typename U, typename X, typename Y, typename = std::enable_if_t<!std::is_same<U, DumbPtrTraits<T>>::value || !std::is_same<Y, DumbPtrTraits<X>>::value>> |
198 | inline void swap(Ref<T, U>& a, Ref<X, Y>& b) |
199 | { |
200 | a.swap(b); |
201 | } |
202 | |
203 | template<typename T, typename U> |
204 | template<typename X, typename Y> |
205 | inline Ref<T, U> Ref<T, U>::replace(Ref<X, Y>&& reference) |
206 | { |
207 | #if ASAN_ENABLED |
208 | if (__asan_address_is_poisoned(this)) |
209 | __asan_unpoison_memory_region(this, sizeof(*this)); |
210 | #endif |
211 | auto oldReference = adoptRef(*m_ptr); |
212 | m_ptr = &reference.leakRef(); |
213 | return oldReference; |
214 | } |
215 | |
216 | template<typename T, typename U = DumbPtrTraits<T>, typename X, typename Y> |
217 | inline Ref<T, U> static_reference_cast(Ref<X, Y>& reference) |
218 | { |
219 | return Ref<T, U>(static_cast<T&>(reference.get())); |
220 | } |
221 | |
222 | template<typename T, typename U = DumbPtrTraits<T>, typename X, typename Y> |
223 | inline Ref<T, U> static_reference_cast(Ref<X, Y>&& reference) |
224 | { |
225 | return adoptRef(static_cast<T&>(reference.leakRef())); |
226 | } |
227 | |
228 | template<typename T, typename U = DumbPtrTraits<T>, typename X, typename Y> |
229 | inline Ref<T, U> static_reference_cast(const Ref<X, Y>& reference) |
230 | { |
231 | return Ref<T, U>(static_cast<T&>(reference.copyRef().get())); |
232 | } |
233 | |
234 | template <typename T, typename U> |
235 | struct GetPtrHelper<Ref<T, U>> { |
236 | typedef T* PtrType; |
237 | static T* getPtr(const Ref<T, U>& p) { return const_cast<T*>(p.ptr()); } |
238 | }; |
239 | |
240 | template <typename T, typename U> |
241 | struct IsSmartPtr<Ref<T, U>> { |
242 | static constexpr bool value = true; |
243 | }; |
244 | |
245 | template<typename T, typename U> |
246 | inline Ref<T, U> adoptRef(T& reference) |
247 | { |
248 | adopted(&reference); |
249 | return Ref<T, U>(reference, Ref<T, U>::Adopt); |
250 | } |
251 | |
252 | template<typename T> |
253 | inline Ref<T> makeRef(T& reference) |
254 | { |
255 | return Ref<T>(reference); |
256 | } |
257 | |
258 | template<typename ExpectedType, typename ArgType, typename PtrTraits> |
259 | inline bool is(Ref<ArgType, PtrTraits>& source) |
260 | { |
261 | return is<ExpectedType>(source.get()); |
262 | } |
263 | |
264 | template<typename ExpectedType, typename ArgType, typename PtrTraits> |
265 | inline bool is(const Ref<ArgType, PtrTraits>& source) |
266 | { |
267 | return is<ExpectedType>(source.get()); |
268 | } |
269 | |
270 | } // namespace WTF |
271 | |
272 | using WTF::Ref; |
273 | using WTF::adoptRef; |
274 | using WTF::makeRef; |
275 | using WTF::static_reference_cast; |
276 | |