RefCounted.h 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. /* CRTP refcounting templates. Do not use unless you are an Expert. */
  6. #ifndef mozilla_RefCounted_h
  7. #define mozilla_RefCounted_h
  8. #include "mozilla/AlreadyAddRefed.h"
  9. #include "mozilla/Assertions.h"
  10. #include "mozilla/Atomics.h"
  11. #include "mozilla/Attributes.h"
  12. #include "mozilla/Move.h"
  13. #include "mozilla/RefCountType.h"
  14. #include "mozilla/TypeTraits.h"
  15. #if defined(MOZILLA_INTERNAL_API)
  16. #include "nsXPCOM.h"
  17. #endif
  18. #if defined(MOZILLA_INTERNAL_API) && \
  19. (defined(DEBUG) || defined(FORCE_BUILD_REFCNT_LOGGING))
  20. #define MOZ_REFCOUNTED_LEAK_CHECKING
  21. #endif
  22. namespace mozilla {
  23. /**
  24. * RefCounted<T> is a sort of a "mixin" for a class T. RefCounted
  25. * manages, well, refcounting for T, and because RefCounted is
  26. * parameterized on T, RefCounted<T> can call T's destructor directly.
  27. * This means T doesn't need to have a virtual dtor and so doesn't
  28. * need a vtable.
  29. *
  30. * RefCounted<T> is created with refcount == 0. Newly-allocated
  31. * RefCounted<T> must immediately be assigned to a RefPtr to make the
  32. * refcount > 0. It's an error to allocate and free a bare
  33. * RefCounted<T>, i.e. outside of the RefPtr machinery. Attempts to
  34. * do so will abort DEBUG builds.
  35. *
  36. * Live RefCounted<T> have refcount > 0. The lifetime (refcounts) of
  37. * live RefCounted<T> are controlled by RefPtr<T> and
  38. * RefPtr<super/subclass of T>. Upon a transition from refcounted==1
  39. * to 0, the RefCounted<T> "dies" and is destroyed. The "destroyed"
  40. * state is represented in DEBUG builds by refcount==0xffffdead. This
  41. * state distinguishes use-before-ref (refcount==0) from
  42. * use-after-destroy (refcount==0xffffdead).
  43. *
  44. * Note that when deriving from RefCounted or AtomicRefCounted, you
  45. * should add MOZ_DECLARE_REFCOUNTED_TYPENAME(ClassName) to the public
  46. * section of your class, where ClassName is the name of your class.
  47. */
  48. namespace detail {
  49. const MozRefCountType DEAD = 0xffffdead;
  50. // When building code that gets compiled into Gecko, try to use the
  51. // trace-refcount leak logging facilities.
  52. #ifdef MOZ_REFCOUNTED_LEAK_CHECKING
  53. class RefCountLogger
  54. {
  55. public:
  56. static void logAddRef(const void* aPointer, MozRefCountType aRefCount,
  57. const char* aTypeName, uint32_t aInstanceSize)
  58. {
  59. MOZ_ASSERT(aRefCount != DEAD);
  60. NS_LogAddRef(const_cast<void*>(aPointer), aRefCount, aTypeName,
  61. aInstanceSize);
  62. }
  63. static void logRelease(const void* aPointer, MozRefCountType aRefCount,
  64. const char* aTypeName)
  65. {
  66. MOZ_ASSERT(aRefCount != DEAD);
  67. NS_LogRelease(const_cast<void*>(aPointer), aRefCount, aTypeName);
  68. }
  69. };
  70. #endif
  71. // This is used WeakPtr.h as well as this file.
  72. enum RefCountAtomicity
  73. {
  74. AtomicRefCount,
  75. NonAtomicRefCount
  76. };
  77. template<typename T, RefCountAtomicity Atomicity>
  78. class RefCounted
  79. {
  80. protected:
  81. RefCounted() : mRefCnt(0) {}
  82. ~RefCounted() { MOZ_ASSERT(mRefCnt == detail::DEAD); }
  83. public:
  84. // Compatibility with nsRefPtr.
  85. void AddRef() const
  86. {
  87. // Note: this method must be thread safe for AtomicRefCounted.
  88. MOZ_ASSERT(int32_t(mRefCnt) >= 0);
  89. #ifndef MOZ_REFCOUNTED_LEAK_CHECKING
  90. ++mRefCnt;
  91. #else
  92. const char* type = static_cast<const T*>(this)->typeName();
  93. uint32_t size = static_cast<const T*>(this)->typeSize();
  94. const void* ptr = static_cast<const T*>(this);
  95. MozRefCountType cnt = ++mRefCnt;
  96. detail::RefCountLogger::logAddRef(ptr, cnt, type, size);
  97. #endif
  98. }
  99. void Release() const
  100. {
  101. // Note: this method must be thread safe for AtomicRefCounted.
  102. MOZ_ASSERT(int32_t(mRefCnt) > 0);
  103. #ifndef MOZ_REFCOUNTED_LEAK_CHECKING
  104. MozRefCountType cnt = --mRefCnt;
  105. #else
  106. const char* type = static_cast<const T*>(this)->typeName();
  107. const void* ptr = static_cast<const T*>(this);
  108. MozRefCountType cnt = --mRefCnt;
  109. // Note: it's not safe to touch |this| after decrementing the refcount,
  110. // except for below.
  111. detail::RefCountLogger::logRelease(ptr, cnt, type);
  112. #endif
  113. if (0 == cnt) {
  114. // Because we have atomically decremented the refcount above, only
  115. // one thread can get a 0 count here, so as long as we can assume that
  116. // everything else in the system is accessing this object through
  117. // RefPtrs, it's safe to access |this| here.
  118. #ifdef DEBUG
  119. mRefCnt = detail::DEAD;
  120. #endif
  121. delete static_cast<const T*>(this);
  122. }
  123. }
  124. // Compatibility with wtf::RefPtr.
  125. void ref() { AddRef(); }
  126. void deref() { Release(); }
  127. MozRefCountType refCount() const { return mRefCnt; }
  128. bool hasOneRef() const
  129. {
  130. MOZ_ASSERT(mRefCnt > 0);
  131. return mRefCnt == 1;
  132. }
  133. private:
  134. mutable typename Conditional<Atomicity == AtomicRefCount,
  135. Atomic<MozRefCountType>,
  136. MozRefCountType>::Type mRefCnt;
  137. };
  138. #ifdef MOZ_REFCOUNTED_LEAK_CHECKING
  139. // Passing override for the optional argument marks the typeName and
  140. // typeSize functions defined by this macro as overrides.
  141. #define MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(T, ...) \
  142. virtual const char* typeName() const __VA_ARGS__ { return #T; } \
  143. virtual size_t typeSize() const __VA_ARGS__ { return sizeof(*this); }
  144. #else
  145. #define MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(T, ...)
  146. #endif
  147. // Note that this macro is expanded unconditionally because it declares only
  148. // two small inline functions which will hopefully get eliminated by the linker
  149. // in non-leak-checking builds.
  150. #define MOZ_DECLARE_REFCOUNTED_TYPENAME(T) \
  151. const char* typeName() const { return #T; } \
  152. size_t typeSize() const { return sizeof(*this); }
  153. } // namespace detail
  154. template<typename T>
  155. class RefCounted : public detail::RefCounted<T, detail::NonAtomicRefCount>
  156. {
  157. public:
  158. ~RefCounted()
  159. {
  160. static_assert(IsBaseOf<RefCounted, T>::value,
  161. "T must derive from RefCounted<T>");
  162. }
  163. };
  164. namespace external {
  165. /**
  166. * AtomicRefCounted<T> is like RefCounted<T>, with an atomically updated
  167. * reference counter.
  168. *
  169. * NOTE: Please do not use this class, use NS_INLINE_DECL_THREADSAFE_REFCOUNTING
  170. * instead.
  171. */
  172. template<typename T>
  173. class AtomicRefCounted :
  174. public mozilla::detail::RefCounted<T, mozilla::detail::AtomicRefCount>
  175. {
  176. public:
  177. ~AtomicRefCounted()
  178. {
  179. static_assert(IsBaseOf<AtomicRefCounted, T>::value,
  180. "T must derive from AtomicRefCounted<T>");
  181. }
  182. };
  183. } // namespace external
  184. } // namespace mozilla
  185. #endif // mozilla_RefCounted_h