Bug 806279 - CC macros refactoring: part 1: implement type-generic CC UNLINK/TRAVERSE macros - r=mccr8,smaug
authorBenoit Jacob <bjacob@mozilla.com>
Thu, 15 Nov 2012 02:32:39 -0500
changeset 113355 e11ac3ecc685341c62669f2724b228dbbac87380
parent 113354 e6a99483698fa284e1b865aed9e4532cbf1baea4
child 113356 3d02d563837372d1d00c16df920973b795e9d3df
push id23869
push useremorley@mozilla.com
push dateThu, 15 Nov 2012 16:18:16 +0000
treeherdermozilla-central@a37525d304d9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmccr8, smaug
bugs806279
milestone19.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 806279 - CC macros refactoring: part 1: implement type-generic CC UNLINK/TRAVERSE macros - r=mccr8,smaug
content/canvas/src/WebGLContext.cpp
content/canvas/src/WebGLContext.h
toolkit/components/places/nsMaybeWeakPtr.h
xpcom/base/nsAutoPtr.h
xpcom/glue/Makefile.in
xpcom/glue/nsCOMArray.h
xpcom/glue/nsCOMPtr.h
xpcom/glue/nsCycleCollectionNoteChild.h
xpcom/glue/nsCycleCollectionParticipant.cpp
xpcom/glue/nsCycleCollectionParticipant.h
xpcom/glue/nsCycleCollectionTraversalCallback.h
xpcom/glue/nsTArray.h
xpcom/glue/nsTObserverArray.h
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -1394,17 +1394,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY_OF_NSCOMPTR(mExtensions)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY_OF_NSCOMPTR(mBound2DTextures)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY_OF_NSCOMPTR(mBoundCubeMapTextures)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mBoundArrayBuffer)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mBoundElementArrayBuffer)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mCurrentProgram)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mBoundFramebuffer)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mBoundRenderbuffer)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY_OF_NSCOMPTR(mAttribBuffers)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAttribBuffers)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebGLContext)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsIDOMWebGLRenderingContext)
   NS_INTERFACE_MAP_ENTRY(nsICanvasRenderingContextInternal)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -7,16 +7,17 @@
 #define WEBGLCONTEXT_H_
 
 #include <stdarg.h>
 #include <vector>
 
 #include "nsTArray.h"
 #include "nsDataHashtable.h"
 #include "nsHashKeys.h"
+#include "nsCycleCollectionNoteChild.h"
 
 #include "nsIDocShell.h"
 
 #include "nsIDOMWebGLRenderingContext.h"
 #include "nsICanvasRenderingContextInternal.h"
 #include "nsHTMLCanvasElement.h"
 #include "nsIDOMHTMLElement.h"
 #include "nsIMemoryReporter.h"
@@ -1521,21 +1522,16 @@ struct WebGLVertexAttribData {
                 return 0;
         }
     }
 
     GLuint actualStride() const {
         if (stride) return stride;
         return size * componentSize();
     }
-
-    // for cycle collection
-    WebGLBuffer* get() {
-        return buf.get();
-    }
 };
 
 class WebGLBuffer MOZ_FINAL
     : public nsISupports
     , public WebGLRefCountedObject<WebGLBuffer>
     , public LinkedListElement<WebGLBuffer>
     , public WebGLContextBoundObject
     , public nsWrapperCache
@@ -3447,11 +3443,44 @@ public:
   WebGLMemoryPressureObserver(WebGLContext *context)
     : mContext(context)
   {}
 
 private:
   WebGLContext *mContext;
 };
 
+} // namespace mozilla
+
+inline void ImplCycleCollectionUnlink(mozilla::WebGLVertexAttribData& aField)
+{
+  aField.buf = nullptr;
+}
+
+inline void
+ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
+                            mozilla::WebGLVertexAttribData& aField,
+                            const char* aName,
+                            uint32_t aFlags = 0)
+{
+  CycleCollectionNoteEdgeName(aCallback, aName, aFlags);
+  aCallback.NoteXPCOMChild(aField.buf);
+}
+
+template <typename T>
+inline void
+ImplCycleCollectionUnlink(mozilla::WebGLRefPtr<T>& aField)
+{
+  aField = nullptr;
+}
+
+template <typename T>
+inline void
+ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
+                            mozilla::WebGLRefPtr<T>& aField,
+                            const char* aName,
+                            uint32_t aFlags = 0)
+{
+  CycleCollectionNoteEdgeName(aCallback, aName, aFlags);
+  aCallback.NoteXPCOMChild(aField);
 }
 
 #endif
