Backout Bug 704623, a=dromaeo regression
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Mon, 20 Feb 2012 14:54:45 +0200
changeset 88712 5b8195516c117120837021c21932c591a04447b7
parent 88711 64d8bba7047f004dc6acbf4a7025fd04e6b71b88
child 88713 0a741052778866996dae6bad02553a33fd7ba95e
push id975
push userffxbld
push dateTue, 13 Mar 2012 21:39:16 +0000
treeherdermozilla-aurora@99faebf9dc36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdromaeo
bugs704623
milestone13.0a1
Backout Bug 704623, a=dromaeo regression
content/base/public/nsINode.h
content/base/src/nsAttrAndChildArray.cpp
content/base/src/nsContentUtils.cpp
content/base/src/nsDOMAttribute.cpp
content/base/src/nsDocument.cpp
content/base/src/nsGenericElement.cpp
dom/base/nsGlobalWindow.cpp
--- a/content/base/public/nsINode.h
+++ b/content/base/public/nsINode.h
@@ -306,34 +306,28 @@ public:
   NS_DECL_DOM_MEMORY_REPORTER_SIZEOF
 
   friend class nsNodeUtils;
   friend class nsNodeWeakReference;
   friend class nsNodeSupportsWeakRefTearoff;
   friend class nsAttrAndChildArray;
 
 #ifdef MOZILLA_INTERNAL_API
-  static nsINode *sOrphanNodeHead;
-
   nsINode(already_AddRefed<nsINodeInfo> aNodeInfo)
   : mNodeInfo(aNodeInfo),
     mParent(nsnull),
     mFlags(0),
-    mBoolFlags(1 << NodeIsOrphan),
-    mNextOrphanNode(sOrphanNodeHead->mNextOrphanNode),
-    mPreviousOrphanNode(sOrphanNodeHead),
+    mBoolFlags(0),
+    mNextSibling(nsnull),
+    mPreviousSibling(nsnull),
     mFirstChild(nsnull),
     mSlots(nsnull)
   {
-    NS_ASSERTION(GetBoolFlag(NodeIsOrphan),
-                 "mBoolFlags not initialized correctly!");
+  }
 
-    mNextOrphanNode->mPreviousOrphanNode = this;
-    sOrphanNodeHead->mNextOrphanNode = this;
-  }
 #endif
 
   virtual ~nsINode();
 
   /**
    * Bit-flags to pass (or'ed together) to IsNodeOfType()
    */
   enum {
@@ -1104,73 +1098,18 @@ public:
     return NS_OK;
   }
   nsresult LookupNamespaceURI(const nsAString& aNamespacePrefix,
                               nsAString& aNamespaceURI);
 
   nsresult IsEqualNode(nsIDOMNode* aOther, bool* aReturn);
   bool IsEqualTo(nsINode* aOther);
 
-  nsIContent* GetNextSibling() const
-  {
-    return NS_UNLIKELY(IsOrphan()) ? nsnull : mNextSibling;
-  }
-
-  nsIContent* GetPreviousSibling() const
-  {
-    return NS_UNLIKELY(IsOrphan()) ? nsnull : mPreviousSibling;
-  }
-
-  // Returns true if this node is an orphan node
-  bool IsOrphan() const
-  {
-#ifdef MOZILLA_INTERNAL_API
-    NS_ASSERTION(this != sOrphanNodeHead, "Orphan node head orphan check?!");
-#endif
-
-    return GetBoolFlag(NodeIsOrphan);
-  }
-
-#ifdef MOZILLA_INTERNAL_API
-  // Mark this node as an orphan node. This marking is only relevant
-  // for this node itself, not its children. Its children are not
-  // considered orphan until they themselves are removed from their
-  // parent and get marked as orphans.
-  void MarkAsOrphan()
-  {
-    NS_ASSERTION(!IsOrphan(), "Orphan node orphaned again?");
-    NS_ASSERTION(this != sOrphanNodeHead, "Orphan node head orphaned?!");
-
-    mNextOrphanNode = sOrphanNodeHead->mNextOrphanNode;
-    mPreviousOrphanNode = sOrphanNodeHead;
-    mNextOrphanNode->mPreviousOrphanNode = this;
-    sOrphanNodeHead->mNextOrphanNode = this;
-
-    SetBoolFlag(NodeIsOrphan);
-  }
-
-  // Unmark this node as an orphan node. Do this before inserting this
-  // node into a parent or otherwise associating it with some other
-  // owner.
-  void MarkAsNonOrphan()
-  {
-    NS_ASSERTION(IsOrphan(), "Non-orphan node un-orphaned");
-    NS_ASSERTION(this != sOrphanNodeHead, "Orphan node head unorphaned?!");
-    NS_ASSERTION(!mParent, "Must not have a parent here!");
-
-    mPreviousOrphanNode->mNextOrphanNode = mNextOrphanNode;
-    mNextOrphanNode->mPreviousOrphanNode = mPreviousOrphanNode;
-    mPreviousOrphanNode = nsnull;
-    mNextOrphanNode = nsnull;
-
-    ClearBoolFlag(NodeIsOrphan);
-  }
-#endif
-
-  static void Init();
+  nsIContent* GetNextSibling() const { return mNextSibling; }
+  nsIContent* GetPreviousSibling() const { return mPreviousSibling; }
 
   /**
    * Get the next node in the pre-order tree traversal of the DOM.  If
    * aRoot is non-null, then it must be an ancestor of |this|
    * (possibly equal to |this|) and only nodes that are descendants of
    * aRoot, not including aRoot itself, will be returned.  Returns
    * null if there are no more nodes to traverse.
    */
