/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/** * Note: the following two IIDs only differ in one bit in the last byte. This * is a hack and is intentional in order to speed up the comparison inside * NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED.
*/ #define NS_XPCOMCYCLECOLLECTIONPARTICIPANT_IID \
{ \
0xc61eac14, 0x5f7a, 0x4481, { \
0x96, 0x5e, 0x7e, 0xaa, 0x6e, 0xff, 0xa8, 0x5e \
} \
}
/** * Special IID to get at the base nsISupports for a class. Usually this is the * canonical nsISupports pointer, but in the case of tearoffs for example it is * the base nsISupports pointer of the tearoff. This allow the cycle collector * to have separate nsCycleCollectionParticipant's for tearoffs or aggregated * classes.
*/ #define NS_CYCLECOLLECTIONISUPPORTS_IID \
{ \
0xc61eac14, 0x5f7a, 0x4481, { \
0x96, 0x5e, 0x7e, 0xaa, 0x6e, 0xff, 0xa8, 0x5f \
} \
}
namespace mozilla { enumclass CCReason : uint8_t {
NO_REASON,
// Purple buffer "overflow": enough objects are suspected to be cycle // collectable to trigger an immediate CC.
MANY_SUSPECTED,
// The previous collection was kCCForced ago, and there are at least // kCCForcedPurpleLimit objects suspected of being cycle collectable.
TIMED,
// Run a CC after a GC has completed.
GC_FINISHED,
// Run a slice of a collection.
SLICE,
// Manual reasons are explicitly triggered with a custom listener (as opposed // to exceeding some internal threshold.) If a CC is already in progress, // continue it. Otherwise, start a new one.
FIRST_MANUAL_REASON = 128,
// We want to GC, but must finish any ongoing cycle collection first.
GC_WAITING = FIRST_MANUAL_REASON,
// CC requested via an API. Used by tests.
API,
// Collecting in order to dump the heap.
DUMP_HEAP,
// Low memory situation detected.
MEM_PRESSURE,
// IPC message to a content process to trigger a CC. The original reason is // not tracked.
IPC_MESSAGE,
// Cycle collection on a worker. The triggering reason is not tracked.
WORKER,
/** * Just holds the IID so NS_GET_IID works.
*/ class nsCycleCollectionISupports { public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_CYCLECOLLECTIONISUPPORTS_IID)
};
class nsCycleCollectionTraversalCallback; class nsISupports; class nsWrapperCache;
namespace JS { template <class T> class Heap; template <typename T> class TenuredHeap;
} /* namespace JS */
/* * A struct defining pure virtual methods which are called when tracing cycle * collection paticipants. The appropriate method is called depending on the * type of JS GC thing.
*/ struct TraceCallbacks { virtualvoid Trace(JS::Heap<JS::Value>* aPtr, constchar* aName, void* aClosure) const = 0; virtualvoid Trace(JS::Heap<jsid>* aPtr, constchar* aName, void* aClosure) const = 0; virtualvoid Trace(JS::Heap<JSObject*>* aPtr, constchar* aName, void* aClosure) const = 0; virtualvoid Trace(nsWrapperCache* aPtr, constchar* aName, void* aClosure) const = 0; virtualvoid Trace(JS::TenuredHeap<JSObject*>* aPtr, constchar* aName, void* aClosure) const = 0; virtualvoid Trace(JS::Heap<JSString*>* aPtr, constchar* aName, void* aClosure) const = 0; virtualvoid Trace(JS::Heap<JSScript*>* aPtr, constchar* aName, void* aClosure) const = 0; virtualvoid Trace(JS::Heap<JSFunction*>* aPtr, constchar* aName, void* aClosure) const = 0;
};
/* * An implementation of TraceCallbacks that calls a single function for all JS * GC thing types encountered. Implemented in * nsCycleCollectorTraceJSHelpers.cpp.
*/ struct TraceCallbackFunc : public TraceCallbacks { typedefvoid (*Func)(JS::GCCellPtr aPtr, constchar* aName, void* aClosure);
// CanSkip is called during nsCycleCollector_forgetSkippable. If it returns // true, aPtr is removed from the purple buffer and therefore might be left // out from the cycle collector graph the next time that's constructed (unless // it's reachable in some other way). // // CanSkip is allowed to expand the set of certainly-alive objects by removing // other objects from the purple buffer, marking JS things black (in the GC // sense), and so forth. Furthermore, if aRemovingAllowed is true, this call // is allowed to remove aPtr itself from the purple buffer. // // Things can return true from CanSkip if either they know they have no // outgoing edges at all in the cycle collection graph (because then they // can't be parts of a cycle) or they know for sure they're alive. bool CanSkip(void* aPtr, bool aRemovingAllowed) { return MightSkip() ? CanSkipReal(aPtr, aRemovingAllowed) : false;
}
// CanSkipInCC is called during construction of the initial set of roots for // the cycle collector graph. If it returns true, aPtr is left out of that // set of roots. Note that the set of roots includes whatever is in the // purple buffer (after earlier CanSkip calls) plus various other sources of // roots, so an object can end up having CanSkipInCC called on it even if it // returned true from CanSkip. One example of this would be an object that // can potentially trace JS things. // // CanSkipInCC is allowed to remove other objects from the purple buffer but // should not remove aPtr and should not mark JS things black. It should also // not modify any reference counts. // // Things can return true from CanSkipInCC if either they know they have no // outgoing edges at all in the cycle collection graph or they know for sure // they're alive _and_ none of their outgoing edges are to gray (in the GC // sense) gcthings. See also nsWrapperCache::HasNothingToTrace and // nsWrapperCache::HasKnownLiveWrapperAndDoesNotNeedTracing. The restriction // on not having outgoing edges to gray gcthings is because if we _do_ have // them that means we have a "strong" edge to a JS thing and since we're alive // we need to trace through it and mark keep them alive. Outgoing edges to // C++ things don't matter here, because the criteria for when a CC // participant is considered alive are slightly different for JS and C++ // things: JS things are only considered alive when reachable via an edge from // a live thing, while C++ things are also considered alive when their // refcount exceeds the number of edges via which they are reachable. bool CanSkipInCC(void* aPtr) { return MightSkip() ? CanSkipInCCReal(aPtr) : false;
}
// CanSkipThis is called during construction of the cycle collector graph, // when we traverse an edge to aPtr and consider adding it to the graph. If // it returns true, aPtr is not added to the graph. // // CanSkipThis is not allowed to change the liveness or reference count of any // objects. // // Things can return true from CanSkipThis if either they know they have no // outgoing edges at all in the cycle collection graph or they know for sure // they're alive. // // Note that CanSkipThis doesn't have to worry about outgoing edges to gray GC // things, because if this object could have those it already got added to the // graph during root set construction. An object should never have // CanSkipThis called on it if it has outgoing strong references to JS things. bool CanSkipThis(void* aPtr) { return MightSkip() ? CanSkipThisReal(aPtr) : false;
}
/////////////////////////////////////////////////////////////////////////////// // Helpers for implementing a QI to nsXPCOMCycleCollectionParticipant ///////////////////////////////////////////////////////////////////////////////
// The IIDs for nsXPCOMCycleCollectionParticipant and nsCycleCollectionISupports // are special in that they only differ in their last byte. This allows for the // optimization below where we first check the first three words of the IID and // if we find a match we check the last word to decide which case we have to // deal with. #define NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(_class) \ if (TopThreeWordsEquals( \
aIID, NS_GET_IID(nsXPCOMCycleCollectionParticipant), \
NS_GET_IID( \
nsCycleCollectionISupports)) && /* The calls to LowWordEquals \ here are repeated inside the \ if branch. This is due to the \ fact that we need to maintain \ the if/else chain for these \ macros, so that the control \ flow never enters the if \ branch unless if we're \ certain one of the \ LowWordEquals() branches will \
get executed. */
(LowWordEquals(aIID, NS_GET_IID(nsXPCOMCycleCollectionParticipant)) || \
LowWordEquals(aIID, NS_GET_IID(nsCycleCollectionISupports)))) { \ if (LowWordEquals(aIID, NS_GET_IID(nsXPCOMCycleCollectionParticipant))) { \
*aInstancePtr = NS_CYCLE_COLLECTION_PARTICIPANT(_class); \ return NS_OK; \
} \ if (LowWordEquals(aIID, NS_GET_IID(nsCycleCollectionISupports))) { \
*aInstancePtr = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this); \ return NS_OK; \
} \ /* Avoid warnings about foundInterface being left uninitialized. */ \
foundInterface = nullptr; \
} else
// The IIDs for nsXPCOMCycleCollectionParticipant and nsCycleCollectionISupports // are special in that they only differ in their last byte. This allows for the // optimization below where we first check the first three words of the IID and // if we find a match we check the last word to decide which case we have to // deal with. #define NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(_class) \
NS_IMETHODIMP _class::QueryInterface(REFNSIID aIID, void** aInstancePtr) { \
MOZ_ASSERT(aInstancePtr, "null out param"); \
\ if (TopThreeWordsEquals(aIID, \
NS_GET_IID(nsXPCOMCycleCollectionParticipant), \
NS_GET_IID(nsCycleCollectionISupports))) { \ if (LowWordEquals(aIID, \
NS_GET_IID(nsXPCOMCycleCollectionParticipant))) { \
*aInstancePtr = NS_CYCLE_COLLECTION_PARTICIPANT(_class); \ return NS_OK; \
} \ if (LowWordEquals(aIID, NS_GET_IID(nsCycleCollectionISupports))) { \
*aInstancePtr = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this); \ return NS_OK; \
} \
} \
nsresult rv = NS_ERROR_FAILURE;
// The default implementation of this class template is empty, because it // should never be used: see the partial specializations below. template <typename T, bool IsXPCOM = std::is_base_of<nsISupports, T>::value> struct DowncastCCParticipantImpl {};
// Specialization for XPCOM CC participants template <typename T> struct DowncastCCParticipantImpl<T, true> { static T* Run(void* aPtr) {
nsISupports* s = static_cast<nsISupports*>(aPtr);
MOZ_ASSERT(NS_CYCLE_COLLECTION_CLASSNAME(T)::CheckForRightISupports(s), "not the nsISupports pointer we expect");
T* rval = NS_CYCLE_COLLECTION_CLASSNAME(T)::Downcast(s);
NS_CHECK_FOR_RIGHT_PARTICIPANT(rval); return rval;
}
};
// See documentation for nsCycleCollectionParticipant::CanSkipInCC for // documentation about this method. #define NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(_class) \
NS_IMETHODIMP_(bool) \
NS_CYCLE_COLLECTION_CLASSNAME(_class)::CanSkipInCCReal(void* p) { \
_class* tmp = DowncastCCParticipant<_class>(p);
// See documentation for nsCycleCollectionParticipant::CanSkipThis for // documentation about this method. #define NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(_class) \
NS_IMETHODIMP_(bool) \
NS_CYCLE_COLLECTION_CLASSNAME(_class)::CanSkipThisReal(void* p) { \
_class* tmp = DowncastCCParticipant<_class>(p);
/////////////////////////////////////////////////////////////////////////////// // Helpers for implementing nsCycleCollectionParticipant::Unlink // // You need to use NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED if you want // the base class Unlink version to be called before your own implementation. // You can use NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED if you want the // base class Unlink to get called after your own implementation. You should // never use them together. ///////////////////////////////////////////////////////////////////////////////
// Base class' CC participant should return NS_SUCCESS_INTERRUPTED_TRAVERSE // from Traverse if it wants derived classes to not traverse anything from // their CC participant.
// NB: The (void)tmp; hack in the TRACE_END macro exists to support // implementations that don't need to do anything in their Trace method. // Without this hack, some compilers warn about the unused tmp local. #define NS_IMPL_CYCLE_COLLECTION_TRACE_END \
(void)tmp; \
}
/////////////////////////////////////////////////////////////////////////////// // Helpers for implementing a concrete nsCycleCollectionParticipant ///////////////////////////////////////////////////////////////////////////////
// If a class defines a participant, then QIing an instance of that class to // nsXPCOMCycleCollectionParticipant should produce that participant. #ifdef DEBUG # define NS_CHECK_FOR_RIGHT_PARTICIPANT_BASE \ virtualvoid CheckForRightParticipant() # define NS_CHECK_FOR_RIGHT_PARTICIPANT_DERIVED \ virtualvoid CheckForRightParticipant() override # define NS_CHECK_FOR_RIGHT_PARTICIPANT_BODY(_class) \
{ \
nsXPCOMCycleCollectionParticipant* p; \
CallQueryInterface(this, &p); \
MOZ_ASSERT(p == &NS_CYCLE_COLLECTION_INNERNAME, \ #_class" should QI to its own CC participant"); \
} # define NS_CHECK_FOR_RIGHT_PARTICIPANT_IMPL(_class) \
NS_CHECK_FOR_RIGHT_PARTICIPANT_BASE \
NS_CHECK_FOR_RIGHT_PARTICIPANT_BODY(_class) # define NS_CHECK_FOR_RIGHT_PARTICIPANT_IMPL_INHERITED(_class) \
NS_CHECK_FOR_RIGHT_PARTICIPANT_DERIVED \
NS_CHECK_FOR_RIGHT_PARTICIPANT_BODY(_class) #else # define NS_CHECK_FOR_RIGHT_PARTICIPANT_IMPL(_class) # define NS_CHECK_FOR_RIGHT_PARTICIPANT_IMPL_INHERITED(_class) #endif
/** * We use this macro to force that classes that inherit from a ccable class and * declare their own participant declare themselves as inherited cc classes. * To avoid possibly unnecessary vtables we only do this checking in debug * builds.
*/ #ifdef DEBUG # define NOT_INHERITED_CANT_OVERRIDE \ virtualvoid BaseCycleCollectable() final {} #else # define NOT_INHERITED_CANT_OVERRIDE #endif
// By default JS holders are treated as if they may store pointers to multiple // zones, but one may optimize GC handling by using single zone holders. #define NS_IMPL_CYCLE_COLLECTION_SINGLE_ZONE_SCRIPT_HOLDER_CLASS(_class) \
_class::NS_CYCLE_COLLECTION_INNERCLASS \
_class::NS_CYCLE_COLLECTION_INNERNAME( \
nsCycleCollectionParticipant::FlagMaybeSingleZoneJSHolder);
// NB: This is not something you usually want to use. It is here to allow // adding things to the CC graph to help debugging via CC logs, but it does not // traverse or unlink anything, so it is useless for anything else. #define NS_IMPL_CYCLE_COLLECTION_0(_class) \
NS_IMPL_CYCLE_COLLECTION_CLASS(_class) \
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class) \
NS_IMPL_CYCLE_COLLECTION_UNLINK_END \
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class) \
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
// If you are looking for NS_IMPL_CYCLE_COLLECTION_INHERITED_0(_class, _base) // you should instead not declare any cycle collected stuff in _class, so it // will just inherit the CC declarations from _base.
/** * Equivalency of the high three words where two IIDs have the same * top three words but not the same low word.
*/ inlinebool TopThreeWordsEquals(const nsID& aID, const nsID& aOther1, const nsID& aOther2) {
MOZ_ASSERT((((uint32_t*)&aOther1.m0)[0] == ((uint32_t*)&aOther2.m0)[0]) &&
(((uint32_t*)&aOther1.m0)[1] == ((uint32_t*)&aOther2.m0)[1]) &&
(((uint32_t*)&aOther1.m0)[2] == ((uint32_t*)&aOther2.m0)[2]) &&
(((uint32_t*)&aOther1.m0)[3] != ((uint32_t*)&aOther2.m0)[3]));
/** * Equivalency of the fourth word where the two IIDs have the same * top three words but not the same low word.
*/ inlinebool LowWordEquals(const nsID& aID, const nsID& aOther) { return (((uint32_t*)&aID.m0)[3] == ((uint32_t*)&aOther.m0)[3]);
}
// Template magic to modify JS::Heap without including relevant headers, to // prevent excessive header dependency. template <typename T> inlinevoid ImplCycleCollectionUnlink(JS::Heap<T>& aField) {
aField.setNull();
} template <typename T> inlinevoid ImplCycleCollectionUnlink(JS::Heap<T*>& aField) {
aField = nullptr;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.