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 // This header provides virtual, non-templated alternatives to MFBT's
8 // RefCounted<T>. It intentionally uses MFBT coding style with the intention of
9 // moving there should there be other use cases for it.
10 
11 #ifndef MOZILLA_GENERICREFCOUNTED_H_
12 #define MOZILLA_GENERICREFCOUNTED_H_
13 
14 #include <type_traits>
15 
16 #include "mozilla/RefPtr.h"
17 #include "mozilla/RefCounted.h"
18 
19 namespace mozilla {
20 
21 /**
22  * Common base class for GenericRefCounted and GenericAtomicRefCounted.
23  *
24  * Having this shared base class, common to both the atomic and non-atomic
25  * cases, allows to have RefPtr's that don't care about whether the
26  * objects they're managing have atomic refcounts or not.
27  */
28 class GenericRefCountedBase {
29  protected:
30   virtual ~GenericRefCountedBase() = default;
31 
32  public:
33   // AddRef() and Release() method names are for compatibility with nsRefPtr.
34   virtual void AddRef() = 0;
35 
36   virtual void Release() = 0;
37 
38   // ref() and deref() method names are for compatibility with wtf::RefPtr.
39   // No virtual keywords here: if a subclass wants to override the refcounting
40   // mechanism, it is welcome to do so by overriding AddRef() and Release().
ref()41   void ref() { AddRef(); }
deref()42   void deref() { Release(); }
43 
44 #ifdef MOZ_REFCOUNTED_LEAK_CHECKING
45   virtual const char* typeName() const = 0;
46   virtual size_t typeSize() const = 0;
47 #endif
48 };
49 
50 namespace detail {
51 
52 template <RefCountAtomicity Atomicity>
53 class GenericRefCounted : public GenericRefCountedBase {
54  protected:
GenericRefCounted()55   GenericRefCounted() : refCnt(0) {}
56 
~GenericRefCounted()57   virtual ~GenericRefCounted() { MOZ_ASSERT(refCnt == detail::DEAD); }
58 
59  public:
AddRef()60   virtual void AddRef() override {
61     // Note: this method must be thread safe for GenericAtomicRefCounted.
62     MOZ_ASSERT(int32_t(refCnt) >= 0);
63     MozRefCountType cnt = ++refCnt;
64     detail::RefCountLogger::logAddRef(this, cnt);
65   }
66 
Release()67   virtual void Release() override {
68     // Note: this method must be thread safe for GenericAtomicRefCounted.
69     MOZ_ASSERT(int32_t(refCnt) > 0);
70     detail::RefCountLogger::ReleaseLogger logger{this};
71     MozRefCountType cnt = --refCnt;
72     // Note: it's not safe to touch |this| after decrementing the refcount,
73     // except for below.
74     logger.logRelease(cnt);
75     if (0 == cnt) {
76       // Because we have atomically decremented the refcount above, only
77       // one thread can get a 0 count here, so as long as we can assume that
78       // everything else in the system is accessing this object through
79       // RefPtrs, it's safe to access |this| here.
80 #ifdef DEBUG
81       refCnt = detail::DEAD;
82 #endif
83       delete this;
84     }
85   }
86 
refCount()87   MozRefCountType refCount() const { return refCnt; }
hasOneRef()88   bool hasOneRef() const {
89     MOZ_ASSERT(refCnt > 0);
90     return refCnt == 1;
91   }
92 
93  private:
94   std::conditional_t<Atomicity == AtomicRefCount, Atomic<MozRefCountType>,
95                      MozRefCountType>
96       refCnt;
97 };
98 
99 }  // namespace detail
100 
101 /**
102  * This reference-counting base class is virtual instead of
103  * being templated, which is useful in cases where one needs
104  * genericity at binary code level, but comes at the cost
105  * of a moderate performance and size overhead, like anything virtual.
106  */
107 class GenericRefCounted
108     : public detail::GenericRefCounted<detail::NonAtomicRefCount> {};
109 
110 /**
111  * GenericAtomicRefCounted is like GenericRefCounted, with an atomically updated
112  * reference counter.
113  */
114 class GenericAtomicRefCounted
115     : public detail::GenericRefCounted<detail::AtomicRefCount> {};
116 
117 }  // namespace mozilla
118 
119 #endif
120