Bug 696201. Switch nsContentList to using an nsTArray as the element store. r=sicking
authorBoris Zbarsky <bzbarsky@mit.edu>
Mon, 31 Oct 2011 22:48:59 -0400
changeset 79492 74e1804b91de46028772433821eeafddc458f159
parent 79491 65ffdabf1b6b1f7d58cdae08b2f1f1ecbb392fd0
child 79493 829a99f28b5c872f5c73d9a2a02a8289de4bddc4
push id21408
push userkhuey@mozilla.com
push dateTue, 01 Nov 2011 14:32:20 +0000
treeherdermozilla-central@cd9add22f090 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssicking
bugs696201
milestone10.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 696201. Switch nsContentList to using an nsTArray as the element store. r=sicking
content/base/src/nsContentList.cpp
content/base/src/nsContentList.h
--- a/content/base/src/nsContentList.cpp
+++ b/content/base/src/nsContentList.cpp
@@ -63,30 +63,29 @@
 #include "nsIContentIterator.h"
 nsresult
 NS_NewPreContentIterator(nsIContentIterator** aInstancePtrResult);
 #define ASSERT_IN_SYNC AssertInSync()
 #else
 #define ASSERT_IN_SYNC PR_BEGIN_MACRO PR_END_MACRO
 #endif
 
-
 using namespace mozilla::dom;
 
 nsBaseContentList::~nsBaseContentList()
 {
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsBaseContentList)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsBaseContentList)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mElements)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSTARRAY(mElements)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsBaseContentList)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mElements)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY_OF_NSCOMPTR(mElements)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsBaseContentList)
   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 #define NS_CONTENT_LIST_INTERFACES(_class)                                    \
     NS_INTERFACE_TABLE_ENTRY(_class, nsINodeList)                             \
@@ -108,17 +107,17 @@ NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsBaseContentList)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsBaseContentList)
 
 
 NS_IMETHODIMP
 nsBaseContentList::GetLength(PRUint32* aLength)
 {
-  *aLength = mElements.Count();
+  *aLength = mElements.Length();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsBaseContentList::Item(PRUint32 aIndex, nsIDOMNode** aReturn)
 {
   nsISupports *tmp = GetNodeAt(aIndex);
@@ -130,49 +129,32 @@ nsBaseContentList::Item(PRUint32 aIndex,
   }
 
   return CallQueryInterface(tmp, aReturn);
 }
 
 nsIContent*
 nsBaseContentList::GetNodeAt(PRUint32 aIndex)
 {
-  return mElements.SafeObjectAt(aIndex);
+  return mElements.SafeElementAt(aIndex);
 }
 
 
 PRInt32
 nsBaseContentList::IndexOf(nsIContent *aContent, bool aDoFlush)
 {
   return mElements.IndexOf(aContent);
 }
 
 PRInt32
 nsBaseContentList::IndexOf(nsIContent* aContent)
 {
   return IndexOf(aContent, true);
 }
 
-void nsBaseContentList::AppendElement(nsIContent *aContent) 
-{
-  mElements.AppendObject(aContent);
-}
-
-void nsBaseContentList::RemoveElement(nsIContent *aContent) 
-{
-  mElements.RemoveObject(aContent);
-}
-
-void nsBaseContentList::InsertElementAt(nsIContent* aContent, PRInt32 aIndex)
-{
-  NS_ASSERTION(aContent, "Element to insert must not be null");
-  mElements.InsertObjectAt(aContent, aIndex);
-}
-
-
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsSimpleContentList)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsSimpleContentList,
                                                   nsBaseContentList)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mRoot)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsSimpleContentList,
                                                 nsBaseContentList)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mRoot)