@@ -1307,18 +1246,16 @@ private:
     NodeIsCCBlackTree,
     // Maybe set if the node is a root of a subtree 
     // which needs to be kept in the purple buffer.
     NodeIsPurpleRoot,
     // Set if the node has an explicit base URI stored
     NodeHasExplicitBaseURI,
     // Set if the element has some style states locked
     ElementHasLockedStyleStates,
-    // Set if the node is an orphan node.
-    NodeIsOrphan,
     // Guard value
     BooleanFlagCount
   };
 
   void SetBoolFlag(BooleanFlag name, bool value) {
     PR_STATIC_ASSERT(BooleanFlagCount <= 8*sizeof(mBoolFlags));
     mBoolFlags = (mBoolFlags & ~(1 << name)) | (value << name);
   }
@@ -1524,34 +1461,18 @@ protected:
 
   PRUint32 mFlags;
 
 private:
   // Boolean flags.
   PRUint32 mBoolFlags;
 
 protected:
-  union {
-    // mNextSibling is used when this node is part of a DOM tree
-    nsIContent* mNextSibling;
-
-    // mNextOrphanNode is used when this is in the linked list of
-    // orphan nodes.
-    nsINode *mNextOrphanNode;
-  };
-
-  union {
-    // mPreviousSibling is used when this node is part of a DOM tree
-    nsIContent* mPreviousSibling;
-
-    // mPreviousOrphanNode is used when this is in the linked list of
-    // orphan nodes.
-    nsINode* mPreviousOrphanNode;
-  };
-
+  nsIContent* mNextSibling;
+  nsIContent* mPreviousSibling;
   nsIContent* mFirstChild;
 
   // Storage for more members that are usually not needed; allocated lazily.
   nsSlots* mSlots;
 };
 
 
 extern const nsIID kThisPtrOffsetsSID;
