forked from Floorp-Projects/Floorp
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Bug 1207245 - part 1 - move RefCounted<T> to its own file
Various bits depend on RefPtr.h to provide RefCounted<T> and RefPtr<T>. It will be easier to manage an automatic conversion from RefPtr<T> to nsRefPtr<T> if we split out the dependency on RefCounted<T> first.
- Loading branch information
Showing
10 changed files
with
224 additions
and
181 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,215 @@ | ||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ | ||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */ | ||
/* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
|
||
/* CRTP refcounting templates. Do not use unless you are an Expert. */ | ||
|
||
#ifndef mozilla_RefCounted_h | ||
#define mozilla_RefCounted_h | ||
|
||
#include "mozilla/AlreadyAddRefed.h" | ||
#include "mozilla/Assertions.h" | ||
#include "mozilla/Atomics.h" | ||
#include "mozilla/Attributes.h" | ||
#include "mozilla/Move.h" | ||
#include "mozilla/RefCountType.h" | ||
#include "mozilla/TypeTraits.h" | ||
|
||
#if defined(MOZILLA_INTERNAL_API) | ||
#include "nsXPCOM.h" | ||
#endif | ||
|
||
#if defined(MOZILLA_INTERNAL_API) && \ | ||
!defined(MOZILLA_XPCOMRT_API) && \ | ||
(defined(DEBUG) || defined(FORCE_BUILD_REFCNT_LOGGING)) | ||
#define MOZ_REFCOUNTED_LEAK_CHECKING | ||
#endif | ||
|
||
namespace mozilla { | ||
|
||
template<typename T> class RefPtr; | ||
|
||
/** | ||
* RefCounted<T> is a sort of a "mixin" for a class T. RefCounted | ||
* manages, well, refcounting for T, and because RefCounted is | ||
* parameterized on T, RefCounted<T> can call T's destructor directly. | ||
* This means T doesn't need to have a virtual dtor and so doesn't | ||
* need a vtable. | ||
* | ||
* RefCounted<T> is created with refcount == 0. Newly-allocated | ||
* RefCounted<T> must immediately be assigned to a RefPtr to make the | ||
* refcount > 0. It's an error to allocate and free a bare | ||
* RefCounted<T>, i.e. outside of the RefPtr machinery. Attempts to | ||
* do so will abort DEBUG builds. | ||
* | ||
* Live RefCounted<T> have refcount > 0. The lifetime (refcounts) of | ||
* live RefCounted<T> are controlled by nsRefPtr<T> and | ||
* nsRefPtr<super/subclass of T>. Upon a transition from refcounted==1 | ||
* to 0, the RefCounted<T> "dies" and is destroyed. The "destroyed" | ||
* state is represented in DEBUG builds by refcount==0xffffdead. This | ||
* state distinguishes use-before-ref (refcount==0) from | ||
* use-after-destroy (refcount==0xffffdead). | ||
* | ||
* Note that when deriving from RefCounted or AtomicRefCounted, you | ||
* should add MOZ_DECLARE_REFCOUNTED_TYPENAME(ClassName) to the public | ||
* section of your class, where ClassName is the name of your class. | ||
*/ | ||
namespace detail { | ||
const MozRefCountType DEAD = 0xffffdead; | ||
|
||
// When building code that gets compiled into Gecko, try to use the | ||
// trace-refcount leak logging facilities. | ||
#ifdef MOZ_REFCOUNTED_LEAK_CHECKING | ||
class RefCountLogger | ||
{ | ||
public: | ||
static void logAddRef(const void* aPointer, MozRefCountType aRefCount, | ||
const char* aTypeName, uint32_t aInstanceSize) | ||
{ | ||
MOZ_ASSERT(aRefCount != DEAD); | ||
NS_LogAddRef(const_cast<void*>(aPointer), aRefCount, aTypeName, | ||
aInstanceSize); | ||
} | ||
|
||
static void logRelease(const void* aPointer, MozRefCountType aRefCount, | ||
const char* aTypeName) | ||
{ | ||
MOZ_ASSERT(aRefCount != DEAD); | ||
NS_LogRelease(const_cast<void*>(aPointer), aRefCount, aTypeName); | ||
} | ||
}; | ||
#endif | ||
|
||
// This is used WeakPtr.h as well as this file. | ||
enum RefCountAtomicity | ||
{ | ||
AtomicRefCount, | ||
NonAtomicRefCount | ||
}; | ||
|
||
template<typename T, RefCountAtomicity Atomicity> | ||
class RefCounted | ||
{ | ||
friend class RefPtr<T>; | ||
|
||
protected: | ||
RefCounted() : mRefCnt(0) {} | ||
~RefCounted() { MOZ_ASSERT(mRefCnt == detail::DEAD); } | ||
|
||
public: | ||
// Compatibility with nsRefPtr. | ||
void AddRef() const | ||
{ | ||
// Note: this method must be thread safe for AtomicRefCounted. | ||
MOZ_ASSERT(int32_t(mRefCnt) >= 0); | ||
#ifndef MOZ_REFCOUNTED_LEAK_CHECKING | ||
++mRefCnt; | ||
#else | ||
const char* type = static_cast<const T*>(this)->typeName(); | ||
uint32_t size = static_cast<const T*>(this)->typeSize(); | ||
const void* ptr = static_cast<const T*>(this); | ||
MozRefCountType cnt = ++mRefCnt; | ||
detail::RefCountLogger::logAddRef(ptr, cnt, type, size); | ||
#endif | ||
} | ||
|
||
void Release() const | ||
{ | ||
// Note: this method must be thread safe for AtomicRefCounted. | ||
MOZ_ASSERT(int32_t(mRefCnt) > 0); | ||
#ifndef MOZ_REFCOUNTED_LEAK_CHECKING | ||
MozRefCountType cnt = --mRefCnt; | ||
#else | ||
const char* type = static_cast<const T*>(this)->typeName(); | ||
const void* ptr = static_cast<const T*>(this); | ||
MozRefCountType cnt = --mRefCnt; | ||
// Note: it's not safe to touch |this| after decrementing the refcount, | ||
// except for below. | ||
detail::RefCountLogger::logRelease(ptr, cnt, type); | ||
#endif | ||
if (0 == cnt) { | ||
// Because we have atomically decremented the refcount above, only | ||
// one thread can get a 0 count here, so as long as we can assume that | ||
// everything else in the system is accessing this object through | ||
// RefPtrs, it's safe to access |this| here. | ||
#ifdef DEBUG | ||
mRefCnt = detail::DEAD; | ||
#endif | ||
delete static_cast<const T*>(this); | ||
} | ||
} | ||
|
||
// Compatibility with wtf::RefPtr. | ||
void ref() { AddRef(); } | ||
void deref() { Release(); } | ||
MozRefCountType refCount() const { return mRefCnt; } | ||
bool hasOneRef() const | ||
{ | ||
MOZ_ASSERT(mRefCnt > 0); | ||
return mRefCnt == 1; | ||
} | ||
|
||
private: | ||
mutable typename Conditional<Atomicity == AtomicRefCount, | ||
Atomic<MozRefCountType>, | ||
MozRefCountType>::Type mRefCnt; | ||
}; | ||
|
||
#ifdef MOZ_REFCOUNTED_LEAK_CHECKING | ||
// Passing override for the optional argument marks the typeName and | ||
// typeSize functions defined by this macro as overrides. | ||
#define MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(T, ...) \ | ||
virtual const char* typeName() const __VA_ARGS__ { return #T; } \ | ||
virtual size_t typeSize() const __VA_ARGS__ { return sizeof(*this); } | ||
#else | ||
#define MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(T, ...) | ||
#endif | ||
|
||
// Note that this macro is expanded unconditionally because it declares only | ||
// two small inline functions which will hopefully get eliminated by the linker | ||
// in non-leak-checking builds. | ||
#define MOZ_DECLARE_REFCOUNTED_TYPENAME(T) \ | ||
const char* typeName() const { return #T; } \ | ||
size_t typeSize() const { return sizeof(*this); } | ||
|
||
} // namespace detail | ||
|
||
template<typename T> | ||
class RefCounted : public detail::RefCounted<T, detail::NonAtomicRefCount> | ||
{ | ||
public: | ||
~RefCounted() | ||
{ | ||
static_assert(IsBaseOf<RefCounted, T>::value, | ||
"T must derive from RefCounted<T>"); | ||
} | ||
}; | ||
|
||
namespace external { | ||
|
||
/** | ||
* AtomicRefCounted<T> is like RefCounted<T>, with an atomically updated | ||
* reference counter. | ||
* | ||
* NOTE: Please do not use this class, use NS_INLINE_DECL_THREADSAFE_REFCOUNTING | ||
* instead. | ||
*/ | ||
template<typename T> | ||
class AtomicRefCounted : | ||
public mozilla::detail::RefCounted<T, mozilla::detail::AtomicRefCount> | ||
{ | ||
public: | ||
~AtomicRefCounted() | ||
{ | ||
static_assert(IsBaseOf<AtomicRefCounted, T>::value, | ||
"T must derive from AtomicRefCounted<T>"); | ||
} | ||
}; | ||
|
||
} // namespace external | ||
|
||
} // namespace mozilla | ||
|
||
#endif // mozilla_RefCounted_h |
Oops, something went wrong.