Bug 578696 part 1. Create new macros to notify nsTObserverArray observers without holding strong refs. No behavior changes yet. r=sicking
authorBoris Zbarsky <bzbarsky@mit.edu>
Wed, 21 Jul 2010 11:33:31 -0400
changeset 48006 32d3428169a2ba60dc3d76061b64576945777741
parent 48005 48cb278e9e6941759cef76139278e633d7162d4e
child 48007 a0556636778c3658bcfdc2814a1478a5497df779
push id14533
push userbzbarsky@mozilla.com
push dateWed, 21 Jul 2010 15:42:13 +0000
treeherdermozilla-central@b20c759afb7c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssicking
bugs578696
milestone2.0b3pre
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 578696 part 1. Create new macros to notify nsTObserverArray observers without holding strong refs. No behavior changes yet. r=sicking
content/base/src/nsDocument.h
content/base/src/nsNodeUtils.cpp
xpcom/glue/nsTObserverArray.h
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -1014,19 +1014,19 @@ protected:
   void DispatchPageTransition(nsPIDOMEventTarget* aDispatchTarget,
                               const nsAString& aType,
                               PRBool aPersisted);
 
   virtual nsPIDOMWindow *GetWindowInternal();
   virtual nsPIDOMWindow *GetInnerWindowInternal();
   virtual nsIScriptGlobalObject* GetScriptHandlingObjectInternal() const;
 
-#define NS_DOCUMENT_NOTIFY_OBSERVERS(func_, params_)                  \
-  NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS(mObservers, nsIDocumentObserver, \
-                                     func_, params_);
+#define NS_DOCUMENT_NOTIFY_OBSERVERS(func_, params_)                        \
+  NS_OBSERVER_ARRAY_NOTIFY_XPCOM_OBSERVERS(mObservers, nsIDocumentObserver, \
+                                           func_, params_);
   
 #ifdef DEBUG
   void VerifyRootContentState();
 #endif
 
   nsDocument(const char* aContentType);
   virtual ~nsDocument();
 
--- a/content/base/src/nsNodeUtils.cpp
+++ b/content/base/src/nsNodeUtils.cpp
@@ -81,67 +81,89 @@ using namespace mozilla::dom;
       NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS(                         \
         slots->mMutationObservers, nsIMutationObserver,           \
         func_, params_);                                          \
     }                                                             \
     node = node->GetNodeParent();                                 \
   } while (node);                                                 \
   PR_END_MACRO
 
