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