--- a/toolkit/components/places/nsMaybeWeakPtr.h
+++ b/toolkit/components/places/nsMaybeWeakPtr.h
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsMaybeWeakPtr_h_
 #define nsMaybeWeakPtr_h_
 
 #include "nsCOMPtr.h"
 #include "nsWeakReference.h"
 #include "nsTArray.h"
+#include "nsCycleCollectionNoteChild.h"
 
 // nsMaybeWeakPtr is a helper object to hold a strong-or-weak reference
 // to the template class.  It's pretty minimal, but sufficient.
 
 class nsMaybeWeakPtr_base
 {
 protected:
   // Returns an addref'd pointer to the requested interface
@@ -65,16 +66,38 @@ public:
 
   nsresult RemoveWeakElement(T *aElement)
   {
     return NS_RemoveWeakElementBase(
       reinterpret_cast<isupports_array_type*>(this), aElement);
   }
 };
 
+template <typename T>
+inline void
+ImplCycleCollectionUnlink(nsMaybeWeakPtrArray<T>& aField)
+{
+  aField.Clear();
+}
+
+template <typename E>
+inline void
+ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
+                            nsMaybeWeakPtrArray<E>& aField,
+                            const char* aName,
+                            uint32_t aFlags = 0)
+{
+  aFlags |= CycleCollectionEdgeNameArrayFlag;
+  size_t length = aField.Length();
+  for (size_t i = 0; i < length; ++i) {
+    CycleCollectionNoteEdgeName(aCallback, aName, aFlags);
+    aCallback.NoteXPCOMChild(aField[i]);
+  }
+}
+
 // Call a method on each element in the array, but only if the element is
 // non-null.
 
 #define ENUMERATE_WEAKARRAY(array, type, method)                           \
   for (uint32_t array_idx = 0; array_idx < array.Length(); ++array_idx) {  \
     const nsCOMPtr<type> &e = array.ElementAt(array_idx);                  \
     if (e)                                                                 \
       e->method;                                                           \
--- a/xpcom/base/nsAutoPtr.h
+++ b/xpcom/base/nsAutoPtr.h
@@ -9,16 +9,18 @@
   // Wrapping includes can speed up compiles (see "Large Scale C++ Software Design")
 #ifndef nsCOMPtr_h___
   // For |already_AddRefed|, |NSCAP_Zero|,
   // |NSCAP_DONT_PROVIDE_NONCONST_OPEQ|,
   // |NSCAP_FEATURE_INLINE_STARTASSIGNMENT|
 #include "nsCOMPtr.h"
 #endif
 
+#include "nsCycleCollectionNoteChild.h"
+
 /*****************************************************************************/
 
 // template <class T> class nsAutoPtrGetterTransfers;
 
 template <class T>
 class nsAutoPtr
   {
     private:
@@ -1067,16 +1069,34 @@ class nsRefPtr
           return reinterpret_cast<T**>(begin_assignment());
 #else
           assign_assuming_AddRef(0);
           return reinterpret_cast<T**>(&mRawPtr);
 #endif
         }
   };
 
+template <typename T>
+inline void
+ImplCycleCollectionUnlink(nsRefPtr<T>& aField)
+{
+  aField = nullptr;
+}
+
+template <typename T>
+inline void
+ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
+                            nsRefPtr<T>& aField,
+                            const char* aName,
+                            uint32_t aFlags = 0)
+{
+  CycleCollectionNoteEdgeName(aCallback, aName, aFlags);
+  aCallback.NoteXPCOMChild(aField);
+}
+
 template <class T>
 inline
 nsRefPtr<T>*
 address_of( nsRefPtr<T>& aPtr )
   {
     return aPtr.get_address();
   }
 
--- a/xpcom/glue/Makefile.in
+++ b/xpcom/glue/Makefile.in
@@ -83,16 +83,18 @@ SDK_HEADERS = \
 EXPORTS_NAMESPACES = mozilla mozilla/threads
 
 EXPORTS = \
 		nsThreadUtils.h \
 		nsTPriorityQueue.h \
 		nsProxyRelease.h \
 		nsXPTCUtils.h \
 		nsCycleCollectorUtils.h \
