Bug 750570, part 4 - Switch most native CC classes to use the purple buffer. r=smaug
authorAndrew McCreight <amccreight@mozilla.com>
Fri, 24 Aug 2012 09:50:06 -0700
changeset 105350 ecbb10bf79b32677e5a673f5cd7bae33b019759b
parent 105349 24368b894189f68944f2acceded49f6a3f0859a4
child 105351 c144761a799fdac1a08a4b32433f4fa3dd1619d4
push id55
push usershu@rfrn.org
push dateThu, 30 Aug 2012 01:33:09 +0000
reviewerssmaug
bugs750570, 774874
milestone17.0a1
Bug 750570, part 4 - Switch most native CC classes to use the purple buffer. r=smaug This patch actually converts over most of the existing native CC classes to use the participant. This is done by converting them to use the newly generalized nsCycleCollectingAutoRefCnt instead of their usual ref count. This is mostly a matter of defining new macros defining AddRef() and Release() for native CC classes with the CC ref count. nsTimeout is left as a legacy native CC class because it is a weird class, but hopefully eventually it too can be converted over. See bug 774874.
accessible/src/base/AccEvent.h
accessible/src/base/NotificationController.cpp
accessible/src/base/NotificationController.h
content/events/src/nsEventListenerManager.h
content/xbl/src/nsXBLBinding.h
content/xbl/src/nsXBLInsertionPoint.h
content/xbl/src/nsXBLPrototypeBinding.cpp
content/xul/templates/src/nsXMLBinding.cpp
content/xul/templates/src/nsXMLBinding.h
dom/base/nsGlobalWindow.cpp
dom/base/nsGlobalWindow.h
editor/txmgr/src/nsTransactionItem.cpp
editor/txmgr/src/nsTransactionItem.h
xpcom/glue/nsCycleCollectionParticipant.h
xpcom/glue/nsISupportsImpl.h
--- a/accessible/src/base/AccEvent.h
+++ b/accessible/src/base/AccEvent.h
@@ -102,17 +102,17 @@ public:
   virtual unsigned int GetEventGroups() const
   {
     return 1U << eGenericEvent;
   }
 
   /**
    * Reference counting and cycle collection.
    */
-  NS_INLINE_DECL_REFCOUNTING(AccEvent)
+  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(AccEvent)
   NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(AccEvent)
 
 protected:
   /**
    * Get an accessible from event target node.
    */
   Accessible* GetAccessibleForNode() const;
 
--- a/accessible/src/base/NotificationController.cpp
+++ b/accessible/src/base/NotificationController.cpp
@@ -50,18 +50,18 @@ NotificationController::~NotificationCon
   NS_ASSERTION(!mDocument, "Controller wasn't shutdown properly!");
   if (mDocument)
     Shutdown();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // NotificationCollector: AddRef/Release and cycle collection
 
-NS_IMPL_ADDREF(NotificationController)
-NS_IMPL_RELEASE(NotificationController)
+NS_IMPL_CYCLE_COLLECTING_NATIVE_ADDREF(NotificationController)
+NS_IMPL_CYCLE_COLLECTING_NATIVE_RELEASE(NotificationController)
 
 NS_IMPL_CYCLE_COLLECTION_NATIVE_CLASS(NotificationController)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_NATIVE(NotificationController)
   if (tmp->mDocument)
     tmp->Shutdown();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
--- a/accessible/src/base/NotificationController.h
+++ b/accessible/src/base/NotificationController.h
@@ -168,17 +168,17 @@ public:
   }
 
 #ifdef DEBUG
   bool IsUpdating() const
     { return mObservingState == eRefreshProcessingForUpdate; }
 #endif
 
 protected:
-  nsAutoRefCnt mRefCnt;
+  nsCycleCollectingAutoRefCnt mRefCnt;
   NS_DECL_OWNINGTHREAD
 
   /**
    * Start to observe refresh to make notifications and events processing after
    * layout.
    */
   void ScheduleProcessing();
 
