Fix for bug 678528 (Traverse mChildNodes (and consolidate node CC code)). r=jst.
authorPeter Van der Beken <peterv@propagandism.org>
Sun, 28 Aug 2011 16:07:24 +0200
changeset 76012 500c2ddb52c1b8d457c72480f2c1f74212860a8f
parent 76011 0be4a94258c28b97a7e6e87b099359c759941b22
child 76013 7c905a200bcc1f914e867a104f9256dcf8c4e37a
push id3
push userfelipc@gmail.com
push dateFri, 30 Sep 2011 20:09:13 +0000
reviewersjst
bugs678528
milestone9.0a1
Fix for bug 678528 (Traverse mChildNodes (and consolidate node CC code)). r=jst.
content/base/public/nsIContent.h
content/base/public/nsINode.h
content/base/src/nsDOMAttribute.cpp
content/base/src/nsDocument.cpp
content/base/src/nsGenericDOMDataNode.cpp
content/base/src/nsGenericElement.cpp
content/base/src/nsGenericElement.h
content/base/src/nsObjectLoadingContent.cpp
content/base/src/nsObjectLoadingContent.h
content/html/content/src/nsHTMLObjectElement.cpp
content/html/content/src/nsHTMLSharedObjectElement.cpp
content/xul/content/src/nsXULElement.cpp
content/xul/content/src/nsXULElement.h
--- a/content/base/public/nsIContent.h
+++ b/content/base/public/nsIContent.h
@@ -1022,33 +1022,9 @@ public:
   // accessibility.tabfocus_applies_to_xul pref - if it is set to true,
   // the tabfocus bit field applies to xul elements.
   static PRBool sTabFocusModelAppliesToXUL;
 
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIContent, NS_ICONTENT_IID)
 
-// Some cycle-collecting helper macros for nsIContent subclasses
-
-#define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_LISTENERMANAGER \
-  if (tmp->HasFlag(NODE_HAS_LISTENERMANAGER)) {           \
-    nsContentUtils::TraverseListenerManager(tmp, cb);     \
-  }
-
-#define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_USERDATA \
-  if (tmp->HasProperties()) {                      \
-    nsNodeUtils::TraverseUserData(tmp, cb);        \
-  }
-
-#define NS_IMPL_CYCLE_COLLECTION_UNLINK_LISTENERMANAGER \
-  if (tmp->HasFlag(NODE_HAS_LISTENERMANAGER)) {         \
-    nsContentUtils::RemoveListenerManager(tmp);         \
-    tmp->UnsetFlags(NODE_HAS_LISTENERMANAGER);          \
-  }
-
-#define NS_IMPL_CYCLE_COLLECTION_UNLINK_USERDATA \
-  if (tmp->HasProperties()) {                    \
-    nsNodeUtils::UnlinkUserData(tmp);            \
-  }
-
-
 #endif /* nsIContent_h___ */
--- a/content/base/public/nsINode.h
+++ b/content/base/public/nsINode.h
@@ -796,16 +796,19 @@ public:
         mWeakReference(nsnull)
     {
     }
 
     // If needed we could remove the vtable pointer this dtor causes by
     // putting a DestroySlots function on nsINode
     virtual ~nsSlots();
 