--- a/content/base/src/nsAttrAndChildArray.cpp
+++ b/content/base/src/nsAttrAndChildArray.cpp
@@ -227,29 +227,23 @@ nsAttrAndChildArray::RemoveChildAt(PRUin
 already_AddRefed<nsIContent>
 nsAttrAndChildArray::TakeChildAt(PRUint32 aPos)
 {
   NS_ASSERTION(aPos < ChildCount(), "out-of-bounds");
 
   PRUint32 childCount = ChildCount();
   void** pos = mImpl->mBuffer + AttrSlotsSize() + aPos;
   nsIContent* child = static_cast<nsIContent*>(*pos);
-
-  MOZ_ASSERT(!child->IsOrphan(), "Child should not be an orphan here");
-
   if (child->mPreviousSibling) {
     child->mPreviousSibling->mNextSibling = child->mNextSibling;
   }
   if (child->mNextSibling) {
     child->mNextSibling->mPreviousSibling = child->mPreviousSibling;
   }
-
-  // Mark the child as an orphan now that it's no longer associated
-  // with its old parent.
-  child->MarkAsOrphan();
+  child->mPreviousSibling = child->mNextSibling = nsnull;
 
   memmove(pos, pos + 1, (childCount - aPos - 1) * sizeof(nsIContent*));
   SetChildCount(childCount - 1);
 
   return child;
 }
 
 PRInt32
@@ -658,31 +652,28 @@ nsAttrAndChildArray::Clear()
 
   nsAutoScriptBlocker scriptBlocker;
   PRUint32 end = slotCount * ATTRSIZE + ChildCount();
   for (i = slotCount * ATTRSIZE; i < end; ++i) {
     nsIContent* child = static_cast<nsIContent*>(mImpl->mBuffer[i]);
     // making this false so tree teardown doesn't end up being
     // O(N*D) (number of nodes times average depth of tree).
     child->UnbindFromTree(false); // XXX is it better to let the owner do this?
-    // Mark the child as an orphan now that it's no longer a child of
-    // its old parent, and make sure to unlink our kids from each
-    // other, since someone else could stil be holding references to
-    // some of them.
-
-    child->MarkAsOrphan();
+    // Make sure to unlink our kids from each other, since someone
+    // else could stil be holding references to some of them.
 
     // XXXbz We probably can't push this assignment down into the |aNullParent|
     // case of UnbindFromTree because we still need the assignment in
     // RemoveChildAt.  In particular, ContentRemoved fires between
     // RemoveChildAt and UnbindFromTree, and in ContentRemoved the sibling
     // chain needs to be correct.  Though maybe we could set the prev and next
     // to point to each other but keep the kid being removed pointing to them
     // through ContentRemoved so consumers can find where it used to be in the
     // list?
+    child->mPreviousSibling = child->mNextSibling = nsnull;
     NS_RELEASE(child);
   }
 
   SetAttrSlotAndChildCount(0, 0);
 }
 
 PRUint32
 nsAttrAndChildArray::NonMappedAttrCount() const
@@ -826,26 +817,18 @@ nsAttrAndChildArray::AddAttrSlot()
 
   return true;
 }
 
 inline void
 nsAttrAndChildArray::SetChildAtPos(void** aPos, nsIContent* aChild,
                                    PRUint32 aIndex, PRUint32 aChildCount)
 {
-  MOZ_ASSERT(aChild->IsOrphan(), "aChild should be an orphan here");
-
-  NS_PRECONDITION(aChild->IsOrphan() || !aChild->GetNextSibling(),
-                  "aChild should be orphan and have no next sibling!");
-  NS_PRECONDITION(aChild->IsOrphan() || !aChild->GetPreviousSibling(),
-                  "aChild should be orphan and have no prev sibling!");
-
-  // Unmark this child as an orphan now that it's a child of its new
-  // parent.
-  aChild->MarkAsNonOrphan();
+  NS_PRECONDITION(!aChild->GetNextSibling(), "aChild with next sibling?");
+  NS_PRECONDITION(!aChild->GetPreviousSibling(), "aChild with prev sibling?");
 
   *aPos = aChild;
   NS_ADDREF(aChild);
   if (aIndex != 0) {
     nsIContent* previous = static_cast<nsIContent*>(*(aPos - 1));
     aChild->mPreviousSibling = previous;
     previous->mNextSibling = aChild;
   }
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -357,18 +357,16 @@ nsresult
 nsContentUtils::Init()
 {
   if (sInitialized) {
     NS_WARNING("Init() called twice");
 
     return NS_OK;
   }
 
-  nsINode::Init();
-
   nsresult rv = NS_GetNameSpaceManager(&sNameSpaceManager);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsXPConnect* xpconnect = nsXPConnect::GetXPConnect();
   NS_ENSURE_TRUE(xpconnect, NS_ERROR_FAILURE);
 
   sXPConnect = xpconnect;
   sThreadJSContextStack = xpconnect;
--- a/content/base/src/nsDOMAttribute.cpp
+++ b/content/base/src/nsDOMAttribute.cpp
@@ -86,17 +86,16 @@ nsDOMAttribute::nsDOMAttribute(nsDOMAttr
     content->AddMutationObserver(this);
   }
 }
 
 nsDOMAttribute::~nsDOMAttribute()
 {
   if (mChild) {
     static_cast<nsTextNode*>(mChild)->UnbindFromAttribute();
-    mChild->MarkAsOrphan();
     NS_RELEASE(mChild);
     mFirstChild = nsnull;
   }
 
   nsIContent* content = GetContentInternal();
   if (content) {
     content->RemoveMutationObserver(this);
   }
@@ -117,17 +116,16 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsDOMAttribute)
   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();
-    tmp->mChild->MarkAsOrphan();
     NS_RELEASE(tmp->mChild);
     tmp->mFirstChild = nsnull;
   }
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 DOMCI_NODE_DATA(Attr, nsDOMAttribute)
 
 // QueryInterface implementation for nsDOMAttribute