+		nsCycleCollectionNoteChild.h \
+		nsCycleCollectionTraversalCallback.h \
 		$(NULL)
 
 EXPORTS_mozilla = \
   AppData.h \
   AutoRestore.h \
   BlockingResourceBase.h \
   CondVar.h \
   DeadlockDetector.h \
--- a/xpcom/glue/nsCOMArray.h
+++ b/xpcom/glue/nsCOMArray.h
@@ -3,16 +3,17 @@
  * 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/. */
 
 #ifndef nsCOMArray_h__
 #define nsCOMArray_h__
 
 #include "mozilla/Attributes.h"
 
+#include "nsCycleCollectionNoteChild.h"
 #include "nsVoidArray.h"
 #include "nsISupports.h"
 
 // See below for the definition of nsCOMArray<T>
 
 // a class that's nsISupports-specific, so that we can contain the
 // work of this class in the XPCOM dll
 class NS_COM_GLUE nsCOMArray_base
@@ -100,18 +101,42 @@ public:
     
 private:
     
     // the actual storage
     nsVoidArray mArray;
 
     // don't implement these, defaults will muck with refcounts!
     nsCOMArray_base& operator=(const nsCOMArray_base& other) MOZ_DELETE;
+
+    // needs to call Clear() which is protected
+    friend void ImplCycleCollectionUnlink(nsCOMArray_base& aField);
 };
 
+inline void
+ImplCycleCollectionUnlink(nsCOMArray_base& aField)
+{
+  aField.Clear();
+}
+
+inline void
+ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
+                            nsCOMArray_base& aField,
+                            const char* aName,
+                            uint32_t aFlags = 0)
+{
+  aFlags |= CycleCollectionEdgeNameArrayFlag;
+  size_t length = aField.Count();
+  for (size_t i = 0; i < length; ++i) {
+    CycleCollectionNoteEdgeName(aCallback, aName, aFlags);
+    aCallback.NoteXPCOMChild(aField[i]);
+  }
+}
+
+
 // a non-XPCOM, refcounting array of XPCOM objects
 // used as a member variable or stack variable - this object is NOT
 // refcounted, but the objects that it holds are
 //
 // most of the read-only accessors like ObjectAt()/etc do NOT refcount
 // on the way out. This means that you can do one of two things:
 //
 // * does an addref, but holds onto a reference
@@ -268,10 +293,31 @@ class nsCOMArray : public nsCOMArray_bas
     }
 
 private:
 
     // don't implement these!
     nsCOMArray<T>& operator=(const nsCOMArray<T>& other) MOZ_DELETE;
 };
 
+template <typename T>
+inline void
+ImplCycleCollectionUnlink(nsCOMArray<T>& aField)
+{
+  aField.Clear();
+}
+
+template <typename E>
+inline void
+ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
+                            nsCOMArray<E>& aField,
+                            const char* aName,
+                            uint32_t aFlags = 0)
+{
+  aFlags |= CycleCollectionEdgeNameArrayFlag;
+  size_t length = aField.Count();
+  for (size_t i = 0; i < length; ++i) {
+    CycleCollectionNoteEdgeName(aCallback, aName, aFlags);
+    aCallback.NoteXPCOMChild(aField[i]);
+  }
+}
 
 #endif
--- a/xpcom/glue/nsCOMPtr.h
+++ b/xpcom/glue/nsCOMPtr.h
@@ -32,16 +32,18 @@
   // for |nsresult|, |NS_ADDREF|, |NS_GET_TEMPLATE_IID| et al
 #endif
 
 #ifndef nscore_h___
 #include "nscore.h"
   // for |NS_COM_GLUE|
 #endif
 
+#include "nsCycleCollectionNoteChild.h"
+
 
 /*
   WARNING:
     This file defines several macros for internal use only.  These macros begin with the
     prefix |NSCAP_|.  Do not use these macros in your own code.  They are for internal use
     only for cross-platform compatibility, and are subject to change without notice.
 */
 
@@ -1121,16 +1123,34 @@ class nsCOMPtr<nsISupports>
           return reinterpret_cast<nsISupports**>(begin_assignment());
 #else
           assign_assuming_AddRef(0);
           return reinterpret_cast<nsISupports**>(&mRawPtr);
 #endif
         }
   };
 