+// This macro expects the ownerDocument of content_ to be in scope as
+// |nsIDocument* doc|
+#define IMPL_STRONGREF_MUTATION_NOTIFICATION(func_, content_, params_)      \
+  PR_BEGIN_MACRO                                                  \
+  nsINode* node = content_;                                       \
+  NS_ASSERTION(node->GetOwnerDoc() == doc, "Bogus document");     \
+  if (doc) {                                                      \
+    static_cast<nsIMutationObserver*>(doc->BindingManager())->    \
+      func_ params_;                                              \
+  }                                                               \
+  do {                                                            \
+    nsINode::nsSlots* slots = node->GetExistingSlots();           \
+    if (slots && !slots->mMutationObservers.IsEmpty()) {          \
+      /* No need to explicitly notify the first observer first    \
+         since that'll happen anyway. */                          \
+      NS_OBSERVER_ARRAY_NOTIFY_XPCOM_OBSERVERS(                         \
+        slots->mMutationObservers, nsIMutationObserver,           \
+        func_, params_);                                          \
+    }                                                             \
+    node = node->GetNodeParent();                                 \
+  } while (node);                                                 \
+  PR_END_MACRO
 
 void
 nsNodeUtils::CharacterDataWillChange(nsIContent* aContent,
                                      CharacterDataChangeInfo* aInfo)
 {
   nsIDocument* doc = aContent->GetOwnerDoc();
-  IMPL_MUTATION_NOTIFICATION(CharacterDataWillChange, aContent,
+  IMPL_STRONGREF_MUTATION_NOTIFICATION(CharacterDataWillChange, aContent,
                              (doc, aContent, aInfo));
 }
 
 void
 nsNodeUtils::CharacterDataChanged(nsIContent* aContent,
                                   CharacterDataChangeInfo* aInfo)
 {
   nsIDocument* doc = aContent->GetOwnerDoc();
-  IMPL_MUTATION_NOTIFICATION(CharacterDataChanged, aContent,
+  IMPL_STRONGREF_MUTATION_NOTIFICATION(CharacterDataChanged, aContent,
                              (doc, aContent, aInfo));
 }
 
 void
 nsNodeUtils::AttributeWillChange(nsIContent* aContent,
                                  PRInt32 aNameSpaceID,
                                  nsIAtom* aAttribute,
                                  PRInt32 aModType)
 {
   nsIDocument* doc = aContent->GetOwnerDoc();
-  IMPL_MUTATION_NOTIFICATION(AttributeWillChange, aContent,
+  IMPL_STRONGREF_MUTATION_NOTIFICATION(AttributeWillChange, aContent,
                              (doc, aContent, aNameSpaceID, aAttribute,
                               aModType));
 }
 
 void
 nsNodeUtils::AttributeChanged(nsIContent* aContent,
                               PRInt32 aNameSpaceID,
                               nsIAtom* aAttribute,
                               PRInt32 aModType)
 {
   nsIDocument* doc = aContent->GetOwnerDoc();
-  IMPL_MUTATION_NOTIFICATION(AttributeChanged, aContent,
+  IMPL_STRONGREF_MUTATION_NOTIFICATION(AttributeChanged, aContent,
                              (doc, aContent, aNameSpaceID, aAttribute,
                               aModType));
 }
 
 void
 nsNodeUtils::ContentAppended(nsIContent* aContainer,
                              nsIContent* aFirstNewContent,
                              PRInt32 aNewIndexInContainer)
 {
   nsIDocument* doc = aContainer->GetOwnerDoc();
 
-  IMPL_MUTATION_NOTIFICATION(ContentAppended, aContainer,
+  IMPL_STRONGREF_MUTATION_NOTIFICATION(ContentAppended, aContainer,
                              (doc, aContainer, aFirstNewContent,
                               aNewIndexInContainer));
 }
 
 void
 nsNodeUtils::ContentInserted(nsINode* aContainer,
                              nsIContent* aChild,
                              PRInt32 aIndexInContainer)
@@ -156,17 +178,17 @@ nsNodeUtils::ContentInserted(nsINode* aC
     container = static_cast<nsIContent*>(aContainer);
     document = doc;
   }
   else {
     container = nsnull;
     document = static_cast<nsIDocument*>(aContainer);
   }
 
-  IMPL_MUTATION_NOTIFICATION(ContentInserted, aContainer,
+  IMPL_STRONGREF_MUTATION_NOTIFICATION(ContentInserted, aContainer,
                              (document, container, aChild, aIndexInContainer));
 }
 
 void
 nsNodeUtils::ContentRemoved(nsINode* aContainer,
                             nsIContent* aChild,
                             PRInt32 aIndexInContainer)
 {
@@ -180,44 +202,44 @@ nsNodeUtils::ContentRemoved(nsINode* aCo
     container = static_cast<nsIContent*>(aContainer);
     document = doc;
   }
   else {
     container = nsnull;
     document = static_cast<nsIDocument*>(aContainer);
   }
 
-  IMPL_MUTATION_NOTIFICATION(ContentRemoved, aContainer,
+  IMPL_STRONGREF_MUTATION_NOTIFICATION(ContentRemoved, aContainer,
                              (document, container, aChild, aIndexInContainer));
 }
 
 void
 nsNodeUtils::ParentChainChanged(nsIContent *aContent)
 {
   // No need to notify observers on the parents since their parent
   // chain must have been changed too and so their observers were
   // notified at that time.
 
   nsINode::nsSlots* slots = aContent->GetExistingSlots();
   if (slots && !slots->mMutationObservers.IsEmpty()) {
-    NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS(
+    NS_OBSERVER_ARRAY_NOTIFY_XPCOM_OBSERVERS(
         slots->mMutationObservers,
         nsIMutationObserver,
         ParentChainChanged,
         (aContent));
   }
 }
 
 void
 nsNodeUtils::LastRelease(nsINode* aNode)
 {
   nsINode::nsSlots* slots = aNode->GetExistingSlots();
   if (slots) {
     if (!slots->mMutationObservers.IsEmpty()) {
-      NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS(slots->mMutationObservers,
+      NS_OBSERVER_ARRAY_NOTIFY_XPCOM_OBSERVERS(slots->mMutationObservers,
                                          nsIMutationObserver,
                                          NodeWillBeDestroyed, (aNode));
     }
 
     PtrBits flags = slots->mFlags | NODE_DOESNT_HAVE_SLOTS;
     delete slots;
     aNode->mFlagsOrSlots = flags;
   }
--- a/xpcom/glue/nsTObserverArray.h
+++ b/xpcom/glue/nsTObserverArray.h
@@ -364,19 +364,29 @@ class nsTObserverArray : public nsAutoTO
     explicit nsTObserverArray(size_type capacity) {
       base_type::mArray.SetCapacity(capacity);
     }
 };
 
 // XXXbz I wish I didn't have to pass in the observer type, but I
 // don't see a way to get it out of array_.
 // Note that this macro only works if the array holds pointers to XPCOM objects.
-#define NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS(array_, obstype_, func_, params_) \
+#define NS_OBSERVER_ARRAY_NOTIFY_XPCOM_OBSERVERS(array_, obstype_, func_, params_) \
   PR_BEGIN_MACRO                                                             \
     nsTObserverArray<obstype_ *>::ForwardIterator iter_(array_);             \
     nsCOMPtr<obstype_> obs_;                                                 \
     while (iter_.HasMore()) {                                                 \
       obs_ = iter_.GetNext();                                                \
       obs_ -> func_ params_ ;                                                \
     }                                                                        \
   PR_END_MACRO
 
+// Note that this macro only works if the array holds pointers to XPCOM objects.
+#define NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS(array_, obstype_, func_, params_) \
+  PR_BEGIN_MACRO                                                             \
+    nsTObserverArray<obstype_ *>::ForwardIterator iter_(array_);             \
+    obstype_* obs_;                                                          \
+    while (iter_.HasMore()) {                                                \
+      obs_ = iter_.GetNext();                                                \
+      obs_ -> func_ params_ ;                                                \
+    }                                                                        \
+  PR_END_MACRO
 #endif // nsTObserverArray_h___