@@ -723,17 +721,16 @@ nsDOMAttribute::EnsureChildState()
   NS_PRECONDITION(!mChild, "Someone screwed up");
 
   nsAutoString value;
   GetValue(value);
 
   if (!value.IsEmpty()) {
     NS_NewTextNode(&mChild, mNodeInfo->NodeInfoManager());
 
-    mChild->MarkAsNonOrphan();
     static_cast<nsTextNode*>(mChild)->BindToAttribute(this);
     mFirstChild = mChild;
 
     mChild->SetText(value, false);
   }
 }
 
 void
@@ -791,11 +788,10 @@ nsDOMAttribute::doRemoveChild(bool aNoti
   NS_RELEASE(mChild);
   mFirstChild = nsnull;
 
   if (aNotify) {
     nsNodeUtils::AttributeChildRemoved(this, child);
   }
 
   child->UnbindFromAttribute();
-  child->MarkAsOrphan();
 }
 
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -1574,18 +1574,17 @@ nsDocument::~nsDocument()
     PR_LOG(gDocumentLeakPRLog, PR_LOG_DEBUG,
            ("DOCUMENT %p destroyed", this));
 #endif
 
 #ifdef DEBUG
   nsCycleCollector_DEBUG_wasFreed(static_cast<nsIDocument*>(this));
 #endif
 
-  NS_ASSERTION(!mIsShowing, "Deleting a currently-showing document");
-  NS_ASSERTION(IsOrphan(), "Deleted document not an orphan?");
+  NS_ASSERTION(!mIsShowing, "Destroying a currently-showing document");
 
   mInDestructor = true;
   mInUnlinkOrDeletion = true;
 
   // Clear mObservers to keep it in sync with the mutationobserver list
   mObservers.Clear();
 
   if (mStyleSheetSetList) {
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -208,26 +208,19 @@ nsINode::nsSlots::Unlink()
   if (mChildNodes) {
     mChildNodes->DropReference();
     NS_RELEASE(mChildNodes);
   }
 }
 
 //----------------------------------------------------------------------
 