@@ -267,17 +267,17 @@ private:
    * Storage for content inserted notification information.
    */
   class ContentInsertion
   {
   public:
     ContentInsertion(DocAccessible* aDocument, Accessible* aContainer);
     virtual ~ContentInsertion() { mDocument = nullptr; }
 
-    NS_INLINE_DECL_REFCOUNTING(ContentInsertion)
+    NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(ContentInsertion)
     NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(ContentInsertion)
 
     bool InitChildList(nsIContent* aStartChildNode, nsIContent* aEndChildNode);
     void Process();
 
   private:
     ContentInsertion();
     ContentInsertion(const ContentInsertion&);
--- a/content/events/src/nsEventListenerManager.h
+++ b/content/events/src/nsEventListenerManager.h
@@ -65,17 +65,17 @@ struct nsListenerStruct
 
 class nsEventListenerManager
 {
 
 public:
   nsEventListenerManager(nsISupports* aTarget);
   virtual ~nsEventListenerManager();
 
-  NS_INLINE_DECL_REFCOUNTING(nsEventListenerManager)
+  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(nsEventListenerManager)
 
   NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(nsEventListenerManager)
 
   void AddEventListener(const nsAString& aType,
                         nsIDOMEventListener* aListener,
                         bool aUseCapture,
                         bool aWantsUntrusted);
   void RemoveEventListener(const nsAString& aType,
--- a/content/xbl/src/nsXBLBinding.h
+++ b/content/xbl/src/nsXBLBinding.h
@@ -40,17 +40,17 @@ public:
    * 1. The binding manager's binding table holds onto all bindings that are
    *    currently attached to a content node.
    * 2. Bindings hold onto their base binding.  This is important since
    *    the base binding itself may not be attached to anything.
    * 3. The binding manager holds an additional reference to bindings
    *    which are queued to fire their constructors.
    */
 
-  NS_INLINE_DECL_REFCOUNTING(nsXBLBinding)
+  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(nsXBLBinding)
 
   NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(nsXBLBinding)
 
   nsXBLPrototypeBinding* PrototypeBinding() { return mPrototypeBinding; }
   nsIContent* GetAnonymousContent() { return mContent.get(); }
 
   nsXBLBinding* GetBaseBinding() { return mNextBinding; }
   void SetBaseBinding(nsXBLBinding *aBinding);
--- a/content/xbl/src/nsXBLInsertionPoint.h
+++ b/content/xbl/src/nsXBLInsertionPoint.h
@@ -12,17 +12,17 @@
 #include "nsCycleCollectionParticipant.h"
 
 class nsXBLInsertionPoint
 {
 public:
   nsXBLInsertionPoint(nsIContent* aParentElement, uint32_t aIndex, nsIContent* aDefContent);
   ~nsXBLInsertionPoint();
 
-  NS_INLINE_DECL_REFCOUNTING(nsXBLInsertionPoint)
+  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(nsXBLInsertionPoint)
 
   NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(nsXBLInsertionPoint)
 
   nsIContent* GetInsertionParent();
   void ClearInsertionParent() { mParentElement = nullptr; }
 
   int32_t GetInsertionIndex() { return mIndex; }
 
--- a/content/xbl/src/nsXBLPrototypeBinding.cpp
+++ b/content/xbl/src/nsXBLPrototypeBinding.cpp
@@ -199,17 +199,17 @@ public:
 
   static void
   Destroy(nsXBLInsertionPointEntry* aSelf) {
     aSelf->~nsXBLInsertionPointEntry();
     kPool->Free(aSelf, sizeof(*aSelf));
     nsXBLInsertionPointEntry::ReleasePool();
   }
 
-  NS_INLINE_DECL_REFCOUNTING(nsXBLInsertionPointEntry)
+  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(nsXBLInsertionPointEntry)
 
 protected:
   nsCOMPtr<nsIContent> mInsertionParent;
   nsCOMPtr<nsIContent> mDefaultContent;
   uint32_t mInsertionIndex;
 
   nsXBLInsertionPointEntry(nsIContent* aParent)
     : mInsertionParent(aParent),
--- a/content/xul/templates/src/nsXMLBinding.cpp
+++ b/content/xul/templates/src/nsXMLBinding.cpp
@@ -2,18 +2,18 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsXULTemplateQueryProcessorXML.h"
 #include "nsXULTemplateResultXML.h"
 #include "nsXMLBinding.h"
 
-NS_IMPL_ADDREF(nsXMLBindingSet)
-NS_IMPL_RELEASE(nsXMLBindingSet)
+NS_IMPL_CYCLE_COLLECTING_NATIVE_ADDREF(nsXMLBindingSet)
+NS_IMPL_CYCLE_COLLECTING_NATIVE_RELEASE(nsXMLBindingSet)
 
 NS_IMPL_CYCLE_COLLECTION_NATIVE_CLASS(nsXMLBindingSet)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_NATIVE(nsXMLBindingSet)
   nsXMLBinding* binding = tmp->mFirst;
   while (binding) {
     binding->mExpr = nullptr;
     binding = binding->mNext;
--- a/content/xul/templates/src/nsXMLBinding.h
+++ b/content/xul/templates/src/nsXMLBinding.h
@@ -44,25 +44,25 @@ struct nsXMLBinding {
  * nsXMLBindingValues objects and the query processor.
  */
 class nsXMLBindingSet MOZ_FINAL
 {
 public:
 
   // results hold a reference to a binding set in their
   // nsXMLBindingValues fields
-  nsAutoRefCnt mRefCnt;
+  nsCycleCollectingAutoRefCnt mRefCnt;
 
   // pointer to the first binding in a linked list
   nsAutoPtr<nsXMLBinding> mFirst;
 
 public:
 
-  NS_IMETHOD_(nsrefcnt) AddRef();
-  NS_IMETHOD_(nsrefcnt) Release();
+  NS_METHOD_(nsrefcnt) AddRef();
+  NS_METHOD_(nsrefcnt) Release();
   NS_DECL_OWNINGTHREAD
   NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(nsXMLBindingSet)
 
   /**
    * Add a binding to the set
    */
   nsresult
   AddBinding(nsIAtom* aVar, nsIDOMXPathExpression* aExpr);
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -549,17 +549,17 @@ nsTimeout::~nsTimeout()
 
     --gTimeoutCnt;
   }
 #endif
 
   MOZ_COUNT_DTOR(nsTimeout);
 }
 
-NS_IMPL_CYCLE_COLLECTION_NATIVE_CLASS(nsTimeout)
+NS_IMPL_CYCLE_COLLECTION_LEGACY_NATIVE_CLASS(nsTimeout)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_NATIVE_0(nsTimeout)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_BEGIN(nsTimeout)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mWindow,
                                                        nsIScriptGlobalObject)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mPrincipal)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mScriptHandler)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsTimeout, AddRef)
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -133,17 +133,17 @@ NS_CreateJSTimeoutHandler(nsGlobalWindow
  * timeout.  Holds a strong reference to an nsIScriptTimeoutHandler, which
  * abstracts the language specific cruft.
  */
 struct nsTimeout : PRCList
 {
   nsTimeout();
   ~nsTimeout();
 
-  NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(nsTimeout)
+  NS_DECL_CYCLE_COLLECTION_LEGACY_NATIVE_CLASS(nsTimeout)
 
   nsrefcnt Release();
   nsrefcnt AddRef();
 
   nsTimeout* Next() {
     // Note: might not actually return an nsTimeout.  Use IsTimeout to check.
     return static_cast<nsTimeout*>(PR_NEXT_LINK(this));
   }
--- a/editor/txmgr/src/nsTransactionItem.cpp
+++ b/editor/txmgr/src/nsTransactionItem.cpp
@@ -21,36 +21,18 @@ nsTransactionItem::nsTransactionItem(nsI
 
 nsTransactionItem::~nsTransactionItem()
 {
   delete mRedoStack;
 
   delete mUndoStack;
 }
 
-nsrefcnt
-nsTransactionItem::AddRef()
-{
-  ++mRefCnt;
-  NS_LOG_ADDREF(this, mRefCnt, "nsTransactionItem",
-                sizeof(nsTransactionItem));
-  return mRefCnt;
-}
-
-nsrefcnt
-nsTransactionItem::Release() {
-  --mRefCnt;
-  NS_LOG_RELEASE(this, mRefCnt, "nsTransactionItem");
-  if (mRefCnt == 0) {
-    mRefCnt = 1;
-    delete this;
-    return 0;
-  }
-  return mRefCnt;
-}
+NS_IMPL_CYCLE_COLLECTING_NATIVE_ADDREF(nsTransactionItem)
+NS_IMPL_CYCLE_COLLECTING_NATIVE_RELEASE(nsTransactionItem)
 
 NS_IMPL_CYCLE_COLLECTION_NATIVE_CLASS(nsTransactionItem)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_NATIVE(nsTransactionItem)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTransaction)
   if (tmp->mRedoStack) {
     tmp->mRedoStack->DoUnlink();
   }
--- a/editor/txmgr/src/nsTransactionItem.h
+++ b/editor/txmgr/src/nsTransactionItem.h
@@ -16,24 +16,23 @@ class nsITransaction;
 class nsTransactionManager;
 class nsTransactionStack;
 
 class nsTransactionItem
 {
   nsCOMPtr<nsITransaction> mTransaction;
   nsTransactionStack      *mUndoStack;
   nsTransactionStack      *mRedoStack;
-  nsAutoRefCnt             mRefCnt;
 
 public:
 
   nsTransactionItem(nsITransaction *aTransaction);
   virtual ~nsTransactionItem();
-  nsrefcnt AddRef();
-  nsrefcnt Release();
+  NS_METHOD_(nsrefcnt) AddRef();
+  NS_METHOD_(nsrefcnt) Release();
 
   NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(nsTransactionItem)
 
   virtual nsresult AddChild(nsTransactionItem *aTransactionItem);
   already_AddRefed<nsITransaction> GetTransaction();
   virtual nsresult GetIsBatch(bool *aIsBatch);
   virtual nsresult GetNumberOfChildren(int32_t *aNumChildren);
   virtual nsresult GetChild(int32_t aIndex, nsTransactionItem **aChild);
@@ -47,11 +46,15 @@ private:
   virtual nsresult UndoChildren(nsTransactionManager *aTxMgr);
   virtual nsresult RedoChildren(nsTransactionManager *aTxMgr);
 
   virtual nsresult RecoverFromUndoError(nsTransactionManager *aTxMgr);
   virtual nsresult RecoverFromRedoError(nsTransactionManager *aTxMgr);
 
   virtual nsresult GetNumberOfUndoItems(int32_t *aNumItems);
   virtual nsresult GetNumberOfRedoItems(int32_t *aNumItems);
+
+protected:
+  nsCycleCollectingAutoRefCnt mRefCnt;
+  NS_DECL_OWNINGTHREAD
 };
 
 #endif // nsTransactionItem_h__
--- a/xpcom/glue/nsCycleCollectionParticipant.h
+++ b/xpcom/glue/nsCycleCollectionParticipant.h
@@ -847,61 +847,91 @@ struct Skippable
   { &_class::TraceImpl }
 
 #define NS_IMPL_CYCLE_COLLECTION_VTABLE(_class)                                \
   NS_IMPL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_VTABLE(_class)
 
 
 // Cycle collector participant implementations.
 
+// A native class is non-nsISupports and uses nsCycleCollectingAutoRefCnt.
 #define NS_IMPL_CYCLE_COLLECTION_NATIVE_CLASS(_class)                          \
   const CCParticipantVTable<NS_CYCLE_COLLECTION_CLASSNAME(_class)>             \
     ::Type _class::NS_CYCLE_COLLECTION_INNERNAME =                             \
   { NS_IMPL_CYCLE_COLLECTION_NATIVE_VTABLE(NS_CYCLE_COLLECTION_CLASSNAME(_class)) };
 
+// For native classes containing JS pointers.
 #define NS_IMPL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(_class)            \
   const CCParticipantVTable<NS_CYCLE_COLLECTION_CLASSNAME(_class)>             \
     ::Type _class::NS_CYCLE_COLLECTION_INNERNAME =                             \
   { NS_IMPL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_VTABLE(NS_CYCLE_COLLECTION_CLASSNAME(_class)) };
 
+// A legacy native class is non-nsISupports, but does not use
+// nsCycleCollectingAutoRefCnt. This should be avoided because it can
+// cause leaks.
+#define NS_IMPL_CYCLE_COLLECTION_LEGACY_NATIVE_CLASS(_class)                   \
+  NS_IMPL_CYCLE_COLLECTION_NATIVE_CLASS(_class)
+
+// For nsISupports classes.
 #define NS_IMPL_CYCLE_COLLECTION_CLASS(_class)                                 \
   const CCParticipantVTable<NS_CYCLE_COLLECTION_CLASSNAME(_class)>             \
     ::Type _class::NS_CYCLE_COLLECTION_INNERNAME =                             \
   { NS_IMPL_CYCLE_COLLECTION_VTABLE(NS_CYCLE_COLLECTION_CLASSNAME(_class)) };
 
 
 // Cycle collector participant declarations.
 
 #define NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS_BODY(_class)                     \
   public:                                                                      \
     static NS_METHOD RootImpl(void *n);                                        \
     static NS_METHOD UnlinkImpl(void *n);                                      \
     static NS_METHOD UnrootImpl(void *n);                                      \
-    static NS_METHOD_(void) UnmarkIfPurpleImpl(void *n) {};                    \
     static NS_METHOD TraverseImpl(NS_CYCLE_COLLECTION_CLASSNAME(_class) *that, \
                            void *n, nsCycleCollectionTraversalCallback &cb);
 
+#define NS_DECL_CYCLE_COLLECTION_NATIVE_UNMARK_IF_PURPLE(_class)               \
+    static NS_METHOD_(void) UnmarkIfPurpleImpl(void *p)                        \
+    {                                                                          \
+        _class *tmp = static_cast<_class *>(p);                                \
+        if (NS_LIKELY(tmp->mRefCnt.IsPurple()))                                \
+            tmp->mRefCnt.unmarkPurple();                                       \
+    }
+
+#define NS_DECL_CYCLE_COLLECTION_STUB_UNMARK_IF_PURPLE(_class)                 \
+    static NS_METHOD_(void) UnmarkIfPurpleImpl(void *p) {}
+
 #define NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(_class)                          \
   class NS_CYCLE_COLLECTION_INNERCLASS                                         \
    : public nsCycleCollectionParticipant                                       \
   {                                                                            \
      NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS_BODY(_class)                        \
+     NS_DECL_CYCLE_COLLECTION_NATIVE_UNMARK_IF_PURPLE(_class)                  \
   };                                                                           \
   NS_CYCLE_COLLECTION_PARTICIPANT_INSTANCE
 
 #define NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(_class)            \
   class NS_CYCLE_COLLECTION_INNERCLASS                                         \
    : public nsScriptObjectTracer                                               \
   {                                                                            \
     NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS_BODY(_class)                         \
+    NS_DECL_CYCLE_COLLECTION_NATIVE_UNMARK_IF_PURPLE(_class)                   \
     static NS_METHOD_(void) TraceImpl(void *p, TraceCallback cb,               \
                                       void *closure);                          \
   };                                                                           \
   NS_CYCLE_COLLECTION_PARTICIPANT_INSTANCE
 
+#define NS_DECL_CYCLE_COLLECTION_LEGACY_NATIVE_CLASS(_class)                   \
+  class NS_CYCLE_COLLECTION_INNERCLASS                                         \
+   : public nsCycleCollectionParticipant                                       \
+  {                                                                            \
+     NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS_BODY(_class)                        \
+     NS_DECL_CYCLE_COLLECTION_STUB_UNMARK_IF_PURPLE(_class)                    \
+  };                                                                           \
+  NS_CYCLE_COLLECTION_PARTICIPANT_INSTANCE
+
 #define NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(_class, _root_function)           \
   NS_METHOD                                                                    \
   NS_CYCLE_COLLECTION_CLASSNAME(_class)::RootImpl(void *p)                     \
   {                                                                            \
     _class *tmp = static_cast<_class*>(p);                                     \
     tmp->_root_function();                                                     \
     return NS_OK;                                                              \
   }
--- a/xpcom/glue/nsISupportsImpl.h
+++ b/xpcom/glue/nsISupportsImpl.h
@@ -285,16 +285,71 @@ public:                                 
 protected:                                                                    \
   nsCycleCollectingAutoRefCnt mRefCnt;                                        \
   NS_DECL_OWNINGTHREAD                                                        \
 public:
 
 
 ///////////////////////////////////////////////////////////////////////////////
 
+/*
+ * Implementation of AddRef and Release for non-nsISupports (ie "native")
+ * cycle-collected classes that use the purple buffer to avoid leaks.
+ */
+
+#define NS_IMPL_CC_NATIVE_ADDREF_BODY(_class)                                 \
+    NS_PRECONDITION(int32_t(mRefCnt) >= 0, "illegal refcnt");                 \
+    NS_ASSERT_OWNINGTHREAD_AND_NOT_CCTHREAD(_class);                          \
+    nsrefcnt count = mRefCnt.incr(this);                                      \
+    NS_LOG_ADDREF(this, count, #_class, sizeof(*this));                       \
+    return count;
+
+#define NS_IMPL_CC_NATIVE_RELEASE_BODY(_class)                                \
+    NS_PRECONDITION(0 != mRefCnt, "dup release");                             \
+    NS_ASSERT_OWNINGTHREAD_AND_NOT_CCTHREAD(_class);                          \
+    nsrefcnt count =                                                          \
+      mRefCnt.decr(static_cast<void*>(this),                                  \
+                   _class::NS_CYCLE_COLLECTION_INNERNAME.GetParticipant());   \
+    NS_LOG_RELEASE(this, count, #_class);                                     \
+    if (count == 0) {                                                         \
+      NS_ASSERT_OWNINGTHREAD(_class);                                         \
+      mRefCnt.stabilizeForDeletion();                                         \
+      delete this;                                                            \
+      return 0;                                                               \
+    }                                                                         \
+    return count;
+
+#define NS_IMPL_CYCLE_COLLECTING_NATIVE_ADDREF(_class)                        \
+NS_METHOD_(nsrefcnt) _class::AddRef(void)                                     \
+{                                                                             \
+  NS_IMPL_CC_NATIVE_ADDREF_BODY(_class)                                       \
+}
+
+#define NS_IMPL_CYCLE_COLLECTING_NATIVE_RELEASE(_class)                       \
+NS_METHOD_(nsrefcnt) _class::Release(void)                                    \
+{                                                                             \
+  NS_IMPL_CC_NATIVE_RELEASE_BODY(_class)                                      \
+}
+
+#define NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(_class)            \
+public:                                                                       \
+  NS_METHOD_(nsrefcnt) AddRef(void) {                                         \
+    NS_IMPL_CC_NATIVE_ADDREF_BODY(_class)                                     \
+  }                                                                           \
+  NS_METHOD_(nsrefcnt) Release(void) {                                        \
+    NS_IMPL_CC_NATIVE_RELEASE_BODY(_class)                                    \
+  }                                                                           \
+protected:                                                                    \
+  nsCycleCollectingAutoRefCnt mRefCnt;                                        \
+  NS_DECL_OWNINGTHREAD                                                        \
+public:
+
+
+///////////////////////////////////////////////////////////////////////////////
+
 /**
  * Previously used to initialize the reference count, but no longer needed.
  *
  * DEPRECATED.
  */
 #define NS_INIT_ISUPPORTS() ((void)0)
 
 /**