+template <typename T>
+inline void
+ImplCycleCollectionUnlink(nsCOMPtr<T>& aField)
+{
+  aField = nullptr;
+}
+
+template <typename T>
+inline void
+ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
+                            nsCOMPtr<T>& aField,
+                            const char* aName,
+                            uint32_t aFlags = 0)
+{
+  CycleCollectionNoteEdgeName(aCallback, aName, aFlags);
+  aCallback.NoteXPCOMChild(aField);
+}
+
 #ifndef NSCAP_FEATURE_USE_BASE
 template <class T>
 void
 nsCOMPtr<T>::assign_with_AddRef( nsISupports* rawPtr )
   {
     if ( rawPtr )
       NSCAP_ADDREF(this, rawPtr);
     assign_assuming_AddRef(reinterpret_cast<T*>(rawPtr));
new file mode 100644
--- /dev/null
+++ b/xpcom/glue/nsCycleCollectionNoteChild.h
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* 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/. */
+
+// This header will be included by headers that define refpointer and array classes
+// in order to specialize CC helpers such as ImplCycleCollectionTraverse for them.
+
+#ifndef nsCycleCollectionNoteChild_h__
+#define nsCycleCollectionNoteChild_h__
+
+#include "nsCycleCollectionTraversalCallback.h"
+#include "mozilla/Likely.h"
+
+enum {
+  CycleCollectionEdgeNameArrayFlag = 1
+};
+
+// Just a helper for appending "[i]". Didn't want to pull in string headers here.
+void
+CycleCollectionNoteEdgeNameImpl(nsCycleCollectionTraversalCallback& aCallback,
+                                const char* aName,
+                                uint32_t aFlags = 0);
+
+// Should be inlined so that in the no-debug-info case this is just a simple if().
+MOZ_ALWAYS_INLINE void
+CycleCollectionNoteEdgeName(nsCycleCollectionTraversalCallback& aCallback,
+                            const char* aName,
+                            uint32_t aFlags = 0)
+{
+  if (MOZ_UNLIKELY(aCallback.WantDebugInfo())) {
+    CycleCollectionNoteEdgeNameImpl(aCallback, aName, aFlags);
+  }
+}
+
+#endif // nsCycleCollectionNoteChild_h__
--- a/xpcom/glue/nsCycleCollectionParticipant.cpp
+++ b/xpcom/glue/nsCycleCollectionParticipant.cpp
@@ -1,16 +1,22 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* 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 "nsCycleCollectionParticipant.h"
 #include "nsCOMPtr.h"
 
+#ifdef MOZILLA_INTERNAL_API
+#include "nsString.h"
+#else
+#include "nsStringAPI.h"
+#endif
+
 void
 nsScriptObjectTracer::NoteJSChild(void *aScriptThing, const char *name,
                                   void *aClosure)
 {
   nsCycleCollectionTraversalCallback *cb =
     static_cast<nsCycleCollectionTraversalCallback*>(aClosure);
   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, name);
   cb->NoteJSChild(aScriptThing);
@@ -43,8 +49,20 @@ nsXPCOMCycleCollectionParticipant::Trace
 bool
 nsXPCOMCycleCollectionParticipant::CheckForRightISupports(nsISupports *s)
 {
     nsISupports* foo;
     s->QueryInterface(NS_GET_IID(nsCycleCollectionISupports),
                       reinterpret_cast<void**>(&foo));
     return s == foo;
 }
+
+void
+CycleCollectionNoteEdgeNameImpl(nsCycleCollectionTraversalCallback& aCallback,
+                                const char* aName,
+                                uint32_t aFlags = 0)
+{
+  nsAutoCString arrayEdgeName(aName);
+  if (aFlags & CycleCollectionEdgeNameArrayFlag) {
+    arrayEdgeName.AppendLiteral("[i]");
+  }
+  aCallback.NoteNextEdgeName(arrayEdgeName.get());
+}
--- a/xpcom/glue/nsCycleCollectionParticipant.h
+++ b/xpcom/glue/nsCycleCollectionParticipant.h
@@ -3,17 +3,19 @@
  * 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/. */
 
 #ifndef nsCycleCollectionParticipant_h__
 #define nsCycleCollectionParticipant_h__
 
 #include "mozilla/Likely.h"
 #include "mozilla/TypeTraits.h"
-#include "nsISupports.h"
+
+#include "nsCycleCollectionNoteChild.h"
+#include "nsCycleCollectionTraversalCallback.h"
 
 #define NS_CYCLECOLLECTIONPARTICIPANT_IID                                      \
 {                                                                              \
     0x9674489b,                                                                \
     0x1f6f,                                                                    \
     0x4550,                                                                    \
     { 0xa7, 0x30, 0xcc, 0xae, 0xdd, 0x10, 0x4c, 0xf9 }                         \
 }
@@ -47,70 +49,18 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsCycleCol
 
 /**
  * Forward declarations
  */
 class nsCycleCollectionParticipant;
 class nsScriptObjectTracer;
 class nsXPCOMCycleCollectionParticipant;
 
-/**
- * Callback definitions
- */
 typedef void
-(* TraceCallback)(void *p, const char *name, void *closure);
-
-class NS_NO_VTABLE nsCycleCollectionTraversalCallback
-{
-public:
-    // You must call DescribeRefCountedNode() with an accurate
-    // refcount, otherwise cycle collection will fail, and probably crash.
-    // If the callback cares about objname, it should put
-    // WANT_DEBUG_INFO in mFlags.
-    NS_IMETHOD_(void) DescribeRefCountedNode(nsrefcnt refcount,
-                                             const char *objname) = 0;
-    NS_IMETHOD_(void) DescribeGCedNode(bool ismarked,
-                                       const char *objname) = 0;
-
-    NS_IMETHOD_(void) NoteXPCOMRoot(nsISupports *root) = 0;
-    NS_IMETHOD_(void) NoteJSRoot(void *root) = 0;
-    NS_IMETHOD_(void) NoteNativeRoot(void *root, nsCycleCollectionParticipant *participant) = 0;
-
-    NS_IMETHOD_(void) NoteXPCOMChild(nsISupports *child) = 0;
-    NS_IMETHOD_(void) NoteJSChild(void *child) = 0;
-    NS_IMETHOD_(void) NoteNativeChild(void *child,
-                                      nsCycleCollectionParticipant *helper) = 0;
-
-    // Give a name to the edge associated with the next call to
-    // NoteXPCOMChild, NoteJSChild, or NoteNativeChild.
-    // Callbacks who care about this should set WANT_DEBUG_INFO in the
-    // flags.
-    NS_IMETHOD_(void) NoteNextEdgeName(const char* name) = 0;
-
-    NS_IMETHOD_(void) NoteWeakMapping(void *map, void *key, void *kdelegate, void *val) = 0;
-
-    enum {
-        // Values for flags:
-
-        // Caller should call NoteNextEdgeName and pass useful objName
-        // to DescribeRefCountedNode and DescribeGCedNode.
-        WANT_DEBUG_INFO = (1<<0),
-
-        // Caller should not skip objects that we know will be
-        // uncollectable.
-        WANT_ALL_TRACES = (1<<1)
-    };
-    uint32_t Flags() const { return mFlags; }
-    bool WantDebugInfo() const { return (mFlags & WANT_DEBUG_INFO) != 0; }
-    bool WantAllTraces() const { return (mFlags & WANT_ALL_TRACES) != 0; }
-protected:
-    nsCycleCollectionTraversalCallback() : mFlags(0) {}
-
-    uint32_t mFlags;
-};
+(* TraceCallback)(void *p, const char* name, void *closure);
 
 /**
  * VTables
  *
  * When using global scope static initialization for simple types with virtual
  * member functions, GCC creates static initializer functions. In order to
  * avoid this from happening, cycle collection participants are defined as
  * function tables.
@@ -438,24 +388,27 @@ public:
     NS_CYCLE_COLLECTION_CLASSNAME(_base_class)::UnlinkImpl(s);
 
 #define NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_NATIVE(_class)                   \
   NS_METHOD                                                                    \
   NS_CYCLE_COLLECTION_CLASSNAME(_class)::UnlinkImpl(void *p)                   \
   {                                                                            \
     _class *tmp = static_cast<_class*>(p);
 
+#define NS_IMPL_CYCLE_COLLECTION_UNLINK(_field)                                \
+    ImplCycleCollectionUnlink(tmp->_field);
+
 #define NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_field)                       \
-    tmp->_field = NULL;    
+    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field)
 
 #define NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(_field)                     \
-    tmp->_field.Clear();
+    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field)
 
 #define NS_IMPL_CYCLE_COLLECTION_UNLINK_NSTARRAY(_field)                       \
-    tmp->_field.Clear();
+    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field)
 
 #define NS_IMPL_CYCLE_COLLECTION_UNLINK_END                                    \
     (void)tmp;                                                                 \
     return NS_OK;                                                              \
   }
 
 #define NS_IMPL_CYCLE_COLLECTION_UNLINK_0(_class)                              \
   NS_METHOD                                                                    \
@@ -511,49 +464,36 @@ public:
   NS_METHOD                                                                    \
   NS_CYCLE_COLLECTION_CLASSNAME(_class)::TraverseImpl                          \
                          (NS_CYCLE_COLLECTION_CLASSNAME(_class) *that, void *p,\
                           nsCycleCollectionTraversalCallback &cb)              \
   {                                                                            \
     _class *tmp = static_cast<_class*>(p);                                     \
     NS_IMPL_CYCLE_COLLECTION_DESCRIBE(_class, tmp->mRefCnt.get())
 
-#define NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(_cb, _name)                         \
-  PR_BEGIN_MACRO                                                               \
-    if (MOZ_UNLIKELY((_cb).WantDebugInfo())) {                                 \
-      (_cb).NoteNextEdgeName(_name);                                           \
-    }                                                                          \
-  PR_END_MACRO
+#define NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field)                              \
+  ImplCycleCollectionTraverse(cb, tmp->_field, #_field, 0);
 
 #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(_field)                       \
   PR_BEGIN_MACRO                                                               \
     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, #_field);                           \
     cb.NoteXPCOMChild(tmp->_field);                                            \
   PR_END_MACRO;
 
 #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_field)                     \
-  PR_BEGIN_MACRO                                                               \
-    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, #_field);                           \
-    cb.NoteXPCOMChild(tmp->_field.get());                                      \
-  PR_END_MACRO;
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field)
 
 #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(_field, _base)    \
   PR_BEGIN_MACRO                                                               \
     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, #_field);                           \
     cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(_base*, tmp->_field));                 \
   PR_END_MACRO;
 
 #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(_field)                   \
-    {                                                                          \
-      int32_t i;                                                               \
-      for (i = 0; i < tmp->_field.Count(); ++i) {                              \
-        NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, #_field "[i]");                 \
-        cb.NoteXPCOMChild(tmp->_field[i]);                                     \
-      }                                                                        \
-    }
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field)
 
 #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_PTR(_ptr, _ptr_class, _name)  \
   PR_BEGIN_MACRO                                                               \
     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, _name);                             \
     cb.NoteNativeChild(_ptr, NS_CYCLE_COLLECTION_PARTICIPANT(_ptr_class));     \
   PR_END_MACRO;
 
 #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(_field, _field_class)  \
@@ -566,23 +506,17 @@ public:
       uint32_t i, length = (_array).Length();                                  \
       for (i = 0; i < length; ++i)                                             \
         NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_PTR((_array)[i],              \
                                                      _element_class,           \
                                                      _name "[i]");             \
     }
 
 #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY_OF_NSCOMPTR(_field)         \
-    {                                                                          \
-      uint32_t i, length = tmp->_field.Length();                               \
-      for (i = 0; i < length; ++i) {                                           \
-        NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, #_field "[i]");                 \
-        cb.NoteXPCOMChild(tmp->_field[i].get());                               \
-      }                                                                        \
-    }
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field)
 
 #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY_MEMBER(_field,              \
                                                           _element_class)      \
     NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY(tmp->_field, _element_class,    \
                                                #_field)
 
 #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS                       \
     that->Trace(p, &nsScriptObjectTracer::NoteJSChild, &cb);
@@ -1207,9 +1141,11 @@ struct Skippable
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f3)                               \
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f4)                               \
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f5)                               \
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f6)                               \
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f7)                               \
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f8)                               \
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
+#define NS_CYCLE_COLLECTION_NOTE_EDGE_NAME CycleCollectionNoteEdgeName
+
 #endif // nsCycleCollectionParticipant_h__
new file mode 100644
--- /dev/null
+++ b/xpcom/glue/nsCycleCollectionTraversalCallback.h
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* 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/. */
+
+#ifndef nsCycleCollectionTraversalCallback_h__
+#define nsCycleCollectionTraversalCallback_h__
+
+#include "nsISupports.h"
+
+class nsCycleCollectionParticipant;
+
+class NS_NO_VTABLE nsCycleCollectionTraversalCallback
+{
+public:
+  // You must call DescribeRefCountedNode() with an accurate
+  // refcount, otherwise cycle collection will fail, and probably crash.
+  // If the callback cares about objname, it should put
+  // WANT_DEBUG_INFO in mFlags.
+  NS_IMETHOD_(void) DescribeRefCountedNode(nsrefcnt refcount,
+                                           const char* objname) = 0;
+  NS_IMETHOD_(void) DescribeGCedNode(bool ismarked,
+                                     const char* objname) = 0;
+
+  NS_IMETHOD_(void) NoteXPCOMRoot(nsISupports *root) = 0;
+  NS_IMETHOD_(void) NoteJSRoot(void *root) = 0;
+  NS_IMETHOD_(void) NoteNativeRoot(void *root, nsCycleCollectionParticipant *participant) = 0;
+
+  NS_IMETHOD_(void) NoteXPCOMChild(nsISupports *child) = 0;
+  NS_IMETHOD_(void) NoteJSChild(void *child) = 0;
+  NS_IMETHOD_(void) NoteNativeChild(void *child,
+                                    nsCycleCollectionParticipant *helper) = 0;
+
+  // Give a name to the edge associated with the next call to
+  // NoteXPCOMChild, NoteJSChild, or NoteNativeChild.
+  // Callbacks who care about this should set WANT_DEBUG_INFO in the
+  // flags.
+  NS_IMETHOD_(void) NoteNextEdgeName(const char* name) = 0;
+
+  NS_IMETHOD_(void) NoteWeakMapping(void *map, void *key, void *kdelegate, void *val) = 0;
+
+  enum {
+    // Values for flags:
+
+    // Caller should call NoteNextEdgeName and pass useful objName
+    // to DescribeRefCountedNode and DescribeGCedNode.
+    WANT_DEBUG_INFO = (1<<0),
+
+    // Caller should not skip objects that we know will be
+    // uncollectable.
+    WANT_ALL_TRACES = (1<<1)
+  };
+  uint32_t Flags() const { return mFlags; }
+  bool WantDebugInfo() const { return (mFlags & WANT_DEBUG_INFO) != 0; }
+  bool WantAllTraces() const { return (mFlags & WANT_ALL_TRACES) != 0; }
+protected:
+  nsCycleCollectionTraversalCallback() : mFlags(0) {}
+
+  uint32_t mFlags;
+};
+
+#endif // nsCycleCollectionTraversalCallback_h__
\ No newline at end of file
--- a/xpcom/glue/nsTArray.h
+++ b/xpcom/glue/nsTArray.h
@@ -7,16 +7,17 @@
 #ifndef nsTArray_h__
 #define nsTArray_h__
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Util.h"
 
 #include <string.h>
 
+#include "nsCycleCollectionNoteChild.h"
 #include "nsAlgorithm.h"
 #include "nscore.h"
 #include "nsQuickSort.h"
 #include "nsDebug.h"
 #include "nsTraceRefcnt.h"
 #include NEW_H
 
 //
@@ -1263,46 +1264,110 @@ protected:
         break;
       }
       elem[parent_index] = elem[index];
     }
     elem[index] = item;
   }
 };
 
