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 // 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.
11 #ifndef MOZILLA_GENERICREFCOUNTED_H_
12 #define MOZILLA_GENERICREFCOUNTED_H_
14 #include <type_traits>
16 #include "mozilla/RefPtr.h"
17 #include "mozilla/RefCounted.h"
22 * Common base class for GenericRefCounted and GenericAtomicRefCounted.
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.
28 class GenericRefCountedBase
{
30 virtual ~GenericRefCountedBase() = default;
33 // AddRef() and Release() method names are for compatibility with nsRefPtr.
34 virtual void AddRef() = 0;
36 virtual void Release() = 0;
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().
41 void ref() { AddRef(); }
42 void deref() { Release(); }
44 #ifdef MOZ_REFCOUNTED_LEAK_CHECKING
45 virtual const char* typeName() const = 0;
46 virtual size_t typeSize() const = 0;
52 template <RefCountAtomicity Atomicity
>
53 class GenericRefCounted
: public GenericRefCountedBase
{
55 GenericRefCounted() : refCnt(0) {}
57 virtual ~GenericRefCounted() { MOZ_ASSERT(refCnt
== detail::DEAD
); }
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
);
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,
74 logger
.logRelease(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.
81 refCnt
= detail::DEAD
;
87 MozRefCountType
refCount() const { return refCnt
; }
88 bool hasOneRef() const {
89 MOZ_ASSERT(refCnt
> 0);
94 std::conditional_t
<Atomicity
== AtomicRefCount
, Atomic
<MozRefCountType
>,
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.
107 class GenericRefCounted
108 : public detail::GenericRefCounted
<detail::NonAtomicRefCount
> {};
111 * GenericAtomicRefCounted is like GenericRefCounted, with an atomically updated
114 class GenericAtomicRefCounted
115 : public detail::GenericRefCounted
<detail::AtomicRefCount
> {};
117 } // namespace mozilla