/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
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,
/** *Participantimplementationclasses
*/ class NS_NO_VTABLE nsCycleCollectionParticipant {
public:
using Flags = uint8_t; static constexpr Flags FlagMightSkip = 1u << 0; static constexpr Flags FlagTraverseShouldTrace = 1u << 1; // The object is a single zone js holder if FlagMaybeSingleZoneJSHolder is set // and FlagMultiZoneJSHolder isn't set. This setup is needed so that // inheriting classes can unset single zone behavior. static constexpr Flags FlagMaybeSingleZoneJSHolder = 1u << 2; static constexpr Flags FlagMultiZoneJSHolder = 1u << 3; static constexpr Flags AllFlags = FlagMightSkip | FlagTraverseShouldTrace |
FlagMaybeSingleZoneJSHolder |
FlagMultiZoneJSHolder;
// 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 \ herearerepeatedinsidethe\ ifbranch.Thisisduetothe\ factthatweneedtomaintain\ theif/elsechainforthese\ macros,sothatthecontrol\ flowneverenterstheif\ branchunlessifwe're\ certainoneofthe\ LowWordEquals()brancheswill\
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 # ifdef __clang__ /* clang-format off */ # define IGNORE_UNNECESSARY_VIRTUAL_SPECIFIER(...) \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wunnecessary-virtual-specifier\"") \
__VA_ARGS__ \
_Pragma("clang diagnostic pop") /* clang-format on */ # else # define IGNORE_UNNECESSARY_VIRTUAL_SPECIFIER(...) __VA_ARGS__ # endif # define NS_CHECK_FOR_RIGHT_PARTICIPANT_BASE \
IGNORE_UNNECESSARY_VIRTUAL_SPECIFIER( \
virtual void CheckForRightParticipant()) # define NS_CHECK_FOR_RIGHT_PARTICIPANT_DERIVED \
IGNORE_UNNECESSARY_VIRTUAL_SPECIFIER( \
virtual void 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
// 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.
¤ 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.0.20Bemerkung:
¤
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 und die Messung sind noch experimentell.