Source code

Revision control

Other Tools

/* -*- 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/. */
// IWYU pragma: private, include "nsISupports.h"
#ifndef nsISupportsImpl_h__
#define nsISupportsImpl_h__
#include "nscore.h"
#include "nsISupportsBase.h"
#include "nsISupportsUtils.h"
#if !defined(XPCOM_GLUE_AVOID_NSPR)
# include "prthread.h" /* needed for cargo-culting headers */
#endif
#include "nsDebug.h"
#include "nsXPCOM.h"
#include <atomic>
#include <type_traits>
#include "mozilla/Attributes.h"
#include "mozilla/Assertions.h"
#include "mozilla/Atomics.h"
#include "mozilla/Compiler.h"
#include "mozilla/Likely.h"
#include "mozilla/MacroArgs.h"
#include "mozilla/MacroForEach.h"
#include "mozilla/TypeTraits.h"
#define MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(X) \
static_assert(!mozilla::IsDestructible<X>::value, \
"Reference-counted class " #X \
" should not have a public destructor. " \
"Make this class's destructor non-public");
inline nsISupports* ToSupports(decltype(nullptr)) { return nullptr; }
inline nsISupports* ToSupports(nsISupports* aSupports) { return aSupports; }
////////////////////////////////////////////////////////////////////////////////
// Macros to help detect thread-safety:
#ifdef MOZ_THREAD_SAFETY_OWNERSHIP_CHECKS_SUPPORTED
# include "prthread.h" /* needed for thread-safety checks */
class nsAutoOwningThread {
public:
nsAutoOwningThread();
// We move the actual assertion checks out-of-line to minimize code bloat,
// but that means we have to pass a non-literal string to MOZ_CRASH_UNSAFE.
// To make that more safe, the public interface requires a literal string
// and passes that to the private interface; we can then be assured that we
// effectively are passing a literal string to MOZ_CRASH_UNSAFE.
template <int N>
void AssertOwnership(const char (&aMsg)[N]) const {
AssertCurrentThreadOwnsMe(aMsg);
}
bool IsCurrentThread() const;
private:
void AssertCurrentThreadOwnsMe(const char* aMsg) const;
void* mThread;
};
class nsISerialEventTarget;
class nsAutoOwningEventTarget {
public:
nsAutoOwningEventTarget();
~nsAutoOwningEventTarget();
// We move the actual assertion checks out-of-line to minimize code bloat,
// but that means we have to pass a non-literal string to MOZ_CRASH_UNSAFE.
// To make that more safe, the public interface requires a literal string
// and passes that to the private interface; we can then be assured that we
// effectively are passing a literal string to MOZ_CRASH_UNSAFE.
template <int N>
void AssertOwnership(const char (&aMsg)[N]) const {
AssertCurrentThreadOwnsMe(aMsg);
}
bool IsCurrentThread() const;
private:
void AssertCurrentThreadOwnsMe(const char* aMsg) const;
nsISerialEventTarget* mTarget;
};
# define NS_DECL_OWNINGTHREAD nsAutoOwningThread _mOwningThread;
# define NS_DECL_OWNINGEVENTTARGET nsAutoOwningEventTarget _mOwningThread;
# define NS_ASSERT_OWNINGTHREAD(_class) \
_mOwningThread.AssertOwnership(#_class " not thread-safe")
#else // !MOZ_THREAD_SAFETY_OWNERSHIP_CHECKS_SUPPORTED
# define NS_DECL_OWNINGTHREAD /* nothing */
# define NS_DECL_OWNINGEVENTTARGET /* nothing */
# define NS_ASSERT_OWNINGTHREAD(_class) ((void)0)
#endif // MOZ_THREAD_SAFETY_OWNERSHIP_CHECKS_SUPPORTED
// Macros for reference-count and constructor logging
#if defined(NS_BUILD_REFCNT_LOGGING)
# define NS_LOG_ADDREF(_p, _rc, _type, _size) \
NS_LogAddRef((_p), (_rc), (_type), (uint32_t)(_size))
# define NS_LOG_RELEASE(_p, _rc, _type) NS_LogRelease((_p), (_rc), (_type))
# define MOZ_ASSERT_CLASSNAME(_type) \
static_assert(std::is_class_v<_type>, \
"Token '" #_type "' is not a class type.")
# define MOZ_ASSERT_NOT_ISUPPORTS(_type) \
static_assert(!std::is_base_of<nsISupports, _type>::value, \
"nsISupports classes don't need to call MOZ_COUNT_CTOR or " \
"MOZ_COUNT_DTOR");
// Note that the following constructor/destructor logging macros are redundant
// for refcounted objects that log via the NS_LOG_ADDREF/NS_LOG_RELEASE macros.
// Refcount logging is preferred.
# define MOZ_COUNT_CTOR(_type) \
do { \
MOZ_ASSERT_CLASSNAME(_type); \
MOZ_ASSERT_NOT_ISUPPORTS(_type); \
NS_LogCtor((void*)this, #_type, sizeof(*this)); \
} while (0)
# define MOZ_COUNT_CTOR_INHERITED(_type, _base) \
do { \
MOZ_ASSERT_CLASSNAME(_type); \
MOZ_ASSERT_CLASSNAME(_base); \
MOZ_ASSERT_NOT_ISUPPORTS(_type); \
NS_LogCtor((void*)this, #_type, sizeof(*this) - sizeof(_base)); \
} while (0)
# define MOZ_LOG_CTOR(_ptr, _name, _size) \
do { \
NS_LogCtor((void*)_ptr, _name, _size); \
} while (0)
# define MOZ_COUNT_DTOR(_type) \
do { \
MOZ_ASSERT_CLASSNAME(_type); \
MOZ_ASSERT_NOT_ISUPPORTS(_type); \
NS_LogDtor((void*)this, #_type, sizeof(*this)); \
} while (0)
# define MOZ_COUNT_DTOR_INHERITED(_type, _base) \
do { \
MOZ_ASSERT_CLASSNAME(_type); \
MOZ_ASSERT_CLASSNAME(_base); \
MOZ_ASSERT_NOT_ISUPPORTS(_type); \
NS_LogDtor((void*)this, #_type, sizeof(*this) - sizeof(_base)); \
} while (0)
# define MOZ_LOG_DTOR(_ptr, _name, _size) \
do { \
NS_LogDtor((void*)_ptr, _name, _size); \
} while (0)
# define MOZ_COUNTED_DEFAULT_CTOR(_type) \
_type() { MOZ_COUNT_CTOR(_type); }
# define MOZ_COUNTED_DTOR_META(_type, _prefix, _postfix) \
_prefix ~_type() _postfix { MOZ_COUNT_DTOR(_type); }
# define MOZ_COUNTED_DTOR_NESTED(_type, _nestedName) \
~_type() { MOZ_COUNT_DTOR(_nestedName); }
/* nsCOMPtr.h allows these macros to be defined by clients
* These logging functions require dynamic_cast<void*>, so they don't
* do anything useful if we don't have dynamic_cast<void*>.
* Note: The explicit comparison to nullptr is needed to avoid warnings
* when _p is a nullptr itself. */
# define NSCAP_LOG_ASSIGNMENT(_c, _p) \
if (_p != nullptr) NS_LogCOMPtrAddRef((_c), ToSupports(_p))
# define NSCAP_LOG_RELEASE(_c, _p) \
if (_p) NS_LogCOMPtrRelease((_c), ToSupports(_p))
#else /* !NS_BUILD_REFCNT_LOGGING */
# define NS_LOG_ADDREF(_p, _rc, _type, _size)
# define NS_LOG_RELEASE(_p, _rc, _type)
# define MOZ_COUNT_CTOR(_type)
# define MOZ_COUNT_CTOR_INHERITED(_type, _base)
# define MOZ_LOG_CTOR(_ptr, _name, _size)
# define MOZ_COUNT_DTOR(_type)
# define MOZ_COUNT_DTOR_INHERITED(_type, _base)
# define MOZ_LOG_DTOR(_ptr, _name, _size)
# define MOZ_COUNTED_DEFAULT_CTOR(_type) _type() = default;
# define MOZ_COUNTED_DTOR_META(_type, _prefix, _postfix) \
_prefix ~_type() _postfix = default;
# define MOZ_COUNTED_DTOR_NESTED(_type, _nestedName) ~_type() = default;
#endif /* NS_BUILD_REFCNT_LOGGING */
#define MOZ_COUNTED_DTOR(_type) MOZ_COUNTED_DTOR_META(_type, , )
#define MOZ_COUNTED_DTOR_OVERRIDE(_type) \
MOZ_COUNTED_DTOR_META(_type, , override)
#define MOZ_COUNTED_DTOR_FINAL(_type) MOZ_COUNTED_DTOR_META(_type, , final)
#define MOZ_COUNTED_DTOR_VIRTUAL(_type) MOZ_COUNTED_DTOR_META(_type, virtual, )
// Support for ISupports classes which interact with cycle collector.
#define NS_NUMBER_OF_FLAGS_IN_REFCNT 2
#define NS_IN_PURPLE_BUFFER (1 << 0)
#define NS_IS_PURPLE (1 << 1)
#define NS_REFCOUNT_CHANGE (1 << NS_NUMBER_OF_FLAGS_IN_REFCNT)
#define NS_REFCOUNT_VALUE(_val) (_val >> NS_NUMBER_OF_FLAGS_IN_REFCNT)
class nsCycleCollectingAutoRefCnt {
public:
typedef void (*Suspect)(void* aPtr, nsCycleCollectionParticipant* aCp,
nsCycleCollectingAutoRefCnt* aRefCnt,
bool* aShouldDelete);
nsCycleCollectingAutoRefCnt() : mRefCntAndFlags(0) {}
explicit nsCycleCollectingAutoRefCnt(uintptr_t aValue)
: mRefCntAndFlags(aValue << NS_NUMBER_OF_FLAGS_IN_REFCNT) {}
nsCycleCollectingAutoRefCnt(const nsCycleCollectingAutoRefCnt&) = delete;
void operator=(const nsCycleCollectingAutoRefCnt&) = delete;
template <Suspect suspect = NS_CycleCollectorSuspect3>
MOZ_ALWAYS_INLINE uintptr_t incr(nsISupports* aOwner) {
return incr<suspect>(aOwner, nullptr);
}
template <Suspect suspect = NS_CycleCollectorSuspect3>
MOZ_ALWAYS_INLINE uintptr_t incr(void* aOwner,
nsCycleCollectionParticipant* aCp) {
mRefCntAndFlags += NS_REFCOUNT_CHANGE;
mRefCntAndFlags &= ~NS_IS_PURPLE;
// For incremental cycle collection, use the purple buffer to track objects
// that have been AddRef'd.
if (!IsInPurpleBuffer()) {
mRefCntAndFlags |= NS_IN_PURPLE_BUFFER;
// Refcount isn't zero, so Suspect won't delete anything.
MOZ_ASSERT(get() > 0);
suspect(aOwner, aCp, this, nullptr);
}
return NS_REFCOUNT_VALUE(mRefCntAndFlags);
}
MOZ_ALWAYS_INLINE void stabilizeForDeletion() {
// Set refcnt to 1 and mark us to be in the purple buffer.
// This way decr won't call suspect again.
mRefCntAndFlags = NS_REFCOUNT_CHANGE | NS_IN_PURPLE_BUFFER;
}
template <Suspect suspect = NS_CycleCollectorSuspect3>
MOZ_ALWAYS_INLINE uintptr_t decr(nsISupports* aOwner,
bool* aShouldDelete = nullptr) {
return decr<suspect>(aOwner, nullptr, aShouldDelete);
}
template <Suspect suspect = NS_CycleCollectorSuspect3>
MOZ_ALWAYS_INLINE uintptr_t decr(void* aOwner,
nsCycleCollectionParticipant* aCp,
bool* aShouldDelete = nullptr) {
MOZ_ASSERT(get() > 0);
if (!IsInPurpleBuffer()) {
mRefCntAndFlags -= NS_REFCOUNT_CHANGE;
mRefCntAndFlags |= (NS_IN_PURPLE_BUFFER | NS_IS_PURPLE);
uintptr_t retval = NS_REFCOUNT_VALUE(mRefCntAndFlags);
// Suspect may delete 'aOwner' and 'this'!
suspect(aOwner, aCp, this, aShouldDelete);
return retval;
}
mRefCntAndFlags -= NS_REFCOUNT_CHANGE;
mRefCntAndFlags |= (NS_IN_PURPLE_BUFFER | NS_IS_PURPLE);
return NS_REFCOUNT_VALUE(mRefCntAndFlags);
}
MOZ_ALWAYS_INLINE void RemovePurple() {
MOZ_ASSERT(IsPurple(), "must be purple");
mRefCntAndFlags &= ~NS_IS_PURPLE;
}
MOZ_ALWAYS_INLINE void RemoveFromPurpleBuffer() {
MOZ_ASSERT(IsInPurpleBuffer());
mRefCntAndFlags &= ~(NS_IS_PURPLE | NS_IN_PURPLE_BUFFER);
}
MOZ_ALWAYS_INLINE bool IsPurple() const {
return !!(mRefCntAndFlags & NS_IS_PURPLE);
}
MOZ_ALWAYS_INLINE bool IsInPurpleBuffer() const {
return !!(mRefCntAndFlags & NS_IN_PURPLE_BUFFER);
}
MOZ_ALWAYS_INLINE nsrefcnt get() const {
return NS_REFCOUNT_VALUE(mRefCntAndFlags);
}
MOZ_ALWAYS_INLINE operator nsrefcnt() const { return get(); }
private:
uintptr_t mRefCntAndFlags;
};
class nsAutoRefCnt {
public:
nsAutoRefCnt() : mValue(0) {}
explicit nsAutoRefCnt(nsrefcnt aValue) : mValue(aValue) {}
nsAutoRefCnt(const nsAutoRefCnt&) = delete;
void operator=(const nsAutoRefCnt&) = delete;
// only support prefix increment/decrement
nsrefcnt operator++() { return ++mValue; }
nsrefcnt operator--() { return --mValue; }
nsrefcnt operator=(nsrefcnt aValue) { return (mValue = aValue); }
operator nsrefcnt() const { return mValue; }
nsrefcnt get() const { return mValue; }
static const bool isThreadSafe = false;
private:
nsrefcnt operator++(int) = delete;
nsrefcnt operator--(int) = delete;
nsrefcnt mValue;
};
namespace mozilla {
class ThreadSafeAutoRefCnt {
public:
ThreadSafeAutoRefCnt() : mValue(0) {}
explicit ThreadSafeAutoRefCnt(nsrefcnt aValue) : mValue(aValue) {}
ThreadSafeAutoRefCnt(const ThreadSafeAutoRefCnt&) = delete;
void operator=(const ThreadSafeAutoRefCnt&) = delete;
// only support prefix increment/decrement
MOZ_ALWAYS_INLINE nsrefcnt operator++() {
// Memory synchronization is not required when incrementing a
// reference count. The first increment of a reference count on a
// thread is not important, since the first use of the object on a
// thread can happen before it. What is important is the transfer
// of the pointer to that thread, which may happen prior to the
// first increment on that thread. The necessary memory
// synchronization is done by the mechanism that transfers the
// pointer between threads.
return mValue.fetch_add(1, std::memory_order_relaxed) + 1;
}
MOZ_ALWAYS_INLINE nsrefcnt operator--() {
// Since this may be the last release on this thread, we need
// release semantics so that prior writes on this thread are visible
// to the thread that destroys the object when it reads mValue with
// acquire semantics.
nsrefcnt result = mValue.fetch_sub(1, std::memory_order_release) - 1;
if (result == 0) {
// We're going to destroy the object on this thread, so we need
// acquire semantics to synchronize with the memory released by
// the last release on other threads, that is, to ensure that
// writes prior to that release are now visible on this thread.
#ifdef MOZ_TSAN
// TSan doesn't understand std::atomic_thread_fence, so in order
// to avoid a false positive for every time a refcounted object
// is deleted, we replace the fence with an atomic operation.
mValue.load(std::memory_order_acquire);
#else
std::atomic_thread_fence(std::memory_order_acquire);
#endif
}
return result;
}
MOZ_ALWAYS_INLINE nsrefcnt operator=(nsrefcnt aValue) {
// Use release semantics since we're not sure what the caller is
// doing.
mValue.store(aValue, std::memory_order_release);
return aValue;
}
MOZ_ALWAYS_INLINE operator nsrefcnt() const { return get(); }
MOZ_ALWAYS_INLINE nsrefcnt get() const {
// Use acquire semantics since we're not sure what the caller is
// doing.
return mValue.load(std::memory_order_acquire);
}
static const bool isThreadSafe = true;
private:
nsrefcnt operator++(int) = delete;
nsrefcnt operator--(int) = delete;
std::atomic<nsrefcnt> mValue;
};
} // namespace mozilla
///////////////////////////////////////////////////////////////////////////////
/**
* Declare the reference count variable and the implementations of the
* AddRef and QueryInterface methods.
*/
#define NS_DECL_ISUPPORTS \
public: \
NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override; \
NS_IMETHOD_(MozExternalRefCountType) AddRef(void) override; \
NS_IMETHOD_(MozExternalRefCountType) Release(void) override; \
using HasThreadSafeRefCnt = std::false_type; \
\
protected: \
nsAutoRefCnt mRefCnt; \
NS_DECL_OWNINGTHREAD \
public:
#define NS_DECL_THREADSAFE_ISUPPORTS \
public: \
NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override; \
NS_IMETHOD_(MozExternalRefCountType) AddRef(void) override; \
NS_IMETHOD_(MozExternalRefCountType) Release(void) override; \
using HasThreadSafeRefCnt = std::true_type; \
\
protected: \
::mozilla::ThreadSafeAutoRefCnt mRefCnt; \
NS_DECL_OWNINGTHREAD \
public:
#define NS_DECL_CYCLE_COLLECTING_ISUPPORTS \
NS_DECL_CYCLE_COLLECTING_ISUPPORTS_META(override) \
NS_IMETHOD_(void) DeleteCycleCollectable(void); \
\
public:
#define NS_DECL_CYCLE_COLLECTING_ISUPPORTS_FINAL \
NS_DECL_CYCLE_COLLECTING_ISUPPORTS_META(final) \
NS_IMETHOD_(void) DeleteCycleCollectable(void); \
\
public:
#define NS_DECL_CYCLE_COLLECTING_ISUPPORTS_FINAL_DELETECYCLECOLLECTABLE \
NS_DECL_CYCLE_COLLECTING_ISUPPORTS_META(override) \
NS_IMETHOD_(void) DeleteCycleCollectable(void) final; \
\
public:
#define NS_DECL_CYCLE_COLLECTING_ISUPPORTS_META(...) \
public: \
NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) __VA_ARGS__; \
NS_IMETHOD_(MozExternalRefCountType) AddRef(void) __VA_ARGS__; \
NS_IMETHOD_(MozExternalRefCountType) Release(void) __VA_ARGS__; \
using HasThreadSafeRefCnt = std::false_type; \
\
protected: \
nsCycleCollectingAutoRefCnt mRefCnt; \
NS_DECL_OWNINGTHREAD \
public:
///////////////////////////////////////////////////////////////////////////////
/*
* Implementation of AddRef and Release for non-nsISupports (ie "native")
* cycle-collected classes that use the purple buffer to avoid leaks.
*/
#define NS_IMPL_CC_NATIVE_ADDREF_BODY(_class) \
MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
NS_ASSERT_OWNINGTHREAD(_class); \
nsrefcnt count = \
mRefCnt.incr(static_cast<void*>(this), \
_class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \
return count;
#define NS_IMPL_CC_MAIN_THREAD_ONLY_NATIVE_ADDREF_BODY(_class) \
MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
NS_ASSERT_OWNINGTHREAD(_class); \
nsrefcnt count = mRefCnt.incr<NS_CycleCollectorSuspectUsingNursery>( \
static_cast<void*>(this), \
_class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \
return count;
#define NS_IMPL_CC_NATIVE_RELEASE_BODY(_class) \
MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
NS_ASSERT_OWNINGTHREAD(_class); \
nsrefcnt count = \
mRefCnt.decr(static_cast<void*>(this), \
_class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
NS_LOG_RELEASE(this, count, #_class); \
return count;
#define NS_IMPL_CC_MAIN_THREAD_ONLY_NATIVE_RELEASE_BODY(_class) \
MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
NS_ASSERT_OWNINGTHREAD(_class); \
nsrefcnt count = mRefCnt.decr<NS_CycleCollectorSuspectUsingNursery>( \
static_cast<void*>(this), \
_class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
NS_LOG_RELEASE(this, count, #_class); \
return count;
#define NS_IMPL_CYCLE_COLLECTING_NATIVE_ADDREF(_class) \
NS_METHOD_(MozExternalRefCountType) _class::AddRef(void) { \
NS_IMPL_CC_NATIVE_ADDREF_BODY(_class) \
}
#define NS_IMPL_CYCLE_COLLECTING_NATIVE_RELEASE_WITH_LAST_RELEASE(_class, \
_last) \
NS_METHOD_(MozExternalRefCountType) _class::Release(void) { \
MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
NS_ASSERT_OWNINGTHREAD(_class); \
bool shouldDelete = false; \
nsrefcnt count = \
mRefCnt.decr(static_cast<void*>(this), \
_class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant(), \
&shouldDelete); \
NS_LOG_RELEASE(this, count, #_class); \
if (count == 0) { \
mRefCnt.incr(static_cast<void*>(this), \
_class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
_last; \
mRefCnt.decr(static_cast<void*>(this), \
_class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
if (shouldDelete) { \
mRefCnt.stabilizeForDeletion(); \
DeleteCycleCollectable(); \
} \
} \
return count; \
}
#define NS_IMPL_CYCLE_COLLECTING_NATIVE_RELEASE(_class) \
NS_METHOD_(MozExternalRefCountType) _class::Release(void) { \
NS_IMPL_CC_NATIVE_RELEASE_BODY(_class) \
}
#define NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(_class) \
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING_META(_class, NS_METHOD_)
#define NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING_VIRTUAL(_class) \
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING_META(_class, NS_IMETHOD_)
#define NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING_INHERITED(_class) \
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING_META(_class, NS_METHOD_, \
override)
#define NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING_META(_class, _decl, \
...) \
public: \
_decl(MozExternalRefCountType) AddRef(void) __VA_ARGS__{ \
NS_IMPL_CC_NATIVE_ADDREF_BODY(_class)} _decl(MozExternalRefCountType) \
Release(void) __VA_ARGS__ { \
NS_IMPL_CC_NATIVE_RELEASE_BODY(_class) \
} \
using HasThreadSafeRefCnt = std::false_type; \
\
protected: \
nsCycleCollectingAutoRefCnt mRefCnt; \
NS_DECL_OWNINGTHREAD \
public:
#define NS_INLINE_DECL_MAIN_THREAD_ONLY_CYCLE_COLLECTING_NATIVE_REFCOUNTING( \
_class) \
public: \
NS_METHOD_(MozExternalRefCountType) \
AddRef(void){NS_IMPL_CC_MAIN_THREAD_ONLY_NATIVE_ADDREF_BODY( \
_class)} NS_METHOD_(MozExternalRefCountType) Release(void) { \
NS_IMPL_CC_MAIN_THREAD_ONLY_NATIVE_RELEASE_BODY(_class) \
} \
using HasThreadSafeRefCnt = std::false_type; \
\
protected: \
nsCycleCollectingAutoRefCnt mRefCnt; \
NS_DECL_OWNINGTHREAD \
public:
///////////////////////////////////////////////////////////////////////////////
/**
* Use this macro to declare and implement the AddRef & Release methods for a
* given non-XPCOM <i>_class</i>.
*
* @param _class The name of the class implementing the method
* @param _destroy A statement that is executed when the object's
* refcount drops to zero.
* @param _decl Name of the macro to be used for the return type of the
* AddRef & Release methods (typically NS_IMETHOD_ or NS_METHOD_).
* @param optional override Mark the AddRef & Release methods as overrides.
*/
#define NS_INLINE_DECL_REFCOUNTING_META(_class, _decl, _destroy, _owning, ...) \
public: \
_decl(MozExternalRefCountType) AddRef(void) __VA_ARGS__ { \
MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
NS_ASSERT_OWNINGTHREAD(_class); \
++mRefCnt; \
NS_LOG_ADDREF(this, mRefCnt, #_class, sizeof(*this)); \
return mRefCnt; \
} \
_decl(MozExternalRefCountType) Release(void) __VA_ARGS__ { \
MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
NS_ASSERT_OWNINGTHREAD(_class); \
--mRefCnt; \
NS_LOG_RELEASE(this, mRefCnt, #_class); \
if (mRefCnt == 0) { \
mRefCnt = 1; /* stabilize */ \
_destroy; \
return 0; \
} \
return mRefCnt; \
} \
using HasThreadSafeRefCnt = std::false_type; \
\
protected: \
nsAutoRefCnt mRefCnt; \
_owning \
public:
/**
* Use this macro to declare and implement the AddRef & Release methods for a
* given non-XPCOM <i>_class</i>.
*
* @param _class The name of the class implementing the method
* @param _destroy A statement that is executed when the object's
* refcount drops to zero.
* @param optional override Mark the AddRef & Release methods as overrides.
*/
#define NS_INLINE_DECL_REFCOUNTING_WITH_DESTROY(_class, _destroy, ...) \
NS_INLINE_DECL_REFCOUNTING_META(_class, NS_METHOD_, _destroy, \
NS_DECL_OWNINGTHREAD, __VA_ARGS__)
/**
* Like NS_INLINE_DECL_REFCOUNTING_WITH_DESTROY with AddRef & Release declared
* virtual.
*/
#define NS_INLINE_DECL_VIRTUAL_REFCOUNTING_WITH_DESTROY(_class, _destroy, ...) \
NS_INLINE_DECL_REFCOUNTING_META(_class, NS_IMETHOD_, _destroy, \
NS_DECL_OWNINGTHREAD, __VA_ARGS__)
/**
* Use this macro to declare and implement the AddRef & Release methods for a
* given non-XPCOM <i>_class</i>.
*
* @param _class The name of the class implementing the method
* @param optional override Mark the AddRef & Release methods as overrides.
*/
#define NS_INLINE_DECL_REFCOUNTING(_class, ...) \
NS_INLINE_DECL_REFCOUNTING_WITH_DESTROY(_class, delete (this), __VA_ARGS__)
/**
* Like NS_INLINE_DECL_REFCOUNTING, however the thread safety check will work
* with any nsISerialEventTarget. This is a workaround until bug 1648031 is
* properly resolved. Once this is done, it will be possible to use
* NS_INLINE_DECL_REFCOUNTING under all circumstances.
*/
#define NS_INLINE_DECL_REFCOUNTING_ONEVENTTARGET(_class, ...) \
NS_INLINE_DECL_REFCOUNTING_META(_class, NS_METHOD_, delete (this), \
NS_DECL_OWNINGEVENTTARGET, __VA_ARGS__)
#define NS_INLINE_DECL_THREADSAFE_REFCOUNTING_META(_class, _decl, _destroy, \
...) \
public: \
_decl(MozExternalRefCountType) AddRef(void) __VA_ARGS__ { \
MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
nsrefcnt count = ++mRefCnt; \
NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \
return (nsrefcnt)count; \
} \
_decl(MozExternalRefCountType) Release(void) __VA_ARGS__ { \
MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
nsrefcnt count = --mRefCnt; \
NS_LOG_RELEASE(this, count, #_class); \
if (count == 0) { \
_destroy; \
return 0; \
} \
return count; \
} \
using HasThreadSafeRefCnt = std::true_type; \
\
protected: \
::mozilla::ThreadSafeAutoRefCnt mRefCnt; \
\
public:
/**
* Use this macro to declare and implement the AddRef & Release methods for a
* given non-XPCOM <i>_class</i> in a threadsafe manner.
*
* DOES NOT DO REFCOUNT STABILIZATION!
*
* @param _class The name of the class implementing the method
* @param _destroy A statement that is executed when the object's
* refcount drops to zero.
* @param optional override Mark the AddRef & Release methods as overrides.
*/
#define NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DESTROY(_class, _destroy, \
...) \
NS_INLINE_DECL_THREADSAFE_REFCOUNTING_META(_class, NS_METHOD_, _destroy, \
__VA_ARGS__)
/**
* Like NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DESTROY with AddRef & Release
* declared virtual.
*/
#define NS_INLINE_DECL_THREADSAFE_VIRTUAL_REFCOUNTING_WITH_DESTROY( \
_class, _destroy, ...) \
NS_INLINE_DECL_THREADSAFE_REFCOUNTING_META(_class, NS_IMETHOD_, _destroy, \
__VA_ARGS__)
/**
* Use this macro to declare and implement the AddRef & Release methods for a
* given non-XPCOM <i>_class</i> in a threadsafe manner.
*
* DOES NOT DO REFCOUNT STABILIZATION!
*
* @param _class The name of the class implementing the method
* @param optional override Mark the AddRef & Release methods as overrides.
*/
#define NS_INLINE_DECL_THREADSAFE_REFCOUNTING(_class, ...) \
NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DESTROY(_class, delete (this), \
__VA_ARGS__)
/**
* Like NS_INLINE_DECL_THREADSAFE_REFCOUNTING with AddRef & Release declared
* virtual.
*/
#define NS_INLINE_DECL_THREADSAFE_VIRTUAL_REFCOUNTING(_class, ...) \
NS_INLINE_DECL_THREADSAFE_VIRTUAL_REFCOUNTING_WITH_DESTROY( \
_class, delete (this), __VA_ARGS__)
/**
* Use this macro in interface classes that you want to be able to reference
* using RefPtr, but don't want to provide a refcounting implemenation. The
* refcounting implementation can be provided by concrete subclasses that
* implement the interface.
*/
#define NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING \
public: \
NS_IMETHOD_(MozExternalRefCountType) AddRef(void) = 0; \
NS_IMETHOD_(MozExternalRefCountType) Release(void) = 0; \
\
public:
/**
* Use this macro to implement the AddRef method for a given <i>_class</i>
* @param _class The name of the class implementing the method
* @param _name The class name to be passed to XPCOM leak checking
*/
#define NS_IMPL_NAMED_ADDREF(_class, _name) \
NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void) { \
MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
MOZ_ASSERT(_name != nullptr, "Must specify a name"); \
if (!