1/*
2 * Copyright (C) 2013-2014 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/GetPtr.h>
31#include <wtf/Noncopyable.h>
32#include <wtf/StdLibExtras.h>
33
34#if ASAN_ENABLED
35extern "C" void __asan_poison_memory_region(void const volatile *addr, size_t size);
36extern "C" void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
37extern "C" bool __asan_address_is_poisoned(void const volatile *addr);
38#endif
39
40namespace WTF {
41
42inline void adopted(const void*) { }
43
44template<typename T> class Ref;
45template<typename T> Ref<T> adoptRef(T&);
46
47template<typename T> class Ref {
48public:
49 ~Ref()
50 {
51#if ASAN_ENABLED
52 if (__asan_address_is_poisoned(this))
53 __asan_unpoison_memory_region(this, sizeof(*this));
54#endif
55 if (m_ptr)
56 m_ptr->deref();
57 }
58
59 Ref(T& object)
60 : m_ptr(&object)
61 {
62 m_ptr->ref();
63 }
64
65 // Use copyRef() instead.
66 Ref(const Ref& other) = delete;
67 template<typename U> Ref(const Ref<U>& other) = delete;
68
69 Ref(Ref&& other)
70 : m_ptr(&other.leakRef())
71 {
72 ASSERT(m_ptr);
73 }
74
75 template<typename U>
76 Ref(Ref<U>&& other)
77 : m_ptr(&other.leakRef())
78 {
79 ASSERT(m_ptr);
80 }
81
82 Ref& operator=(T& object)
83 {
84 ASSERT(m_ptr);
85 object.ref();
86 m_ptr->deref();
87 m_ptr = &object;
88 ASSERT(m_ptr);
89 return *this;
90 }
91
92 // Use copyRef() and the move assignment operators instead.
93 Ref& operator=(const Ref& reference) = delete;
94 template<typename U> Ref& operator=(const Ref<U>& reference) = delete;
95
96 Ref& operator=(Ref&& reference)
97 {
98 ASSERT(m_ptr);
99 m_ptr->deref();
100 m_ptr = &reference.leakRef();
101 ASSERT(m_ptr);
102 return *this;
103 }
104
105 template<typename U> Ref& operator=(Ref<U>&& reference)
106 {
107 ASSERT(m_ptr);
108 m_ptr->deref();
109 m_ptr = &reference.leakRef();
110 ASSERT(m_ptr);
111 return *this;
112 }
113
114 const T* operator->() const { ASSERT(m_ptr); return m_ptr; }
115 T* operator->() { ASSERT(m_ptr); return m_ptr; }
116
117 const T* ptr() const { ASSERT(m_ptr); return m_ptr; }
118 T* ptr() { ASSERT(m_ptr); return m_ptr; }
119
120 const T& get() const { ASSERT(m_ptr); return *m_ptr; }
121 T& get() { ASSERT(m_ptr); return *m_ptr; }
122
123 operator T&() { ASSERT(m_ptr); return *m_ptr; }
124 operator const T&() const { ASSERT(m_ptr); return *m_ptr; }
125
126 template<typename U> Ref<T> replace(Ref<U>&&) WARN_UNUSED_RETURN;
127
128#if COMPILER_SUPPORTS(CXX_REFERENCE_QUALIFIED_FUNCTIONS)
129 Ref copyRef() && = delete;
130 Ref copyRef() const & WARN_UNUSED_RETURN { return Ref(*m_ptr); }
131#else
132 Ref copyRef() const WARN_UNUSED_RETURN { return Ref(*m_ptr); }
133#endif
134
135 T& leakRef() WARN_UNUSED_RETURN
136 {
137 ASSERT(m_ptr);
138
139 T& result = *std::exchange(m_ptr, nullptr);
140#if ASAN_ENABLED
141 __asan_poison_memory_region(this, sizeof(*this));
142#endif
143 return result;
144 }
145
146private:
147 friend Ref adoptRef<T>(T&);
148
149 enum AdoptTag { Adopt };
150 Ref(T& object, AdoptTag)
151 : m_ptr(&object)
152 {
153 }
154
155 T* m_ptr;
156};
157
158template<typename T> template<typename U> inline Ref<T> Ref<T>::replace(Ref<U>&& reference)
159{
160 auto oldReference = adoptRef(*m_ptr);
161 m_ptr = &reference.leakRef();
162 return oldReference;
163}
164
165template<typename T, typename U> inline Ref<T> static_reference_cast(Ref<U>& reference)
166{
167 return Ref<T>(static_cast<T&>(reference.get()));
168}
169
170template<typename T, typename U> inline Ref<T> static_reference_cast(const Ref<U>& reference)
171{
172 return Ref<T>(static_cast<T&>(reference.copyRef().get()));
173}
174
175template <typename T>
176struct GetPtrHelper<Ref<T>> {
177 typedef T* PtrType;
178 static T* getPtr(const Ref<T>& p) { return const_cast<T*>(p.ptr()); }
179};
180
181template<typename T>
182inline Ref<T> adoptRef(T& reference)
183{
184 adopted(&reference);
185 return Ref<T>(reference, Ref<T>::Adopt);
186
187}
188
189} // namespace WTF
190
191using WTF::Ref;
192using WTF::adoptRef;
193using WTF::static_reference_cast;
194
195#endif // WTF_Ref_h
196