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#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
36extern "C" void __asan_poison_memory_region(void const volatile *addr, size_t size);
37extern "C" void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
38extern "C" int __asan_address_is_poisoned(void const volatile *addr);
39#endif
40
41namespace WTF {
42
43inline void adopted(const void*) { }
44
45template<typename T, typename PtrTraits> class Ref;
46template<typename T, typename PtrTraits = DumbPtrTraits<T>> Ref<T, PtrTraits> adoptRef(T&);
47
48template<typename T, typename PtrTraits>
49class Ref {
50public:
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
141private:
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
154template<typename T, typename U> Ref<T, U> adoptRef(T&);
155template<typename T> Ref<T> makeRef(T&);
156
157template<typename T, typename U>
158inline Ref<T, U>& Ref<T, U>::operator=(T& reference)
159{
160 Ref copiedReference = reference;
161 swap(copiedReference);
162 return *this;
163}
164
165template<typename T, typename U>
166inline 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
177template<typename T, typename U>
178template<typename X, typename Y>
179inline 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
190template<typename T, typename U>
191template<typename X, typename Y>
192inline void Ref<T, U>::swap(Ref<X, Y>& other)
193{
194 U::swap(m_ptr, other.m_ptr);
195}
196
197template<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>>
198inline void swap(Ref<T, U>& a, Ref<X, Y>& b)
199{
200 a.swap(b);
201}
202
203template<typename T, typename U>
204template<typename X, typename Y>
205inline 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
216template<typename T, typename U = DumbPtrTraits<T>, typename X, typename Y>
217inline Ref<T, U> static_reference_cast(Ref<X, Y>& reference)
218{
219 return Ref<T, U>(static_cast<T&>(reference.get()));
220}
221
222template<typename T, typename U = DumbPtrTraits<T>, typename X, typename Y>
223inline Ref<T, U> static_reference_cast(Ref<X, Y>&& reference)
224{
225 return adoptRef(static_cast<T&>(reference.leakRef()));
226}
227
228template<typename T, typename U = DumbPtrTraits<T>, typename X, typename Y>
229inline 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
234template <typename T, typename U>
235struct 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
240template <typename T, typename U>
241struct IsSmartPtr<Ref<T, U>> {
242 static const bool value = true;
243};
244
245template<typename T, typename U>
246inline Ref<T, U> adoptRef(T& reference)
247{
248 adopted(&reference);
249 return Ref<T, U>(reference, Ref<T, U>::Adopt);
250}
251
252template<typename T>
253inline Ref<T> makeRef(T& reference)
254{
255 return Ref<T>(reference);
256}
257
258template<typename ExpectedType, typename ArgType, typename PtrTraits>
259inline bool is(Ref<ArgType, PtrTraits>& source)
260{
261 return is<ExpectedType>(source.get());
262}
263
264template<typename ExpectedType, typename ArgType, typename PtrTraits>
265inline bool is(const Ref<ArgType, PtrTraits>& source)
266{
267 return is<ExpectedType>(source.get());
268}
269
270} // namespace WTF
271
272using WTF::Ref;
273using WTF::adoptRef;
274using WTF::makeRef;
275using WTF::static_reference_cast;
276