1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090 |
- /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* 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 thread-safety checks */
- #endif // !XPCOM_GLUE_AVOID_NSPR
- #include "nsDebug.h"
- #include "nsXPCOM.h"
- #include "mozilla/Atomics.h"
- #include "mozilla/Attributes.h"
- #include "mozilla/Assertions.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(nsISupports* aSupports)
- {
- return aSupports;
- }
- inline nsISupports*
- ToCanonicalSupports(nsISupports* aSupports)
- {
- return nullptr;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Macros to help detect thread-safety:
- #ifdef MOZ_THREAD_SAFETY_OWNERSHIP_CHECKS_SUPPORTED
- class nsAutoOwningThread
- {
- public:
- nsAutoOwningThread() { mThread = PR_GetCurrentThread(); }
- void* GetThread() const { return mThread; }
- private:
- void* mThread;
- };
- #define NS_DECL_OWNINGTHREAD nsAutoOwningThread _mOwningThread;
- #define NS_ASSERT_OWNINGTHREAD_AGGREGATE(agg, _class) \
- NS_CheckThreadSafe(agg->_mOwningThread.GetThread(), #_class " not thread-safe")
- #define NS_ASSERT_OWNINGTHREAD(_class) NS_ASSERT_OWNINGTHREAD_AGGREGATE(this, _class)
- #else // !DEBUG && !(NIGHTLY_BUILD && !MOZ_PROFILING)
- #define NS_DECL_OWNINGTHREAD /* nothing */
- #define NS_ASSERT_OWNINGTHREAD_AGGREGATE(agg, _class) ((void)0)
- #define NS_ASSERT_OWNINGTHREAD(_class) ((void)0)
- #endif // DEBUG || (NIGHTLY_BUILD && !MOZ_PROFILING)
- // 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))
- #include "mozilla/TypeTraits.h"
- #define MOZ_ASSERT_CLASSNAME(_type) \
- static_assert(mozilla::IsClass<_type>::value, \
- "Token '" #_type "' is not a class type.")
- // 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); \
- 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); \
- 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); \
- 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); \
- 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)
- /* 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),static_cast<nsISupports*>(_p))
- #define NSCAP_LOG_RELEASE(_c, _p) \
- if (_p) \
- NS_LogCOMPtrRelease((_c), static_cast<nsISupports*>(_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)
- #endif /* NS_BUILD_REFCNT_LOGGING */
- // 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:
- 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;
- MOZ_ALWAYS_INLINE uintptr_t incr(nsISupports* aOwner)
- {
- return incr(aOwner, nullptr);
- }
- 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);
- NS_CycleCollectorSuspect3(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;
- }
- MOZ_ALWAYS_INLINE uintptr_t decr(nsISupports* aOwner,
- bool* aShouldDelete = nullptr)
- {
- return decr(aOwner, nullptr, aShouldDelete);
- }
- 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'!
- NS_CycleCollectorSuspect3(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++() { return ++mValue; }
- MOZ_ALWAYS_INLINE nsrefcnt operator--() { return --mValue; }
- MOZ_ALWAYS_INLINE nsrefcnt operator=(nsrefcnt aValue)
- {
- return (mValue = aValue);
- }
- MOZ_ALWAYS_INLINE operator nsrefcnt() const { return mValue; }
- MOZ_ALWAYS_INLINE nsrefcnt get() const { return mValue; }
- static const bool isThreadSafe = true;
- private:
- nsrefcnt operator++(int) = delete;
- nsrefcnt operator--(int) = delete;
- // In theory, RelaseAcquire consistency (but no weaker) is sufficient for
- // the counter. Making it weaker could speed up builds on ARM (but not x86),
- // but could break pre-existing code that assumes sequential consistency.
- 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; \
- typedef mozilla::FalseType HasThreadSafeRefCnt; \
- 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; \
- typedef mozilla::TrueType HasThreadSafeRefCnt; \
- protected: \
- ::mozilla::ThreadSafeAutoRefCnt mRefCnt; \
- NS_DECL_OWNINGTHREAD \
- public:
- #define NS_DECL_CYCLE_COLLECTING_ISUPPORTS \
- public: \
- NS_IMETHOD QueryInterface(REFNSIID aIID, \
- void** aInstancePtr) override; \
- NS_IMETHOD_(MozExternalRefCountType) AddRef(void) override; \
- NS_IMETHOD_(MozExternalRefCountType) Release(void) override; \
- NS_IMETHOD_(void) DeleteCycleCollectable(void); \
- typedef mozilla::FalseType HasThreadSafeRefCnt; \
- 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_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_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) \
- public: \
- NS_METHOD_(MozExternalRefCountType) AddRef(void) { \
- NS_IMPL_CC_NATIVE_ADDREF_BODY(_class) \
- } \
- NS_METHOD_(MozExternalRefCountType) Release(void) { \
- NS_IMPL_CC_NATIVE_RELEASE_BODY(_class) \
- } \
- typedef mozilla::FalseType HasThreadSafeRefCnt; \
- 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 optional override Mark the AddRef & Release methods as overrides.
- */
- #define NS_INLINE_DECL_REFCOUNTING_WITH_DESTROY(_class, _destroy, ...) \
- public: \
- NS_METHOD_(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; \
- } \
- NS_METHOD_(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; \
- } \
- typedef mozilla::FalseType HasThreadSafeRefCnt; \
- protected: \
- nsAutoRefCnt 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 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__)
- #define NS_INLINE_DECL_THREADSAFE_REFCOUNTING_META(_class, _decl, ...) \
- 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) { \
- delete (this); \
- return 0; \
- } \
- return count; \
- } \
- typedef mozilla::TrueType HasThreadSafeRefCnt; \
- 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
- */
- #define NS_INLINE_DECL_THREADSAFE_REFCOUNTING(_class, ...) \
- NS_INLINE_DECL_THREADSAFE_REFCOUNTING_META(_class, NS_METHOD_, __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_REFCOUNTING_META(_class, NS_IMETHOD_, __VA_ARGS__)
- /**
- * Use this macro to implement the AddRef method for a given <i>_class</i>
- * @param _class The name of the class implementing the method
- */
- #define NS_IMPL_ADDREF(_class) \
- NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void) \
- { \
- MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
- MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
- if (!mRefCnt.isThreadSafe) \
- NS_ASSERT_OWNINGTHREAD(_class); \
- nsrefcnt count = ++mRefCnt; \
- NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \
- return count; \
- }
- /**
- * Use this macro to implement the AddRef method for a given <i>_class</i>
- * implemented as a wholly owned aggregated object intended to implement
- * interface(s) for its owner
- * @param _class The name of the class implementing the method
- * @param _aggregator the owning/containing object
- */
- #define NS_IMPL_ADDREF_USING_AGGREGATOR(_class, _aggregator) \
- NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void) \
- { \
- MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
- NS_PRECONDITION(_aggregator, "null aggregator"); \
- return (_aggregator)->AddRef(); \
- }
- /**
- * Use this macro to implement the Release method for a given
- * <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.
- *
- * For example,
- *
- * NS_IMPL_RELEASE_WITH_DESTROY(Foo, Destroy(this))
- *
- * will cause
- *
- * Destroy(this);
- *
- * to be invoked when the object's refcount drops to zero. This
- * allows for arbitrary teardown activity to occur (e.g., deallocation
- * of object allocated with placement new).
- */
- #define NS_IMPL_RELEASE_WITH_DESTROY(_class, _destroy) \
- NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) \
- { \
- MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
- if (!mRefCnt.isThreadSafe) \
- NS_ASSERT_OWNINGTHREAD(_class); \
- nsrefcnt count = --mRefCnt; \
- NS_LOG_RELEASE(this, count, #_class); \
- if (count == 0) { \
- mRefCnt = 1; /* stabilize */ \
- _destroy; \
- return 0; \
- } \
- return count; \
- }
- /**
- * Use this macro to implement the Release method for a given <i>_class</i>
- * @param _class The name of the class implementing the method
- *
- * A note on the 'stabilization' of the refcnt to one. At that point,
- * the object's refcount will have gone to zero. The object's
- * destructor may trigger code that attempts to QueryInterface() and
- * Release() 'this' again. Doing so will temporarily increment and
- * decrement the refcount. (Only a logic error would make one try to
- * keep a permanent hold on 'this'.) To prevent re-entering the
- * destructor, we make sure that no balanced refcounting can return
- * the refcount to |0|.
- */
- #define NS_IMPL_RELEASE(_class) \
- NS_IMPL_RELEASE_WITH_DESTROY(_class, delete (this))
- /**
- * Use this macro to implement the Release method for a given <i>_class</i>
- * implemented as a wholly owned aggregated object intended to implement
- * interface(s) for its owner
- * @param _class The name of the class implementing the method
- * @param _aggregator the owning/containing object
- */
- #define NS_IMPL_RELEASE_USING_AGGREGATOR(_class, _aggregator) \
- NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) \
- { \
- NS_PRECONDITION(_aggregator, "null aggregator"); \
- return (_aggregator)->Release(); \
- }
- #define NS_IMPL_CYCLE_COLLECTING_ADDREF(_class) \
- NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void) \
- { \
- MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
- MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
- NS_ASSERT_OWNINGTHREAD(_class); \
- nsISupports *base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this); \
- nsrefcnt count = mRefCnt.incr(base); \
- NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \
- return count; \
- }
- #define NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(_class, _destroy) \
- NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) \
- { \
- MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
- NS_ASSERT_OWNINGTHREAD(_class); \
- nsISupports *base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this); \
- nsrefcnt count = mRefCnt.decr(base); \
- NS_LOG_RELEASE(this, count, #_class); \
- return count; \
- } \
- NS_IMETHODIMP_(void) _class::DeleteCycleCollectable(void) \
- { \
- _destroy; \
- }
- #define NS_IMPL_CYCLE_COLLECTING_RELEASE(_class) \
- NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(_class, delete (this))
- // _LAST_RELEASE can be useful when certain resources should be released
- // as soon as we know the object will be deleted.
- #define NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(_class, _last) \
- NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) \
- { \
- MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
- NS_ASSERT_OWNINGTHREAD(_class); \
- bool shouldDelete = false; \
- nsISupports *base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this); \
- nsrefcnt count = mRefCnt.decr(base, &shouldDelete); \
- NS_LOG_RELEASE(this, count, #_class); \
- if (count == 0) { \
- mRefCnt.incr(base); \
- _last; \
- mRefCnt.decr(base); \
- if (shouldDelete) { \
- mRefCnt.stabilizeForDeletion(); \
- DeleteCycleCollectable(); \
- } \
- } \
- return count; \
- } \
- NS_IMETHODIMP_(void) _class::DeleteCycleCollectable(void) \
- { \
- delete this; \
- }
- ///////////////////////////////////////////////////////////////////////////////
- /**
- * There are two ways of implementing QueryInterface, and we use both:
- *
- * Table-driven QueryInterface uses a static table of IID->offset mappings
- * and a shared helper function. Using it tends to reduce codesize and improve
- * runtime performance (due to processor cache hits).
- *
- * Macro-driven QueryInterface generates a QueryInterface function directly
- * using common macros. This is necessary if special QueryInterface features
- * are being used (such as tearoffs and conditional interfaces).
- *
- * These methods can be combined into a table-driven function call followed
- * by custom code for tearoffs and conditionals.
- */
- struct QITableEntry
- {
- const nsIID* iid; // null indicates end of the QITableEntry array
- int32_t offset;
- };
- nsresult NS_FASTCALL
- NS_TableDrivenQI(void* aThis, REFNSIID aIID,
- void** aInstancePtr, const QITableEntry* aEntries);
- /**
- * Implement table-driven queryinterface
- */
- #define NS_INTERFACE_TABLE_HEAD(_class) \
- NS_IMETHODIMP _class::QueryInterface(REFNSIID aIID, void** aInstancePtr) \
- { \
- NS_ASSERTION(aInstancePtr, \
- "QueryInterface requires a non-NULL destination!"); \
- nsresult rv = NS_ERROR_FAILURE;
- #define NS_INTERFACE_TABLE_BEGIN \
- static const QITableEntry table[] = {
- #define NS_INTERFACE_TABLE_ENTRY(_class, _interface) \
- { &NS_GET_IID(_interface), \
- int32_t(reinterpret_cast<char*>( \
- static_cast<_interface*>((_class*) 0x1000)) - \
- reinterpret_cast<char*>((_class*) 0x1000)) \
- },
- #define NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(_class, _interface, _implClass) \
- { &NS_GET_IID(_interface), \
- int32_t(reinterpret_cast<char*>( \
- static_cast<_interface*>( \
- static_cast<_implClass*>( \
- (_class*) 0x1000))) - \
- reinterpret_cast<char*>((_class*) 0x1000)) \
- },
- /*
- * XXX: we want to use mozilla::ArrayLength (or equivalent,
- * MOZ_ARRAY_LENGTH) in this condition, but some versions of GCC don't
- * see that the static_assert condition is actually constant in those
- * cases, even with constexpr support (?).
- */
- #define NS_INTERFACE_TABLE_END_WITH_PTR(_ptr) \
- { nullptr, 0 } }; \
- static_assert((sizeof(table)/sizeof(table[0])) > 1, "need at least 1 interface"); \
- rv = NS_TableDrivenQI(static_cast<void*>(_ptr), \
- aIID, aInstancePtr, table);
- #define NS_INTERFACE_TABLE_END \
- NS_INTERFACE_TABLE_END_WITH_PTR(this)
- #define NS_INTERFACE_TABLE_TAIL \
- return rv; \
- }
- #define NS_INTERFACE_TABLE_TAIL_INHERITING(_baseclass) \
- if (NS_SUCCEEDED(rv)) \
- return rv; \
- return _baseclass::QueryInterface(aIID, aInstancePtr); \
- }
- #define NS_INTERFACE_TABLE_TAIL_USING_AGGREGATOR(_aggregator) \
- if (NS_SUCCEEDED(rv)) \
- return rv; \
- NS_ASSERTION(_aggregator, "null aggregator"); \
- return _aggregator->QueryInterface(aIID, aInstancePtr) \
- }
- /**
- * This implements query interface with two assumptions: First, the
- * class in question implements nsISupports and its own interface and
- * nothing else. Second, the implementation of the class's primary
- * inheritance chain leads to its own interface.
- *
- * @param _class The name of the class implementing the method
- * @param _classiiddef The name of the #define symbol that defines the IID
- * for the class (e.g. NS_ISUPPORTS_IID)
- */
- #define NS_IMPL_QUERY_HEAD(_class) \
- NS_IMETHODIMP _class::QueryInterface(REFNSIID aIID, void** aInstancePtr) \
- { \
- NS_ASSERTION(aInstancePtr, \
- "QueryInterface requires a non-NULL destination!"); \
- nsISupports* foundInterface;
- #define NS_IMPL_QUERY_BODY(_interface) \
- if ( aIID.Equals(NS_GET_IID(_interface)) ) \
- foundInterface = static_cast<_interface*>(this); \
- else
- #define NS_IMPL_QUERY_BODY_CONDITIONAL(_interface, condition) \
- if ( (condition) && aIID.Equals(NS_GET_IID(_interface))) \
- foundInterface = static_cast<_interface*>(this); \
- else
- #define NS_IMPL_QUERY_BODY_AMBIGUOUS(_interface, _implClass) \
- if ( aIID.Equals(NS_GET_IID(_interface)) ) \
- foundInterface = static_cast<_interface*>( \
- static_cast<_implClass*>(this)); \
- else
- #define NS_IMPL_QUERY_BODY_AGGREGATED(_interface, _aggregate) \
- if ( aIID.Equals(NS_GET_IID(_interface)) ) \
- foundInterface = static_cast<_interface*>(_aggregate); \
- else
- #define NS_IMPL_QUERY_TAIL_GUTS \
- foundInterface = 0; \
- nsresult status; \
- if ( !foundInterface ) \
- { \
- /* nsISupports should be handled by this point. If not, fail. */ \
- MOZ_ASSERT(!aIID.Equals(NS_GET_IID(nsISupports))); \
- status = NS_NOINTERFACE; \
- } \
- else \
- { \
- NS_ADDREF(foundInterface); \
- status = NS_OK; \
- } \
- *aInstancePtr = foundInterface; \
- return status; \
- }
- #define NS_IMPL_QUERY_TAIL_INHERITING(_baseclass) \
- foundInterface = 0; \
- nsresult status; \
- if ( !foundInterface ) \
- status = _baseclass::QueryInterface(aIID, (void**)&foundInterface); \
- else \
- { \
- NS_ADDREF(foundInterface); \
- status = NS_OK; \
- } \
- *aInstancePtr = foundInterface; \
- return status; \
- }
- #define NS_IMPL_QUERY_TAIL_USING_AGGREGATOR(_aggregator) \
- foundInterface = 0; \
- nsresult status; \
- if ( !foundInterface ) { \
- NS_ASSERTION(_aggregator, "null aggregator"); \
- status = _aggregator->QueryInterface(aIID, (void**)&foundInterface); \
- } else \
- { \
- NS_ADDREF(foundInterface); \
- status = NS_OK; \
- } \
- *aInstancePtr = foundInterface; \
- return status; \
- }
- #define NS_IMPL_QUERY_TAIL(_supports_interface) \
- NS_IMPL_QUERY_BODY_AMBIGUOUS(nsISupports, _supports_interface) \
- NS_IMPL_QUERY_TAIL_GUTS
- /*
- This is the new scheme. Using this notation now will allow us to switch to
- a table driven mechanism when it's ready. Note the difference between this
- and the (currently) underlying NS_IMPL_QUERY_INTERFACE mechanism. You must
- explicitly mention |nsISupports| when using the interface maps.
- */
- #define NS_INTERFACE_MAP_BEGIN(_implClass) NS_IMPL_QUERY_HEAD(_implClass)
- #define NS_INTERFACE_MAP_ENTRY(_interface) NS_IMPL_QUERY_BODY(_interface)
- #define NS_INTERFACE_MAP_ENTRY_CONDITIONAL(_interface, condition) \
- NS_IMPL_QUERY_BODY_CONDITIONAL(_interface, condition)
- #define NS_INTERFACE_MAP_ENTRY_AGGREGATED(_interface,_aggregate) \
- NS_IMPL_QUERY_BODY_AGGREGATED(_interface,_aggregate)
- #define NS_INTERFACE_MAP_END NS_IMPL_QUERY_TAIL_GUTS
- #define NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(_interface, _implClass) \
- NS_IMPL_QUERY_BODY_AMBIGUOUS(_interface, _implClass)
- #define NS_INTERFACE_MAP_END_INHERITING(_baseClass) \
- NS_IMPL_QUERY_TAIL_INHERITING(_baseClass)
- #define NS_INTERFACE_MAP_END_AGGREGATED(_aggregator) \
- NS_IMPL_QUERY_TAIL_USING_AGGREGATOR(_aggregator)
- #define NS_INTERFACE_TABLE0(_class) \
- NS_INTERFACE_TABLE_BEGIN \
- NS_INTERFACE_TABLE_ENTRY(_class, nsISupports) \
- NS_INTERFACE_TABLE_END
- #define NS_INTERFACE_TABLE(aClass, ...) \
- MOZ_STATIC_ASSERT_VALID_ARG_COUNT(__VA_ARGS__); \
- NS_INTERFACE_TABLE_BEGIN \
- MOZ_FOR_EACH(NS_INTERFACE_TABLE_ENTRY, (aClass,), (__VA_ARGS__)) \
- NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(aClass, nsISupports, \
- MOZ_ARG_1(__VA_ARGS__)) \
- NS_INTERFACE_TABLE_END
- #define NS_IMPL_QUERY_INTERFACE0(_class) \
- NS_INTERFACE_TABLE_HEAD(_class) \
- NS_INTERFACE_TABLE0(_class) \
- NS_INTERFACE_TABLE_TAIL
- #define NS_IMPL_QUERY_INTERFACE(aClass, ...) \
- NS_INTERFACE_TABLE_HEAD(aClass) \
- NS_INTERFACE_TABLE(aClass, __VA_ARGS__) \
- NS_INTERFACE_TABLE_TAIL
- /**
- * Declare that you're going to inherit from something that already
- * implements nsISupports, but also implements an additional interface, thus
- * causing an ambiguity. In this case you don't need another mRefCnt, you
- * just need to forward the definitions to the appropriate superclass. E.g.
- *
- * class Bar : public Foo, public nsIBar { // both provide nsISupports
- * public:
- * NS_DECL_ISUPPORTS_INHERITED
- * ...other nsIBar and Bar methods...
- * };
- */
- #define NS_DECL_ISUPPORTS_INHERITED \
- public: \
- NS_IMETHOD QueryInterface(REFNSIID aIID, \
- void** aInstancePtr) override; \
- NS_IMETHOD_(MozExternalRefCountType) AddRef(void) override; \
- NS_IMETHOD_(MozExternalRefCountType) Release(void) override; \
- /**
- * These macros can be used in conjunction with NS_DECL_ISUPPORTS_INHERITED
- * to implement the nsISupports methods, forwarding the invocations to a
- * superclass that already implements nsISupports.
- *
- * Note that I didn't make these inlined because they're virtual methods.
- */
- #define NS_IMPL_ADDREF_INHERITED(Class, Super) \
- NS_IMETHODIMP_(MozExternalRefCountType) Class::AddRef(void) \
- { \
- MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(Class) \
- nsrefcnt r = Super::AddRef(); \
- NS_LOG_ADDREF(this, r, #Class, sizeof(*this)); \
- return r; \
- }
- #define NS_IMPL_RELEASE_INHERITED(Class, Super) \
- NS_IMETHODIMP_(MozExternalRefCountType) Class::Release(void) \
- { \
- nsrefcnt r = Super::Release(); \
- NS_LOG_RELEASE(this, r, #Class); \
- return r; \
- }
- /**
- * As above but not logging the addref/release; needed if the base
- * class might be aggregated.
- */
- #define NS_IMPL_NONLOGGING_ADDREF_INHERITED(Class, Super) \
- NS_IMETHODIMP_(MozExternalRefCountType) Class::AddRef(void) \
- { \
- MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(Class) \
- return Super::AddRef(); \
- }
- #define NS_IMPL_NONLOGGING_RELEASE_INHERITED(Class, Super) \
- NS_IMETHODIMP_(MozExternalRefCountType) Class::Release(void) \
- { \
- return Super::Release(); \
- }
- #define NS_INTERFACE_TABLE_INHERITED0(Class) /* Nothing to do here */
- #define NS_INTERFACE_TABLE_INHERITED(aClass, ...) \
- MOZ_STATIC_ASSERT_VALID_ARG_COUNT(__VA_ARGS__); \
- NS_INTERFACE_TABLE_BEGIN \
- MOZ_FOR_EACH(NS_INTERFACE_TABLE_ENTRY, (aClass,), (__VA_ARGS__)) \
- NS_INTERFACE_TABLE_END
- #define NS_IMPL_QUERY_INTERFACE_INHERITED(aClass, aSuper, ...) \
- NS_INTERFACE_TABLE_HEAD(aClass) \
- NS_INTERFACE_TABLE_INHERITED(aClass, __VA_ARGS__) \
- NS_INTERFACE_TABLE_TAIL_INHERITING(aSuper)
- /**
- * Convenience macros for implementing all nsISupports methods for
- * a simple class.
- * @param _class The name of the class implementing the method
- * @param _classiiddef The name of the #define symbol that defines the IID
- * for the class (e.g. NS_ISUPPORTS_IID)
- */
- #define NS_IMPL_ISUPPORTS0(_class) \
- NS_IMPL_ADDREF(_class) \
- NS_IMPL_RELEASE(_class) \
- NS_IMPL_QUERY_INTERFACE0(_class)
- #define NS_IMPL_ISUPPORTS(aClass, ...) \
- NS_IMPL_ADDREF(aClass) \
- NS_IMPL_RELEASE(aClass) \
- NS_IMPL_QUERY_INTERFACE(aClass, __VA_ARGS__)
- #define NS_IMPL_ISUPPORTS_INHERITED0(aClass, aSuper) \
- NS_INTERFACE_TABLE_HEAD(aClass) \
- NS_INTERFACE_TABLE_TAIL_INHERITING(aSuper) \
- NS_IMPL_ADDREF_INHERITED(aClass, aSuper) \
- NS_IMPL_RELEASE_INHERITED(aClass, aSuper) \
- #define NS_IMPL_ISUPPORTS_INHERITED(aClass, aSuper, ...) \
- NS_IMPL_QUERY_INTERFACE_INHERITED(aClass, aSuper, __VA_ARGS__) \
- NS_IMPL_ADDREF_INHERITED(aClass, aSuper) \
- NS_IMPL_RELEASE_INHERITED(aClass, aSuper)
- /*
- * Macro to glue together a QI that starts with an interface table
- * and segues into an interface map (e.g. it uses singleton classinfo
- * or tearoffs).
- */
- #define NS_INTERFACE_TABLE_TO_MAP_SEGUE \
- if (rv == NS_OK) return rv; \
- nsISupports* foundInterface;
- ///////////////////////////////////////////////////////////////////////////////
- /**
- *
- * Threadsafe implementations of the ISupports convenience macros.
- *
- * @note These are not available when linking against the standalone glue,
- * because the implementation requires PR_ symbols.
- */
- #define NS_INTERFACE_MAP_END_THREADSAFE NS_IMPL_QUERY_TAIL_GUTS
- /**
- * Macro to generate nsIClassInfo methods for classes which do not have
- * corresponding nsIFactory implementations.
- */
- #define NS_IMPL_THREADSAFE_CI(_class) \
- NS_IMETHODIMP \
- _class::GetInterfaces(uint32_t* _count, nsIID*** _array) \
- { \
- return NS_CI_INTERFACE_GETTER_NAME(_class)(_count, _array); \
- } \
- \
- NS_IMETHODIMP \
- _class::GetScriptableHelper(nsIXPCScriptable** _retval) \
- { \
- *_retval = nullptr; \
- return NS_OK; \
- } \
- \
- NS_IMETHODIMP \
- _class::GetContractID(char** _contractID) \
- { \
- *_contractID = nullptr; \
- return NS_OK; \
- } \
- \
- NS_IMETHODIMP \
- _class::GetClassDescription(char** _classDescription) \
- { \
- *_classDescription = nullptr; \
- return NS_OK; \
- } \
- \
- NS_IMETHODIMP \
- _class::GetClassID(nsCID** _classID) \
- { \
- *_classID = nullptr; \
- return NS_OK; \
- } \
- \
- NS_IMETHODIMP \
- _class::GetFlags(uint32_t* _flags) \
- { \
- *_flags = nsIClassInfo::THREADSAFE; \
- return NS_OK; \
- } \
- \
- NS_IMETHODIMP \
- _class::GetClassIDNoAlloc(nsCID* _classIDNoAlloc) \
- { \
- return NS_ERROR_NOT_AVAILABLE; \
- }
- #endif
|