@@ -528,17 +510,17 @@ NS_INTERFACE_MAP_END_INHERITING(nsBaseCo
 NS_IMPL_ADDREF_INHERITED(nsContentList, nsBaseContentList)
 NS_IMPL_RELEASE_INHERITED(nsContentList, nsBaseContentList)
 
 PRUint32
 nsContentList::Length(bool aDoFlush)
 {
   BringSelfUpToDate(aDoFlush);
     
-  return mElements.Count();
+  return mElements.Length();
 }
 
 nsIContent *
 nsContentList::Item(PRUint32 aIndex, bool aDoFlush)
 {
   if (mRootNode && aDoFlush && mFlushesNeeded) {
     // XXX sXBL/XBL2 issue
     nsIDocument* doc = mRootNode->GetCurrentDoc();
@@ -550,25 +532,25 @@ nsContentList::Item(PRUint32 aIndex, boo
 
   if (mState != LIST_UP_TO_DATE)
     PopulateSelf(NS_MIN(aIndex, PR_UINT32_MAX - 1) + 1);
 
   ASSERT_IN_SYNC;
   NS_ASSERTION(!mRootNode || mState != LIST_DIRTY,
                "PopulateSelf left the list in a dirty (useless) state!");
 
-  return mElements.SafeObjectAt(aIndex);
+  return mElements.SafeElementAt(aIndex);
 }
 
 nsIContent *
 nsContentList::NamedItem(const nsAString& aName, bool aDoFlush)
 {
   BringSelfUpToDate(aDoFlush);
     
-  PRInt32 i, count = mElements.Count();
+  PRUint32 i, count = mElements.Length();
 
   // Typically IDs and names are atomized
   nsCOMPtr<nsIAtom> name = do_GetAtom(aName);
   NS_ENSURE_TRUE(name, nsnull);
 
   for (i = 0; i < count; i++) {
     nsIContent *content = mElements[i];
     // XXX Should this pass eIgnoreCase?
@@ -672,28 +654,28 @@ nsContentList::AttributeChanged(nsIDocum
       !MayContainRelevantNodes(aElement->GetNodeParent()) ||
       !nsContentUtils::IsInSameAnonymousTree(mRootNode, aElement)) {
     // Either we're already dirty or this notification doesn't affect
     // whether we might match aElement.
     return;
   }
   
   if (Match(aElement)) {
-    if (mElements.IndexOf(aElement) == -1) {
+    if (mElements.IndexOf(aElement) == mElements.NoIndex) {
       // We match aElement now, and it's not in our list already.  Just dirty
       // ourselves; this is simpler than trying to figure out where to insert
       // aElement.
       SetDirty();
     }
   } else {
     // We no longer match aElement.  Remove it from our list.  If it's
     // already not there, this is a no-op (though a potentially
     // expensive one).  Either way, no change of mState is required
     // here.
-    mElements.RemoveObject(aElement);
+    mElements.RemoveElement(aElement);
   }
 }
 
 void
 nsContentList::ContentAppended(nsIDocument* aDocument, nsIContent* aContainer,
                                nsIContent* aFirstNewContent,
                                PRInt32 aNewIndexInContainer)
 {
@@ -717,17 +699,17 @@ nsContentList::ContentAppended(nsIDocume
    * should come during pageload and be at the end of the document.
    * Do a bit of work to see whether we could just append to what we
    * already have.
    */
   
   PRInt32 count = aContainer->GetChildCount();
 
   if (count > 0) {
-    PRInt32 ourCount = mElements.Count();
+    PRUint32 ourCount = mElements.Length();
     bool appendToList = false;
     if (ourCount == 0) {
       appendToList = true;
     } else {
       nsIContent* ourLastContent = mElements[ourCount - 1];
       /*
        * We want to append instead of invalidating if the first thing
        * that got appended comes after ourLastContent.
@@ -767,23 +749,23 @@ nsContentList::ContentAppended(nsIDocume
      * We're up to date.  That means someone's actively using us; we
      * may as well grab this content....
      */
     if (mDeep) {
       for (nsIContent* cur = aFirstNewContent;
            cur;
            cur = cur->GetNextNode(aContainer)) {
         if (cur->IsElement() && Match(cur->AsElement())) {
-          mElements.AppendObject(cur);
+          mElements.AppendElement(cur);
         }
       }
     } else {
       for (nsIContent* cur = aFirstNewContent; cur; cur = cur->GetNextSibling()) {
         if (cur->IsElement() && Match(cur->AsElement())) {
-          mElements.AppendObject(cur);
+          mElements.AppendElement(cur);
         }
       }
     }
 
     ASSERT_IN_SYNC;
   }
 }
 
@@ -896,54 +878,55 @@ void
 nsContentList::PopulateSelf(PRUint32 aNeededLength)
 {
   if (!mRootNode) {
     return;
   }
 
   ASSERT_IN_SYNC;
 
-  PRUint32 count = mElements.Count();
+  PRUint32 count = mElements.Length();
   NS_ASSERTION(mState != LIST_DIRTY || count == 0,
                "Reset() not called when setting state to LIST_DIRTY?");
 
   if (count >= aNeededLength) // We're all set
     return;
 
   PRUint32 elementsToAppend = aNeededLength - count;
 #ifdef DEBUG
-  PRUint32 invariant = elementsToAppend + mElements.Count();
+  PRUint32 invariant = elementsToAppend + mElements.Length();
 #endif
 
   if (mDeep) {
     // If we already have nodes start searching at the last one, otherwise
     // start searching at the root.
     nsINode* cur = count ? mElements[count - 1] : mRootNode;
     do {
       cur = cur->GetNextNode(mRootNode);
       if (!cur) {
         break;
       }
       if (cur->IsElement() && Match(cur->AsElement())) {
-        mElements.AppendObject(cur->AsElement());
+        // Append AsElement() to get nsIContent instead of nsINode
+        mElements.AppendElement(cur->AsElement());
         --elementsToAppend;
       }
     } while (elementsToAppend);
   } else {
     nsIContent* cur =
       count ? mElements[count-1]->GetNextSibling() : mRootNode->GetFirstChild();
     for ( ; cur && elementsToAppend; cur = cur->GetNextSibling()) {
       if (cur->IsElement() && Match(cur->AsElement())) {
-        mElements.AppendObject(cur);
+        mElements.AppendElement(cur);
         --elementsToAppend;
       }
     }
   }
 
-  NS_ASSERTION(elementsToAppend + mElements.Count() == invariant,
+  NS_ASSERTION(elementsToAppend + mElements.Length() == invariant,
                "Something is awry!");
 
   if (elementsToAppend != 0)
     mState = LIST_UP_TO_DATE;
   else
     mState = LIST_LAZY;
 
   ASSERT_IN_SYNC;
@@ -1019,17 +1002,17 @@ nsCacheableFuncStringContentList::Remove
 void
 nsContentList::AssertInSync()
 {
   if (mState == LIST_DIRTY) {
     return;
   }
 
   if (!mRootNode) {
-    NS_ASSERTION(mElements.Count() == 0 && mState == LIST_DIRTY,
+    NS_ASSERTION(mElements.Length() == 0 && mState == LIST_DIRTY,
                  "Empty iterator isn't quite empty?");
     return;
   }
 
   // XXX This code will need to change if nsContentLists can ever match
   // elements that are outside of the document element.
   nsIContent *root;
   if (mRootNode->IsNodeOfType(nsINode::eDOCUMENT)) {
@@ -1041,34 +1024,34 @@ nsContentList::AssertInSync()
 
   nsCOMPtr<nsIContentIterator> iter;
   if (mDeep) {
     NS_NewPreContentIterator(getter_AddRefs(iter));
     iter->Init(root);
     iter->First();
   }
 
-  PRInt32 cnt = 0, index = 0;
+  PRUint32 cnt = 0, index = 0;
   while (true) {
-    if (cnt == mElements.Count() && mState == LIST_LAZY) {
+    if (cnt == mElements.Length() && mState == LIST_LAZY) {
       break;
     }
 
     nsIContent *cur = mDeep ? iter->GetCurrentNode() :
                               mRootNode->GetChildAt(index++);
     if (!cur) {
       break;
     }
 
     if (cur->IsElement() && Match(cur->AsElement())) {
-      NS_ASSERTION(cnt < mElements.Count() && mElements[cnt] == cur,
+      NS_ASSERTION(cnt < mElements.Length() && mElements[cnt] == cur,
                    "Elements is out of sync");
       ++cnt;
     }
 
     if (mDeep) {
       iter->Next();
     }
   }
 
-  NS_ASSERTION(cnt == mElements.Count(), "Too few elements");
+  NS_ASSERTION(cnt == mElements.Length(), "Too few elements");
 }
 #endif
--- a/content/base/src/nsContentList.h
+++ b/content/base/src/nsContentList.h
@@ -40,17 +40,17 @@
  * is a commonly used NodeList implementation (used for
  * getElementsByTagName, some properties on nsIDOMHTMLDocument, etc).
  */
 
 #ifndef nsContentList_h___
 #define nsContentList_h___
 
 #include "nsISupports.h"
-#include "nsCOMArray.h"
+#include "nsTArray.h"
 #include "nsString.h"
 #include "nsIHTMLCollection.h"
 #include "nsIDOMNodeList.h"
 #include "nsINodeList.h"
 #include "nsStubMutationObserver.h"
 #include "nsIAtom.h"
 #include "nsINameSpaceManager.h"
 #include "nsCycleCollectionParticipant.h"
@@ -95,49 +95,59 @@ public:
 
   // nsIDOMNodeList
   NS_DECL_NSIDOMNODELIST
 
   // nsINodeList
   virtual PRInt32 IndexOf(nsIContent* aContent);
   
   PRUint32 Length() const { 
-    return mElements.Count();
+    return mElements.Length();
   }
 
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsBaseContentList)
 
-  void AppendElement(nsIContent *aContent);
+  void AppendElement(nsIContent *aContent)
+  {
+    mElements.AppendElement(aContent);
+  }
   void MaybeAppendElement(nsIContent* aContent)
   {
     if (aContent)
       AppendElement(aContent);
   }
 
   /**
    * Insert the element at a given index, shifting the objects at
    * the given index and later to make space.
    * @param aContent Element to insert, must not be null
    * @param aIndex Index to insert the element at.
    */
-  void InsertElementAt(nsIContent* aContent, PRInt32 aIndex);
+  void InsertElementAt(nsIContent* aContent, PRInt32 aIndex)
+  {
+    NS_ASSERTION(aContent, "Element to insert must not be null");
+    mElements.InsertElementAt(aIndex, aContent);
+  }
 
-  void RemoveElement(nsIContent *aContent); 
+  void RemoveElement(nsIContent *aContent)
+  {
+    mElements.RemoveElement(aContent);
+  }
 
   void Reset() {
     mElements.Clear();
   }
 
   virtual PRInt32 IndexOf(nsIContent *aContent, bool aDoFlush);
 
   virtual JSObject* WrapObject(JSContext *cx, XPCWrappedNativeScope *scope,
                                bool *triedToWrap) = 0;
 
 protected:
-  nsCOMArray<nsIContent> mElements;
+  nsTArray< nsCOMPtr<nsIContent> > mElements;
 };
 
 
 class nsSimpleContentList : public nsBaseContentList
 {
 public:
   nsSimpleContentList(nsINode *aRoot) : nsBaseContentList(),
                                         mRoot(aRoot)