michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: // IWYU pragma: private, include "nsISupports.h" michael@0: michael@0: michael@0: #ifndef nsISupportsImpl_h__ michael@0: #define nsISupportsImpl_h__ michael@0: michael@0: #include "nscore.h" michael@0: #include "nsISupportsBase.h" michael@0: #include "nsISupportsUtils.h" michael@0: michael@0: michael@0: #if !defined(XPCOM_GLUE_AVOID_NSPR) michael@0: #include "prthread.h" /* needed for thread-safety checks */ michael@0: #endif // !XPCOM_GLUE_AVOID_NSPR michael@0: michael@0: #include "nsDebug.h" michael@0: #include "nsXPCOM.h" michael@0: #ifndef XPCOM_GLUE michael@0: #include "mozilla/Atomics.h" michael@0: #endif michael@0: #include "mozilla/Attributes.h" michael@0: #include "mozilla/Assertions.h" michael@0: #include "mozilla/Likely.h" michael@0: #include "mozilla/MacroArgs.h" michael@0: #include "mozilla/MacroForEach.h" michael@0: michael@0: inline nsISupports* michael@0: ToSupports(nsISupports* p) michael@0: { michael@0: return p; michael@0: } michael@0: michael@0: inline nsISupports* michael@0: ToCanonicalSupports(nsISupports* p) michael@0: { michael@0: return nullptr; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // Macros to help detect thread-safety: michael@0: michael@0: #if (defined(DEBUG) || (defined(NIGHTLY_BUILD) && !defined(MOZ_PROFILING))) && !defined(XPCOM_GLUE_AVOID_NSPR) michael@0: michael@0: class nsAutoOwningThread { michael@0: public: michael@0: nsAutoOwningThread() { mThread = PR_GetCurrentThread(); } michael@0: void *GetThread() const { return mThread; } michael@0: michael@0: private: michael@0: void *mThread; michael@0: }; michael@0: michael@0: #define NS_DECL_OWNINGTHREAD nsAutoOwningThread _mOwningThread; michael@0: #define NS_ASSERT_OWNINGTHREAD_AGGREGATE(agg, _class) \ michael@0: NS_CheckThreadSafe(agg->_mOwningThread.GetThread(), #_class " not thread-safe") michael@0: #define NS_ASSERT_OWNINGTHREAD(_class) NS_ASSERT_OWNINGTHREAD_AGGREGATE(this, _class) michael@0: #else // !DEBUG && !(NIGHTLY_BUILD && !MOZ_PROFILING) michael@0: michael@0: #define NS_DECL_OWNINGTHREAD /* nothing */ michael@0: #define NS_ASSERT_OWNINGTHREAD_AGGREGATE(agg, _class) ((void)0) michael@0: #define NS_ASSERT_OWNINGTHREAD(_class) ((void)0) michael@0: michael@0: #endif // DEBUG || (NIGHTLY_BUILD && !MOZ_PROFILING) michael@0: michael@0: michael@0: // Macros for reference-count and constructor logging michael@0: michael@0: #ifdef NS_BUILD_REFCNT_LOGGING michael@0: michael@0: #define NS_LOG_ADDREF(_p, _rc, _type, _size) \ michael@0: NS_LogAddRef((_p), (_rc), (_type), (uint32_t) (_size)) michael@0: michael@0: #define NS_LOG_RELEASE(_p, _rc, _type) \ michael@0: NS_LogRelease((_p), (_rc), (_type)) michael@0: michael@0: // Note that the following constructor/destructor logging macros are redundant michael@0: // for refcounted objects that log via the NS_LOG_ADDREF/NS_LOG_RELEASE macros. michael@0: // Refcount logging is preferred. michael@0: #define MOZ_COUNT_CTOR(_type) \ michael@0: do { \ michael@0: NS_LogCtor((void*)this, #_type, sizeof(*this)); \ michael@0: } while (0) michael@0: michael@0: #define MOZ_COUNT_CTOR_INHERITED(_type, _base) \ michael@0: do { \ michael@0: NS_LogCtor((void*)this, #_type, sizeof(*this) - sizeof(_base)); \ michael@0: } while (0) michael@0: michael@0: #define MOZ_COUNT_DTOR(_type) \ michael@0: do { \ michael@0: NS_LogDtor((void*)this, #_type, sizeof(*this)); \ michael@0: } while (0) michael@0: michael@0: #define MOZ_COUNT_DTOR_INHERITED(_type, _base) \ michael@0: do { \ michael@0: NS_LogDtor((void*)this, #_type, sizeof(*this) - sizeof(_base)); \ michael@0: } while (0) michael@0: michael@0: /* nsCOMPtr.h allows these macros to be defined by clients michael@0: * These logging functions require dynamic_cast, so they don't michael@0: * do anything useful if we don't have dynamic_cast. */ michael@0: #define NSCAP_LOG_ASSIGNMENT(_c, _p) \ michael@0: if (_p) \ michael@0: NS_LogCOMPtrAddRef((_c),static_cast(_p)) michael@0: michael@0: #define NSCAP_LOG_RELEASE(_c, _p) \ michael@0: if (_p) \ michael@0: NS_LogCOMPtrRelease((_c), static_cast(_p)) michael@0: michael@0: #else /* !NS_BUILD_REFCNT_LOGGING */ michael@0: michael@0: #define NS_LOG_ADDREF(_p, _rc, _type, _size) michael@0: #define NS_LOG_RELEASE(_p, _rc, _type) michael@0: #define MOZ_COUNT_CTOR(_type) michael@0: #define MOZ_COUNT_CTOR_INHERITED(_type, _base) michael@0: #define MOZ_COUNT_DTOR(_type) michael@0: #define MOZ_COUNT_DTOR_INHERITED(_type, _base) michael@0: michael@0: #endif /* NS_BUILD_REFCNT_LOGGING */ michael@0: michael@0: michael@0: // Support for ISupports classes which interact with cycle collector. michael@0: michael@0: #define NS_NUMBER_OF_FLAGS_IN_REFCNT 2 michael@0: #define NS_IN_PURPLE_BUFFER (1 << 0) michael@0: #define NS_IS_PURPLE (1 << 1) michael@0: #define NS_REFCOUNT_CHANGE (1 << NS_NUMBER_OF_FLAGS_IN_REFCNT) michael@0: #define NS_REFCOUNT_VALUE(_val) (_val >> NS_NUMBER_OF_FLAGS_IN_REFCNT) michael@0: michael@0: class nsCycleCollectingAutoRefCnt { michael@0: michael@0: public: michael@0: nsCycleCollectingAutoRefCnt() michael@0: : mRefCntAndFlags(0) michael@0: {} michael@0: michael@0: nsCycleCollectingAutoRefCnt(uintptr_t aValue) michael@0: : mRefCntAndFlags(aValue << NS_NUMBER_OF_FLAGS_IN_REFCNT) michael@0: { michael@0: } michael@0: michael@0: MOZ_ALWAYS_INLINE uintptr_t incr(nsISupports *owner) michael@0: { michael@0: return incr(owner, nullptr); michael@0: } michael@0: michael@0: MOZ_ALWAYS_INLINE uintptr_t incr(void *owner, nsCycleCollectionParticipant *p) michael@0: { michael@0: mRefCntAndFlags += NS_REFCOUNT_CHANGE; michael@0: mRefCntAndFlags &= ~NS_IS_PURPLE; michael@0: // For incremental cycle collection, use the purple buffer to track objects michael@0: // that have been AddRef'd. michael@0: if (!IsInPurpleBuffer()) { michael@0: mRefCntAndFlags |= NS_IN_PURPLE_BUFFER; michael@0: // Refcount isn't zero, so Suspect won't delete anything. michael@0: MOZ_ASSERT(get() > 0); michael@0: NS_CycleCollectorSuspect3(owner, p, this, nullptr); michael@0: } michael@0: return NS_REFCOUNT_VALUE(mRefCntAndFlags); michael@0: } michael@0: michael@0: MOZ_ALWAYS_INLINE void stabilizeForDeletion() michael@0: { michael@0: // Set refcnt to 1 and mark us to be in the purple buffer. michael@0: // This way decr won't call suspect again. michael@0: mRefCntAndFlags = NS_REFCOUNT_CHANGE | NS_IN_PURPLE_BUFFER; michael@0: } michael@0: michael@0: MOZ_ALWAYS_INLINE uintptr_t decr(nsISupports *owner, michael@0: bool *shouldDelete = nullptr) michael@0: { michael@0: return decr(owner, nullptr, shouldDelete); michael@0: } michael@0: michael@0: MOZ_ALWAYS_INLINE uintptr_t decr(void *owner, nsCycleCollectionParticipant *p, michael@0: bool *shouldDelete = nullptr) michael@0: { michael@0: MOZ_ASSERT(get() > 0); michael@0: if (!IsInPurpleBuffer()) { michael@0: mRefCntAndFlags -= NS_REFCOUNT_CHANGE; michael@0: mRefCntAndFlags |= (NS_IN_PURPLE_BUFFER | NS_IS_PURPLE); michael@0: uintptr_t retval = NS_REFCOUNT_VALUE(mRefCntAndFlags); michael@0: // Suspect may delete 'owner' and 'this'! michael@0: NS_CycleCollectorSuspect3(owner, p, this, shouldDelete); michael@0: return retval; michael@0: } michael@0: mRefCntAndFlags -= NS_REFCOUNT_CHANGE; michael@0: mRefCntAndFlags |= (NS_IN_PURPLE_BUFFER | NS_IS_PURPLE); michael@0: return NS_REFCOUNT_VALUE(mRefCntAndFlags); michael@0: } michael@0: michael@0: MOZ_ALWAYS_INLINE void RemovePurple() michael@0: { michael@0: MOZ_ASSERT(IsPurple(), "must be purple"); michael@0: mRefCntAndFlags &= ~NS_IS_PURPLE; michael@0: } michael@0: michael@0: MOZ_ALWAYS_INLINE void RemoveFromPurpleBuffer() michael@0: { michael@0: MOZ_ASSERT(IsInPurpleBuffer()); michael@0: mRefCntAndFlags &= ~(NS_IS_PURPLE | NS_IN_PURPLE_BUFFER); michael@0: } michael@0: michael@0: MOZ_ALWAYS_INLINE bool IsPurple() const michael@0: { michael@0: return !!(mRefCntAndFlags & NS_IS_PURPLE); michael@0: } michael@0: michael@0: MOZ_ALWAYS_INLINE bool IsInPurpleBuffer() const michael@0: { michael@0: return !!(mRefCntAndFlags & NS_IN_PURPLE_BUFFER); michael@0: } michael@0: michael@0: MOZ_ALWAYS_INLINE nsrefcnt get() const michael@0: { michael@0: return NS_REFCOUNT_VALUE(mRefCntAndFlags); michael@0: } michael@0: michael@0: MOZ_ALWAYS_INLINE operator nsrefcnt() const michael@0: { michael@0: return get(); michael@0: } michael@0: michael@0: private: michael@0: uintptr_t mRefCntAndFlags; michael@0: }; michael@0: michael@0: class nsAutoRefCnt { michael@0: michael@0: public: michael@0: nsAutoRefCnt() : mValue(0) {} michael@0: nsAutoRefCnt(nsrefcnt aValue) : mValue(aValue) {} michael@0: michael@0: // only support prefix increment/decrement michael@0: nsrefcnt operator++() { return ++mValue; } michael@0: nsrefcnt operator--() { return --mValue; } michael@0: michael@0: nsrefcnt operator=(nsrefcnt aValue) { return (mValue = aValue); } michael@0: operator nsrefcnt() const { return mValue; } michael@0: nsrefcnt get() const { return mValue; } michael@0: michael@0: static const bool isThreadSafe = false; michael@0: private: michael@0: nsrefcnt operator++(int) MOZ_DELETE; michael@0: nsrefcnt operator--(int) MOZ_DELETE; michael@0: nsrefcnt mValue; michael@0: }; michael@0: michael@0: #ifndef XPCOM_GLUE michael@0: namespace mozilla { michael@0: class ThreadSafeAutoRefCnt { michael@0: public: michael@0: ThreadSafeAutoRefCnt() : mValue(0) {} michael@0: ThreadSafeAutoRefCnt(nsrefcnt aValue) : mValue(aValue) {} michael@0: michael@0: // only support prefix increment/decrement michael@0: MOZ_ALWAYS_INLINE nsrefcnt operator++() { return ++mValue; } michael@0: MOZ_ALWAYS_INLINE nsrefcnt operator--() { return --mValue; } michael@0: michael@0: MOZ_ALWAYS_INLINE nsrefcnt operator=(nsrefcnt aValue) { return (mValue = aValue); } michael@0: MOZ_ALWAYS_INLINE operator nsrefcnt() const { return mValue; } michael@0: MOZ_ALWAYS_INLINE nsrefcnt get() const { return mValue; } michael@0: michael@0: static const bool isThreadSafe = true; michael@0: private: michael@0: nsrefcnt operator++(int) MOZ_DELETE; michael@0: nsrefcnt operator--(int) MOZ_DELETE; michael@0: // In theory, RelaseAcquire consistency (but no weaker) is sufficient for michael@0: // the counter. Making it weaker could speed up builds on ARM (but not x86), michael@0: // but could break pre-existing code that assumes sequential consistency. michael@0: Atomic mValue; michael@0: }; michael@0: } michael@0: #endif michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: /** michael@0: * Declare the reference count variable and the implementations of the michael@0: * AddRef and QueryInterface methods. michael@0: */ michael@0: michael@0: #define NS_DECL_ISUPPORTS \ michael@0: public: \ michael@0: NS_IMETHOD QueryInterface(REFNSIID aIID, \ michael@0: void** aInstancePtr); \ michael@0: NS_IMETHOD_(MozExternalRefCountType) AddRef(void); \ michael@0: NS_IMETHOD_(MozExternalRefCountType) Release(void); \ michael@0: protected: \ michael@0: nsAutoRefCnt mRefCnt; \ michael@0: NS_DECL_OWNINGTHREAD \ michael@0: public: michael@0: michael@0: #define NS_DECL_THREADSAFE_ISUPPORTS \ michael@0: public: \ michael@0: NS_IMETHOD QueryInterface(REFNSIID aIID, \ michael@0: void** aInstancePtr); \ michael@0: NS_IMETHOD_(MozExternalRefCountType) AddRef(void); \ michael@0: NS_IMETHOD_(MozExternalRefCountType) Release(void); \ michael@0: protected: \ michael@0: ::mozilla::ThreadSafeAutoRefCnt mRefCnt; \ michael@0: NS_DECL_OWNINGTHREAD \ michael@0: public: michael@0: michael@0: #define NS_DECL_CYCLE_COLLECTING_ISUPPORTS \ michael@0: public: \ michael@0: NS_IMETHOD QueryInterface(REFNSIID aIID, \ michael@0: void** aInstancePtr); \ michael@0: NS_IMETHOD_(MozExternalRefCountType) AddRef(void); \ michael@0: NS_IMETHOD_(MozExternalRefCountType) Release(void); \ michael@0: NS_IMETHOD_(void) DeleteCycleCollectable(void); \ michael@0: protected: \ michael@0: nsCycleCollectingAutoRefCnt mRefCnt; \ michael@0: NS_DECL_OWNINGTHREAD \ michael@0: public: michael@0: michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: /* michael@0: * Implementation of AddRef and Release for non-nsISupports (ie "native") michael@0: * cycle-collected classes that use the purple buffer to avoid leaks. michael@0: */ michael@0: michael@0: #define NS_IMPL_CC_NATIVE_ADDREF_BODY(_class) \ michael@0: MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \ michael@0: NS_ASSERT_OWNINGTHREAD(_class); \ michael@0: nsrefcnt count = \ michael@0: mRefCnt.incr(static_cast(this), \ michael@0: _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \ michael@0: NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \ michael@0: return count; michael@0: michael@0: #define NS_IMPL_CC_NATIVE_RELEASE_BODY(_class) \ michael@0: MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \ michael@0: NS_ASSERT_OWNINGTHREAD(_class); \ michael@0: nsrefcnt count = \ michael@0: mRefCnt.decr(static_cast(this), \ michael@0: _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \ michael@0: NS_LOG_RELEASE(this, count, #_class); \ michael@0: return count; michael@0: michael@0: #define NS_IMPL_CYCLE_COLLECTING_NATIVE_ADDREF(_class) \ michael@0: NS_METHOD_(MozExternalRefCountType) _class::AddRef(void) \ michael@0: { \ michael@0: NS_IMPL_CC_NATIVE_ADDREF_BODY(_class) \ michael@0: } michael@0: michael@0: #define NS_IMPL_CYCLE_COLLECTING_NATIVE_RELEASE_WITH_LAST_RELEASE(_class, _last) \ michael@0: NS_METHOD_(MozExternalRefCountType) _class::Release(void) \ michael@0: { \ michael@0: MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \ michael@0: NS_ASSERT_OWNINGTHREAD(_class); \ michael@0: bool shouldDelete = false; \ michael@0: nsrefcnt count = \ michael@0: mRefCnt.decr(static_cast(this), \ michael@0: _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant(), \ michael@0: &shouldDelete); \ michael@0: NS_LOG_RELEASE(this, count, #_class); \ michael@0: if (count == 0) { \ michael@0: mRefCnt.incr(static_cast(this), \ michael@0: _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \ michael@0: _last; \ michael@0: mRefCnt.decr(static_cast(this), \ michael@0: _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \ michael@0: if (shouldDelete) { \ michael@0: mRefCnt.stabilizeForDeletion(); \ michael@0: DeleteCycleCollectable(); \ michael@0: } \ michael@0: } \ michael@0: return count; \ michael@0: } michael@0: michael@0: #define NS_IMPL_CYCLE_COLLECTING_NATIVE_RELEASE(_class) \ michael@0: NS_METHOD_(MozExternalRefCountType) _class::Release(void) \ michael@0: { \ michael@0: NS_IMPL_CC_NATIVE_RELEASE_BODY(_class) \ michael@0: } michael@0: michael@0: #define NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(_class) \ michael@0: public: \ michael@0: NS_METHOD_(MozExternalRefCountType) AddRef(void) { \ michael@0: NS_IMPL_CC_NATIVE_ADDREF_BODY(_class) \ michael@0: } \ michael@0: NS_METHOD_(MozExternalRefCountType) Release(void) { \ michael@0: NS_IMPL_CC_NATIVE_RELEASE_BODY(_class) \ michael@0: } \ michael@0: protected: \ michael@0: nsCycleCollectingAutoRefCnt mRefCnt; \ michael@0: NS_DECL_OWNINGTHREAD \ michael@0: public: michael@0: michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: /** michael@0: * Previously used to initialize the reference count, but no longer needed. michael@0: * michael@0: * DEPRECATED. michael@0: */ michael@0: #define NS_INIT_ISUPPORTS() ((void)0) michael@0: michael@0: /** michael@0: * Use this macro to declare and implement the AddRef & Release methods for a michael@0: * given non-XPCOM _class. michael@0: * michael@0: * @param _class The name of the class implementing the method michael@0: */ michael@0: #define NS_INLINE_DECL_REFCOUNTING(_class) \ michael@0: public: \ michael@0: NS_METHOD_(MozExternalRefCountType) AddRef(void) { \ michael@0: MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \ michael@0: NS_ASSERT_OWNINGTHREAD(_class); \ michael@0: ++mRefCnt; \ michael@0: NS_LOG_ADDREF(this, mRefCnt, #_class, sizeof(*this)); \ michael@0: return mRefCnt; \ michael@0: } \ michael@0: NS_METHOD_(MozExternalRefCountType) Release(void) { \ michael@0: MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \ michael@0: NS_ASSERT_OWNINGTHREAD(_class); \ michael@0: --mRefCnt; \ michael@0: NS_LOG_RELEASE(this, mRefCnt, #_class); \ michael@0: if (mRefCnt == 0) { \ michael@0: NS_ASSERT_OWNINGTHREAD(_class); \ michael@0: mRefCnt = 1; /* stabilize */ \ michael@0: delete this; \ michael@0: return 0; \ michael@0: } \ michael@0: return mRefCnt; \ michael@0: } \ michael@0: protected: \ michael@0: nsAutoRefCnt mRefCnt; \ michael@0: NS_DECL_OWNINGTHREAD \ michael@0: public: michael@0: michael@0: /** michael@0: * Use this macro to declare and implement the AddRef & Release methods for a michael@0: * given non-XPCOM _class in a threadsafe manner. michael@0: * michael@0: * DOES NOT DO REFCOUNT STABILIZATION! michael@0: * michael@0: * @param _class The name of the class implementing the method michael@0: */ michael@0: #define NS_INLINE_DECL_THREADSAFE_REFCOUNTING(_class) \ michael@0: public: \ michael@0: NS_METHOD_(MozExternalRefCountType) AddRef(void) { \ michael@0: MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \ michael@0: nsrefcnt count = ++mRefCnt; \ michael@0: NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \ michael@0: return (nsrefcnt) count; \ michael@0: } \ michael@0: NS_METHOD_(MozExternalRefCountType) Release(void) { \ michael@0: MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \ michael@0: nsrefcnt count = --mRefCnt; \ michael@0: NS_LOG_RELEASE(this, count, #_class); \ michael@0: if (count == 0) { \ michael@0: delete (this); \ michael@0: return 0; \ michael@0: } \ michael@0: return count; \ michael@0: } \ michael@0: protected: \ michael@0: ::mozilla::ThreadSafeAutoRefCnt mRefCnt; \ michael@0: public: michael@0: michael@0: /** michael@0: * Use this macro to implement the AddRef method for a given _class michael@0: * @param _class The name of the class implementing the method michael@0: */ michael@0: #define NS_IMPL_ADDREF(_class) \ michael@0: NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void) \ michael@0: { \ michael@0: MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \ michael@0: if (!mRefCnt.isThreadSafe) \ michael@0: NS_ASSERT_OWNINGTHREAD(_class); \ michael@0: nsrefcnt count = ++mRefCnt; \ michael@0: NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \ michael@0: return count; \ michael@0: } michael@0: michael@0: /** michael@0: * Use this macro to implement the AddRef method for a given _class michael@0: * implemented as a wholly owned aggregated object intended to implement michael@0: * interface(s) for its owner michael@0: * @param _class The name of the class implementing the method michael@0: * @param _aggregator the owning/containing object michael@0: */ michael@0: #define NS_IMPL_ADDREF_USING_AGGREGATOR(_class, _aggregator) \ michael@0: NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void) \ michael@0: { \ michael@0: NS_PRECONDITION(_aggregator, "null aggregator"); \ michael@0: return (_aggregator)->AddRef(); \ michael@0: } michael@0: michael@0: /** michael@0: * Use this macro to implement the Release method for a given michael@0: * _class. michael@0: * @param _class The name of the class implementing the method michael@0: * @param _destroy A statement that is executed when the object's michael@0: * refcount drops to zero. michael@0: * michael@0: * For example, michael@0: * michael@0: * NS_IMPL_RELEASE_WITH_DESTROY(Foo, Destroy(this)) michael@0: * michael@0: * will cause michael@0: * michael@0: * Destroy(this); michael@0: * michael@0: * to be invoked when the object's refcount drops to zero. This michael@0: * allows for arbitrary teardown activity to occur (e.g., deallocation michael@0: * of object allocated with placement new). michael@0: */ michael@0: #define NS_IMPL_RELEASE_WITH_DESTROY(_class, _destroy) \ michael@0: NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) \ michael@0: { \ michael@0: MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \ michael@0: if (!mRefCnt.isThreadSafe) \ michael@0: NS_ASSERT_OWNINGTHREAD(_class); \ michael@0: nsrefcnt count = --mRefCnt; \ michael@0: NS_LOG_RELEASE(this, count, #_class); \ michael@0: if (count == 0) { \ michael@0: if (!mRefCnt.isThreadSafe) \ michael@0: NS_ASSERT_OWNINGTHREAD(_class); \ michael@0: mRefCnt = 1; /* stabilize */ \ michael@0: _destroy; \ michael@0: return 0; \ michael@0: } \ michael@0: return count; \ michael@0: } michael@0: michael@0: /** michael@0: * Use this macro to implement the Release method for a given _class michael@0: * @param _class The name of the class implementing the method michael@0: * michael@0: * A note on the 'stabilization' of the refcnt to one. At that point, michael@0: * the object's refcount will have gone to zero. The object's michael@0: * destructor may trigger code that attempts to QueryInterface() and michael@0: * Release() 'this' again. Doing so will temporarily increment and michael@0: * decrement the refcount. (Only a logic error would make one try to michael@0: * keep a permanent hold on 'this'.) To prevent re-entering the michael@0: * destructor, we make sure that no balanced refcounting can return michael@0: * the refcount to |0|. michael@0: */ michael@0: #define NS_IMPL_RELEASE(_class) \ michael@0: NS_IMPL_RELEASE_WITH_DESTROY(_class, delete (this)) michael@0: michael@0: /** michael@0: * Use this macro to implement the Release method for a given _class michael@0: * implemented as a wholly owned aggregated object intended to implement michael@0: * interface(s) for its owner michael@0: * @param _class The name of the class implementing the method michael@0: * @param _aggregator the owning/containing object michael@0: */ michael@0: #define NS_IMPL_RELEASE_USING_AGGREGATOR(_class, _aggregator) \ michael@0: NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) \ michael@0: { \ michael@0: NS_PRECONDITION(_aggregator, "null aggregator"); \ michael@0: return (_aggregator)->Release(); \ michael@0: } michael@0: michael@0: michael@0: #define NS_IMPL_CYCLE_COLLECTING_ADDREF(_class) \ michael@0: NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void) \ michael@0: { \ michael@0: MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \ michael@0: NS_ASSERT_OWNINGTHREAD(_class); \ michael@0: nsISupports *base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this); \ michael@0: nsrefcnt count = mRefCnt.incr(base); \ michael@0: NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \ michael@0: return count; \ michael@0: } michael@0: michael@0: #define NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(_class, _destroy) \ michael@0: NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) \ michael@0: { \ michael@0: MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \ michael@0: NS_ASSERT_OWNINGTHREAD(_class); \ michael@0: nsISupports *base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this); \ michael@0: nsrefcnt count = mRefCnt.decr(base); \ michael@0: NS_LOG_RELEASE(this, count, #_class); \ michael@0: return count; \ michael@0: } \ michael@0: NS_IMETHODIMP_(void) _class::DeleteCycleCollectable(void) \ michael@0: { \ michael@0: _destroy; \ michael@0: } michael@0: michael@0: #define NS_IMPL_CYCLE_COLLECTING_RELEASE(_class) \ michael@0: NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(_class, delete (this)) michael@0: michael@0: // _LAST_RELEASE can be useful when certain resources should be released michael@0: // as soon as we know the object will be deleted. michael@0: #define NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(_class, _last) \ michael@0: NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) \ michael@0: { \ michael@0: MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \ michael@0: NS_ASSERT_OWNINGTHREAD(_class); \ michael@0: bool shouldDelete = false; \ michael@0: nsISupports *base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this); \ michael@0: nsrefcnt count = mRefCnt.decr(base, &shouldDelete); \ michael@0: NS_LOG_RELEASE(this, count, #_class); \ michael@0: if (count == 0) { \ michael@0: mRefCnt.incr(base); \ michael@0: _last; \ michael@0: mRefCnt.decr(base); \ michael@0: if (shouldDelete) { \ michael@0: mRefCnt.stabilizeForDeletion(); \ michael@0: DeleteCycleCollectable(); \ michael@0: } \ michael@0: } \ michael@0: return count; \ michael@0: } \ michael@0: NS_IMETHODIMP_(void) _class::DeleteCycleCollectable(void) \ michael@0: { \ michael@0: delete this; \ michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: /** michael@0: * There are two ways of implementing QueryInterface, and we use both: michael@0: * michael@0: * Table-driven QueryInterface uses a static table of IID->offset mappings michael@0: * and a shared helper function. Using it tends to reduce codesize and improve michael@0: * runtime performance (due to processor cache hits). michael@0: * michael@0: * Macro-driven QueryInterface generates a QueryInterface function directly michael@0: * using common macros. This is necessary if special QueryInterface features michael@0: * are being used (such as tearoffs and conditional interfaces). michael@0: * michael@0: * These methods can be combined into a table-driven function call followed michael@0: * by custom code for tearoffs and conditionals. michael@0: */ michael@0: michael@0: struct QITableEntry michael@0: { michael@0: const nsIID *iid; // null indicates end of the QITableEntry array michael@0: int32_t offset; michael@0: }; michael@0: michael@0: NS_COM_GLUE nsresult NS_FASTCALL michael@0: NS_TableDrivenQI(void* aThis, REFNSIID aIID, michael@0: void **aInstancePtr, const QITableEntry* entries); michael@0: michael@0: /** michael@0: * Implement table-driven queryinterface michael@0: */ michael@0: michael@0: #define NS_INTERFACE_TABLE_HEAD(_class) \ michael@0: NS_IMETHODIMP _class::QueryInterface(REFNSIID aIID, void** aInstancePtr) \ michael@0: { \ michael@0: NS_ASSERTION(aInstancePtr, \ michael@0: "QueryInterface requires a non-NULL destination!"); \ michael@0: nsresult rv = NS_ERROR_FAILURE; michael@0: michael@0: #define NS_INTERFACE_TABLE_BEGIN \ michael@0: static const QITableEntry table[] = { michael@0: michael@0: #define NS_INTERFACE_TABLE_ENTRY(_class, _interface) \ michael@0: { &_interface::COMTypeInfo::kIID, \ michael@0: int32_t(reinterpret_cast( \ michael@0: static_cast<_interface*>((_class*) 0x1000)) - \ michael@0: reinterpret_cast((_class*) 0x1000)) \ michael@0: }, michael@0: michael@0: #define NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(_class, _interface, _implClass) \ michael@0: { &_interface::COMTypeInfo::kIID, \ michael@0: int32_t(reinterpret_cast( \ michael@0: static_cast<_interface*>( \ michael@0: static_cast<_implClass*>( \ michael@0: (_class*) 0x1000))) - \ michael@0: reinterpret_cast((_class*) 0x1000)) \ michael@0: }, michael@0: michael@0: /* michael@0: * XXX: we want to use mozilla::ArrayLength (or equivalent, michael@0: * MOZ_ARRAY_LENGTH) in this condition, but some versions of GCC don't michael@0: * see that the static_assert condition is actually constant in those michael@0: * cases, even with constexpr support (?). michael@0: */ michael@0: #define NS_INTERFACE_TABLE_END_WITH_PTR(_ptr) \ michael@0: { nullptr, 0 } }; \ michael@0: static_assert((sizeof(table)/sizeof(table[0])) > 1, "need at least 1 interface"); \ michael@0: rv = NS_TableDrivenQI(static_cast(_ptr), \ michael@0: aIID, aInstancePtr, table); michael@0: michael@0: #define NS_INTERFACE_TABLE_END \ michael@0: NS_INTERFACE_TABLE_END_WITH_PTR(this) michael@0: michael@0: #define NS_INTERFACE_TABLE_TAIL \ michael@0: return rv; \ michael@0: } michael@0: michael@0: #define NS_INTERFACE_TABLE_TAIL_INHERITING(_baseclass) \ michael@0: if (NS_SUCCEEDED(rv)) \ michael@0: return rv; \ michael@0: return _baseclass::QueryInterface(aIID, aInstancePtr); \ michael@0: } michael@0: michael@0: #define NS_INTERFACE_TABLE_TAIL_USING_AGGREGATOR(_aggregator) \ michael@0: if (NS_SUCCEEDED(rv)) \ michael@0: return rv; \ michael@0: NS_ASSERTION(_aggregator, "null aggregator"); \ michael@0: return _aggregator->QueryInterface(aIID, aInstancePtr) \ michael@0: } michael@0: michael@0: /** michael@0: * This implements query interface with two assumptions: First, the michael@0: * class in question implements nsISupports and its own interface and michael@0: * nothing else. Second, the implementation of the class's primary michael@0: * inheritance chain leads to its own interface. michael@0: * michael@0: * @param _class The name of the class implementing the method michael@0: * @param _classiiddef The name of the #define symbol that defines the IID michael@0: * for the class (e.g. NS_ISUPPORTS_IID) michael@0: */ michael@0: michael@0: #define NS_IMPL_QUERY_HEAD(_class) \ michael@0: NS_IMETHODIMP _class::QueryInterface(REFNSIID aIID, void** aInstancePtr) \ michael@0: { \ michael@0: NS_ASSERTION(aInstancePtr, \ michael@0: "QueryInterface requires a non-NULL destination!"); \ michael@0: nsISupports* foundInterface; michael@0: michael@0: #define NS_IMPL_QUERY_BODY(_interface) \ michael@0: if ( aIID.Equals(NS_GET_IID(_interface)) ) \ michael@0: foundInterface = static_cast<_interface*>(this); \ michael@0: else michael@0: michael@0: #define NS_IMPL_QUERY_BODY_CONDITIONAL(_interface, condition) \ michael@0: if ( (condition) && aIID.Equals(NS_GET_IID(_interface))) \ michael@0: foundInterface = static_cast<_interface*>(this); \ michael@0: else michael@0: michael@0: #define NS_IMPL_QUERY_BODY_AMBIGUOUS(_interface, _implClass) \ michael@0: if ( aIID.Equals(NS_GET_IID(_interface)) ) \ michael@0: foundInterface = static_cast<_interface*>( \ michael@0: static_cast<_implClass*>(this)); \ michael@0: else michael@0: michael@0: #define NS_IMPL_QUERY_BODY_AGGREGATED(_interface, _aggregate) \ michael@0: if ( aIID.Equals(NS_GET_IID(_interface)) ) \ michael@0: foundInterface = static_cast<_interface*>(_aggregate); \ michael@0: else michael@0: michael@0: #define NS_IMPL_QUERY_TAIL_GUTS \ michael@0: foundInterface = 0; \ michael@0: nsresult status; \ michael@0: if ( !foundInterface ) \ michael@0: { \ michael@0: /* nsISupports should be handled by this point. If not, fail. */ \ michael@0: MOZ_ASSERT(!aIID.Equals(NS_GET_IID(nsISupports))); \ michael@0: status = NS_NOINTERFACE; \ michael@0: } \ michael@0: else \ michael@0: { \ michael@0: NS_ADDREF(foundInterface); \ michael@0: status = NS_OK; \ michael@0: } \ michael@0: *aInstancePtr = foundInterface; \ michael@0: return status; \ michael@0: } michael@0: michael@0: #define NS_IMPL_QUERY_TAIL_INHERITING(_baseclass) \ michael@0: foundInterface = 0; \ michael@0: nsresult status; \ michael@0: if ( !foundInterface ) \ michael@0: status = _baseclass::QueryInterface(aIID, (void**)&foundInterface); \ michael@0: else \ michael@0: { \ michael@0: NS_ADDREF(foundInterface); \ michael@0: status = NS_OK; \ michael@0: } \ michael@0: *aInstancePtr = foundInterface; \ michael@0: return status; \ michael@0: } michael@0: michael@0: #define NS_IMPL_QUERY_TAIL_USING_AGGREGATOR(_aggregator) \ michael@0: foundInterface = 0; \ michael@0: nsresult status; \ michael@0: if ( !foundInterface ) { \ michael@0: NS_ASSERTION(_aggregator, "null aggregator"); \ michael@0: status = _aggregator->QueryInterface(aIID, (void**)&foundInterface); \ michael@0: } else \ michael@0: { \ michael@0: NS_ADDREF(foundInterface); \ michael@0: status = NS_OK; \ michael@0: } \ michael@0: *aInstancePtr = foundInterface; \ michael@0: return status; \ michael@0: } michael@0: michael@0: #define NS_IMPL_QUERY_TAIL(_supports_interface) \ michael@0: NS_IMPL_QUERY_BODY_AMBIGUOUS(nsISupports, _supports_interface) \ michael@0: NS_IMPL_QUERY_TAIL_GUTS michael@0: michael@0: michael@0: /* michael@0: This is the new scheme. Using this notation now will allow us to switch to michael@0: a table driven mechanism when it's ready. Note the difference between this michael@0: and the (currently) underlying NS_IMPL_QUERY_INTERFACE mechanism. You must michael@0: explicitly mention |nsISupports| when using the interface maps. michael@0: */ michael@0: #define NS_INTERFACE_MAP_BEGIN(_implClass) NS_IMPL_QUERY_HEAD(_implClass) michael@0: #define NS_INTERFACE_MAP_ENTRY(_interface) NS_IMPL_QUERY_BODY(_interface) michael@0: #define NS_INTERFACE_MAP_ENTRY_CONDITIONAL(_interface, condition) \ michael@0: NS_IMPL_QUERY_BODY_CONDITIONAL(_interface, condition) michael@0: #define NS_INTERFACE_MAP_ENTRY_AGGREGATED(_interface,_aggregate) \ michael@0: NS_IMPL_QUERY_BODY_AGGREGATED(_interface,_aggregate) michael@0: michael@0: #define NS_INTERFACE_MAP_END NS_IMPL_QUERY_TAIL_GUTS michael@0: #define NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(_interface, _implClass) \ michael@0: NS_IMPL_QUERY_BODY_AMBIGUOUS(_interface, _implClass) michael@0: #define NS_INTERFACE_MAP_END_INHERITING(_baseClass) \ michael@0: NS_IMPL_QUERY_TAIL_INHERITING(_baseClass) michael@0: #define NS_INTERFACE_MAP_END_AGGREGATED(_aggregator) \ michael@0: NS_IMPL_QUERY_TAIL_USING_AGGREGATOR(_aggregator) michael@0: michael@0: #define NS_INTERFACE_TABLE0(_class) \ michael@0: NS_INTERFACE_TABLE_BEGIN \ michael@0: NS_INTERFACE_TABLE_ENTRY(_class, nsISupports) \ michael@0: NS_INTERFACE_TABLE_END michael@0: michael@0: #define NS_INTERFACE_TABLE(aClass, ...) \ michael@0: MOZ_STATIC_ASSERT_VALID_ARG_COUNT(__VA_ARGS__); \ michael@0: NS_INTERFACE_TABLE_BEGIN \ michael@0: MOZ_FOR_EACH(NS_INTERFACE_TABLE_ENTRY, (aClass,), (__VA_ARGS__)) \ michael@0: NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(aClass, nsISupports, \ michael@0: MOZ_ARG_1(__VA_ARGS__)) \ michael@0: NS_INTERFACE_TABLE_END michael@0: michael@0: #define NS_IMPL_QUERY_INTERFACE0(_class) \ michael@0: NS_INTERFACE_TABLE_HEAD(_class) \ michael@0: NS_INTERFACE_TABLE0(_class) \ michael@0: NS_INTERFACE_TABLE_TAIL michael@0: michael@0: #define NS_IMPL_QUERY_INTERFACE(aClass, ...) \ michael@0: NS_INTERFACE_TABLE_HEAD(aClass) \ michael@0: NS_INTERFACE_TABLE(aClass, __VA_ARGS__) \ michael@0: NS_INTERFACE_TABLE_TAIL michael@0: michael@0: /** michael@0: * Declare that you're going to inherit from something that already michael@0: * implements nsISupports, but also implements an additional interface, thus michael@0: * causing an ambiguity. In this case you don't need another mRefCnt, you michael@0: * just need to forward the definitions to the appropriate superclass. E.g. michael@0: * michael@0: * class Bar : public Foo, public nsIBar { // both provide nsISupports michael@0: * public: michael@0: * NS_DECL_ISUPPORTS_INHERITED michael@0: * ...other nsIBar and Bar methods... michael@0: * }; michael@0: */ michael@0: #define NS_DECL_ISUPPORTS_INHERITED \ michael@0: public: \ michael@0: NS_IMETHOD QueryInterface(REFNSIID aIID, \ michael@0: void** aInstancePtr); \ michael@0: NS_IMETHOD_(MozExternalRefCountType) AddRef(void); \ michael@0: NS_IMETHOD_(MozExternalRefCountType) Release(void); \ michael@0: michael@0: /** michael@0: * These macros can be used in conjunction with NS_DECL_ISUPPORTS_INHERITED michael@0: * to implement the nsISupports methods, forwarding the invocations to a michael@0: * superclass that already implements nsISupports. michael@0: * michael@0: * Note that I didn't make these inlined because they're virtual methods. michael@0: */ michael@0: michael@0: #define NS_IMPL_ADDREF_INHERITED(Class, Super) \ michael@0: NS_IMETHODIMP_(MozExternalRefCountType) Class::AddRef(void) \ michael@0: { \ michael@0: nsrefcnt r = Super::AddRef(); \ michael@0: NS_LOG_ADDREF(this, r, #Class, sizeof(*this)); \ michael@0: return r; \ michael@0: } michael@0: michael@0: #define NS_IMPL_RELEASE_INHERITED(Class, Super) \ michael@0: NS_IMETHODIMP_(MozExternalRefCountType) Class::Release(void) \ michael@0: { \ michael@0: nsrefcnt r = Super::Release(); \ michael@0: NS_LOG_RELEASE(this, r, #Class); \ michael@0: return r; \ michael@0: } michael@0: michael@0: /** michael@0: * As above but not logging the addref/release; needed if the base michael@0: * class might be aggregated. michael@0: */ michael@0: #define NS_IMPL_NONLOGGING_ADDREF_INHERITED(Class, Super) \ michael@0: NS_IMETHODIMP_(MozExternalRefCountType) Class::AddRef(void) \ michael@0: { \ michael@0: return Super::AddRef(); \ michael@0: } michael@0: michael@0: #define NS_IMPL_NONLOGGING_RELEASE_INHERITED(Class, Super) \ michael@0: NS_IMETHODIMP_(MozExternalRefCountType) Class::Release(void) \ michael@0: { \ michael@0: return Super::Release(); \ michael@0: } michael@0: michael@0: #define NS_INTERFACE_TABLE_INHERITED0(Class) /* Nothing to do here */ michael@0: michael@0: #define NS_INTERFACE_TABLE_INHERITED(aClass, ...) \ michael@0: MOZ_STATIC_ASSERT_VALID_ARG_COUNT(__VA_ARGS__); \ michael@0: NS_INTERFACE_TABLE_BEGIN \ michael@0: MOZ_FOR_EACH(NS_INTERFACE_TABLE_ENTRY, (aClass,), (__VA_ARGS__)) \ michael@0: NS_INTERFACE_TABLE_END michael@0: michael@0: #define NS_IMPL_QUERY_INTERFACE_INHERITED0(aClass, aSuper) \ michael@0: NS_INTERFACE_TABLE_HEAD(aClass) \ michael@0: NS_INTERFACE_TABLE_INHERITED0(aClass) \ michael@0: NS_INTERFACE_TABLE_TAIL_INHERITING(aSuper) michael@0: michael@0: #define NS_IMPL_QUERY_INTERFACE_INHERITED(aClass, aSuper, ...) \ michael@0: NS_INTERFACE_TABLE_HEAD(aClass) \ michael@0: NS_INTERFACE_TABLE_INHERITED(aClass, __VA_ARGS__) \ michael@0: NS_INTERFACE_TABLE_TAIL_INHERITING(aSuper) michael@0: michael@0: /** michael@0: * Convenience macros for implementing all nsISupports methods for michael@0: * a simple class. michael@0: * @param _class The name of the class implementing the method michael@0: * @param _classiiddef The name of the #define symbol that defines the IID michael@0: * for the class (e.g. NS_ISUPPORTS_IID) michael@0: */ michael@0: michael@0: #define NS_IMPL_ISUPPORTS0(_class) \ michael@0: NS_IMPL_ADDREF(_class) \ michael@0: NS_IMPL_RELEASE(_class) \ michael@0: NS_IMPL_QUERY_INTERFACE0(_class) michael@0: michael@0: #define NS_IMPL_ISUPPORTS(aClass, ...) \ michael@0: NS_IMPL_ADDREF(aClass) \ michael@0: NS_IMPL_RELEASE(aClass) \ michael@0: NS_IMPL_QUERY_INTERFACE(aClass, __VA_ARGS__) michael@0: michael@0: #define NS_IMPL_ISUPPORTS_INHERITED0(aClass, aSuper) \ michael@0: NS_IMPL_QUERY_INTERFACE_INHERITED0(aClass, aSuper) \ michael@0: NS_IMPL_ADDREF_INHERITED(aClass, aSuper) \ michael@0: NS_IMPL_RELEASE_INHERITED(aClass, aSuper) \ michael@0: michael@0: #define NS_IMPL_ISUPPORTS_INHERITED(aClass, aSuper, ...) \ michael@0: NS_IMPL_QUERY_INTERFACE_INHERITED(aClass, aSuper, __VA_ARGS__) \ michael@0: NS_IMPL_ADDREF_INHERITED(aClass, aSuper) \ michael@0: NS_IMPL_RELEASE_INHERITED(aClass, aSuper) michael@0: michael@0: /* michael@0: * Macro to glue together a QI that starts with an interface table michael@0: * and segues into an interface map (e.g. it uses singleton classinfo michael@0: * or tearoffs). michael@0: */ michael@0: #define NS_INTERFACE_TABLE_TO_MAP_SEGUE \ michael@0: if (rv == NS_OK) return rv; \ michael@0: nsISupports* foundInterface; michael@0: michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: /** michael@0: * michael@0: * Threadsafe implementations of the ISupports convenience macros. michael@0: * michael@0: * @note These are not available when linking against the standalone glue, michael@0: * because the implementation requires PR_ symbols. michael@0: */ michael@0: #define NS_INTERFACE_MAP_END_THREADSAFE NS_IMPL_QUERY_TAIL_GUTS michael@0: michael@0: /** michael@0: * Macro to generate nsIClassInfo methods for classes which do not have michael@0: * corresponding nsIFactory implementations. michael@0: */ michael@0: #define NS_IMPL_THREADSAFE_CI(_class) \ michael@0: NS_IMETHODIMP \ michael@0: _class::GetInterfaces(uint32_t* _count, nsIID*** _array) \ michael@0: { \ michael@0: return NS_CI_INTERFACE_GETTER_NAME(_class)(_count, _array); \ michael@0: } \ michael@0: \ michael@0: NS_IMETHODIMP \ michael@0: _class::GetHelperForLanguage(uint32_t _language, nsISupports** _retval) \ michael@0: { \ michael@0: *_retval = nullptr; \ michael@0: return NS_OK; \ michael@0: } \ michael@0: \ michael@0: NS_IMETHODIMP \ michael@0: _class::GetContractID(char** _contractID) \ michael@0: { \ michael@0: *_contractID = nullptr; \ michael@0: return NS_OK; \ michael@0: } \ michael@0: \ michael@0: NS_IMETHODIMP \ michael@0: _class::GetClassDescription(char** _classDescription) \ michael@0: { \ michael@0: *_classDescription = nullptr; \ michael@0: return NS_OK; \ michael@0: } \ michael@0: \ michael@0: NS_IMETHODIMP \ michael@0: _class::GetClassID(nsCID** _classID) \ michael@0: { \ michael@0: *_classID = nullptr; \ michael@0: return NS_OK; \ michael@0: } \ michael@0: \ michael@0: NS_IMETHODIMP \ michael@0: _class::GetImplementationLanguage(uint32_t* _language) \ michael@0: { \ michael@0: *_language = nsIProgrammingLanguage::CPLUSPLUS; \ michael@0: return NS_OK; \ michael@0: } \ michael@0: \ michael@0: NS_IMETHODIMP \ michael@0: _class::GetFlags(uint32_t* _flags) \ michael@0: { \ michael@0: *_flags = nsIClassInfo::THREADSAFE; \ michael@0: return NS_OK; \ michael@0: } \ michael@0: \ michael@0: NS_IMETHODIMP \ michael@0: _class::GetClassIDNoAlloc(nsCID* _classIDNoAlloc) \ michael@0: { \ michael@0: return NS_ERROR_NOT_AVAILABLE; \ michael@0: } michael@0: michael@0: #endif