LCOV - code coverage report
Current view: top level - mfbt - RefCounted.h (source / functions) Hit Total Coverage
Test: output.info Lines: 35 35 100.0 %
Date: 2017-07-14 16:53:18 Functions: 155 391 39.6 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13