NS_CYCLE_COLLECTION_CLASSNAME(nsXPCWrappedJS)::Traverse (void *p, nsCycleCollectionTraversalCallback &cb) { nsISupports *s = static_cast<nsISupports*>(p); NS_ASSERTION(CheckForRightISupports(s), "not the nsISupports pointer we expect"); nsXPCWrappedJS *tmp = Downcast(s); nsrefcnt refcnt = tmp->mRefCnt.get(); if (cb.WantDebugInfo()) { char name[72]; if (tmp->GetClass()) JS_snprintf(name, sizeof(name), "nsXPCWrappedJS (%s)", tmp->GetClass()->GetInterfaceName()); else JS_snprintf(name, sizeof(name), "nsXPCWrappedJS"); cb.DescribeRefCountedNode(refcnt, name); } else { NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsXPCWrappedJS, refcnt) } // nsXPCWrappedJS keeps its own refcount artificially at or above 1, see the // comment above nsXPCWrappedJS::AddRef. NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "self"); cb.NoteXPCOMChild(s); if (refcnt > 1) { // nsXPCWrappedJS roots its mJSObj when its refcount is > 1, see // the comment above nsXPCWrappedJS::AddRef. NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mJSObj"); cb.NoteJSChild(tmp->GetJSObjectPreserveColor()); } nsXPCWrappedJS* root = tmp->GetRootWrapper(); if (root == tmp) { // The root wrapper keeps the aggregated native object alive. NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "aggregated native"); cb.NoteXPCOMChild(tmp->GetAggregatedNativeObject()); } else { // Non-root wrappers keep their root alive. NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "root"); cb.NoteXPCOMChild(static_cast<nsIXPConnectWrappedJS*>(root)); } return NS_OK; }
NS_CYCLE_COLLECTION_CLASSNAME(nsXPCWrappedJS)::Traverse (void *p, nsCycleCollectionTraversalCallback &cb) { nsISupports *s = static_cast<nsISupports*>(p); MOZ_ASSERT(CheckForRightISupports(s), "not the nsISupports pointer we expect"); nsXPCWrappedJS *tmp = Downcast(s); nsrefcnt refcnt = tmp->mRefCnt.get(); if (cb.WantDebugInfo()) { char name[72]; if (tmp->GetClass()) JS_snprintf(name, sizeof(name), "nsXPCWrappedJS (%s)", tmp->GetClass()->GetInterfaceName()); else JS_snprintf(name, sizeof(name), "nsXPCWrappedJS"); cb.DescribeRefCountedNode(refcnt, name); } else { NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsXPCWrappedJS, refcnt) } // A wrapper that is subject to finalization will only die when its JS object dies. if (tmp->IsSubjectToFinalization()) return NS_OK; // Don't let the extra reference for nsSupportsWeakReference keep a wrapper that is // not subject to finalization alive. NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "self"); cb.NoteXPCOMChild(s); if (tmp->IsValid()) { MOZ_ASSERT(refcnt > 1); NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mJSObj"); cb.NoteJSChild(tmp->GetJSObjectPreserveColor()); } if (tmp->IsRootWrapper()) { NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "aggregated native"); cb.NoteXPCOMChild(tmp->GetAggregatedNativeObject()); } else { NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "root"); cb.NoteXPCOMChild(ToSupports(tmp->GetRootWrapper())); } return NS_OK; }
static NS_METHOD TraverseImpl(JSContextParticipant *that, void *n, nsCycleCollectionTraversalCallback &cb) { JSContext *cx = static_cast<JSContext*>(n); // JSContexts do not have an internal refcount and always have a single // owner (e.g., nsJSContext). Thus, the default refcount is 1. However, // in the (abnormal) case of synchronous cycle-collection, the context // may be actively executing code in which case we want to treat it as // rooted by adding an extra refcount. unsigned refCount = js::ContextHasOutstandingRequests(cx) ? 2 : 1; cb.DescribeRefCountedNode(refCount, "JSContext"); if (JSObject *global = js::GetDefaultGlobalForContext(cx)) { NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "[global object]"); cb.NoteJSChild(global); } return NS_OK; }