Unreviewed, rolling out r234489.
[WebKit-https.git] / Source / WTF / wtf / Ref.h
1 /*
2  * Copyright (C) 2013-2018 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 #ifndef WTF_Ref_h
27 #define WTF_Ref_h
28
29 #include <wtf/Assertions.h>
30 #include <wtf/DumbPtrTraits.h>
31 #include <wtf/Forward.h>
32 #include <wtf/GetPtr.h>
33 #include <wtf/StdLibExtras.h>
34 #include <wtf/TypeCasts.h>
35
36 #if ASAN_ENABLED
37 extern "C" void __asan_poison_memory_region(void const volatile *addr, size_t size);
38 extern "C" void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
39 extern "C" int __asan_address_is_poisoned(void const volatile *addr);
40 #endif
41
42 namespace WTF {
43
44 inline void adopted(const void*) { }
45
46 template<typename T, typename PtrTraits> class Ref;
47 template<typename T, typename PtrTraits = DumbPtrTraits<T>> Ref<T, PtrTraits> adoptRef(T&);
48
49 template<typename T, typename PtrTraits>
50 class Ref {
51 public:
52     static constexpr bool isRef = true;
53
54     ~Ref()
55     {
56 #if ASAN_ENABLED
57         if (__asan_address_is_poisoned(this))
58             __asan_unpoison_memory_region(this, sizeof(*this));
59 #endif
60         if (m_ptr)
61             PtrTraits::unwrap(m_ptr)->deref();
62     }
63
64     Ref(T& object)
65         : m_ptr(&object)
66     {
67         object.ref();
68     }
69
70     // Use copyRef() instead.
71     Ref(const Ref& other) = delete;
72     template<typename X, typename Y> Ref(const Ref<X, Y>& other) = delete;
73
74     Ref(Ref&& other)
75         : m_ptr(&other.leakRef())
76     {
77         ASSERT(m_ptr);
78     }
79
80     template<typename X, typename Y>
81     Ref(Ref<X, Y>&& other)
82         : m_ptr(&other.leakRef())
83     {
84         ASSERT(m_ptr);
85     }
86
87     Ref& operator=(T&);
88     Ref& operator=(Ref&&);
89     template<typename X, typename Y> Ref& operator=(Ref<X, Y>&&);
90
91     // Use copyRef() and the move assignment operators instead.
92     Ref& operator=(const Ref&) = delete;
93     template<typename X, typename Y> Ref& operator=(const Ref<X, Y>&) = delete;
94
95     template<typename X, typename Y> void swap(Ref<X, Y>&);
96
97     // Hash table deleted values, which are only constructed and never copied or destroyed.
98     Ref(HashTableDeletedValueType) : m_ptr(hashTableDeletedValue()) { }
99     bool isHashTableDeletedValue() const { return m_ptr == hashTableDeletedValue(); }
100     static T* hashTableDeletedValue() { return reinterpret_cast<T*>(-1); }
101
102     Ref(HashTableEmptyValueType) : m_ptr(hashTableEmptyValue()) { }
103     bool isHashTableEmptyValue() const { return m_ptr == hashTableEmptyValue(); }
104     static T* hashTableEmptyValue() { return nullptr; }
105
106     const T* ptrAllowingHashTableEmptyValue() const { ASSERT(m_ptr || isHashTableEmptyValue()); return PtrTraits::unwrap(m_ptr); }
107     T* ptrAllowingHashTableEmptyValue() { ASSERT(m_ptr || isHashTableEmptyValue()); return PtrTraits::unwrap(m_ptr); }
108
109     void assignToHashTableEmptyValue(Ref&& reference)
110     {
111 #if ASAN_ENABLED
112         if (__asan_address_is_poisoned(this))
113             __asan_unpoison_memory_region(this, sizeof(*this));
114 #endif
115         ASSERT(m_ptr == hashTableEmptyValue());
116         m_ptr = &reference.leakRef();
117         ASSERT(m_ptr);
118     }
119
120     T* operator->() const { ASSERT(m_ptr); return PtrTraits::unwrap(m_ptr); }
121     T* ptr() const RETURNS_NONNULL { ASSERT(m_ptr); return PtrTraits::unwrap(m_ptr); }
122     T& get() const { ASSERT(m_ptr); return *PtrTraits::unwrap(m_ptr); }
123     operator T&() const { ASSERT(m_ptr); return *PtrTraits::unwrap(m_ptr); }
124     bool operator!() const { ASSERT(m_ptr); return !*m_ptr; }
125
126     template<typename X, typename Y> Ref<T, PtrTraits> replace(Ref<X, Y>&&) WARN_UNUSED_RETURN;
127
128     Ref copyRef() && = delete;
129     Ref copyRef() const & WARN_UNUSED_RETURN { return Ref(*m_ptr); }
130
131     T& leakRef() WARN_UNUSED_RETURN
132     {
133         ASSERT(m_ptr);
134
135         T& result = *PtrTraits::exchange(m_ptr, nullptr);
136 #if ASAN_ENABLED
137         __asan_poison_memory_region(this, sizeof(*this));
138 #endif
139         return result;
140     }
141
142 private:
143     friend Ref adoptRef<T>(T&);
144     template<typename X, typename Y> friend class Ref;
145
146     enum AdoptTag { Adopt };
147     Ref(T& object, AdoptTag)
148         : m_ptr(&object)
149     {
150     }
151
152     typename PtrTraits::StorageType m_ptr;
153 };
154
155 template<typename T, typename U> Ref<T, U> adoptRef(T&);
156 template<typename T> Ref<T> makeRef(T&);
157
158 template<typename T, typename U>
159 inline Ref<T, U>& Ref<T, U>::operator=(T& reference)
160 {
161     Ref copiedReference = reference;
162     swap(copiedReference);
163     return *this;
164 }
165
166 template<typename T, typename U>
167 inline Ref<T, U>& Ref<T, U>::operator=(Ref&& reference)
168 {
169 #if ASAN_ENABLED
170     if (__asan_address_is_poisoned(this))
171         __asan_unpoison_memory_region(this, sizeof(*this));
172 #endif
173     Ref movedReference = WTFMove(reference);
174     swap(movedReference);
175     return *this;
176 }
177
178 template<typename T, typename U>
179 template<typename X, typename Y>
180 inline Ref<T, U>& Ref<T, U>::operator=(Ref<X, Y>&& reference)
181 {
182 #if ASAN_ENABLED
183     if (__asan_address_is_poisoned(this))
184         __asan_unpoison_memory_region(this, sizeof(*this));
185 #endif
186     Ref movedReference = WTFMove(reference);
187     swap(movedReference);
188     return *this;
189 }
190
191 template<typename T, typename U>
192 template<typename X, typename Y>
193 inline void Ref<T, U>::swap(Ref<X, Y>& other)
194 {
195     U::swap(m_ptr, other.m_ptr);
196 }
197
198 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>>
199 inline void swap(Ref<T, U>& a, Ref<X, Y>& b)
200 {
201     a.swap(b);
202 }
203
204 template<typename T, typename U>
205 template<typename X, typename Y>
206 inline Ref<T, U> Ref<T, U>::replace(Ref<X, Y>&& reference)
207 {
208 #if ASAN_ENABLED
209     if (__asan_address_is_poisoned(this))
210         __asan_unpoison_memory_region(this, sizeof(*this));
211 #endif
212     auto oldReference = adoptRef(*m_ptr);
213     m_ptr = &reference.leakRef();
214     return oldReference;
215 }
216
217 template<typename T, typename U = DumbPtrTraits<T>, typename X, typename Y>
218 inline Ref<T, U> static_reference_cast(Ref<X, Y>& reference)
219 {
220     return Ref<T, U>(static_cast<T&>(reference.get()));
221 }
222
223 template<typename T, typename U = DumbPtrTraits<T>, typename X, typename Y>
224 inline Ref<T, U> static_reference_cast(Ref<X, Y>&& reference)
225 {
226     return adoptRef(static_cast<T&>(reference.leakRef()));
227 }
228
229 template<typename T, typename U = DumbPtrTraits<T>, typename X, typename Y>
230 inline Ref<T, U> static_reference_cast(const Ref<X, Y>& reference)
231 {
232     return Ref<T, U>(static_cast<T&>(reference.copyRef().get()));
233 }
234
235 template <typename T, typename U>
236 struct GetPtrHelper<Ref<T, U>> {
237     typedef T* PtrType;
238     static T* getPtr(const Ref<T, U>& p) { return const_cast<T*>(p.ptr()); }
239 };
240
241 template <typename T, typename U>
242 struct IsSmartPtr<Ref<T, U>> {
243     static const bool value = true;
244 };
245
246 template<typename T, typename U>
247 inline Ref<T, U> adoptRef(T& reference)
248 {
249     adopted(&reference);
250     return Ref<T, U>(reference, Ref<T, U>::Adopt);
251 }
252
253 template<typename T>
254 inline Ref<T> makeRef(T& reference)
255 {
256     return Ref<T>(reference);
257 }
258
259 template<typename ExpectedType, typename ArgType, typename PtrTraits>
260 inline bool is(Ref<ArgType, PtrTraits>& source)
261 {
262     return is<ExpectedType>(source.get());
263 }
264
265 template<typename ExpectedType, typename ArgType, typename PtrTraits>
266 inline bool is(const Ref<ArgType, PtrTraits>& source)
267 {
268     return is<ExpectedType>(source.get());
269 }
270
271 template<typename Poison, typename T> struct PoisonedPtrTraits;
272
273 template<typename Poison, typename T>
274 using PoisonedRef = Ref<T, PoisonedPtrTraits<Poison, T>>;
275
276 } // namespace WTF
277
278 using WTF::PoisonedRef;
279 using WTF::Ref;
280 using WTF::adoptRef;
281 using WTF::makeRef;
282 using WTF::static_reference_cast;
283
284 #endif // WTF_Ref_h