+template <typename E, typename Alloc>
+inline void
+ImplCycleCollectionUnlink(nsTArray<E, Alloc>& aField)
+{
+  aField.Clear();
+}
+
+template <typename E, typename Alloc>
+inline void
+ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
+                            nsTArray<E, Alloc>& aField,
+                            const char* aName,
+                            uint32_t aFlags = 0)
+{
+  aFlags |= CycleCollectionEdgeNameArrayFlag;
+  size_t length = aField.Length();
+  for (size_t i = 0; i < length; ++i) {
+    ImplCycleCollectionTraverse(aCallback, aField[i], aName, aFlags);
+  }
+}
+
 //
 // Convenience subtypes of nsTArray.
 //
-template<class E>
+template <class E>
 class FallibleTArray : public nsTArray<E, nsTArrayFallibleAllocator>
 {
 public:
   typedef nsTArray<E, nsTArrayFallibleAllocator>   base_type;
   typedef typename base_type::size_type            size_type;
 
   FallibleTArray() {}
   explicit FallibleTArray(size_type capacity) : base_type(capacity) {}
   FallibleTArray(const FallibleTArray& other) : base_type(other) {}
 };
 
+template <typename E>
+inline void
+ImplCycleCollectionUnlink(FallibleTArray<E>& aField)
+{
+  aField.Clear();
+}
+
+template <typename E>
+inline void
+ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
+                            FallibleTArray<E>& aField,
+                            const char* aName,
+                            uint32_t aFlags = 0)
+{
+  aFlags |= CycleCollectionEdgeNameArrayFlag;
+  size_t length = aField.Length();
+  for (size_t i = 0; i < length; ++i) {
+    ImplCycleCollectionTraverse(aCallback, aField[i], aName, aFlags);
+  }
+}
+
+
 #ifdef MOZALLOC_HAVE_XMALLOC