+    void Traverse(nsCycleCollectionTraversalCallback &cb);
+    void Unlink();
+
     /**
      * A list of mutation observers
      */
     nsTObserverArray<nsIMutationObserver*> mMutationObservers;
 
     /**
      * An object implementing nsIDOMNodeList for this content (childNodes)
      * @see nsIDOMNodeList
@@ -1337,16 +1340,20 @@ protected:
 #define EVENT(name_, id_, type_, struct_)                         \
   NS_IMETHOD GetOn##name_(JSContext *cx, jsval *vp);              \
   NS_IMETHOD SetOn##name_(JSContext *cx, const jsval &v);
 #define TOUCH_EVENT EVENT
 #include "nsEventNameList.h"
 #undef TOUCH_EVENT
 #undef EVENT  
 
+  static void Trace(nsINode *tmp, TraceCallback cb, void *closure);
+  static bool Traverse(nsINode *tmp, nsCycleCollectionTraversalCallback &cb);
+  static void Unlink(nsINode *tmp);
+
   nsCOMPtr<nsINodeInfo> mNodeInfo;
 
   nsINode* mParent;
 
   PRUint32 mFlags;
 
 private:
   // Boolean flags.
--- a/content/base/src/nsDOMAttribute.cpp
+++ b/content/base/src/nsDOMAttribute.cpp
@@ -55,17 +55,16 @@
 #include "nsGkAtoms.h"
 #include "nsCOMArray.h"
 #include "nsNodeUtils.h"
 #include "nsEventListenerManager.h"
 #include "nsTextNode.h"
 #include "mozAutoDocUpdate.h"
 #include "nsMutationEvent.h"
 #include "nsPLDOMEvent.h"
-#include "nsContentUtils.h" // NS_IMPL_CYCLE_COLLECTION_UNLINK_LISTENERMANAGER
 
 using namespace mozilla::dom;
 
 //----------------------------------------------------------------------
 PRBool nsDOMAttribute::sInitialized;
 
 nsDOMAttribute::nsDOMAttribute(nsDOMAttributeMap *aAttrMap,
                                already_AddRefed<nsINodeInfo> aNodeInfo,
@@ -100,35 +99,35 @@ nsDOMAttribute::~nsDOMAttribute()
     content->RemoveMutationObserver(this);
   }
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMAttribute)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMAttribute)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mNodeInfo)
+
+  if (!nsINode::Traverse(tmp, cb)) {
+    return NS_SUCCESS_INTERRUPTED_TRAVERSE;
+  }
+
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mChild)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_LISTENERMANAGER
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_USERDATA
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsDOMAttribute)
-  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
+  nsINode::Trace(tmp, aCallback, aClosure);
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMAttribute)
+  nsINode::Unlink(tmp);
   if (tmp->mChild) {
     static_cast<nsTextNode*>(tmp->mChild)->UnbindFromAttribute();
     NS_RELEASE(tmp->mChild);
     tmp->mFirstChild = nsnull;
   }
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_LISTENERMANAGER
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_USERDATA
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 DOMCI_NODE_DATA(Attr, nsDOMAttribute)
 
 // QueryInterface implementation for nsDOMAttribute
 NS_INTERFACE_TABLE_HEAD(nsDOMAttribute)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_NODE_INTERFACE_TABLE5(nsDOMAttribute, nsIDOMAttr, nsIAttribute, nsIDOMNode,
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -1820,34 +1820,30 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
   else {
     NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsDocument, tmp->mRefCnt.get())
   }
 
   // Always need to traverse script objects, so do that before we check
   // if we're uncollectable.
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 
-  if (nsCCUncollectableMarker::InGeneration(cb, tmp->GetMarkedCCGeneration())) {
+  if (!nsINode::Traverse(tmp, cb)) {
     return NS_SUCCESS_INTERRUPTED_TRAVERSE;
   }
 
   tmp->mIdentifierMap.EnumerateEntries(IdentifierMapEntryTraverse, &cb);
 
   tmp->mExternalResourceMap.Traverse(&cb);
 
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mNodeInfo)
-
   // Traverse the mChildren nsAttrAndChildArray.
   for (PRInt32 indx = PRInt32(tmp->mChildren.ChildCount()); indx > 0; --indx) {
     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mChildren[i]");
     cb.NoteXPCOMChild(tmp->mChildren.ChildAt(indx - 1));
   }
 
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_USERDATA
-
   // Traverse all nsIDocument pointer members.
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mCachedRootElement)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mSecurityInfo)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDisplayDocument)
 
   // Traverse all nsDocument nsCOMPtrs.
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mParser)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mScriptGlobalObject)
@@ -1896,28 +1892,30 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
 
   if (tmp->mSubDocuments && tmp->mSubDocuments->ops) {
     PL_DHashTableEnumerate(tmp->mSubDocuments, SubDocTraverser, &cb);
   }
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsDocument)
-  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
+  nsINode::Trace(tmp, aCallback, aClosure);
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument)
   tmp->mInUnlinkOrDeletion = PR_TRUE;
 
   // Clear out our external resources
   tmp->mExternalResourceMap.Shutdown();
 
   nsAutoScriptBlocker scriptBlocker;
 
+  nsINode::Unlink(tmp);
+
   // Unlink the mChildren nsAttrAndChildArray.
   for (PRInt32 indx = PRInt32(tmp->mChildren.ChildCount()) - 1; 
        indx >= 0; --indx) {
     tmp->mChildren.ChildAt(indx)->UnbindFromTree();
     tmp->mChildren.RemoveChildAt(indx);
   }
   tmp->mFirstChild = nsnull;
 
@@ -1925,19 +1923,16 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCachedRootElement)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDisplayDocument)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFirstBaseNodeWithHref)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDOMImplementation)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mImageMaps)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOriginalDocument)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCachedEncoder)
 
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_USERDATA
-
   tmp->mParentDocument = nsnull;
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mPreloadingImages)
 
   
   if (tmp->mBoxObjectTable) {
    tmp->mBoxObjectTable->EnumerateRead(ClearAllBoxObjects, nsnull);
    delete tmp->mBoxObjectTable;
--- a/content/base/src/nsGenericDOMDataNode.cpp
+++ b/content/base/src/nsGenericDOMDataNode.cpp
@@ -88,46 +88,36 @@ nsGenericDOMDataNode::~nsGenericDOMDataN
   if (GetParent()) {
     NS_RELEASE(mParent);
   }
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGenericDOMDataNode)
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGenericDOMDataNode)
-  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
+  nsINode::Trace(tmp, aCallback, aClosure);
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsGenericDOMDataNode)
   // Always need to traverse script objects, so do that before we check
   // if we're uncollectable.
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 
-  nsIDocument* currentDoc = tmp->GetCurrentDoc();
-  if (currentDoc && nsCCUncollectableMarker::InGeneration(
-                      cb, currentDoc->GetMarkedCCGeneration())) {
+  if (!nsINode::Traverse(tmp, cb)) {
     return NS_SUCCESS_INTERRUPTED_TRAVERSE;
   }
 
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mNodeInfo)
-
   nsIDocument* ownerDoc = tmp->GetOwnerDoc();
   if (ownerDoc) {
     ownerDoc->BindingManager()->Traverse(tmp, cb);
   }
-
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_LISTENERMANAGER
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_USERDATA
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(GetParent())
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGenericDOMDataNode)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_LISTENERMANAGER
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_USERDATA
+  nsINode::Unlink(tmp);
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN(nsGenericDOMDataNode)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsGenericDOMDataNode)
   NS_INTERFACE_MAP_ENTRY(nsIContent)
   NS_INTERFACE_MAP_ENTRY(nsINode)
   NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -169,16 +169,32 @@ nsINode::nsSlots::~nsSlots()
     NS_RELEASE(mChildNodes);
   }
 
   if (mWeakReference) {
     mWeakReference->NoticeNodeDestruction();
   }
 }
 
+void
+nsINode::nsSlots::Traverse(nsCycleCollectionTraversalCallback &cb)
+{
+  NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mChildNodes");
+  cb.NoteXPCOMChild(mChildNodes);
+}
+
+void
+nsINode::nsSlots::Unlink()
+{
+  if (mChildNodes) {
+    mChildNodes->DropReference();
+    NS_RELEASE(mChildNodes);
+  }
+}
+
 //----------------------------------------------------------------------
 
 nsINode::~nsINode()
 {
   NS_ASSERTION(!HasSlots(), "nsNodeUtils::LastRelease was not called?");
 }
 
 void*
@@ -1137,16 +1153,73 @@ nsINode::GetListenerManager(PRBool aCrea
 }
 
 nsIScriptContext*
 nsINode::GetContextForEventHandlers(nsresult* aRv)
 {
   return nsContentUtils::GetContextForEventHandlers(this, aRv);
 }
 
+/* static */
+void
+nsINode::Trace(nsINode *tmp, TraceCallback cb, void *closure)
+{
+  nsContentUtils::TraceWrapper(tmp, cb, closure);
+}
+
+/* static */
+bool
+nsINode::Traverse(nsINode *tmp, nsCycleCollectionTraversalCallback &cb)
+{
+  nsIDocument *currentDoc = tmp->GetCurrentDoc();
+  if (currentDoc &&
+      nsCCUncollectableMarker::InGeneration(cb, currentDoc->GetMarkedCCGeneration())) {
+    return false;
+  }
+
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mNodeInfo)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(GetParent())
+
+  nsSlots *slots = tmp->GetExistingSlots();
+  if (slots) {
+    slots->Traverse(cb);
+  }
+
+  if (tmp->HasProperties()) {
+    nsNodeUtils::TraverseUserData(tmp, cb);
+  }
+
+  if (tmp->HasFlag(NODE_HAS_LISTENERMANAGER)) {
+    nsContentUtils::TraverseListenerManager(tmp, cb);
+  }
+
+  return true;
+}
+
+/* static */
+void
+nsINode::Unlink(nsINode *tmp)
+{
+  nsContentUtils::ReleaseWrapper(tmp, tmp);
+
+  nsSlots *slots = tmp->GetExistingSlots();
+  if (slots) {
+    slots->Unlink();
+  }
+
+  if (tmp->HasFlag(NODE_HAS_LISTENERMANAGER)) {
+    nsContentUtils::RemoveListenerManager(tmp);
+    tmp->UnsetFlags(NODE_HAS_LISTENERMANAGER);
+  }
+
+  if (tmp->HasProperties()) {
+    nsNodeUtils::UnlinkUserData(tmp);
+  }
+}
+
 //----------------------------------------------------------------------
 
 nsEventStates
 Element::IntrinsicState() const
 {
   return IsEditable() ? NS_EVENT_STATE_MOZ_READWRITE :
                         NS_EVENT_STATE_MOZ_READONLY;
 }
