michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 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: michael@0: #ifndef nsCycleCollectionParticipant_h__ michael@0: #define nsCycleCollectionParticipant_h__ michael@0: michael@0: #include "mozilla/MacroArgs.h" michael@0: #include "mozilla/MacroForEach.h" michael@0: #include "nsCycleCollectionNoteChild.h" michael@0: #include "js/RootingAPI.h" michael@0: michael@0: #define NS_XPCOMCYCLECOLLECTIONPARTICIPANT_IID \ michael@0: { \ michael@0: 0x9674489b, \ michael@0: 0x1f6f, \ michael@0: 0x4550, \ michael@0: { 0xa7, 0x30, 0xcc, 0xae, 0xdd, 0x10, 0x4c, 0xf9 } \ michael@0: } michael@0: michael@0: /** michael@0: * Special IID to get at the base nsISupports for a class. Usually this is the michael@0: * canonical nsISupports pointer, but in the case of tearoffs for example it is michael@0: * the base nsISupports pointer of the tearoff. This allow the cycle collector michael@0: * to have separate nsCycleCollectionParticipant's for tearoffs or aggregated michael@0: * classes. michael@0: */ michael@0: #define NS_CYCLECOLLECTIONISUPPORTS_IID \ michael@0: { \ michael@0: 0xc61eac14, \ michael@0: 0x5f7a, \ michael@0: 0x4481, \ michael@0: { 0x96, 0x5e, 0x7e, 0xaa, 0x6e, 0xff, 0xa8, 0x5f } \ michael@0: } michael@0: michael@0: /** michael@0: * Just holds the IID so NS_GET_IID works. michael@0: */ michael@0: class nsCycleCollectionISupports michael@0: { michael@0: public: michael@0: NS_DECLARE_STATIC_IID_ACCESSOR(NS_CYCLECOLLECTIONISUPPORTS_IID) michael@0: }; michael@0: michael@0: NS_DEFINE_STATIC_IID_ACCESSOR(nsCycleCollectionISupports, michael@0: NS_CYCLECOLLECTIONISUPPORTS_IID) michael@0: michael@0: namespace JS { michael@0: template class Heap; michael@0: } /* namespace JS */ michael@0: michael@0: /* michael@0: * A struct defining pure virtual methods which are called when tracing cycle michael@0: * collection paticipants. The appropriate method is called depending on the michael@0: * type of JS GC thing. michael@0: */ michael@0: struct TraceCallbacks michael@0: { michael@0: virtual void Trace(JS::Heap* p, const char* name, void* closure) const = 0; michael@0: virtual void Trace(JS::Heap* p, const char* name, void* closure) const = 0; michael@0: virtual void Trace(JS::Heap* p, const char* name, void* closure) const = 0; michael@0: virtual void Trace(JS::TenuredHeap* p, const char* name, void* closure) const = 0; michael@0: virtual void Trace(JS::Heap* p, const char* name, void* closure) const = 0; michael@0: virtual void Trace(JS::Heap* p, const char* name, void* closure) const = 0; michael@0: virtual void Trace(JS::Heap* p, const char* name, void* closure) const = 0; michael@0: }; michael@0: michael@0: /* michael@0: * An implementation of TraceCallbacks that calls a single function for all JS michael@0: * GC thing types encountered. michael@0: */ michael@0: struct TraceCallbackFunc : public TraceCallbacks michael@0: { michael@0: typedef void (* Func)(void* p, const char* name, void* closure); michael@0: michael@0: explicit TraceCallbackFunc(Func cb) : mCallback(cb) {} michael@0: michael@0: virtual void Trace(JS::Heap* p, const char* name, void* closure) const MOZ_OVERRIDE; michael@0: virtual void Trace(JS::Heap* p, const char* name, void* closure) const MOZ_OVERRIDE; michael@0: virtual void Trace(JS::Heap* p, const char* name, void* closure) const MOZ_OVERRIDE; michael@0: virtual void Trace(JS::TenuredHeap* p, const char* name, void* closure) const MOZ_OVERRIDE; michael@0: virtual void Trace(JS::Heap* p, const char* name, void* closure) const MOZ_OVERRIDE; michael@0: virtual void Trace(JS::Heap* p, const char* name, void* closure) const MOZ_OVERRIDE; michael@0: virtual void Trace(JS::Heap* p, const char* name, void* closure) const MOZ_OVERRIDE; michael@0: michael@0: private: michael@0: Func mCallback; michael@0: }; michael@0: michael@0: /** michael@0: * Participant implementation classes michael@0: */ michael@0: class NS_NO_VTABLE nsCycleCollectionParticipant michael@0: { michael@0: public: michael@0: MOZ_CONSTEXPR nsCycleCollectionParticipant() : mMightSkip(false) {} michael@0: MOZ_CONSTEXPR nsCycleCollectionParticipant(bool aSkip) : mMightSkip(aSkip) {} michael@0: michael@0: NS_IMETHOD Traverse(void *p, nsCycleCollectionTraversalCallback &cb) = 0; michael@0: michael@0: NS_IMETHOD_(void) Root(void *p) = 0; michael@0: NS_IMETHOD_(void) Unlink(void *p) = 0; michael@0: NS_IMETHOD_(void) Unroot(void *p) = 0; michael@0: michael@0: NS_IMETHOD_(void) Trace(void *p, const TraceCallbacks &cb, void *closure) {}; michael@0: michael@0: // If CanSkip returns true, p is removed from the purple buffer during michael@0: // a call to nsCycleCollector_forgetSkippable(). michael@0: // Note, calling CanSkip may remove objects from the purple buffer! michael@0: // If aRemovingAllowed is true, p can be removed from the purple buffer. michael@0: bool CanSkip(void *p, bool aRemovingAllowed) michael@0: { michael@0: return mMightSkip ? CanSkipReal(p, aRemovingAllowed) : false; michael@0: } michael@0: michael@0: // If CanSkipInCC returns true, p is skipped when selecting roots for the michael@0: // cycle collector graph. michael@0: // Note, calling CanSkipInCC may remove other objects from the purple buffer! michael@0: bool CanSkipInCC(void *p) michael@0: { michael@0: return mMightSkip ? CanSkipInCCReal(p) : false; michael@0: } michael@0: michael@0: // If CanSkipThis returns true, p is not added to the graph. michael@0: // This method is called during cycle collection, so don't michael@0: // change the state of any objects! michael@0: bool CanSkipThis(void *p) michael@0: { michael@0: return mMightSkip ? CanSkipThisReal(p) : false; michael@0: } michael@0: michael@0: NS_IMETHOD_(void) DeleteCycleCollectable(void *n) = 0; michael@0: michael@0: protected: michael@0: NS_IMETHOD_(bool) CanSkipReal(void *p, bool aRemovingAllowed) michael@0: { michael@0: NS_ASSERTION(false, "Forgot to implement CanSkipReal?"); michael@0: return false; michael@0: } michael@0: NS_IMETHOD_(bool) CanSkipInCCReal(void *p) michael@0: { michael@0: NS_ASSERTION(false, "Forgot to implement CanSkipInCCReal?"); michael@0: return false; michael@0: } michael@0: NS_IMETHOD_(bool) CanSkipThisReal(void *p) michael@0: { michael@0: NS_ASSERTION(false, "Forgot to implement CanSkipThisReal?"); michael@0: return false; michael@0: } michael@0: michael@0: private: michael@0: const bool mMightSkip; michael@0: }; michael@0: michael@0: class NS_NO_VTABLE nsScriptObjectTracer : public nsCycleCollectionParticipant michael@0: { michael@0: public: michael@0: MOZ_CONSTEXPR nsScriptObjectTracer() : nsCycleCollectionParticipant(false) {} michael@0: MOZ_CONSTEXPR nsScriptObjectTracer(bool aSkip) : nsCycleCollectionParticipant(aSkip) {} michael@0: michael@0: NS_IMETHOD_(void) Trace(void *p, const TraceCallbacks &cb, void *closure) = 0; michael@0: michael@0: static void NS_COM_GLUE NoteJSChild(void *aScriptThing, const char *name, michael@0: void *aClosure); michael@0: }; michael@0: michael@0: class NS_NO_VTABLE nsXPCOMCycleCollectionParticipant : public nsScriptObjectTracer michael@0: { michael@0: public: michael@0: MOZ_CONSTEXPR nsXPCOMCycleCollectionParticipant() : nsScriptObjectTracer(false) {} michael@0: MOZ_CONSTEXPR nsXPCOMCycleCollectionParticipant(bool aSkip) : nsScriptObjectTracer(aSkip) {} michael@0: michael@0: NS_DECLARE_STATIC_IID_ACCESSOR(NS_XPCOMCYCLECOLLECTIONPARTICIPANT_IID) michael@0: michael@0: NS_IMETHOD_(void) Root(void *p); michael@0: NS_IMETHOD_(void) Unroot(void *p); michael@0: michael@0: NS_IMETHOD_(void) Trace(void *p, const TraceCallbacks &cb, void *closure); michael@0: michael@0: static bool CheckForRightISupports(nsISupports *s); michael@0: }; michael@0: michael@0: NS_DEFINE_STATIC_IID_ACCESSOR(nsXPCOMCycleCollectionParticipant, michael@0: NS_XPCOMCYCLECOLLECTIONPARTICIPANT_IID) michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: // Helpers for implementing a QI to nsXPCOMCycleCollectionParticipant michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: #define NS_CYCLE_COLLECTION_CLASSNAME(_class) \ michael@0: _class::NS_CYCLE_COLLECTION_INNERCLASS michael@0: michael@0: #define NS_IMPL_QUERY_CYCLE_COLLECTION(_class) \ michael@0: if ( aIID.Equals(NS_GET_IID(nsXPCOMCycleCollectionParticipant)) ) { \ michael@0: *aInstancePtr = NS_CYCLE_COLLECTION_PARTICIPANT(_class); \ michael@0: return NS_OK; \ michael@0: } else michael@0: michael@0: #define NS_IMPL_QUERY_CYCLE_COLLECTION_ISUPPORTS(_class) \ michael@0: if ( aIID.Equals(NS_GET_IID(nsCycleCollectionISupports)) ) { \ michael@0: *aInstancePtr = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this); \ michael@0: return NS_OK; \ michael@0: } else michael@0: michael@0: #define NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION(_class) \ michael@0: NS_IMPL_QUERY_CYCLE_COLLECTION(_class) michael@0: michael@0: #define NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION_ISUPPORTS(_class) \ michael@0: NS_IMPL_QUERY_CYCLE_COLLECTION_ISUPPORTS(_class) michael@0: michael@0: #define NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(_class) \ michael@0: NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION(_class) \ michael@0: NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION_ISUPPORTS(_class) michael@0: michael@0: #define NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(_class) \ michael@0: NS_INTERFACE_MAP_BEGIN(_class) \ michael@0: NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(_class) michael@0: michael@0: #define NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(_class) \ michael@0: NS_INTERFACE_MAP_BEGIN(_class) \ michael@0: NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION(_class) michael@0: michael@0: #define NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(_class) \ michael@0: if (rv == NS_OK) return rv; \ michael@0: nsISupports* foundInterface; \ michael@0: NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(_class) michael@0: michael@0: #define NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(_class) \ michael@0: NS_IMETHODIMP _class::QueryInterface(REFNSIID aIID, void** aInstancePtr) \ michael@0: { \ michael@0: NS_PRECONDITION(aInstancePtr, "null out param"); \ michael@0: \ michael@0: if ( aIID.Equals(NS_GET_IID(nsXPCOMCycleCollectionParticipant)) ) { \ michael@0: *aInstancePtr = NS_CYCLE_COLLECTION_PARTICIPANT(_class); \ michael@0: return NS_OK; \ michael@0: } \ michael@0: nsresult rv; michael@0: michael@0: #define NS_CYCLE_COLLECTION_UPCAST(obj, clazz) \ michael@0: NS_CYCLE_COLLECTION_CLASSNAME(clazz)::Upcast(obj) michael@0: michael@0: #ifdef DEBUG michael@0: #define NS_CHECK_FOR_RIGHT_PARTICIPANT(_ptr) _ptr->CheckForRightParticipant() michael@0: #else michael@0: #define NS_CHECK_FOR_RIGHT_PARTICIPANT(_ptr) michael@0: #endif michael@0: michael@0: // The default implementation of this class template is empty, because it michael@0: // should never be used: see the partial specializations below. michael@0: template ::value> michael@0: struct DowncastCCParticipantImpl michael@0: { michael@0: }; michael@0: michael@0: // Specialization for XPCOM CC participants michael@0: template michael@0: struct DowncastCCParticipantImpl michael@0: { michael@0: static T* Run(void *p) michael@0: { michael@0: nsISupports *s = static_cast(p); michael@0: MOZ_ASSERT(NS_CYCLE_COLLECTION_CLASSNAME(T)::CheckForRightISupports(s), michael@0: "not the nsISupports pointer we expect"); michael@0: T *rval = NS_CYCLE_COLLECTION_CLASSNAME(T)::Downcast(s); michael@0: NS_CHECK_FOR_RIGHT_PARTICIPANT(rval); michael@0: return rval; michael@0: } michael@0: }; michael@0: michael@0: // Specialization for native CC participants michael@0: template michael@0: struct DowncastCCParticipantImpl michael@0: { michael@0: static T* Run(void *p) michael@0: { michael@0: return static_cast(p); michael@0: } michael@0: }; michael@0: michael@0: template michael@0: T* DowncastCCParticipant(void *p) michael@0: { michael@0: return DowncastCCParticipantImpl::Run(p); michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: // Helpers for implementing CanSkip methods michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: #define NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(_class) \ michael@0: NS_IMETHODIMP_(bool) \ michael@0: NS_CYCLE_COLLECTION_CLASSNAME(_class)::CanSkipReal(void *p, \ michael@0: bool aRemovingAllowed) \ michael@0: { \ michael@0: _class *tmp = DowncastCCParticipant<_class >(p); michael@0: michael@0: #define NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END \ michael@0: (void)tmp; \ michael@0: return false; \ michael@0: } michael@0: michael@0: #define NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(_class) \ michael@0: NS_IMETHODIMP_(bool) \ michael@0: NS_CYCLE_COLLECTION_CLASSNAME(_class)::CanSkipInCCReal(void *p) \ michael@0: { \ michael@0: _class *tmp = DowncastCCParticipant<_class >(p); michael@0: michael@0: #define NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END \ michael@0: (void)tmp; \ michael@0: return false; \ michael@0: } michael@0: michael@0: #define NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(_class) \ michael@0: NS_IMETHODIMP_(bool) \ michael@0: NS_CYCLE_COLLECTION_CLASSNAME(_class)::CanSkipThisReal(void *p) \ michael@0: { \ michael@0: _class *tmp = DowncastCCParticipant<_class >(p); michael@0: michael@0: #define NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END \ michael@0: (void)tmp; \ michael@0: return false; \ michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: // Helpers for implementing nsCycleCollectionParticipant::Unlink michael@0: // michael@0: // You need to use NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED if you want michael@0: // the base class Unlink version to be called before your own implementation. michael@0: // You can use NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED if you want the michael@0: // base class Unlink to get called after your own implementation. You should michael@0: // never use them together. michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: #define NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class) \ michael@0: NS_IMETHODIMP_(void) \ michael@0: NS_CYCLE_COLLECTION_CLASSNAME(_class)::Unlink(void *p) \ michael@0: { \ michael@0: _class *tmp = DowncastCCParticipant<_class >(p); michael@0: michael@0: #define NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(_class, _base_class) \ michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class) \ michael@0: nsISupports *s = static_cast(p); \ michael@0: NS_CYCLE_COLLECTION_CLASSNAME(_base_class)::Unlink(s); michael@0: michael@0: #define NS_IMPL_CYCLE_COLLECTION_UNLINK_HELPER(_field) \ michael@0: ImplCycleCollectionUnlink(tmp->_field); michael@0: michael@0: #define NS_IMPL_CYCLE_COLLECTION_UNLINK(...) \ michael@0: MOZ_STATIC_ASSERT_VALID_ARG_COUNT(__VA_ARGS__); \ michael@0: MOZ_FOR_EACH(NS_IMPL_CYCLE_COLLECTION_UNLINK_HELPER, (), (__VA_ARGS__)) michael@0: michael@0: #define NS_IMPL_CYCLE_COLLECTION_UNLINK_END \ michael@0: (void)tmp; \ michael@0: } michael@0: michael@0: #define NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(_base_class) \ michael@0: nsISupports *s = static_cast(p); \ michael@0: NS_CYCLE_COLLECTION_CLASSNAME(_base_class)::Unlink(s); \ michael@0: (void)tmp; \ michael@0: } michael@0: michael@0: #define NS_IMPL_CYCLE_COLLECTION_UNLINK_0(_class) \ michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class) \ michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK_END michael@0: michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: // Helpers for implementing nsCycleCollectionParticipant::Traverse michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: #define NS_IMPL_CYCLE_COLLECTION_DESCRIBE(_class, _refcnt) \ michael@0: cb.DescribeRefCountedNode(_refcnt, #_class); michael@0: michael@0: #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(_class) \ michael@0: NS_IMETHODIMP \ michael@0: NS_CYCLE_COLLECTION_CLASSNAME(_class)::Traverse \ michael@0: (void *p, nsCycleCollectionTraversalCallback &cb) \ michael@0: { \ michael@0: _class *tmp = DowncastCCParticipant<_class >(p); michael@0: michael@0: #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class) \ michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(_class) \ michael@0: NS_IMPL_CYCLE_COLLECTION_DESCRIBE(_class, tmp->mRefCnt.get()) michael@0: michael@0: // Base class' CC participant should return NS_SUCCESS_INTERRUPTED_TRAVERSE michael@0: // from Traverse if it wants derived classes to not traverse anything from michael@0: // their CC participant. michael@0: michael@0: #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(_class, _base_class) \ michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(_class) \ michael@0: nsISupports *s = static_cast(p); \ michael@0: if (NS_CYCLE_COLLECTION_CLASSNAME(_base_class)::Traverse(s, cb) \ michael@0: == NS_SUCCESS_INTERRUPTED_TRAVERSE) { \ michael@0: return NS_SUCCESS_INTERRUPTED_TRAVERSE; \ michael@0: } michael@0: michael@0: #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_HELPER(_field) \ michael@0: ImplCycleCollectionTraverse(cb, tmp->_field, #_field, 0); michael@0: michael@0: #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE(...) \ michael@0: MOZ_STATIC_ASSERT_VALID_ARG_COUNT(__VA_ARGS__); \ michael@0: MOZ_FOR_EACH(NS_IMPL_CYCLE_COLLECTION_TRAVERSE_HELPER, (), (__VA_ARGS__)) michael@0: michael@0: #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(_field) \ michael@0: CycleCollectionNoteChild(cb, tmp->_field, #_field); michael@0: michael@0: #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS \ michael@0: { \ michael@0: TraceCallbackFunc noteJsChild(&nsScriptObjectTracer::NoteJSChild); \ michael@0: Trace(p, noteJsChild, &cb); \ michael@0: } michael@0: michael@0: #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END \ michael@0: (void)tmp; \ michael@0: return NS_OK; \ michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: // Helpers for implementing nsScriptObjectTracer::Trace michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: #define NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(_class) \ michael@0: void \ michael@0: NS_CYCLE_COLLECTION_CLASSNAME(_class)::Trace(void *p, \ michael@0: const TraceCallbacks &aCallbacks, \ michael@0: void *aClosure) \ michael@0: { \ michael@0: _class *tmp = DowncastCCParticipant<_class >(p); michael@0: michael@0: #define NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(_class, _base_class) \ michael@0: NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(_class) \ michael@0: nsISupports *s = static_cast(p); \ michael@0: NS_CYCLE_COLLECTION_CLASSNAME(_base_class)::Trace(s, aCallbacks, aClosure); michael@0: michael@0: #define NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(_field) \ michael@0: if (tmp->_field) \ michael@0: aCallbacks.Trace(&tmp->_field, #_field, aClosure); michael@0: michael@0: #define NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(_field) \ michael@0: aCallbacks.Trace(&tmp->_field, #_field, aClosure); michael@0: michael@0: // NB: The (void)tmp; hack in the TRACE_END macro exists to support michael@0: // implementations that don't need to do anything in their Trace method. michael@0: // Without this hack, some compilers warn about the unused tmp local. michael@0: #define NS_IMPL_CYCLE_COLLECTION_TRACE_END \ michael@0: (void)tmp; \ michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: // Helpers for implementing a concrete nsCycleCollectionParticipant michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: // If a class defines a participant, then QIing an instance of that class to michael@0: // nsXPCOMCycleCollectionParticipant should produce that participant. michael@0: #ifdef DEBUG michael@0: #define NS_CHECK_FOR_RIGHT_PARTICIPANT_IMPL(_class) \ michael@0: virtual void CheckForRightParticipant() \ michael@0: { \ michael@0: nsXPCOMCycleCollectionParticipant *p; \ michael@0: CallQueryInterface(this, &p); \ michael@0: MOZ_ASSERT(p == &NS_CYCLE_COLLECTION_INNERNAME, \ michael@0: #_class " should QI to its own CC participant"); \ michael@0: } michael@0: #else michael@0: #define NS_CHECK_FOR_RIGHT_PARTICIPANT_IMPL(_class) michael@0: #endif michael@0: michael@0: #define NS_DECL_CYCLE_COLLECTION_CLASS_BODY_NO_UNLINK(_class, _base) \ michael@0: public: \ michael@0: NS_IMETHOD Traverse(void *p, nsCycleCollectionTraversalCallback &cb); \ michael@0: NS_IMETHOD_(void) DeleteCycleCollectable(void *p) \ michael@0: { \ michael@0: DowncastCCParticipant<_class>(p)->DeleteCycleCollectable(); \ michael@0: } \ michael@0: static _class* Downcast(nsISupports* s) \ michael@0: { \ michael@0: return static_cast<_class*>(static_cast<_base*>(s)); \ michael@0: } \ michael@0: static nsISupports* Upcast(_class *p) \ michael@0: { \ michael@0: return NS_ISUPPORTS_CAST(_base*, p); \ michael@0: } \ michael@0: template \ michael@0: friend nsISupports* \ michael@0: ToSupports(T* p, NS_CYCLE_COLLECTION_INNERCLASS* dummy); michael@0: michael@0: #define NS_DECL_CYCLE_COLLECTION_CLASS_BODY(_class, _base) \ michael@0: NS_DECL_CYCLE_COLLECTION_CLASS_BODY_NO_UNLINK(_class, _base) \ michael@0: NS_IMETHOD_(void) Unlink(void *p); michael@0: michael@0: #define NS_PARTICIPANT_AS(type, participant) \ michael@0: const_cast(reinterpret_cast(participant)) michael@0: michael@0: #define NS_IMPL_GET_XPCOM_CYCLE_COLLECTION_PARTICIPANT(_class) \ michael@0: static MOZ_CONSTEXPR nsXPCOMCycleCollectionParticipant* GetParticipant() \ michael@0: { \ michael@0: return &_class::NS_CYCLE_COLLECTION_INNERNAME; \ michael@0: } michael@0: michael@0: /** michael@0: * We use this macro to force that classes that inherit from a ccable class and michael@0: * declare their own participant declare themselves as inherited cc classes. michael@0: * To avoid possibly unnecessary vtables we only do this checking in debug michael@0: * builds. michael@0: */ michael@0: #ifdef DEBUG michael@0: #define NOT_INHERITED_CANT_OVERRIDE virtual void BaseCycleCollectable() MOZ_FINAL {} michael@0: #else michael@0: #define NOT_INHERITED_CANT_OVERRIDE michael@0: #endif michael@0: michael@0: #define NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(_class, _base) \ michael@0: class NS_CYCLE_COLLECTION_INNERCLASS \ michael@0: : public nsXPCOMCycleCollectionParticipant \ michael@0: { \ michael@0: NS_DECL_CYCLE_COLLECTION_CLASS_BODY(_class, _base) \ michael@0: NS_IMPL_GET_XPCOM_CYCLE_COLLECTION_PARTICIPANT(_class) \ michael@0: }; \ michael@0: NS_CHECK_FOR_RIGHT_PARTICIPANT_IMPL(_class) \ michael@0: static NS_CYCLE_COLLECTION_INNERCLASS NS_CYCLE_COLLECTION_INNERNAME; \ michael@0: NOT_INHERITED_CANT_OVERRIDE michael@0: michael@0: #define NS_DECL_CYCLE_COLLECTION_CLASS(_class) \ michael@0: NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(_class, _class) michael@0: michael@0: // Cycle collector helper for ambiguous classes that can sometimes be skipped. michael@0: #define NS_DECL_CYCLE_COLLECTION_SKIPPABLE_CLASS_AMBIGUOUS(_class, _base) \ michael@0: class NS_CYCLE_COLLECTION_INNERCLASS \ michael@0: : public nsXPCOMCycleCollectionParticipant \ michael@0: { \ michael@0: public: \ michael@0: MOZ_CONSTEXPR NS_CYCLE_COLLECTION_INNERCLASS () \ michael@0: : nsXPCOMCycleCollectionParticipant(true) {} \ michael@0: private: \ michael@0: NS_DECL_CYCLE_COLLECTION_CLASS_BODY(_class, _base) \ michael@0: NS_IMETHOD_(bool) CanSkipReal(void *p, bool aRemovingAllowed); \ michael@0: NS_IMETHOD_(bool) CanSkipInCCReal(void *p); \ michael@0: NS_IMETHOD_(bool) CanSkipThisReal(void *p); \ michael@0: NS_IMPL_GET_XPCOM_CYCLE_COLLECTION_PARTICIPANT(_class) \ michael@0: }; \ michael@0: NS_CHECK_FOR_RIGHT_PARTICIPANT_IMPL(_class) \ michael@0: static NS_CYCLE_COLLECTION_INNERCLASS NS_CYCLE_COLLECTION_INNERNAME; \ michael@0: NOT_INHERITED_CANT_OVERRIDE michael@0: michael@0: #define NS_DECL_CYCLE_COLLECTION_SKIPPABLE_CLASS(_class) \ michael@0: NS_DECL_CYCLE_COLLECTION_SKIPPABLE_CLASS_AMBIGUOUS(_class, _class) michael@0: michael@0: #define NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(_class, _base) \ michael@0: class NS_CYCLE_COLLECTION_INNERCLASS \ michael@0: : public nsXPCOMCycleCollectionParticipant \ michael@0: { \ michael@0: NS_DECL_CYCLE_COLLECTION_CLASS_BODY(_class, _base) \ michael@0: NS_IMETHOD_(void) Trace(void *p, const TraceCallbacks &cb, void *closure); \ michael@0: NS_IMPL_GET_XPCOM_CYCLE_COLLECTION_PARTICIPANT(_class) \ michael@0: }; \ michael@0: NS_CHECK_FOR_RIGHT_PARTICIPANT_IMPL(_class) \ michael@0: static NS_CYCLE_COLLECTION_INNERCLASS NS_CYCLE_COLLECTION_INNERNAME; \ michael@0: NOT_INHERITED_CANT_OVERRIDE michael@0: michael@0: #define NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_AMBIGUOUS(_class, _base) \ michael@0: class NS_CYCLE_COLLECTION_INNERCLASS \ michael@0: : public nsXPCOMCycleCollectionParticipant \ michael@0: { \ michael@0: public: \ michael@0: MOZ_CONSTEXPR NS_CYCLE_COLLECTION_INNERCLASS () \ michael@0: : nsXPCOMCycleCollectionParticipant(true) {} \ michael@0: private: \ michael@0: NS_DECL_CYCLE_COLLECTION_CLASS_BODY(_class, _base) \ michael@0: NS_IMETHOD_(void) Trace(void *p, const TraceCallbacks &cb, void *closure); \ michael@0: NS_IMETHOD_(bool) CanSkipReal(void *p, bool aRemovingAllowed); \ michael@0: NS_IMETHOD_(bool) CanSkipInCCReal(void *p); \ michael@0: NS_IMETHOD_(bool) CanSkipThisReal(void *p); \ michael@0: NS_IMPL_GET_XPCOM_CYCLE_COLLECTION_PARTICIPANT(_class) \ michael@0: }; \ michael@0: NS_CHECK_FOR_RIGHT_PARTICIPANT_IMPL(_class) \ michael@0: static NS_CYCLE_COLLECTION_INNERCLASS NS_CYCLE_COLLECTION_INNERNAME; \ michael@0: NOT_INHERITED_CANT_OVERRIDE michael@0: michael@0: #define NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(_class) \ michael@0: NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_AMBIGUOUS(_class, _class) michael@0: michael@0: #define NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_INHERITED(_class, \ michael@0: _base_class) \ michael@0: class NS_CYCLE_COLLECTION_INNERCLASS \ michael@0: : public NS_CYCLE_COLLECTION_CLASSNAME(_base_class) \ michael@0: { \ michael@0: NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_BODY(_class, _base_class) \ michael@0: NS_IMETHOD_(void) Trace(void *p, const TraceCallbacks &cb, void *closure); \ michael@0: NS_IMETHOD_(bool) CanSkipReal(void *p, bool aRemovingAllowed); \ michael@0: NS_IMETHOD_(bool) CanSkipInCCReal(void *p); \ michael@0: NS_IMETHOD_(bool) CanSkipThisReal(void *p); \ michael@0: NS_IMPL_GET_XPCOM_CYCLE_COLLECTION_PARTICIPANT(_class) \ michael@0: }; \ michael@0: NS_CHECK_FOR_RIGHT_PARTICIPANT_IMPL(_class) \ michael@0: static NS_CYCLE_COLLECTION_INNERCLASS NS_CYCLE_COLLECTION_INNERNAME; michael@0: michael@0: #define NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(_class) \ michael@0: NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(_class, _class) michael@0: michael@0: #define NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_BODY_NO_UNLINK(_class, \ michael@0: _base_class) \ michael@0: public: \ michael@0: NS_IMETHOD Traverse(void *p, nsCycleCollectionTraversalCallback &cb); \ michael@0: static _class* Downcast(nsISupports* s) \ michael@0: { \ michael@0: return static_cast<_class*>(static_cast<_base_class*>( \ michael@0: NS_CYCLE_COLLECTION_CLASSNAME(_base_class)::Downcast(s))); \ michael@0: } michael@0: michael@0: #define NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_BODY(_class, _base_class) \ michael@0: NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_BODY_NO_UNLINK(_class, _base_class) \ michael@0: NS_IMETHOD_(void) Unlink(void *p); michael@0: michael@0: #define NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(_class, _base_class) \ michael@0: class NS_CYCLE_COLLECTION_INNERCLASS \ michael@0: : public NS_CYCLE_COLLECTION_CLASSNAME(_base_class) \ michael@0: { \ michael@0: public: \ michael@0: NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_BODY(_class, _base_class) \ michael@0: NS_IMPL_GET_XPCOM_CYCLE_COLLECTION_PARTICIPANT(_class) \ michael@0: }; \ michael@0: NS_CHECK_FOR_RIGHT_PARTICIPANT_IMPL(_class) \ michael@0: static NS_CYCLE_COLLECTION_INNERCLASS NS_CYCLE_COLLECTION_INNERNAME; michael@0: michael@0: #define NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(_class, \ michael@0: _base_class) \ michael@0: class NS_CYCLE_COLLECTION_INNERCLASS \ michael@0: : public NS_CYCLE_COLLECTION_CLASSNAME(_base_class) \ michael@0: { \ michael@0: public: \ michael@0: NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_BODY_NO_UNLINK(_class, _base_class) \ michael@0: NS_IMPL_GET_XPCOM_CYCLE_COLLECTION_PARTICIPANT(_class) \ michael@0: }; \ michael@0: NS_CHECK_FOR_RIGHT_PARTICIPANT_IMPL(_class) \ michael@0: static NS_CYCLE_COLLECTION_INNERCLASS NS_CYCLE_COLLECTION_INNERNAME; michael@0: michael@0: #define NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(_class, \ michael@0: _base_class) \ michael@0: class NS_CYCLE_COLLECTION_INNERCLASS \ michael@0: : public NS_CYCLE_COLLECTION_CLASSNAME(_base_class) \ michael@0: { \ michael@0: NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_BODY(_class, _base_class) \ michael@0: NS_IMETHOD_(void) Trace(void *p, const TraceCallbacks &cb, void *closure); \ michael@0: NS_IMPL_GET_XPCOM_CYCLE_COLLECTION_PARTICIPANT(_class) \ michael@0: }; \ michael@0: NS_CHECK_FOR_RIGHT_PARTICIPANT_IMPL(_class) \ michael@0: static NS_CYCLE_COLLECTION_INNERCLASS NS_CYCLE_COLLECTION_INNERNAME; michael@0: michael@0: // Cycle collector participant declarations. michael@0: michael@0: #define NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS_BODY(_class) \ michael@0: public: \ michael@0: NS_IMETHOD_(void) Root(void *n); \ michael@0: NS_IMETHOD_(void) Unlink(void *n); \ michael@0: NS_IMETHOD_(void) Unroot(void *n); \ michael@0: NS_IMETHOD Traverse(void *n, nsCycleCollectionTraversalCallback &cb); \ michael@0: NS_IMETHOD_(void) DeleteCycleCollectable(void *n) \ michael@0: { \ michael@0: DowncastCCParticipant<_class>(n)->DeleteCycleCollectable(); \ michael@0: } \ michael@0: static _class* Downcast(void* s) \ michael@0: { \ michael@0: return DowncastCCParticipant<_class>(s); \ michael@0: } \ michael@0: static void* Upcast(_class *p) \ michael@0: { \ michael@0: return static_cast(p); \ michael@0: } michael@0: michael@0: #define NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(_class) \ michael@0: void DeleteCycleCollectable(void) \ michael@0: { \ michael@0: delete this; \ michael@0: } \ michael@0: class NS_CYCLE_COLLECTION_INNERCLASS \ michael@0: : public nsCycleCollectionParticipant \ michael@0: { \ michael@0: NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS_BODY(_class) \ michael@0: static MOZ_CONSTEXPR nsCycleCollectionParticipant* GetParticipant() \ michael@0: { \ michael@0: return &_class::NS_CYCLE_COLLECTION_INNERNAME; \ michael@0: } \ michael@0: }; \ michael@0: static NS_CYCLE_COLLECTION_INNERCLASS NS_CYCLE_COLLECTION_INNERNAME; michael@0: michael@0: #define NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(_class) \ michael@0: void DeleteCycleCollectable(void) \ michael@0: { \ michael@0: delete this; \ michael@0: } \ michael@0: class NS_CYCLE_COLLECTION_INNERCLASS \ michael@0: : public nsScriptObjectTracer \ michael@0: { \ michael@0: NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS_BODY(_class) \ michael@0: NS_IMETHOD_(void) Trace(void *p, const TraceCallbacks &cb, void *closure); \ michael@0: static MOZ_CONSTEXPR nsScriptObjectTracer* GetParticipant() \ michael@0: { \ michael@0: return &_class::NS_CYCLE_COLLECTION_INNERNAME; \ michael@0: } \ michael@0: }; \ michael@0: static NS_CYCLE_COLLECTION_INNERCLASS NS_CYCLE_COLLECTION_INNERNAME; michael@0: michael@0: #define NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(_class, _root_function) \ michael@0: NS_IMETHODIMP_(void) \ michael@0: NS_CYCLE_COLLECTION_CLASSNAME(_class)::Root(void *p) \ michael@0: { \ michael@0: _class *tmp = static_cast<_class*>(p); \ michael@0: tmp->_root_function(); \ michael@0: } michael@0: michael@0: #define NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(_class, _unroot_function) \ michael@0: NS_IMETHODIMP_(void) \ michael@0: NS_CYCLE_COLLECTION_CLASSNAME(_class)::Unroot(void *p) \ michael@0: { \ michael@0: _class *tmp = static_cast<_class*>(p); \ michael@0: tmp->_unroot_function(); \ michael@0: } michael@0: michael@0: #define NS_IMPL_CYCLE_COLLECTION_CLASS(_class) \ michael@0: _class::NS_CYCLE_COLLECTION_INNERCLASS _class::NS_CYCLE_COLLECTION_INNERNAME; michael@0: michael@0: // NB: This is not something you usually want to use. It is here to allow michael@0: // adding things to the CC graph to help debugging via CC logs, but it does not michael@0: // traverse or unlink anything, so it is useless for anything else. michael@0: #define NS_IMPL_CYCLE_COLLECTION_0(_class) \ michael@0: NS_IMPL_CYCLE_COLLECTION_CLASS(_class) \ michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class) \ michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK_END \ michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class) \ michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END michael@0: michael@0: #define NS_IMPL_CYCLE_COLLECTION(_class, ...) \ michael@0: NS_IMPL_CYCLE_COLLECTION_CLASS(_class) \ michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class) \ michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK(__VA_ARGS__) \ michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK_END \ michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class) \ michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(__VA_ARGS__) \ michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END michael@0: michael@0: #define NS_IMPL_CYCLE_COLLECTION_INHERITED(_class, _base, ...) \ michael@0: NS_IMPL_CYCLE_COLLECTION_CLASS(_class) \ michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(_class, _base) \ michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK(__VA_ARGS__) \ michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK_END \ michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(_class, _base) \ michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(__VA_ARGS__) \ michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END michael@0: michael@0: #define NS_CYCLE_COLLECTION_NOTE_EDGE_NAME CycleCollectionNoteEdgeName michael@0: michael@0: #endif // nsCycleCollectionParticipant_h__