Bumping manifests a=b2g-bump
[gecko.git] / mfbt / RefPtr.h
blob0cb6b1cd2953389febd28a0c68a521c8fd445b01
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /* Helpers for defining and using refcounted objects. */
9 #ifndef mozilla_RefPtr_h
10 #define mozilla_RefPtr_h
12 #include "mozilla/Assertions.h"
13 #include "mozilla/Atomics.h"
14 #include "mozilla/Attributes.h"
15 #include "mozilla/NullPtr.h"
16 #include "mozilla/RefCountType.h"
17 #include "mozilla/TypeTraits.h"
18 #if defined(MOZILLA_INTERNAL_API)
19 #include "nsXPCOM.h"
20 #endif
22 #if defined(MOZILLA_INTERNAL_API) && \
23 (defined(DEBUG) || defined(FORCE_BUILD_REFCNT_LOGGING))
24 #define MOZ_REFCOUNTED_LEAK_CHECKING
25 #endif
27 namespace mozilla {
29 template<typename T> class RefCounted;
30 template<typename T> class RefPtr;
31 template<typename T> class TemporaryRef;
32 template<typename T> class OutParamRef;
33 template<typename T> OutParamRef<T> byRef(RefPtr<T>&);
35 /**
36 * RefCounted<T> is a sort of a "mixin" for a class T. RefCounted
37 * manages, well, refcounting for T, and because RefCounted is
38 * parameterized on T, RefCounted<T> can call T's destructor directly.
39 * This means T doesn't need to have a virtual dtor and so doesn't
40 * need a vtable.
42 * RefCounted<T> is created with refcount == 0. Newly-allocated
43 * RefCounted<T> must immediately be assigned to a RefPtr to make the
44 * refcount > 0. It's an error to allocate and free a bare
45 * RefCounted<T>, i.e. outside of the RefPtr machinery. Attempts to
46 * do so will abort DEBUG builds.
48 * Live RefCounted<T> have refcount > 0. The lifetime (refcounts) of
49 * live RefCounted<T> are controlled by RefPtr<T> and
50 * RefPtr<super/subclass of T>. Upon a transition from refcounted==1
51 * to 0, the RefCounted<T> "dies" and is destroyed. The "destroyed"
52 * state is represented in DEBUG builds by refcount==0xffffdead. This
53 * state distinguishes use-before-ref (refcount==0) from
54 * use-after-destroy (refcount==0xffffdead).
56 * Note that when deriving from RefCounted or AtomicRefCounted, you
57 * should add MOZ_DECLARE_REFCOUNTED_TYPENAME(ClassName) to the public
58 * section of your class, where ClassName is the name of your class.
60 namespace detail {
61 #ifdef DEBUG
62 const MozRefCountType DEAD = 0xffffdead;
63 #endif
65 // When building code that gets compiled into Gecko, try to use the
66 // trace-refcount leak logging facilities.
67 #ifdef MOZ_REFCOUNTED_LEAK_CHECKING
68 class RefCountLogger
70 public:
71 static void logAddRef(const void* aPointer, MozRefCountType aRefCount,
72 const char* aTypeName, uint32_t aInstanceSize)
74 MOZ_ASSERT(aRefCount != DEAD);
75 NS_LogAddRef(const_cast<void*>(aPointer), aRefCount, aTypeName,
76 aInstanceSize);
79 static void logRelease(const void* aPointer, MozRefCountType aRefCount,
80 const char* aTypeName)
82 MOZ_ASSERT(aRefCount != DEAD);
83 NS_LogRelease(const_cast<void*>(aPointer), aRefCount, aTypeName);
86 #endif
88 // This is used WeakPtr.h as well as this file.
89 enum RefCountAtomicity
91 AtomicRefCount,
92 NonAtomicRefCount
95 template<typename T, RefCountAtomicity Atomicity>
96 class RefCounted
98 friend class RefPtr<T>;
100 protected:
101 RefCounted() : mRefCnt(0) {}
102 ~RefCounted() { MOZ_ASSERT(mRefCnt == detail::DEAD); }
104 public:
105 // Compatibility with nsRefPtr.
106 void AddRef() const
108 // Note: this method must be thread safe for AtomicRefCounted.
109 MOZ_ASSERT(int32_t(mRefCnt) >= 0);
110 #ifndef MOZ_REFCOUNTED_LEAK_CHECKING
111 ++mRefCnt;
112 #else
113 const char* type = static_cast<const T*>(this)->typeName();
114 uint32_t size = static_cast<const T*>(this)->typeSize();
115 const void* ptr = static_cast<const T*>(this);
116 MozRefCountType cnt = ++mRefCnt;
117 detail::RefCountLogger::logAddRef(ptr, cnt, type, size);
118 #endif
121 void Release() const
123 // Note: this method must be thread safe for AtomicRefCounted.
124 MOZ_ASSERT(int32_t(mRefCnt) > 0);
125 #ifndef MOZ_REFCOUNTED_LEAK_CHECKING
126 MozRefCountType cnt = --mRefCnt;
127 #else
128 const char* type = static_cast<const T*>(this)->typeName();
129 const void* ptr = static_cast<const T*>(this);
130 MozRefCountType cnt = --mRefCnt;
131 // Note: it's not safe to touch |this| after decrementing the refcount,
132 // except for below.
133 detail::RefCountLogger::logRelease(ptr, cnt, type);
134 #endif
135 if (0 == cnt) {
136 // Because we have atomically decremented the refcount above, only
137 // one thread can get a 0 count here, so as long as we can assume that
138 // everything else in the system is accessing this object through
139 // RefPtrs, it's safe to access |this| here.
140 #ifdef DEBUG
141 mRefCnt = detail::DEAD;
142 #endif
143 delete static_cast<const T*>(this);
147 // Compatibility with wtf::RefPtr.
148 void ref() { AddRef(); }
149 void deref() { Release(); }
150 MozRefCountType refCount() const { return mRefCnt; }
151 bool hasOneRef() const
153 MOZ_ASSERT(mRefCnt > 0);
154 return mRefCnt == 1;
157 private:
158 mutable typename Conditional<Atomicity == AtomicRefCount,
159 Atomic<MozRefCountType>,
160 MozRefCountType>::Type mRefCnt;
163 #ifdef MOZ_REFCOUNTED_LEAK_CHECKING
164 #define MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(T) \
165 virtual const char* typeName() const { return #T; } \
166 virtual size_t typeSize() const { return sizeof(*this); }
167 #else
168 #define MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(T)
169 #endif
171 // Note that this macro is expanded unconditionally because it declares only
172 // two small inline functions which will hopefully get eliminated by the linker
173 // in non-leak-checking builds.
174 #define MOZ_DECLARE_REFCOUNTED_TYPENAME(T) \
175 const char* typeName() const { return #T; } \
176 size_t typeSize() const { return sizeof(*this); }
178 } // namespace detail
180 template<typename T>
181 class RefCounted : public detail::RefCounted<T, detail::NonAtomicRefCount>
183 public:
184 ~RefCounted()
186 static_assert(IsBaseOf<RefCounted, T>::value,
187 "T must derive from RefCounted<T>");
191 namespace external {
194 * AtomicRefCounted<T> is like RefCounted<T>, with an atomically updated
195 * reference counter.
197 * NOTE: Please do not use this class, use NS_INLINE_DECL_THREADSAFE_REFCOUNTING
198 * instead.
200 template<typename T>
201 class AtomicRefCounted :
202 public mozilla::detail::RefCounted<T, mozilla::detail::AtomicRefCount>
204 public:
205 ~AtomicRefCounted()
207 static_assert(IsBaseOf<AtomicRefCounted, T>::value,
208 "T must derive from AtomicRefCounted<T>");
212 } // namespace external
215 * RefPtr points to a refcounted thing that has AddRef and Release
216 * methods to increase/decrease the refcount, respectively. After a
217 * RefPtr<T> is assigned a T*, the T* can be used through the RefPtr
218 * as if it were a T*.
220 * A RefPtr can forget its underlying T*, which results in the T*
221 * being wrapped in a temporary object until the T* is either
222 * re-adopted from or released by the temporary.
224 template<typename T>
225 class RefPtr
227 // To allow them to use unref()
228 friend class TemporaryRef<T>;
229 friend class OutParamRef<T>;
231 struct DontRef {};
233 public:
234 RefPtr() : mPtr(0) {}
235 RefPtr(const RefPtr& aOther) : mPtr(ref(aOther.mPtr)) {}
236 MOZ_IMPLICIT RefPtr(const TemporaryRef<T>& aOther) : mPtr(aOther.drop()) {}
237 MOZ_IMPLICIT RefPtr(T* aVal) : mPtr(ref(aVal)) {}
239 template<typename U>
240 RefPtr(const RefPtr<U>& aOther) : mPtr(ref(aOther.get())) {}
242 ~RefPtr() { unref(mPtr); }
244 RefPtr& operator=(const RefPtr& aOther)
246 assign(ref(aOther.mPtr));
247 return *this;
249 RefPtr& operator=(const TemporaryRef<T>& aOther)
251 assign(aOther.drop());
252 return *this;
254 RefPtr& operator=(T* aVal)
256 assign(ref(aVal));
257 return *this;
260 template<typename U>
261 RefPtr& operator=(const RefPtr<U>& aOther)
263 assign(ref(aOther.get()));
264 return *this;
267 TemporaryRef<T> forget()
269 T* tmp = mPtr;
270 mPtr = nullptr;
271 return TemporaryRef<T>(tmp, DontRef());
274 T* get() const { return mPtr; }
275 operator T*() const { return mPtr; }
276 T* operator->() const { return mPtr; }
277 T& operator*() const { return *mPtr; }
278 template<typename U>
279 operator TemporaryRef<U>() { return TemporaryRef<U>(mPtr); }
281 private:
282 void assign(T* aVal)
284 unref(mPtr);
285 mPtr = aVal;
288 T* mPtr;
290 static MOZ_ALWAYS_INLINE T* ref(T* aVal)
292 if (aVal) {
293 aVal->AddRef();
295 return aVal;
298 static MOZ_ALWAYS_INLINE void unref(T* aVal)
300 if (aVal) {
301 aVal->Release();
307 * TemporaryRef<T> represents an object that holds a temporary
308 * reference to a T. TemporaryRef objects can't be manually ref'd or
309 * unref'd (being temporaries, not lvalues), so can only relinquish
310 * references to other objects, or unref on destruction.
312 template<typename T>
313 class TemporaryRef
315 // To allow it to construct TemporaryRef from a bare T*
316 friend class RefPtr<T>;
318 typedef typename RefPtr<T>::DontRef DontRef;
320 public:
321 MOZ_IMPLICIT TemporaryRef(T* aVal) : mPtr(RefPtr<T>::ref(aVal)) {}
322 TemporaryRef(const TemporaryRef& aOther) : mPtr(aOther.drop()) {}
324 template<typename U>
325 TemporaryRef(const TemporaryRef<U>& aOther) : mPtr(aOther.drop()) {}
327 ~TemporaryRef() { RefPtr<T>::unref(mPtr); }
329 T* drop() const
331 T* tmp = mPtr;
332 mPtr = nullptr;
333 return tmp;
336 private:
337 TemporaryRef(T* aVal, const DontRef&) : mPtr(aVal) {}
339 mutable T* mPtr;
341 TemporaryRef() MOZ_DELETE;
342 void operator=(const TemporaryRef&) MOZ_DELETE;
346 * OutParamRef is a wrapper that tracks a refcounted pointer passed as
347 * an outparam argument to a function. OutParamRef implements COM T**
348 * outparam semantics: this requires the callee to AddRef() the T*
349 * returned through the T** outparam on behalf of the caller. This
350 * means the caller (through OutParamRef) must Release() the old
351 * object contained in the tracked RefPtr. It's OK if the callee
352 * returns the same T* passed to it through the T** outparam, as long
353 * as the callee obeys the COM discipline.
355 * Prefer returning TemporaryRef<T> from functions over creating T**
356 * outparams and passing OutParamRef<T> to T**. Prefer RefPtr<T>*
357 * outparams over T** outparams.
359 template<typename T>
360 class OutParamRef
362 friend OutParamRef byRef<T>(RefPtr<T>&);
364 public:
365 ~OutParamRef()
367 RefPtr<T>::unref(mRefPtr.mPtr);
368 mRefPtr.mPtr = mTmp;
371 operator T**() { return &mTmp; }
373 private:
374 explicit OutParamRef(RefPtr<T>& p) : mRefPtr(p), mTmp(p.get()) {}
376 RefPtr<T>& mRefPtr;
377 T* mTmp;
379 OutParamRef() MOZ_DELETE;
380 OutParamRef& operator=(const OutParamRef&) MOZ_DELETE;
384 * byRef cooperates with OutParamRef to implement COM outparam semantics.
386 template<typename T>
387 OutParamRef<T>
388 byRef(RefPtr<T>& aPtr)
390 return OutParamRef<T>(aPtr);
393 } // namespace mozilla
395 #endif /* mozilla_RefPtr_h */