@@ -2187,16 +2260,55 @@ nsGenericElement::nsDOMSlots::~nsDOMSlot
     mAttributeMap->DropReference();
   }
 
   if (mClassList) {
     mClassList->DropReference();
   }
 }
 
+void
+nsGenericElement::nsDOMSlots::Traverse(nsCycleCollectionTraversalCallback &cb, bool aIsXUL)
+{
+  NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mStyle");
+  cb.NoteXPCOMChild(mStyle.get());
+
+#ifdef MOZ_SMIL
+  NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mSMILOverrideStyle");
+  cb.NoteXPCOMChild(mSMILOverrideStyle.get());
+#endif // MOZ_SMIL
+
+  NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mAttributeMap");
+  cb.NoteXPCOMChild(mAttributeMap.get());
+
+  if (aIsXUL) {
+    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mControllers");
+    cb.NoteXPCOMChild(mControllers);
+  }
+
+  NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mChildrenList");
+  cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIDOMNodeList*, mChildrenList));
+}
+
+void
+nsGenericElement::nsDOMSlots::Unlink(bool aIsXUL)
+{
+  mStyle = nsnull;
+#ifdef MOZ_SMIL
+  mSMILOverrideStyle = nsnull;
+#endif // MOZ_SMIL
+  if (mAttributeMap) {
+    mAttributeMap->DropReference();
+    mAttributeMap = nsnull;
+  }
+  if (aIsXUL)
+    NS_IF_RELEASE(mControllers);
+  mChildrenList = nsnull;
+}
+
 nsGenericElement::nsGenericElement(already_AddRefed<nsINodeInfo> aNodeInfo)
   : Element(aNodeInfo)
 {
   NS_ABORT_IF_FALSE(mNodeInfo->NodeType() == nsIDOMNode::ELEMENT_NODE ||
                     (mNodeInfo->NodeType() ==
                        nsIDOMNode::DOCUMENT_FRAGMENT_NODE &&
                      mNodeInfo->Equals(nsGkAtoms::documentFragmentNodeName,
                                        kNameSpaceID_None)),
@@ -4105,19 +4217,17 @@ nsINode::IsSameNode(nsIDOMNode* aOther, 
 
 //----------------------------------------------------------------------
 
 // nsISupports implementation
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGenericElement)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGenericElement)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_LISTENERMANAGER
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_USERDATA
+  nsINode::Unlink(tmp);
 
   if (tmp->HasProperties() && tmp->IsXUL()) {
     tmp->DeleteProperty(nsGkAtoms::contextmenulistener);
     tmp->DeleteProperty(nsGkAtoms::popuplistener);
   }
 
   // Unlink child content (and unbind our subtree).
   {
@@ -4135,40 +4245,30 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
       tmp->mFirstChild = nsnull;
     }
   }  
 
   // Unlink any DOM slots of interest.
   {
     nsDOMSlots *slots = tmp->GetExistingDOMSlots();
     if (slots) {
-      slots->mStyle = nsnull;
-#ifdef MOZ_SMIL
-      slots->mSMILOverrideStyle = nsnull;
-#endif // MOZ_SMIL
-      if (slots->mAttributeMap) {
-        slots->mAttributeMap->DropReference();
-        slots->mAttributeMap = nsnull;
-      }
-      if (tmp->IsXUL())
-        NS_IF_RELEASE(slots->mControllers);
-      slots->mChildrenList = nsnull;
+      slots->Unlink(tmp->IsXUL());
     }
   }
 
   {
     nsIDocument *doc;
     if (!tmp->GetNodeParent() && (doc = tmp->GetOwnerDoc())) {
       doc->BindingManager()->RemovedFromDocument(tmp, doc);
     }
   }
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGenericElement)
-  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
+  nsINode::Trace(tmp, aCallback, aClosure);
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 static const char* kNSURIs[] = {
   " ([none])",
   " (xmlns)",
   " (xml)",
   " (xhtml)",
   " (XLink)",
@@ -4199,30 +4299,25 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
   else {
     NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsGenericElement, tmp->mRefCnt.get())
   }
 
   // Always need to traverse script objects, so do that before we check
   // if we're uncollectable.
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 
-  nsIDocument* currentDoc = tmp->GetCurrentDoc();
-  if (currentDoc && nsCCUncollectableMarker::InGeneration(
-                      cb, currentDoc->GetMarkedCCGeneration())) {
+  if (!nsINode::Traverse(tmp, cb)) {
     return NS_SUCCESS_INTERRUPTED_TRAVERSE;
   }
 
   nsIDocument* ownerDoc = tmp->GetOwnerDoc();
   if (ownerDoc) {
     ownerDoc->BindingManager()->Traverse(tmp, cb);
   }
 
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_LISTENERMANAGER
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_USERDATA
-
   if (tmp->HasProperties() && tmp->IsXUL()) {
     nsISupports* property =
       static_cast<nsISupports*>
                  (tmp->GetProperty(nsGkAtoms::contextmenulistener));
     cb.NoteXPCOMChild(property);
     property = static_cast<nsISupports*>
                           (tmp->GetProperty(nsGkAtoms::popuplistener));
     cb.NoteXPCOMChild(property);
@@ -4243,41 +4338,23 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
 
     PRUint32 kids = tmp->mAttrsAndChildren.ChildCount();
     for (i = 0; i < kids; i++) {
       NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mAttrsAndChildren[i]");
       cb.NoteXPCOMChild(tmp->mAttrsAndChildren.GetSafeChildAt(i));
     }
   }
 
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mNodeInfo)
-
   // Traverse any DOM slots of interest.
   {
     nsDOMSlots *slots = tmp->GetExistingDOMSlots();
     if (slots) {
-      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "slots mStyle");
-      cb.NoteXPCOMChild(slots->mStyle.get());
-
-#ifdef MOZ_SMIL
-      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "slots mSMILOverrideStyle");
-      cb.NoteXPCOMChild(slots->mSMILOverrideStyle.get());
-#endif // MOZ_SMIL
-
-      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "slots mAttributeMap");
-      cb.NoteXPCOMChild(slots->mAttributeMap.get());
-
-      if (tmp->IsXUL())
-        cb.NoteXPCOMChild(slots->mControllers);
-      cb.NoteXPCOMChild(
-        static_cast<nsIDOMNodeList*>(slots->mChildrenList.get()));
+      slots->Traverse(cb, tmp->IsXUL());
     }
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(GetParent())
-  }
-  
+  }
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 
 NS_INTERFACE_MAP_BEGIN(nsGenericElement)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsGenericElement)
   NS_INTERFACE_MAP_ENTRY(nsIContent)
   NS_INTERFACE_MAP_ENTRY(nsINode)