-template<class E>
+template <class E>
 class InfallibleTArray : public nsTArray<E, nsTArrayInfallibleAllocator>
 {
 public:
   typedef nsTArray<E, nsTArrayInfallibleAllocator> base_type;
   typedef typename base_type::size_type            size_type;
  
   InfallibleTArray() {}
   explicit InfallibleTArray(size_type capacity) : base_type(capacity) {}
   InfallibleTArray(const InfallibleTArray& other) : base_type(other) {}
 };
+
+template <typename E>
+inline void ImplCycleCollectionUnlink(InfallibleTArray<E>& aField)
+{
+  aField.Clear();
+}
+
+template <typename E>
+inline void
+ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
+                            InfallibleTArray<E>& aField,
+                            const char* aName,
+                            uint32_t aFlags = 0)
+{
+  aFlags |= CycleCollectionEdgeNameArrayFlag;
+  size_t length = aField.Length();
+  for (size_t i = 0; i < length; ++i) {
+    ImplCycleCollectionTraverse(aCallback, aField[i], aName, aFlags);
+  }
+}
+
 #endif
 
-template<class TArrayBase, uint32_t N>
+template <class TArrayBase, uint32_t N>
 class nsAutoArrayBase : public TArrayBase
 {
 public:
   typedef TArrayBase base_type;
   typedef typename base_type::Header Header;
   typedef typename base_type::elem_type elem_type;
 
 protected:
--- a/xpcom/glue/nsTObserverArray.h
+++ b/xpcom/glue/nsTObserverArray.h
@@ -2,16 +2,17 @@
 /* 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/. */
 
 #ifndef nsTObserverArray_h___
 #define nsTObserverArray_h___
 
 #include "nsTArray.h"
+#include "nsCycleCollectionNoteChild.h"
 
 /**
  * An array of observers. Like a normal array, but supports iterators that are
  * stable even if the array is modified during iteration.
  * The template parameter T is the observer type the array will hold;
  * N is the number of built-in storage slots that come with the array.
  * NOTE: You probably want to use nsTObserverArray, unless you specifically
  * want built-in storage. See below.
@@ -369,16 +370,37 @@ class nsTObserverArray : public nsAutoTO
     nsTObserverArray() {}
 
     // Initialize this array and pre-allocate some number of elements.
     explicit nsTObserverArray(size_type capacity) {
       base_type::mArray.SetCapacity(capacity);
     }
 };
 
+template <typename T>
+inline void
+ImplCycleCollectionUnlink(nsTObserverArray<T>& aField)
+{
+  aField.Clear();
+}
+
+template <typename T>
+inline void
+ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
+                            nsTObserverArray<T>& aField,
+                            const char* aName,
+                            uint32_t aFlags = 0)
+{
+  aFlags |= CycleCollectionEdgeNameArrayFlag;
+  size_t length = aField.Length();
+  for (size_t i = 0; i < length; ++i) {
+    ImplCycleCollectionTraverse(aCallback, aField[i], aName, aFlags);
+  }
+}
+
 // 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_XPCOM_OBSERVERS(array_, obstype_, func_, params_) \
   PR_BEGIN_MACRO                                                             \
     nsTObserverArray<obstype_ *>::ForwardIterator iter_(array_);             \
     nsCOMPtr<obstype_> obs_;                                                 \
     while (iter_.HasMore()) {                                                 \