OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. | |
3 * | |
4 * This library is free software; you can redistribute it and/or | |
5 * modify it under the terms of the GNU Library General Public | |
6 * License as published by the Free Software Foundation; either | |
7 * version 2 of the License, or (at your option) any later version. | |
8 * | |
9 * This library is distributed in the hope that it will be useful, | |
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
12 * Library General Public License for more details. | |
13 * | |
14 * You should have received a copy of the GNU Library General Public License | |
15 * along with this library; see the file COPYING.LIB. If not, write to | |
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | |
17 * Boston, MA 02110-1301, USA. | |
18 * | |
19 */ | |
20 | |
21 #ifndef RefCounted_h | |
22 #define RefCounted_h | |
23 | |
24 #include <wtf/Assertions.h> | |
25 #include <wtf/FastAllocBase.h> | |
26 #include <wtf/Noncopyable.h> | |
27 #include <wtf/OwnPtr.h> | |
28 #include <wtf/ThreadRestrictionVerifier.h> | |
29 #include <wtf/UnusedParam.h> | |
30 | |
31 namespace WTF { | |
32 | |
33 #ifdef NDEBUG | |
34 #define CHECK_REF_COUNTED_LIFECYCLE 0 | |
35 #else | |
36 #define CHECK_REF_COUNTED_LIFECYCLE 1 | |
37 #endif | |
38 | |
39 // This base class holds the non-template methods and attributes. | |
40 // The RefCounted class inherits from it reducing the template bloat | |
41 // generated by the compiler (technique called template hoisting). | |
42 class RefCountedBase { | |
43 public: | |
44 void ref() | |
45 { | |
46 #if CHECK_REF_COUNTED_LIFECYCLE | |
47 // Start thread verification as soon as the ref count gets to 2. This | |
48 // heuristic reflects the fact that items are often created on one threa
d | |
49 // and then given to another thread to be used. | |
50 // FIXME: Make this restriction tigher. Especially as we move to more | |
51 // common methods for sharing items across threads like CrossThreadCopie
r.h | |
52 // We should be able to add a "detachFromThread" method to make this exp
licit. | |
53 if (m_refCount == 1) | |
54 m_verifier.setShared(true); | |
55 // If this assert fires, it either indicates a thread safety issue or | |
56 // that the verification needs to change. See ThreadRestrictionVerifier
for | |
57 // the different modes. | |
58 ASSERT(m_verifier.isSafeToUse()); | |
59 ASSERT(!m_deletionHasBegun); | |
60 ASSERT(!m_adoptionIsRequired); | |
61 #endif | |
62 ++m_refCount; | |
63 } | |
64 | |
65 bool hasOneRef() const | |
66 { | |
67 #if CHECK_REF_COUNTED_LIFECYCLE | |
68 ASSERT(m_verifier.isSafeToUse()); | |
69 ASSERT(!m_deletionHasBegun); | |
70 #endif | |
71 return m_refCount == 1; | |
72 } | |
73 | |
74 int refCount() const | |
75 { | |
76 #if CHECK_REF_COUNTED_LIFECYCLE | |
77 ASSERT(m_verifier.isSafeToUse()); | |
78 #endif | |
79 return m_refCount; | |
80 } | |
81 | |
82 void setMutexForVerifier(Mutex&); | |
83 | |
84 #if HAVE(DISPATCH_H) | |
85 void setDispatchQueueForVerifier(dispatch_queue_t); | |
86 #endif | |
87 | |
88 // Turns off verification. Use of this method is discouraged (instead extend | |
89 // ThreadRestrictionVerifier to verify your case). | |
90 // NB. It is necessary to call this in the constructor of many objects in | |
91 // JavaScriptCore, because JavaScriptCore objects may be used from multiple | |
92 // threads even if the reference counting is done in a racy manner. This is | |
93 // because a JSC instance may be used from multiple threads so long as all | |
94 // accesses into that instance are protected by a per-instance lock. It woul
d | |
95 // be absolutely wrong to prohibit this pattern, and it would be a disastrou
s | |
96 // regression to require that the objects within that instance use a thread- | |
97 // safe version of reference counting. | |
98 void turnOffVerifier() | |
99 { | |
100 #if CHECK_REF_COUNTED_LIFECYCLE | |
101 m_verifier.turnOffVerification(); | |
102 #endif | |
103 } | |
104 | |
105 void relaxAdoptionRequirement() | |
106 { | |
107 #if CHECK_REF_COUNTED_LIFECYCLE | |
108 ASSERT(!m_deletionHasBegun); | |
109 ASSERT(m_adoptionIsRequired); | |
110 m_adoptionIsRequired = false; | |
111 #endif | |
112 } | |
113 | |
114 // Helper for generating JIT code. Please do not use for non-JIT purposes. | |
115 const int* addressOfCount() const | |
116 { | |
117 return &m_refCount; | |
118 } | |
119 | |
120 protected: | |
121 RefCountedBase() | |
122 : m_refCount(1) | |
123 #if CHECK_REF_COUNTED_LIFECYCLE | |
124 , m_deletionHasBegun(false) | |
125 , m_adoptionIsRequired(true) | |
126 #endif | |
127 { | |
128 } | |
129 | |
130 ~RefCountedBase() | |
131 { | |
132 #if CHECK_REF_COUNTED_LIFECYCLE | |
133 ASSERT(m_deletionHasBegun); | |
134 ASSERT(!m_adoptionIsRequired); | |
135 #endif | |
136 } | |
137 | |
138 // Returns whether the pointer should be freed or not. | |
139 bool derefBase() | |
140 { | |
141 #if CHECK_REF_COUNTED_LIFECYCLE | |
142 ASSERT(m_verifier.isSafeToUse()); | |
143 ASSERT(!m_deletionHasBegun); | |
144 ASSERT(!m_adoptionIsRequired); | |
145 #endif | |
146 | |
147 ASSERT(m_refCount > 0); | |
148 if (m_refCount == 1) { | |
149 #if CHECK_REF_COUNTED_LIFECYCLE | |
150 m_deletionHasBegun = true; | |
151 #endif | |
152 return true; | |
153 } | |
154 | |
155 --m_refCount; | |
156 #if CHECK_REF_COUNTED_LIFECYCLE | |
157 // Stop thread verification when the ref goes to 1 because it | |
158 // is safe to be passed to another thread at this point. | |
159 if (m_refCount == 1) | |
160 m_verifier.setShared(false); | |
161 #endif | |
162 return false; | |
163 } | |
164 | |
165 #if CHECK_REF_COUNTED_LIFECYCLE | |
166 bool deletionHasBegun() const | |
167 { | |
168 return m_deletionHasBegun; | |
169 } | |
170 #endif | |
171 | |
172 private: | |
173 | |
174 #if CHECK_REF_COUNTED_LIFECYCLE | |
175 friend void adopted(RefCountedBase*); | |
176 #endif | |
177 | |
178 int m_refCount; | |
179 #if CHECK_REF_COUNTED_LIFECYCLE | |
180 bool m_deletionHasBegun; | |
181 bool m_adoptionIsRequired; | |
182 ThreadRestrictionVerifier m_verifier; | |
183 #endif | |
184 }; | |
185 | |
186 #if CHECK_REF_COUNTED_LIFECYCLE | |
187 inline void adopted(RefCountedBase* object) | |
188 { | |
189 if (!object) | |
190 return; | |
191 ASSERT(!object->m_deletionHasBegun); | |
192 object->m_adoptionIsRequired = false; | |
193 } | |
194 #endif | |
195 | |
196 template<typename T> class RefCounted : public RefCountedBase { | |
197 WTF_MAKE_NONCOPYABLE(RefCounted); WTF_MAKE_FAST_ALLOCATED; | |
198 public: | |
199 void deref() | |
200 { | |
201 if (derefBase()) | |
202 delete static_cast<T*>(this); | |
203 } | |
204 | |
205 protected: | |
206 RefCounted() { } | |
207 ~RefCounted() | |
208 { | |
209 } | |
210 }; | |
211 | |
212 template<typename T> class RefCountedCustomAllocated : public RefCountedBase { | |
213 WTF_MAKE_NONCOPYABLE(RefCountedCustomAllocated); | |
214 | |
215 public: | |
216 void deref() | |
217 { | |
218 if (derefBase()) | |
219 delete static_cast<T*>(this); | |
220 } | |
221 | |
222 protected: | |
223 ~RefCountedCustomAllocated() | |
224 { | |
225 } | |
226 }; | |
227 | |
228 #if CHECK_REF_COUNTED_LIFECYCLE | |
229 inline void RefCountedBase::setMutexForVerifier(Mutex& mutex) | |
230 { | |
231 m_verifier.setMutexMode(mutex); | |
232 } | |
233 #else | |
234 inline void RefCountedBase::setMutexForVerifier(Mutex&) { } | |
235 #endif | |
236 | |
237 #if HAVE(DISPATCH_H) | |
238 #if CHECK_REF_COUNTED_LIFECYCLE | |
239 inline void RefCountedBase::setDispatchQueueForVerifier(dispatch_queue_t queue) | |
240 { | |
241 m_verifier.setDispatchQueueMode(queue); | |
242 } | |
243 #else | |
244 inline void RefCountedBase::setDispatchQueueForVerifier(dispatch_queue_t) { } | |
245 #endif | |
246 #endif // HAVE(DISPATCH_H) | |
247 | |
248 } // namespace WTF | |
249 | |
250 using WTF::RefCounted; | |
251 using WTF::RefCountedCustomAllocated; | |
252 | |
253 #endif // RefCounted_h | |
OLD | NEW |