--- a/content/base/src/nsGenericElement.h
+++ b/content/base/src/nsGenericElement.h
@@ -821,16 +821,19 @@ public:
    * accessed through the DOM.
    */
   class nsDOMSlots : public nsINode::nsSlots
   {
   public:
     nsDOMSlots();
     virtual ~nsDOMSlots();
 
+    void Traverse(nsCycleCollectionTraversalCallback &cb, bool aIsXUL);
+    void Unlink(bool aIsXUL);
+
     /**
      * The .style attribute (an interface that forwards to the actual
      * style rules)
      * @see nsGenericHTMLElement::GetStyle
      */
     nsCOMPtr<nsICSSDeclaration> mStyle;
 
     /**
--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -1520,20 +1520,23 @@ nsObjectLoadingContent::RemovedFromDocum
     mFrameLoader = nsnull;
 
     // Clear the current URI, so that LoadObject doesn't think that we
     // have already loaded the content.
     mURI = nsnull;
   }
 }
 
+/* static */
 void
-nsObjectLoadingContent::Traverse(nsCycleCollectionTraversalCallback &cb)
+nsObjectLoadingContent::Traverse(nsObjectLoadingContent *tmp,
+                                 nsCycleCollectionTraversalCallback &cb)
 {
-  cb.NoteXPCOMChild(static_cast<nsIFrameLoader*>(mFrameLoader));
+  NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mFrameLoader");
+  cb.NoteXPCOMChild(static_cast<nsIFrameLoader*>(tmp->mFrameLoader));
 }
 
 // <private>
 /* static */ PRBool
 nsObjectLoadingContent::IsSuccessfulRequest(nsIRequest* aRequest)
 {
   nsresult status;
   nsresult rv = aRequest->GetStatus(&status);
--- a/content/base/src/nsObjectLoadingContent.h
+++ b/content/base/src/nsObjectLoadingContent.h
@@ -217,17 +217,18 @@ class nsObjectLoadingContent : public ns
     /**
      * Subclasses must call this function when they are removed from the
      * document.
      *
      * XXX This is a temporary workaround for docshell suckyness
      */
     void RemovedFromDocument();
 
-    void Traverse(nsCycleCollectionTraversalCallback &cb);
+    static void Traverse(nsObjectLoadingContent *tmp,
+                         nsCycleCollectionTraversalCallback &cb);
 
     void CreateStaticClone(nsObjectLoadingContent* aDest) const;
   private:
     /**
      * Check whether the given request represents a successful load.
      */
     static PRBool IsSuccessfulRequest(nsIRequest* aRequest);
 
--- a/content/html/content/src/nsHTMLObjectElement.cpp
+++ b/content/html/content/src/nsHTMLObjectElement.cpp
@@ -191,17 +191,17 @@ nsHTMLObjectElement::DoneAddingChildren(
     StartObjectLoad(aHaveNotified);
   }
   return NS_OK;
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsHTMLObjectElement)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsHTMLObjectElement,
                                                   nsGenericHTMLFormElement)