-nsINode *nsINode::sOrphanNodeHead = nsnull;
-
 nsINode::~nsINode()
 {
   NS_ASSERTION(!HasSlots(), "nsNodeUtils::LastRelease was not called?");
-
-  MOZ_ASSERT(IsOrphan(), "Node should be orphan by the time it's deleted!");
-
-  mPreviousOrphanNode->mNextOrphanNode = mNextOrphanNode;
-  mNextOrphanNode->mPreviousOrphanNode = mPreviousOrphanNode;
 }
 
 void*
 nsINode::GetProperty(PRUint16 aCategory, nsIAtom *aPropertyName,
                      nsresult *aStatus) const
 {
   return OwnerDoc()->PropertyTable(aCategory)->GetProperty(this, aPropertyName,
                                                            aStatus);
@@ -3264,17 +3257,17 @@ nsGenericElement::UnbindFromTree(bool aD
     DeleteProperty(nsGkAtoms::transitionsProperty);
     DeleteProperty(nsGkAtoms::animationsOfBeforeProperty);
     DeleteProperty(nsGkAtoms::animationsOfAfterProperty);
     DeleteProperty(nsGkAtoms::animationsProperty);
   }
 
   // Unset this since that's what the old code effectively did.
   UnsetFlags(NODE_FORCE_XBL_BINDINGS);
-
+  
 #ifdef MOZ_XUL
   nsXULElement* xulElem = nsXULElement::FromContent(this);
   if (xulElem) {
     xulElem->SetXULBindingParent(nsnull);
   }
   else
 #endif
   {
@@ -3858,32 +3851,17 @@ nsGenericElement::GetTextContent(nsAStri
 }
 
 NS_IMETHODIMP
 nsGenericElement::SetTextContent(const nsAString& aTextContent)
 {
   return nsContentUtils::SetNodeTextContent(this, aTextContent, false);
 }
 
-// static
-void
-nsINode::Init()
-{
-  // Allocate static storage for the head of the list of orphan nodes
-  static MOZ_ALIGNED_DECL(char orphanNodeListHead[sizeof(nsINode)], 8);
-  sOrphanNodeHead = reinterpret_cast<nsINode *>(&orphanNodeListHead[0]);
-
-  sOrphanNodeHead->mNextOrphanNode = sOrphanNodeHead;
-  sOrphanNodeHead->mPreviousOrphanNode = sOrphanNodeHead;
-
-  sOrphanNodeHead->mFirstChild = reinterpret_cast<nsIContent *>(0xdeadbeef);
-  sOrphanNodeHead->mParent = reinterpret_cast<nsIContent *>(0xdeadbeef);
-}
-
-// static
+/* static */
 nsresult
 nsGenericElement::DispatchEvent(nsPresContext* aPresContext,
                                 nsEvent* aEvent,
                                 nsIContent* aTarget,
                                 bool aFullDispatch,
                                 nsEventStatus* aStatus)
 {
   NS_PRECONDITION(aTarget, "Must have target");
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1044,20 +1044,16 @@ nsGlobalWindow::~nsGlobalWindow()
     // If our outer window's inner window is this window, null out the
     // outer window's reference to this window that's being deleted.
     nsGlobalWindow *outer = GetOuterWindowInternal();
     if (outer && outer->mInnerWindow == this) {
       outer->mInnerWindow = nsnull;
     }
   }
 
-  if (IsInnerWindow() && mDocument) {
-    mDoc->MarkAsOrphan();
-  }
-
   mDocument = nsnull;           // Forces Release
   mDoc = nsnull;
 
   NS_ASSERTION(!mArguments, "mArguments wasn't cleaned up properly!");
 
   CleanUp(true);
 
 #ifdef DEBUG
@@ -1310,18 +1306,16 @@ nsGlobalWindow::FreeInnerObjects(bool aC
     mNavigator = nsnull;
   }
 
   if (mDocument) {
     NS_ASSERTION(mDoc, "Why is mDoc null?");
 
     // Remember the document's principal.
     mDocumentPrincipal = mDoc->NodePrincipal();
-
-    mDoc->MarkAsOrphan();
   }
 
 #ifdef DEBUG
   if (mDocument)
     nsCycleCollector_DEBUG_shouldBeFreed(nsCOMPtr<nsISupports>(do_QueryInterface(mDocument)));
 #endif
 
   // Remove our reference to the document and the document principal.
@@ -2263,24 +2257,23 @@ nsGlobalWindow::SetNewDocument(nsIDocume
   // alive etc.
 
   if ((!reUseInnerWindow || aDocument != oldDoc) && !aState) {
     nsCOMPtr<nsIHTMLDocument> html_doc(do_QueryInterface(mDocument));
     nsWindowSH::InstallGlobalScopePolluter(cx, newInnerWindow->mJSObject,
                                            html_doc);
   }
 
-  aDocument->SetScriptGlobalObject(newInnerWindow);
+  if (aDocument) {
+    aDocument->SetScriptGlobalObject(newInnerWindow);
+  }
 
   if (!aState) {
     if (reUseInnerWindow) {
       if (newInnerWindow->mDoc != aDocument) {
-        newInnerWindow->mDoc->MarkAsOrphan();
-        aDocument->MarkAsNonOrphan();
-
         newInnerWindow->mDocument = do_QueryInterface(aDocument);
         newInnerWindow->mDoc = aDocument;
 
         // We're reusing the inner window for a new document. In this
         // case we don't clear the inner window's scope, but we must
         // make sure the cached document property gets updated.
 
         // XXXmarkh - tell other languages about this?
@@ -2389,19 +2382,16 @@ nsGlobalWindow::InnerSetNewDocument(nsID
     nsIURI *uri = aDocument->GetDocumentURI();
     nsCAutoString spec;
     if (uri)
       uri->GetSpec(spec);
     PR_LogPrint("DOMWINDOW %p SetNewDocument %s", this, spec.get());
   }
 #endif
 
-  MOZ_ASSERT(aDocument->IsOrphan(), "New document must be orphan!");
-  aDocument->MarkAsNonOrphan();
-
   mDocument = do_QueryInterface(aDocument);
   mDoc = aDocument;
   mLocalStorage = nsnull;
   mSessionStorage = nsnull;
 
 #ifdef DEBUG
   mLastOpenedURI = aDocument->GetDocumentURI();
 #endif