diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index 0dd07d9c33e9..2134071fde24 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -1724,7 +1724,7 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(nsDocument, nsNodeUtils::LastRelease(this)) NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsDocument) - return nsGenericElement::CanSkip(tmp); + return nsGenericElement::CanSkip(tmp, aRemovingAllowed); NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsDocument) diff --git a/content/base/src/nsGenericDOMDataNode.cpp b/content/base/src/nsGenericDOMDataNode.cpp index 4f1c0f35fc2f..207449862bde 100644 --- a/content/base/src/nsGenericDOMDataNode.cpp +++ b/content/base/src/nsGenericDOMDataNode.cpp @@ -98,7 +98,7 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGenericDOMDataNode) NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGenericDOMDataNode) - return nsGenericElement::CanSkip(tmp); + return nsGenericElement::CanSkip(tmp, aRemovingAllowed); NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsGenericDOMDataNode) diff --git a/content/base/src/nsGenericElement.cpp b/content/base/src/nsGenericElement.cpp index fc59325ab7ef..5756df87f1ae 100644 --- a/content/base/src/nsGenericElement.cpp +++ b/content/base/src/nsGenericElement.cpp @@ -4634,7 +4634,7 @@ NodeHasActiveFrame(nsIDocument* aCurrentDoc, nsINode* aNode) // since checking the blackness of the current document is usually fast and we // don't want slow down such common cases. bool -nsGenericElement::CanSkip(nsINode* aNode) +nsGenericElement::CanSkip(nsINode* aNode, bool aRemovingAllowed) { // Don't try to optimize anything during shutdown. if (nsCCUncollectableMarker::sGeneration == 0) { @@ -4693,7 +4693,7 @@ nsGenericElement::CanSkip(nsINode* aNode) } // No need to put stuff to the nodesToClear array, if we can clear it // already here. - if (node->IsPurple() && node != aNode) { + if (node->IsPurple() && (node != aNode || aRemovingAllowed)) { node->RemovePurple(); } MarkNodeChildren(node); @@ -4729,8 +4729,9 @@ nsGenericElement::CanSkip(nsINode* aNode) for (PRUint32 i = 0; i < nodesToClear.Length(); ++i) { nsIContent* n = nodesToClear[i]; MarkNodeChildren(n); - // Can't remove currently handled purple node. - if (n != aNode && n->IsPurple()) { + // Can't remove currently handled purple node, + // unless aRemovingAllowed is true. + if ((n != aNode || aRemovingAllowed) && n->IsPurple()) { n->RemovePurple(); } } @@ -4760,7 +4761,7 @@ nsGenericElement::InitCCCallbacks() } NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGenericElement) - return nsGenericElement::CanSkip(tmp); + return nsGenericElement::CanSkip(tmp, aRemovingAllowed); NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsGenericElement) diff --git a/content/base/src/nsGenericElement.h b/content/base/src/nsGenericElement.h index 1ef6e8ea1976..75e630a6f7fe 100644 --- a/content/base/src/nsGenericElement.h +++ b/content/base/src/nsGenericElement.h @@ -623,7 +623,7 @@ public: mRefCnt.RemovePurple(); } - static bool CanSkip(nsINode* aNode); + static bool CanSkip(nsINode* aNode, bool aRemovingAllowed); static bool CanSkipInCC(nsINode* aNode); static bool CanSkipThis(nsINode* aNode); static void MarkNodeChildren(nsINode* aNode); diff --git a/js/xpconnect/src/XPCJSRuntime.cpp b/js/xpconnect/src/XPCJSRuntime.cpp index a57556c26952..3bc55abf66d8 100644 --- a/js/xpconnect/src/XPCJSRuntime.cpp +++ b/js/xpconnect/src/XPCJSRuntime.cpp @@ -584,7 +584,7 @@ UnmarkJSHolder(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32_t number, void *arg) { ObjectHolder* entry = reinterpret_cast(hdr); - entry->tracer->CanSkip(entry->holder); + entry->tracer->CanSkip(entry->holder, true); return JS_DHASH_NEXT; } diff --git a/xpcom/base/nsCycleCollector.cpp b/xpcom/base/nsCycleCollector.cpp index 276262ffad52..d013f2886157 100644 --- a/xpcom/base/nsCycleCollector.cpp +++ b/xpcom/base/nsCycleCollector.cpp @@ -2006,7 +2006,7 @@ nsPurpleBuffer::RemoveSkippable() nsISupports* o = canonicalize(e->mObject); nsXPCOMCycleCollectionParticipant* cp; ToParticipant(o, &cp); - if (!cp->CanSkip(o)) { + if (!cp->CanSkip(o, false)) { continue; } cp->UnmarkPurple(o); diff --git a/xpcom/glue/nsCycleCollectionParticipant.h b/xpcom/glue/nsCycleCollectionParticipant.h index 79ea16c46ccb..7bcefbebd335 100644 --- a/xpcom/glue/nsCycleCollectionParticipant.h +++ b/xpcom/glue/nsCycleCollectionParticipant.h @@ -148,9 +148,10 @@ public: // If CanSkip returns true, p is removed from the purple buffer during // a call to nsCycleCollector_forgetSkippable(). // Note, calling CanSkip may remove objects from the purple buffer! - bool CanSkip(void *p) + // If aRemovingAllowed is true, p can be removed from the purple buffer. + bool CanSkip(void *p, bool aRemovingAllowed) { - return mMightSkip ? CanSkipReal(p) : false; + return mMightSkip ? CanSkipReal(p, aRemovingAllowed) : false; } // If CanSkipInCC returns true, p is skipped when selecting roots for the @@ -169,7 +170,7 @@ public: return mMightSkip ? CanSkipThisReal(p) : false; } protected: - NS_IMETHOD_(bool) CanSkipReal(void *p) + NS_IMETHOD_(bool) CanSkipReal(void *p, bool aRemovingAllowed) { NS_ASSERTION(false, "Forgot to implement CanSkipReal?"); return false; @@ -300,7 +301,8 @@ public: #define NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(_class) \ NS_IMETHODIMP_(bool) \ - NS_CYCLE_COLLECTION_CLASSNAME(_class)::CanSkipReal(void *p) \ + NS_CYCLE_COLLECTION_CLASSNAME(_class)::CanSkipReal(void *p, \ + bool aRemovingAllowed) \ { \ nsISupports *s = static_cast(p); \ NS_ASSERTION(CheckForRightISupports(s), \ @@ -653,7 +655,7 @@ public: NS_DECL_CYCLE_COLLECTION_CLASS_BODY(_class, _base) \ NS_IMETHOD_(void) Trace(void *p, TraceCallback cb, void *closure); \ protected: \ - NS_IMETHOD_(bool) CanSkipReal(void *p); \ + NS_IMETHOD_(bool) CanSkipReal(void *p, bool aRemovingAllowed); \ NS_IMETHOD_(bool) CanSkipInCCReal(void *p); \ NS_IMETHOD_(bool) CanSkipThisReal(void *p); \ }; \ @@ -676,7 +678,7 @@ public: NS_IMETHOD_(void) Trace(void *p, TraceCallback cb, void *closure); \ NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_BODY(_class, _base_class) \ protected: \ - NS_IMETHOD_(bool) CanSkipReal(void *p); \ + NS_IMETHOD_(bool) CanSkipReal(void *p, bool aRemovingAllowed); \ NS_IMETHOD_(bool) CanSkipInCCReal(void *p); \ NS_IMETHOD_(bool) CanSkipThisReal(void *p); \ }; \