-  tmp->Traverse(cb);
+  nsObjectLoadingContent::Traverse(tmp, cb);
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_ADDREF_INHERITED(nsHTMLObjectElement, nsGenericElement) 
 NS_IMPL_RELEASE_INHERITED(nsHTMLObjectElement, nsGenericElement) 
 
 DOMCI_NODE_DATA(HTMLObjectElement, nsHTMLObjectElement)
 
 NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsHTMLObjectElement)
--- a/content/html/content/src/nsHTMLSharedObjectElement.cpp
+++ b/content/html/content/src/nsHTMLSharedObjectElement.cpp
@@ -211,17 +211,17 @@ nsHTMLSharedObjectElement::DoneAddingChi
   }
 
   return NS_OK;
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsHTMLSharedObjectElement)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsHTMLSharedObjectElement,
                                                   nsGenericHTMLElement)
-  tmp->Traverse(cb);
+  nsObjectLoadingContent::Traverse(tmp, cb);
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_ADDREF_INHERITED(nsHTMLSharedObjectElement, nsGenericElement) 
 NS_IMPL_RELEASE_INHERITED(nsHTMLSharedObjectElement, nsGenericElement) 
 
 DOMCI_DATA(HTMLAppletElement, nsHTMLSharedObjectElement)
 DOMCI_DATA(HTMLEmbedElement, nsHTMLSharedObjectElement)
 
--- a/content/xul/content/src/nsXULElement.cpp
+++ b/content/xul/content/src/nsXULElement.cpp
@@ -248,16 +248,23 @@ nsXULElement::nsXULSlots::nsXULSlots()
 nsXULElement::nsXULSlots::~nsXULSlots()
 {
     NS_IF_RELEASE(mControllers); // Forces release
     if (mFrameLoader) {
         mFrameLoader->Destroy();
     }
 }
 
+void
+nsXULElement::nsXULSlots::Traverse(nsCycleCollectionTraversalCallback &cb)
+{
+    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mFrameLoader");
+    cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIFrameLoader*, mFrameLoader));
+}
+
 nsINode::nsSlots*
 nsXULElement::CreateSlots()
 {
     return new nsXULSlots();
 }
 
 /* static */
 already_AddRefed<nsXULElement>
@@ -367,20 +374,17 @@ NS_TrustedNewXULElement(nsIContent** aRe
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULElement)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXULElement,
                                                   nsStyledElement)
     NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mPrototype,
                                                     nsXULPrototypeElement)
     {
         nsXULSlots* slots = static_cast<nsXULSlots*>(tmp->GetExistingSlots());
         if (slots) {
-            NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mFrameLoader");
-            nsISupports *frameLoader =
-                static_cast<nsIFrameLoader*>(slots->mFrameLoader);
-            cb.NoteXPCOMChild(frameLoader);
+            slots->Traverse(cb);
         }
     }
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_ADDREF_INHERITED(nsXULElement, nsStyledElement)
 NS_IMPL_RELEASE_INHERITED(nsXULElement, nsStyledElement)
 
 DOMCI_NODE_DATA(XULElement, nsXULElement)
--- a/content/xul/content/src/nsXULElement.h
+++ b/content/xul/content/src/nsXULElement.h
@@ -588,20 +588,22 @@ protected:
     // Helper routine that crawls a parent chain looking for a tree element.
     NS_IMETHOD GetParentTree(nsIDOMXULMultiSelectControlElement** aTreeElement);
 
     nsresult AddPopupListener(nsIAtom* aName);
 
     class nsXULSlots : public nsGenericElement::nsDOMSlots
     {
     public:
-       nsXULSlots();
-       virtual ~nsXULSlots();
+        nsXULSlots();
+        virtual ~nsXULSlots();
 
-       nsRefPtr<nsFrameLoader> mFrameLoader;
+        void Traverse(nsCycleCollectionTraversalCallback &cb);
+
+        nsRefPtr<nsFrameLoader> mFrameLoader;
     };
 
     virtual nsINode::nsSlots* CreateSlots();
 
     nsresult LoadSrc();
 
     // Required fields
     nsRefPtr<nsXULPrototypeElement>     mPrototype;