Bug 671299 (part 3) - Add style sheet memory reporters. r=dbaron.
authorNicholas Nethercote <nnethercote@mozilla.com>
Mon, 02 Jan 2012 18:19:14 -0800
changeset 89203 b2f1b368e2f25a5791a4b146f0ac709ca9f029fe
parent 89202 81de95739be64201cd1d71f6584f13d13b1f8635
child 89204 67b0e13d7a629c69ef02979de6f4f3083d560824
push idunknown
push userunknown
push dateunknown
reviewersdbaron
bugs671299
milestone13.0a1
Bug 671299 (part 3) - Add style sheet memory reporters. r=dbaron.
content/base/public/nsIDocument.h
content/base/src/nsDocument.cpp
content/base/src/nsDocument.h
dom/base/nsDOMMemoryReporter.cpp
dom/base/nsGlobalWindow.cpp
dom/base/nsGlobalWindow.h
dom/workers/WorkerPrivate.cpp
js/xpconnect/src/XPCJSRuntime.cpp
js/xpconnect/src/xpcpublic.h
layout/base/nsPresContext.h
layout/style/AnimationCommon.cpp
layout/style/Declaration.cpp
layout/style/Declaration.h
layout/style/GroupRule.h
layout/style/ImportRule.h
layout/style/NameSpaceRule.h
layout/style/Rule.h
layout/style/StyleRule.cpp
layout/style/StyleRule.h
layout/style/nsAnimationManager.cpp
layout/style/nsCSSDataBlock.cpp
layout/style/nsCSSDataBlock.h
layout/style/nsCSSRules.cpp
layout/style/nsCSSRules.h
layout/style/nsCSSStyleSheet.cpp
layout/style/nsCSSStyleSheet.h
layout/style/nsCSSValue.cpp
layout/style/nsCSSValue.h
layout/style/nsIStyleSheet.h
layout/style/nsLayoutStylesheetCache.cpp
layout/style/nsLayoutStylesheetCache.h
xpcom/base/nsIMemoryReporter.idl
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -1612,16 +1612,18 @@ public:
 
   void SetNeedStyleFlush() {
     mNeedStyleFlush = true;
     if (mDisplayDocument) {
       mDisplayDocument->SetNeedStyleFlush();
     }
   }
 
+  virtual size_t SizeOfStyleSheets(nsMallocSizeOfFun aMallocSizeOf) const = 0;
+
 private:
   PRUint64 mWarnedAbout;
 
 protected:
   ~nsIDocument()
   {
     // XXX The cleanup of mNodeInfoManager (calling DropDocumentReference and
     //     releasing it) happens in the nsDocument destructor. We'd prefer to
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -9129,8 +9129,23 @@ nsDocument::GetMozVisibilityState(nsAStr
   static const char states[][8] = {
     "hidden",
     "visible"
   };
   PR_STATIC_ASSERT(NS_ARRAY_LENGTH(states) == eVisibilityStateCount);
   aState.AssignASCII(states[mVisibilityState]);
   return NS_OK;
 }
+
+static size_t
+SizeOfStyleSheetsElementIncludingThis(nsIStyleSheet* aStyleSheet,
+                                      nsMallocSizeOfFun aMallocSizeOf,
+                                      void* aData)
+{
+  return aStyleSheet->SizeOfIncludingThis(aMallocSizeOf);
+}
+
+/* virtual */ size_t
+nsDocument::SizeOfStyleSheets(nsMallocSizeOfFun aMallocSizeOf) const
+{
+  return mStyleSheets.SizeOfExcludingThis(SizeOfStyleSheetsElementIncludingThis,
+                                          aMallocSizeOf); 
+}
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -986,16 +986,18 @@ public:
   Element* FullScreenStackTop();
 
   // This method may fire a DOM event; if it does so it will happen
   // synchronously.
   void UpdateVisibilityState();
   // Posts an event to call UpdateVisibilityState
   virtual void PostVisibilityUpdateEvent();
 
+  virtual size_t SizeOfStyleSheets(nsMallocSizeOfFun aMallocSizeOf) const;
+
 protected:
   friend class nsNodeUtils;
 
   // Returns true if a request for DOM full-screen is currently enabled in
   // this document. This returns true if there are no windowed plugins in this
   // doc tree, and if the document is visible, and if the api is not
   // disabled by pref. aIsCallerChrome must contain the return value of
   // nsContentUtils::IsCallerChrome() from the context we're checking.
--- a/dom/base/nsDOMMemoryReporter.cpp
+++ b/dom/base/nsDOMMemoryReporter.cpp
@@ -83,24 +83,32 @@ AppendWindowURI(nsGlobalWindow *aWindow,
   // (such as about:memory) have to undo this change.
   spec.ReplaceChar('/', '\\');
 
   aStr += spec;
 
   return true;
 }
 
+struct WindowTotals
+{
+  WindowTotals() : mDom(0), mStyleSheets(0) {}
+  size_t mDom;
+  size_t mStyleSheets;
+};
+
+NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(WindowStyleSheetsMallocSizeOf,
+                                     "window/style-sheets")
+
 static void
-CollectWindowMemoryUsage(nsGlobalWindow *aWindow,
-                         nsIMemoryMultiReporterCallback *aCb,
-                         nsISupports *aClosure)
+CollectWindowReports(nsGlobalWindow *aWindow,
+                     WindowTotals *aWindowTotals,
+                     nsIMemoryMultiReporterCallback *aCb,
+                     nsISupports *aClosure)
 {
-  NS_NAMED_LITERAL_CSTRING(kWindowDesc,
-                           "Memory used by a window and the DOM within it.");
-
   // DOM window objects fall into one of three categories:
   // - "active" windows are currently either displayed in an active
   //   tab, or a child of such a window.
   // - "cached" windows are in the fastback cache.
   // - "other" windows are closed (or navigated away from w/o being
   //   cached) yet held alive by either a website or our code. The
   //   latter case may be a memory leak, but not necessarily.
   //
@@ -114,17 +122,17 @@ CollectWindowMemoryUsage(nsGlobalWindow 
   // For outer windows we simply group them all together and just show
   // the combined count and amount of memory used, which is generally
   // a constant amount per window (since all the actual data lives in
   // the inner window).
   //
   // The path we give to the reporter callback for inner windows are
   // as follows:
   //
-  //   explicit/dom/window-objects/<category>/top=<top-outer-id> (inner=<top-inner-id>)/inner-window(id=<id>, uri=<uri>)
+  //   explicit/dom+style/window-objects/<category>/top=<top-outer-id> (inner=<top-inner-id>)/inner-window(id=<id>, uri=<uri>)
   //
   // Where:
   // - <category> is active, cached, or other, as described above.
   // - <top-outer-id> is the window id (nsPIDOMWindow::WindowID()) of
   //   the top outer window (i.e. tab, or top level chrome window).
   // - <top-inner-id> is the window id of the top window's inner
   //   window.
   // - <id> is the window id of the inner window in question.
@@ -133,72 +141,92 @@ CollectWindowMemoryUsage(nsGlobalWindow 
   // Exposing the window ids is done to get logical grouping in
   // about:memory, and also for debuggability since one can get to the
   // nsGlobalWindow for a window id by calling the static method
   // nsGlobalWindow::GetInnerWindowWithId(id) (or
   // GetOuterWindowWithId(id) in a debugger.
   //
   // For outer windows we simply use:
   // 
-  //   explicit/dom/window-objects/<category>/outer-windows
+  //   explicit/dom+style/window-objects/<category>/outer-windows
   //
   // Which gives us simple counts of how many outer windows (and their
   // combined sizes) per category.
 
-  nsCAutoString str("explicit/dom/window-objects/");
+  nsCAutoString windowPath("explicit/dom+style/window-objects/");
 
   nsIDocShell *docShell = aWindow->GetDocShell();
 
   nsGlobalWindow *top = aWindow->GetTop();
-  PRInt64 windowSize = aWindow->SizeOf();
+  PRInt64 windowDOMSize = aWindow->SizeOf();
+  PRInt64 styleSheetsSize = aWindow->SizeOfStyleSheets(WindowStyleSheetsMallocSizeOf);
 
   if (docShell && aWindow->IsFrozen()) {
-    str += NS_LITERAL_CSTRING("cached/");
+    windowPath += NS_LITERAL_CSTRING("cached/");
   } else if (docShell) {
-    str += NS_LITERAL_CSTRING("active/");
+    windowPath += NS_LITERAL_CSTRING("active/");
   } else {
-    str += NS_LITERAL_CSTRING("other/");
+    windowPath += NS_LITERAL_CSTRING("other/");
   }
 
   if (aWindow->IsInnerWindow()) {
-    str += NS_LITERAL_CSTRING("top=");
+    windowPath += NS_LITERAL_CSTRING("top=");
 
     if (top) {
-      str.AppendInt(top->WindowID());
+      windowPath.AppendInt(top->WindowID());
 
       nsGlobalWindow *topInner = top->GetCurrentInnerWindowInternal();
       if (topInner) {
-        str += NS_LITERAL_CSTRING(" (inner=");
-        str.AppendInt(topInner->WindowID());
-        str += NS_LITERAL_CSTRING(")");
+        windowPath += NS_LITERAL_CSTRING(" (inner=");
+        windowPath.AppendInt(topInner->WindowID());
+        windowPath += NS_LITERAL_CSTRING(")");
       }
     } else {
-      str += NS_LITERAL_CSTRING("none");
+      windowPath += NS_LITERAL_CSTRING("none");
     }
 
-    str += NS_LITERAL_CSTRING("/inner-window(id=");
-    str.AppendInt(aWindow->WindowID());
-    str += NS_LITERAL_CSTRING(", uri=");
+    windowPath += NS_LITERAL_CSTRING("/inner-window(id=");
+    windowPath.AppendInt(aWindow->WindowID());
+    windowPath += NS_LITERAL_CSTRING(", uri=");
 
-    if (!AppendWindowURI(aWindow, str)) {
-      str += NS_LITERAL_CSTRING("[system]");
+    if (!AppendWindowURI(aWindow, windowPath)) {
+      windowPath += NS_LITERAL_CSTRING("[system]");
     }
 
-    str += NS_LITERAL_CSTRING(")");
+    windowPath += NS_LITERAL_CSTRING(")");
   } else {
     // Combine all outer windows per section (active/cached/other) as
     // they basically never contain anything of interest, and are
     // always pretty much the same size.
 
-    str += NS_LITERAL_CSTRING("outer-windows");
+    windowPath += NS_LITERAL_CSTRING("outer-windows");
   }
 
-  aCb->Callback(EmptyCString(), str, nsIMemoryReporter::KIND_HEAP,
-                nsIMemoryReporter::UNITS_BYTES, windowSize, kWindowDesc,
-                aClosure);
+  if (windowDOMSize > 0) {
+    nsCAutoString domPath(windowPath);
+    domPath += "/dom";
+    NS_NAMED_LITERAL_CSTRING(kWindowDesc,
+                             "Memory used by a window and the DOM within it.");
+    aCb->Callback(EmptyCString(), domPath, nsIMemoryReporter::KIND_HEAP,
+                  nsIMemoryReporter::UNITS_BYTES, windowDOMSize, kWindowDesc,
+                  aClosure);
+    aWindowTotals->mDom += windowDOMSize;
+  }
+
+  if (styleSheetsSize > 0) {
+    nsCAutoString styleSheetsPath(windowPath);
+    styleSheetsPath += "/style-sheets";
+    NS_NAMED_LITERAL_CSTRING(kStyleSheetsDesc,
+                             "Memory used by style sheets within a window.");
+    aCb->Callback(EmptyCString(), styleSheetsPath,
+                  nsIMemoryReporter::KIND_HEAP,
+                  nsIMemoryReporter::UNITS_BYTES, styleSheetsSize,
+                  kStyleSheetsDesc, aClosure);
+    aWindowTotals->mStyleSheets += styleSheetsSize;
+  }
 }
 
 typedef nsTArray< nsRefPtr<nsGlobalWindow> > WindowArray;
 
 static
 PLDHashOperator
 GetWindows(const PRUint64& aId, nsGlobalWindow*& aWindow, void* aClosure)
 {
@@ -218,20 +246,37 @@ nsDOMMemoryMultiReporter::CollectReports
   // Hold on to every window in memory so that window objects can't be
   // destroyed while we're calling the memory reporter callback.
   WindowArray windows;
   windowsById->Enumerate(GetWindows, &windows);
 
   // Collect window memory usage.
   nsRefPtr<nsGlobalWindow> *w = windows.Elements();
   nsRefPtr<nsGlobalWindow> *end = w + windows.Length();
+  WindowTotals windowTotals;
   for (; w != end; ++w) {
-    CollectWindowMemoryUsage(*w, aCb, aClosure);
+    CollectWindowReports(*w, &windowTotals, aCb, aClosure);
   }
 
+  NS_NAMED_LITERAL_CSTRING(kDomTotalWindowsDesc,
+    "Memory used for the DOM within windows.  This is the sum of all windows' "
+    "'dom' numbers.");
+  aCb->Callback(EmptyCString(), NS_LITERAL_CSTRING("dom-total-window"),
+                nsIMemoryReporter::KIND_OTHER,
+                nsIMemoryReporter::UNITS_BYTES, windowTotals.mDom,
+                kDomTotalWindowsDesc, aClosure);
+
+  NS_NAMED_LITERAL_CSTRING(kLayoutTotalWindowStyleSheetsDesc,
+    "Memory used for style sheets within windows.  This is the sum of all windows' "
+    "'style-sheets' numbers.");
+  aCb->Callback(EmptyCString(), NS_LITERAL_CSTRING("style-sheets-total-window"),
+                nsIMemoryReporter::KIND_OTHER,
+                nsIMemoryReporter::UNITS_BYTES, windowTotals.mStyleSheets,
+                kLayoutTotalWindowStyleSheetsDesc, aClosure);
+
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMMemoryMultiReporter::GetExplicitNonHeap(PRInt64* aAmount)
 {
   // This reporter only measures heap memory.
   *aAmount = 0;
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -10291,16 +10291,26 @@ nsGlobalWindow::SizeOf() const
     }
   }
 
   size += mNavigator ? mNavigator->SizeOf() : 0;
 
   return size;
 }
 
+size_t
+nsGlobalWindow::SizeOfStyleSheets(nsMallocSizeOfFun aMallocSizeOf) const
+{
+  size_t n = 0;
+  if (IsInnerWindow() && mDoc) {
+    n += mDoc->SizeOfStyleSheets(aMallocSizeOf);
+  }
+  return n;
+}
+
 // nsGlobalChromeWindow implementation
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalChromeWindow)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGlobalChromeWindow,
                                                   nsGlobalWindow)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mBrowserDOMWindow)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mMessageManager)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -571,16 +571,17 @@ public:
 
   static bool HasPerformanceSupport();
 
   static WindowByIdTable* GetWindowsTable() {
     return sWindowsById;
   }
 
   PRInt64 SizeOf() const;
+  size_t SizeOfStyleSheets(nsMallocSizeOfFun aMallocSizeOf) const;
 
   void UnmarkGrayTimers();
 private:
   // Enable updates for the accelerometer.
   void EnableDeviceMotionUpdates();
 
   // Disables updates for the accelerometer.
   void DisableDeviceMotionUpdates();
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -150,16 +150,18 @@ SwapToISupportsArray(SmartPtr<T>& aSrc,
   T* raw = nsnull;
   aSrc.swap(raw);
 
   nsISupports* rawSupports =
     static_cast<typename ISupportsBaseInfo<T>::ISupportsBase*>(raw);
   dest->swap(rawSupports);
 }
 
+NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(JsWorkerMallocSizeOf, "js-worker")
+
 class WorkerMemoryReporter : public nsIMemoryMultiReporter
 {
   WorkerPrivate* mWorkerPrivate;
   nsCString mAddressString;
   nsCString mPathPrefix;
 
 public:
   NS_DECL_ISUPPORTS
@@ -227,17 +229,17 @@ public:
   }
 
   NS_IMETHOD
   CollectReports(nsIMemoryMultiReporterCallback* aCallback,
                  nsISupports* aClosure)
   {
     AssertIsOnMainThread();
 
-    JS::RuntimeStats rtStats(xpc::JsMallocSizeOf, xpc::GetCompartmentName,
+    JS::RuntimeStats rtStats(JsWorkerMallocSizeOf, xpc::GetCompartmentName,
                              xpc::DestroyCompartmentName);
     nsresult rv = CollectForRuntime(/* isQuick = */false, &rtStats);
     if (NS_FAILED(rv)) {
       return rv;
     }
 
     // Always report, even if we're disabled, so that we at least get an entry
     // in about::memory.
@@ -1518,17 +1520,17 @@ public:
   }
 
   bool
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
   {
     JSAutoSuspendRequest asr(aCx);
 
     *mSucceeded = mIsQuick
-      ? JS::GetExplicitNonHeapForRuntime(JS_GetRuntime(aCx), static_cast<int64_t*>(mData), xpc::JsMallocSizeOf)
+      ? JS::GetExplicitNonHeapForRuntime(JS_GetRuntime(aCx), static_cast<int64_t*>(mData), JsWorkerMallocSizeOf)
       : JS::CollectRuntimeStats(JS_GetRuntime(aCx), static_cast<JS::RuntimeStats*>(mData));
 
     {
       MutexAutoLock lock(mMutex);
       mDone = true;
       mCondVar.Notify();
     }
 
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -1270,18 +1270,16 @@ GetCompartmentName(JSContext *cx, JSComp
 }
 
 void
 DestroyCompartmentName(void *string)
 {
     delete static_cast<nsCString*>(string);
 }
 
-NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(JsMallocSizeOf, "js")
-
 } // namespace xpc
 
 namespace {
 
 template <int N>
 inline void
 ReportMemory(const nsACString &path, PRInt32 kind, PRInt32 units,
              PRInt64 amount, const char (&desc)[N],
@@ -1720,41 +1718,43 @@ ReportJSRuntimeStats(const JS::RuntimeSt
     // should equal rtStats.gcHeapChunkTotal.
     JS_ASSERT(gcTotal == rtStats.gcHeapChunkTotal);
 }
 
 } // namespace memory
 } // namespace xpconnect
 } // namespace mozilla
 
+NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(JsMallocSizeOf, "js")
+
 class XPConnectJSCompartmentsMultiReporter : public nsIMemoryMultiReporter
 {
 public:
     NS_DECL_ISUPPORTS
 
     NS_IMETHOD CollectReports(nsIMemoryMultiReporterCallback *callback,
                               nsISupports *closure)
     {
         XPCJSRuntime *xpcrt = nsXPConnect::GetRuntimeInstance();
 
         // In the first step we get all the stats and stash them in a local
         // data structure.  In the second step we pass all the stashed stats to
         // the callback.  Separating these steps is important because the
         // callback may be a JS function, and executing JS while getting these
         // stats seems like a bad idea.
-        JS::RuntimeStats rtStats(xpc::JsMallocSizeOf, xpc::GetCompartmentName,
+        JS::RuntimeStats rtStats(JsMallocSizeOf, xpc::GetCompartmentName,
                                  xpc::DestroyCompartmentName);
         if (!JS::CollectRuntimeStats(xpcrt->GetJSRuntime(), &rtStats))
             return NS_ERROR_FAILURE;
 
         size_t xpconnect;
         {
             xpconnect =
-                xpcrt->SizeOfIncludingThis(xpc::JsMallocSizeOf) +
-                XPCWrappedNativeScope::SizeOfAllScopesIncludingThis(xpc::JsMallocSizeOf);
+                xpcrt->SizeOfIncludingThis(JsMallocSizeOf) +
+                XPCWrappedNativeScope::SizeOfAllScopesIncludingThis(JsMallocSizeOf);
         }
 
         NS_NAMED_LITERAL_CSTRING(pathPrefix, "explicit/js/");
 
         // This is the second step (see above).
         ReportJSRuntimeStats(rtStats, pathPrefix, callback, closure);
 
         ReportMemoryBytes(pathPrefix + NS_LITERAL_CSTRING("xpconnect"),
@@ -1850,17 +1850,17 @@ public:
         return NS_OK;
     }
 
     NS_IMETHOD
     GetExplicitNonHeap(PRInt64 *n)
     {
         JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->GetJSRuntime();
 
-        if (!JS::GetExplicitNonHeapForRuntime(rt, reinterpret_cast<int64_t*>(n), xpc::JsMallocSizeOf))
+        if (!JS::GetExplicitNonHeapForRuntime(rt, reinterpret_cast<int64_t*>(n), JsMallocSizeOf))
             return NS_ERROR_FAILURE;
 
         return NS_OK;
     }
 };
 
 NS_IMPL_THREADSAFE_ISUPPORTS1(XPConnectJSCompartmentsMultiReporter
                               , nsIMemoryMultiReporter
--- a/js/xpconnect/src/xpcpublic.h
+++ b/js/xpconnect/src/xpcpublic.h
@@ -214,17 +214,16 @@ bool Base64Decode(JSContext *cx, JS::Val
  * Convert an nsString to jsval, returning true on success.
  * Note, the ownership of the string buffer may be moved from str to rval.
  * If that happens, str will point to an empty string after this call.
  */
 bool StringToJsval(JSContext *cx, nsString &str, JS::Value *rval);
 
 void *GetCompartmentName(JSContext *cx, JSCompartment *c);
 void DestroyCompartmentName(void *string);
-size_t JsMallocSizeOf(const void *ptr);
 
 } // namespace xpc
 
 class nsIMemoryMultiReporterCallback;
 
 namespace mozilla {
 namespace xpconnect {
 namespace memory {
--- a/layout/base/nsPresContext.h
+++ b/layout/base/nsPresContext.h
@@ -960,19 +960,20 @@ public:
     mContainsUpdatePluginGeometryFrame = aValue;
   }
 
   bool MayHaveFixedBackgroundFrames() { return mMayHaveFixedBackgroundFrames; }
   void SetHasFixedBackgroundFrame() { mMayHaveFixedBackgroundFrames = true; }
 
   virtual NS_MUST_OVERRIDE size_t
         SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const {
-    // XXX: lots of things hang off nsPresContext and should be included in
-    // this measurement.  Bug 671299 may add them.
     return 0;
+
+    // Measurement of other members may be added later if DMD finds it is
+    // worthwhile.
   }
   virtual NS_MUST_OVERRIDE size_t
         SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const {
     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
   }
 
   bool IsRootContentDocument();
 
@@ -1313,19 +1314,27 @@ public:
 
   /**
    * Run all runnables that need to get called before the next paint.
    */
   void FlushWillPaintObservers();
 
   virtual NS_MUST_OVERRIDE size_t
         SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const MOZ_OVERRIDE {
-    // XXX: several things hang off an nsRootPresContext and should be included
-    // in this measurement.  Bug 671299 may do this.
     return nsPresContext::SizeOfExcludingThis(aMallocSizeOf);
+
+    // Measurement of the following members may be added later if DMD finds it is
+    // worthwhile:
+    // - mNotifyDidPaintTimer
+    // - mRegisteredPlugins
+    // - mWillPaintObservers
+    // - mWillPaintFallbackEvent
+    //
+    // The following member are not measured:
+    // - mUpdatePluginGeometryForFrame, because it is non-owning
   }
   virtual NS_MUST_OVERRIDE size_t
         SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const MOZ_OVERRIDE {
     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
   }
 
 protected:
   class RunWillPaintObservers : public nsRunnable {
--- a/layout/style/AnimationCommon.cpp
+++ b/layout/style/AnimationCommon.cpp
@@ -124,17 +124,23 @@ CommonAnimationManager::HasAttributeDepe
 CommonAnimationManager::MediumFeaturesChanged(nsPresContext* aPresContext)
 {
   return false;
 }
 
 /* virtual */ size_t
 CommonAnimationManager::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const
 {
-  // XXX: could measure mProperytValuePairs here.  Bug 671299 may do this.
+  // Measurement of the following members may be added later if DMD finds it is
+  // worthwhile:
+  // - mElementData
+  //
+  // The following members are not measured
+  // - mPresContext, because it's non-owning
+
   return 0;
 }
 
 /* virtual */ size_t
 CommonAnimationManager::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
 {
   return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
 }
--- a/layout/style/Declaration.cpp
+++ b/layout/style/Declaration.cpp
@@ -989,10 +989,20 @@ Declaration::EnsureMutable()
   NS_ABORT_IF_FALSE(mData, "should only be called when not expanded");
   if (!IsMutable()) {
     return new Declaration(*this);
   } else {
     return this;
   }
 }
 
+size_t
+Declaration::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
+{
+  size_t n = aMallocSizeOf(this);
+  n += mOrder.SizeOfExcludingThis(aMallocSizeOf);
+  n += mData          ? mData         ->SizeOfIncludingThis(aMallocSizeOf) : 0;
+  n += mImportantData ? mImportantData->SizeOfIncludingThis(aMallocSizeOf) : 0;
+  return n;
+}
+
 } // namespace mozilla::css
 } // namespace mozilla
--- a/layout/style/Declaration.h
+++ b/layout/style/Declaration.h
@@ -252,16 +252,18 @@ private:
                                       nsAutoString& aValue,
                                       nsAString& aResult) const;
 
 public:
   nsCSSProperty OrderValueAt(PRUint32 aValue) const {
     return nsCSSProperty(mOrder.ElementAt(aValue));
   }
 
+  size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
+
 private:
   nsAutoTArray<PRUint8, 8> mOrder;
 
   // never null, except while expanded, or before the first call to
   // InitializeEmpty or CompressFrom.
   nsAutoPtr<nsCSSCompressedDataBlock> mData;
 
   // may be null
--- a/layout/style/GroupRule.h
+++ b/layout/style/GroupRule.h
@@ -91,16 +91,21 @@ public:
   nsresult DeleteStyleRuleAt(PRUint32 aIndex);
   nsresult InsertStyleRulesAt(PRUint32 aIndex,
                               nsCOMArray<Rule>& aRules);
   nsresult ReplaceStyleRule(Rule *aOld, Rule *aNew);
 
   virtual bool UseForPresentation(nsPresContext* aPresContext,
                                     nsMediaQueryResultCacheKey& aKey) = 0;
 
+  NS_MUST_OVERRIDE size_t   // non-virtual -- it is only called by subclasses
+    SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
+  virtual size_t
+    SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const = 0;
+
 protected:
   // to help implement nsIDOMCSSRule
   nsresult AppendRulesToCssText(nsAString& aCssText);
 
   // to implement common methods on nsIDOMCSSMediaRule and
   // nsIDOMCSSMozDocumentRule
   nsresult GetCssRules(nsIDOMCSSRuleList* *aRuleList);
   nsresult InsertRule(const nsAString & aRule, PRUint32 aIndex,
--- a/layout/style/ImportRule.h
+++ b/layout/style/ImportRule.h
@@ -76,16 +76,18 @@ public:
 #endif
 
   // Rule methods
   virtual PRInt32 GetType() const;
   virtual already_AddRefed<Rule> Clone() const;
 
   void SetSheet(nsCSSStyleSheet*);
 
+  virtual size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
+
   // nsIDOMCSSRule interface
   NS_DECL_NSIDOMCSSRULE
 
   // nsIDOMCSSImportRule interface
   NS_DECL_NSIDOMCSSIMPORTRULE
 
 private:
   nsString  mURLSpec;
--- a/layout/style/NameSpaceRule.h
+++ b/layout/style/NameSpaceRule.h
@@ -79,16 +79,19 @@ public:
   // Rule methods
   virtual PRInt32 GetType() const;
   virtual already_AddRefed<Rule> Clone() const;
 
   nsIAtom* GetPrefix() const { return mPrefix; }
 
   void GetURLSpec(nsString& aURLSpec) const { aURLSpec = mURLSpec; }
 
+  virtual NS_MUST_OVERRIDE size_t
+    SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
+
   // nsIDOMCSSRule interface
   NS_DECL_NSIDOMCSSRULE
 
 private:
   nsCOMPtr<nsIAtom> mPrefix;
   nsString          mURLSpec;
 };
 
--- a/layout/style/Rule.h
+++ b/layout/style/Rule.h
@@ -124,16 +124,26 @@ public:
   // Note that this returns null for inline style rules since they aren't
   // supposed to have a DOM rule representation (and our code wouldn't work).
   virtual nsIDOMCSSRule* GetDOMRule() = 0;
 
   // to implement methods on nsIDOMCSSRule
   nsresult GetParentRule(nsIDOMCSSRule** aParentRule);
   nsresult GetParentStyleSheet(nsIDOMCSSStyleSheet** aSheet);
 
+  // This is pure virtual because all of Rule's data members are non-owning and
+  // thus measured elsewhere.
+  virtual NS_MUST_OVERRIDE size_t
+    SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const = 0;
+
+  // This is used to measure nsCOMArray<Rule>s.
+  static size_t SizeOfCOMArrayElementIncludingThis(css::Rule* aElement,
+                                                   nsMallocSizeOfFun aMallocSizeOf,
+                                                   void* aData);
+
 protected:
   nsCSSStyleSheet*  mSheet;
   GroupRule*        mParentRule;
 };
 
 } // namespace css
 } // namespace mozilla
 
--- a/layout/style/StyleRule.cpp
+++ b/layout/style/StyleRule.cpp
@@ -120,16 +120,32 @@ nsAtomList::Clone(bool aDeep) const
   if (!result)
     return nsnull;
 
   if (aDeep)
     NS_CSS_CLONE_LIST_MEMBER(nsAtomList, this, mNext, result, (false));
   return result;
 }
 
+size_t
+nsAtomList::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
+{
+  size_t n = 0;
+  const nsAtomList* a = this;
+  while (a) {
+    n += aMallocSizeOf(a);
+
+    // The following members aren't measured:
+    // - a->mAtom, because it may be shared
+
+    a = a->mNext;
+  }
+  return n;
+}
+
 nsAtomList::~nsAtomList(void)
 {
   MOZ_COUNT_DTOR(nsAtomList);
   NS_CSS_DELETE_LIST_MEMBER(nsAtomList, this, mNext);
 }
 
 nsPseudoClassList::nsPseudoClassList(nsCSSPseudoClasses::Type aType)
   : mType(aType),
@@ -199,16 +215,42 @@ nsPseudoClassList::Clone(bool aDeep) con
 
   if (aDeep)
     NS_CSS_CLONE_LIST_MEMBER(nsPseudoClassList, this, mNext, result,
                              (false));
 
   return result;
 }
 
+size_t
+nsPseudoClassList::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
+{
+  size_t n = 0;
+  const nsPseudoClassList* p = this;
+  while (p) {
+    n += aMallocSizeOf(p);
+    if (!p->u.mMemory) {
+      // do nothing
+
+    } else if (nsCSSPseudoClasses::HasStringArg(p->mType)) {
+      n += aMallocSizeOf(p->u.mString);
+
+    } else if (nsCSSPseudoClasses::HasNthPairArg(p->mType)) {
+      n += aMallocSizeOf(p->u.mNumbers);
+
+    } else {
+      NS_ASSERTION(nsCSSPseudoClasses::HasSelectorListArg(p->mType),
+                   "unexpected pseudo-class");
+      n += p->u.mSelectors->SizeOfIncludingThis(aMallocSizeOf);
+    }
+    p = p->mNext;
+  }
+  return n;
+}
+
 nsPseudoClassList::~nsPseudoClassList(void)
 {
   MOZ_COUNT_DTOR(nsPseudoClassList);
   if (nsCSSPseudoClasses::HasSelectorListArg(mType)) {
     delete u.mSelectors;
   } else if (u.mMemory) {
     NS_Free(u.mMemory);
   }
@@ -805,16 +847,44 @@ nsCSSSelector::AppendToStringWithoutComb
 
 bool
 nsCSSSelector::CanBeNamespaced(bool aIsNegated) const
 {
   return !aIsNegated ||
          (!mIDList && !mClassList && !mPseudoClassList && !mAttrList);
 }
 
+size_t
+nsCSSSelector::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
+{
+  size_t n = 0;
+  const nsCSSSelector* s = this;
+  while (s) {
+    n += aMallocSizeOf(s);
+
+    #define MEASURE(x)   n += x ? x->SizeOfIncludingThis(aMallocSizeOf) : 0;
+
+    MEASURE(s->mIDList);
+    MEASURE(s->mClassList);
+    MEASURE(s->mPseudoClassList);
+    MEASURE(s->mNegations);
+
+    // Measurement of the following members may be added later if DMD finds it is
+    // worthwhile:
+    // - s->mAttrList
+    //
+    // The following members aren't measured:
+    // - s->mLowercaseTag, because it's an atom and therefore shared
+    // - s->mCasedTag, because it's an atom and therefore shared
+
+    s = s->mNext;
+  }
+  return n;
+}
+
 // -- nsCSSSelectorList -------------------------------
 
 nsCSSSelectorList::nsCSSSelectorList(void)
   : mSelectors(nsnull),
     mWeight(0),
     mNext(nsnull)
 {
   MOZ_COUNT_CTOR(nsCSSSelectorList);
@@ -867,16 +937,29 @@ nsCSSSelectorList::Clone(bool aDeep) con
 
   if (aDeep) {
     NS_CSS_CLONE_LIST_MEMBER(nsCSSSelectorList, this, mNext, result,
                              (false));
   }
   return result;
 }
 
+size_t
+nsCSSSelectorList::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
+{
+  size_t n = 0;
+  const nsCSSSelectorList* s = this;
+  while (s) {
+    n += aMallocSizeOf(s);
+    n += s->mSelectors ? s->mSelectors->SizeOfIncludingThis(aMallocSizeOf) : 0;
+    s = s->mNext;
+  }
+  return n;
+}
+
 // -- ImportantRule ----------------------------------
 
 namespace mozilla {
 namespace css {
 
 ImportantRule::ImportantRule(Declaration* aDeclaration)
   : mDeclaration(aDeclaration)
 {
@@ -1417,10 +1500,26 @@ StyleRule::GetSelectorText(nsAString& aS
 void
 StyleRule::SetSelectorText(const nsAString& aSelectorText)
 {
   // XXX TBI - get a parser and re-parse the selectors,
   // XXX then need to re-compute the cascade
   // XXX and dirty sheet
 }
 
+/* virtual */ size_t
+StyleRule::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
+{
+  size_t n = aMallocSizeOf(this);
+  n += mSelector ? mSelector->SizeOfIncludingThis(aMallocSizeOf) : 0;
+  n += mDeclaration ? mDeclaration->SizeOfIncludingThis(aMallocSizeOf) : 0;
+
+  // Measurement of the following members may be added later if DMD finds it is
+  // worthwhile:
+  // - mImportantRule;
+  // - mDOMRule;
+
+  return n;
+}
+
+
 } // namespace css
 } // namespace mozilla
--- a/layout/style/StyleRule.h
+++ b/layout/style/StyleRule.h
@@ -65,16 +65,18 @@ struct nsAtomList {
 public:
   nsAtomList(nsIAtom* aAtom);
   nsAtomList(const nsString& aAtomValue);
   ~nsAtomList(void);
 
   /** Do a deep clone.  Should be used only on the first in the linked list. */
   nsAtomList* Clone() const { return Clone(true); }
 
+  size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
+
   nsCOMPtr<nsIAtom> mAtom;
   nsAtomList*       mNext;
 private: 
   nsAtomList* Clone(bool aDeep) const;
 
   nsAtomList(const nsAtomList& aCopy) MOZ_DELETE;
   nsAtomList& operator=(const nsAtomList& aCopy) MOZ_DELETE;
 };
@@ -86,16 +88,18 @@ public:
   nsPseudoClassList(nsCSSPseudoClasses::Type aType, const PRInt32 *aIntPair);
   nsPseudoClassList(nsCSSPseudoClasses::Type aType,
                     nsCSSSelectorList *aSelectorList /* takes ownership */);
   ~nsPseudoClassList(void);
 
   /** Do a deep clone.  Should be used only on the first in the linked list. */
   nsPseudoClassList* Clone() const { return Clone(true); }
 
+  size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
+
   union {
     // For a given value of mType, we have either:
     //   a. no value, which means mMemory is always null
     //      (if none of the conditions for (b), (c), or (d) is true)
     //   b. a string value, which means mString/mMemory is non-null
     //      (if nsCSSPseudoClasses::HasStringArg(mType))
     //   c. an integer pair value, which means mNumbers/mMemory is non-null
     //      (if nsCSSPseudoClasses::HasNthPairArg(mType))
@@ -212,16 +216,18 @@ public:
   nsCSSPseudoElements::Type PseudoType() const {
     return static_cast<nsCSSPseudoElements::Type>(mPseudoType);
   }
   void SetPseudoType(nsCSSPseudoElements::Type aType) {
     NS_ASSERTION(aType > PR_INT16_MIN && aType < PR_INT16_MAX, "Out of bounds");
     mPseudoType = static_cast<PRInt16>(aType);
   }
 
+  size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
+
   // For case-sensitive documents, mLowercaseTag is the same as mCasedTag,
   // but in case-insensitive documents (HTML) mLowercaseTag is lowercase.
   // Also, for pseudo-elements mCasedTag will be null but mLowercaseTag
   // contains their name.
   nsCOMPtr<nsIAtom> mLowercaseTag;
   nsCOMPtr<nsIAtom> mCasedTag;
   nsAtomList*     mIDList;
   nsAtomList*     mClassList;
@@ -266,16 +272,18 @@ struct nsCSSSelectorList {
    */
   void ToString(nsAString& aResult, nsCSSStyleSheet* aSheet);
 
   /**
    * Do a deep clone.  Should be used only on the first in the list.
    */
   nsCSSSelectorList* Clone() const { return Clone(true); }
 
+  size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
+
   nsCSSSelector*     mSelectors;
   PRInt32            mWeight;
   nsCSSSelectorList* mNext;
 private: 
   nsCSSSelectorList* Clone(bool aDeep) const;
 
   nsCSSSelectorList(const nsCSSSelectorList& aCopy) MOZ_DELETE;
   nsCSSSelectorList& operator=(const nsCSSSelectorList& aCopy) MOZ_DELETE;
@@ -375,16 +383,18 @@ public:
 
   // The new mapping function.
   virtual void MapRuleInfoInto(nsRuleData* aRuleData);
 
 #ifdef DEBUG
   virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const;
 #endif
 
+  virtual size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
+
 private:
   ~StyleRule();
 
 private:
   nsCSSSelectorList*      mSelector; // null for style attribute
   Declaration*            mDeclaration;
   ImportantRule*          mImportantRule; // initialized by RuleMatched
   DOMCSSStyleRule*        mDOMRule;
--- a/layout/style/nsAnimationManager.cpp
+++ b/layout/style/nsAnimationManager.cpp
@@ -430,19 +430,22 @@ nsAnimationManager::RulesMatching(AnonBo
 nsAnimationManager::RulesMatching(XULTreeRuleProcessorData* aData)
 {
 }
 #endif
 
 /* virtual */ size_t
 nsAnimationManager::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const
 {
-  // XXX: various other members in nsAnimationManager could be measured here.
-  // Bug 671299 may do this.
   return CommonAnimationManager::SizeOfExcludingThis(aMallocSizeOf);
+
+  // Measurement of the following members may be added later if DMD finds it is
+  // worthwhile:
+  // - mKeyframesRules
+  // - mPendingEvents
 }
 
 /* virtual */ size_t
 nsAnimationManager::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
 {
   return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
 }
 
--- a/layout/style/nsCSSDataBlock.cpp
+++ b/layout/style/nsCSSDataBlock.cpp
@@ -302,16 +302,30 @@ nsCSSCompressedDataBlock::~nsCSSCompress
 /* static */ nsCSSCompressedDataBlock*
 nsCSSCompressedDataBlock::CreateEmptyBlock()
 {
     nsCSSCompressedDataBlock *result = new(0) nsCSSCompressedDataBlock();
     result->SetBlockEnd(result->Block());
     return result;
 }
 
+size_t
+nsCSSCompressedDataBlock::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
+{
+    size_t n = aMallocSizeOf(this);
+
+    const char* cursor = Block();
+    const char* cursor_end = BlockEnd();
+    while (cursor < cursor_end) {
+        n += ValueAtCursor(cursor)->SizeOfExcludingThis(aMallocSizeOf);
+        cursor += CDBValueStorage_advance;
+    }
+    return n;
+}
+
 /*****************************************************************************/
 
 nsCSSExpandedDataBlock::nsCSSExpandedDataBlock()
 {
     AssertInitialState();
 }
 
 nsCSSExpandedDataBlock::~nsCSSExpandedDataBlock()
--- a/layout/style/nsCSSDataBlock.h
+++ b/layout/style/nsCSSDataBlock.h
@@ -116,16 +116,18 @@ public:
      */
     nsCSSCompressedDataBlock* Clone() const;
 
     /**
      * Create a new nsCSSCompressedDataBlock holding no declarations.
      */
     static nsCSSCompressedDataBlock* CreateEmptyBlock();
 
+    size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
+
 private:
     void* operator new(size_t aBaseSize, size_t aDataSize) {
         NS_ABORT_IF_FALSE(aBaseSize == sizeof(nsCSSCompressedDataBlock),
                           "unexpected size for nsCSSCompressedDataBlock");
         return ::operator new(aBaseSize + aDataSize);
     }
 
     /**
--- a/layout/style/nsCSSRules.cpp
+++ b/layout/style/nsCSSRules.cpp
@@ -112,16 +112,23 @@ nsresult
 Rule::GetParentStyleSheet(nsIDOMCSSStyleSheet** aSheet)
 {
   NS_ENSURE_ARG_POINTER(aSheet);
 
   NS_IF_ADDREF(*aSheet = mSheet);
   return NS_OK;
 }
 
+size_t
+Rule::SizeOfCOMArrayElementIncludingThis(css::Rule* aElement,
+                                         nsMallocSizeOfFun aMallocSizeOf,
+                                         void* aData)
+{
+  return aElement->SizeOfIncludingThis(aMallocSizeOf);
+}
 
 // -------------------------------
 // Style Rule List for group rules
 //
 
 class GroupRuleRuleList MOZ_FINAL : public nsICSSRuleList
 {
 public:
@@ -317,17 +324,25 @@ CharsetRule::GetParentStyleSheet(nsIDOMC
 }
 
 NS_IMETHODIMP
 CharsetRule::GetParentRule(nsIDOMCSSRule** aParentRule)
 {
   return Rule::GetParentRule(aParentRule);
 }
 
+/* virtual */ size_t
+CharsetRule::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
+{
+  return aMallocSizeOf(this);
 
+  // Measurement of the following members may be added later if DMD finds it is
+  // worthwhile:
+  // - mEncoding
+}
 
 // -------------------------------------------
 // ImportRule
 //
 
 ImportRule::ImportRule(nsMediaList* aMedia, const nsString& aURLSpec)
   : Rule()
   , mURLSpec(aURLSpec)
@@ -485,16 +500,30 @@ NS_IMETHODIMP
 ImportRule::GetStyleSheet(nsIDOMCSSStyleSheet * *aStyleSheet)
 {
   NS_ENSURE_ARG_POINTER(aStyleSheet);
 
   NS_IF_ADDREF(*aStyleSheet = mChildSheet);
   return NS_OK;
 }
 
+/* virtual */ size_t
+ImportRule::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
+{
+  return aMallocSizeOf(this);
+
+  // Measurement of the following members may be added later if DMD finds it is
+  // worthwhile:
+  // - mURLSpec
+  //
+  // The following members are not measured:
+  // - mMedia, because it is measured via nsCSSStyleSheet::mMedia
+  // - mChildSheet, because it is measured via nsCSSStyleSheetInner::mSheets
+}
+
 } // namespace css
 } // namespace mozilla
 
 // must be outside the namespace
 DOMCI_DATA(CSSImportRule, css::ImportRule)
 
 static bool
 CloneRuleInto(css::Rule* aRule, void* aArray)
@@ -690,16 +719,27 @@ GroupRule::DeleteRule(PRUint32 aIndex)
     return NS_ERROR_DOM_INDEX_SIZE_ERR;
 
   NS_ASSERTION(PRUint32(mRules.Count()) <= PR_INT32_MAX,
                "Too many style rules!");
 
   return mSheet->DeleteRuleFromGroup(this, aIndex);
 }
 
+/* virtual */ size_t
+GroupRule::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const
+{
+  return mRules.SizeOfExcludingThis(Rule::SizeOfCOMArrayElementIncludingThis,
+                                    aMallocSizeOf);
+
+  // Measurement of the following members may be added later if DMD finds it is
+  // worthwhile:
+  // - mRuleCollection
+}
+
 
 // -------------------------------------------
 // nsICSSMediaRule
 //
 MediaRule::MediaRule()
 {
 }
 
@@ -861,16 +901,29 @@ MediaRule::UseForPresentation(nsPresCont
                                    nsMediaQueryResultCacheKey& aKey)
 {
   if (mMedia) {
     return mMedia->Matches(aPresContext, &aKey);
   }
   return true;
 }
 
+/* virtual */ size_t
+MediaRule::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
+{
+  size_t n = aMallocSizeOf(this);
+  n += GroupRule::SizeOfExcludingThis(aMallocSizeOf);
+
+  // Measurement of the following members may be added later if DMD finds it is
+  // worthwhile:
+  // - mMedia
+
+  return n;
+}
+
 } // namespace css
 } // namespace mozilla
 
 // Must be outside namespace
 DOMCI_DATA(CSSMediaRule, css::MediaRule)
 
 namespace mozilla {
 namespace css {
@@ -1070,16 +1123,29 @@ DocumentRule::UseForPresentation(nsPresC
   return false;
 }
 
 DocumentRule::URL::~URL()
 {
   NS_CSS_DELETE_LIST_MEMBER(DocumentRule::URL, this, next);
 }
 
+/* virtual */ size_t
+DocumentRule::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
+{
+  size_t n = aMallocSizeOf(this);
+  n += GroupRule::SizeOfExcludingThis(aMallocSizeOf);
+
+  // Measurement of the following members may be added later if DMD finds it is
+  // worthwhile:
+  // - mURLs
+
+  return n;
+}
+
 } // namespace css
 } // namespace mozilla
 
 // Must be outside namespace
 DOMCI_DATA(CSSMozDocumentRule, css::DocumentRule)
 
 // -------------------------------------------
 // NameSpaceRule
@@ -1194,16 +1260,28 @@ NameSpaceRule::GetParentStyleSheet(nsIDO
 }
 
 NS_IMETHODIMP
 NameSpaceRule::GetParentRule(nsIDOMCSSRule** aParentRule)
 {
   return Rule::GetParentRule(aParentRule);
 }
 
+/* virtual */ size_t
+NameSpaceRule::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
+{
+  return aMallocSizeOf(this);
+
+  // Measurement of the following members may be added later if DMD finds it is
+  // worthwhile:
+  // - mPrefix
+  // - mURLSpec
+}
+
+
 } // namespace css
 } // namespace mozilla
 
 // Must be outside namespace
 DOMCI_DATA(CSSNameSpaceRule, css::NameSpaceRule)
 
 // -------------------------------------------
 // nsCSSFontFaceStyleDecl and related routines
@@ -1655,16 +1733,27 @@ nsCSSFontFaceRule::GetDesc(nsCSSFontDesc
 {
   NS_PRECONDITION(aDescID > eCSSFontDesc_UNKNOWN &&
                   aDescID < eCSSFontDesc_COUNT,
                   "aDescID out of range in nsCSSFontFaceRule::GetDesc");
 
   aValue = mDecl.*nsCSSFontFaceStyleDecl::Fields[aDescID];
 }
 
+/* virtual */ size_t
+nsCSSFontFaceRule::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
+{
+  return aMallocSizeOf(this);
+
+  // Measurement of the following members may be added later if DMD finds it is
+  // worthwhile:
+  // - mDecl
+}
+
+
 // -------------------------------------------
 // nsCSSKeyframeStyleDeclaration
 //
 
 nsCSSKeyframeStyleDeclaration::nsCSSKeyframeStyleDeclaration(nsCSSKeyframeRule *aRule)
   : mRule(aRule)
 {
 }
@@ -1877,16 +1966,29 @@ nsCSSKeyframeRule::ChangeDeclaration(css
 {
   mDeclaration = aDeclaration;
 
   if (mSheet) {
     mSheet->SetModifiedByChildRule();
   }
 }
 
+/* virtual */ size_t
+nsCSSKeyframeRule::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
+{
+  return aMallocSizeOf(this);
+
+  // Measurement of the following members may be added later if DMD finds it is
+  // worthwhile:
+  // - mKeys
+  // - mDeclaration
+  // - mDOMDeclaration
+}
+
+
 // -------------------------------------------
 // nsCSSKeyframesRule
 //
 
 nsCSSKeyframesRule::nsCSSKeyframesRule(const nsCSSKeyframesRule& aCopy)
   // copy everything except our reference count.  GroupRule's copy
   // constructor also doesn't copy the lazily-constructed
   // mRuleCollection.
@@ -2074,8 +2176,22 @@ nsCSSKeyframesRule::FindRule(const nsASt
 /* virtual */ bool
 nsCSSKeyframesRule::UseForPresentation(nsPresContext* aPresContext,
                                        nsMediaQueryResultCacheKey& aKey)
 {
   NS_ABORT_IF_FALSE(false, "should not be called");
   return false;
 }
 
+/* virtual */ size_t
+nsCSSKeyframesRule::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
+{
+  size_t n = aMallocSizeOf(this);
+  n += GroupRule::SizeOfExcludingThis(aMallocSizeOf);
+
+  // Measurement of the following members may be added later if DMD finds it is
+  // worthwhile:
+  // - mName
+
+  return n;
+}
+
+
--- a/layout/style/nsCSSRules.h
+++ b/layout/style/nsCSSRules.h
@@ -106,16 +106,19 @@ public:
 
   // rest of GroupRule
   virtual bool UseForPresentation(nsPresContext* aPresContext,
                                     nsMediaQueryResultCacheKey& aKey);
 
   // @media rule methods
   nsresult SetMedia(nsMediaList* aMedia);
   
+  virtual NS_MUST_OVERRIDE size_t
+    SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
+
 protected:
   nsRefPtr<nsMediaList> mMedia;
 };
 
 class DocumentRule MOZ_FINAL : public GroupRule,
                                public nsIDOMCSSMozDocumentRule
 {
 public:
@@ -169,16 +172,19 @@ public:
       , next(aOther.next ? new URL(*aOther.next) : nsnull)
     {
     }
     ~URL();
   };
 
   void SetURLs(URL *aURLs) { mURLs = aURLs; }
 
+  virtual NS_MUST_OVERRIDE size_t
+    SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
+
 protected:
   nsAutoPtr<URL> mURLs; // linked list of |struct URL| above.
 };
 
 } // namespace css
 } // namespace mozilla
 
 // A nsCSSFontFaceStyleDecl is always embedded in a nsCSSFontFaceRule.
@@ -236,16 +242,18 @@ public:
   NS_DECL_NSIDOMCSSRULE
 
   // nsIDOMCSSFontFaceRule interface
   NS_DECL_NSIDOMCSSFONTFACERULE
 
   void SetDesc(nsCSSFontDesc aDescID, nsCSSValue const & aValue);
   void GetDesc(nsCSSFontDesc aDescID, nsCSSValue & aValue);
 
+  virtual size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
+
 protected:
   friend class nsCSSFontFaceStyleDecl;
   nsCSSFontFaceStyleDecl mDecl;
 };
 
 // nsFontFaceRuleContainer - used for associating sheet type with 
 // specific @font-face rules
 struct nsFontFaceRuleContainer {
@@ -296,16 +304,18 @@ public:
 
   // nsIDOMCSSRule interface
   NS_DECL_NSIDOMCSSRULE
 
   // nsIDOMCSSCharsetRule methods
   NS_IMETHOD GetEncoding(nsAString& aEncoding);
   NS_IMETHOD SetEncoding(const nsAString& aEncoding);
 
+  virtual size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
+
 private:
   nsString  mEncoding;
 };
 
 } // namespace css
 } // namespace mozilla
 
 class nsCSSKeyframeRule;
@@ -373,16 +383,18 @@ public:
   // nsIDOMMozCSSKeyframeRule interface
   NS_DECL_NSIDOMMOZCSSKEYFRAMERULE
 
   const nsTArray<float>& GetKeys() const     { return mKeys; }
   mozilla::css::Declaration* Declaration()   { return mDeclaration; }
 
   void ChangeDeclaration(mozilla::css::Declaration* aDeclaration);
 
+  virtual size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
+
 private:
   nsAutoTArray<float, 1>                     mKeys;
   nsAutoPtr<mozilla::css::Declaration>       mDeclaration;
   // lazily created when needed:
   nsRefPtr<nsCSSKeyframeStyleDeclaration>    mDOMDeclaration;
 };
 
 class nsCSSKeyframesRule MOZ_FINAL : public mozilla::css::GroupRule,
@@ -419,15 +431,17 @@ public:
   NS_DECL_NSIDOMMOZCSSKEYFRAMESRULE
 
   // rest of GroupRule
   virtual bool UseForPresentation(nsPresContext* aPresContext,
                                     nsMediaQueryResultCacheKey& aKey);
 
   const nsString& GetName() { return mName; }
 
+  virtual size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
+
 private:
   PRUint32 FindRuleIndexForKey(const nsAString& aKey);
 
   nsString                                   mName;
 };
 
 #endif /* !defined(nsCSSRules_h_) */
--- a/layout/style/nsCSSStyleSheet.cpp
+++ b/layout/style/nsCSSStyleSheet.cpp
@@ -869,16 +869,40 @@ nsCSSStyleSheet::RebuildChildList(css::R
   }
 
   (*builder->sheetSlot) = cssSheet;
   builder->SetParentLinks(*builder->sheetSlot);
   builder->sheetSlot = &(*builder->sheetSlot)->mNext;
   return true;
 }
 
+size_t
+nsCSSStyleSheet::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
+{
+  size_t n = 0;
+  const nsCSSStyleSheet* s = this;
+  while (s) {
+    n += aMallocSizeOf(s);
+    n += s->mInner->SizeOfIncludingThis(aMallocSizeOf);
+
+    // Measurement of the following members may be added later if DMD finds it is
+    // worthwhile:
+    // - s->mTitle
+    // - s->mMedia
+    // - s->mRuleCollection
+    // - s->mRuleProcessors
+    //
+    // The following members are not measured:
+    // - s->mOwnerRule, because it's non-owning
+
+    s = s->mNext;
+  }
+  return n;
+}
+
 nsCSSStyleSheetInner::nsCSSStyleSheetInner(nsCSSStyleSheetInner& aCopy,
                                            nsCSSStyleSheet* aPrimarySheet)
   : mSheets(),
     mSheetURI(aCopy.mSheetURI),
     mOriginalSheetURI(aCopy.mOriginalSheetURI),
     mBaseURI(aCopy.mBaseURI),
     mPrincipal(aCopy.mPrincipal),
     mComplete(aCopy.mComplete)
@@ -978,16 +1002,38 @@ nsCSSStyleSheetInner::CreateNamespaceMap
   mNameSpaceMap = nsXMLNameSpaceMap::Create(false);
   NS_ENSURE_TRUE(mNameSpaceMap, NS_ERROR_OUT_OF_MEMORY);
   // Override the default namespace map behavior for the null prefix to
   // return the wildcard namespace instead of the null namespace.
   mNameSpaceMap->AddPrefix(nsnull, kNameSpaceID_Unknown);
   return NS_OK;
 }
 
+size_t
+nsCSSStyleSheetInner::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
+{
+  size_t n = aMallocSizeOf(this);
+  n += mOrderedRules.SizeOfExcludingThis(css::Rule::SizeOfCOMArrayElementIncludingThis,
+                                         aMallocSizeOf);
+  n += mFirstChild ? mFirstChild->SizeOfIncludingThis(aMallocSizeOf) : 0;
+
+  // Measurement of the following members may be added later if DMD finds it is
+  // worthwhile:
+  // - mSheetURI
+  // - mOriginalSheetURI
+  // - mBaseURI
+  // - mPrincipal
+  // - mNameSpaceMap
+  //
+  // The following members are not measured:
+  // - mSheets, because it's non-owning
+
+  return n;
+}
+
 // -------------------------------
 // CSS Style Sheet
 //
 
 nsCSSStyleSheet::nsCSSStyleSheet()
   : mTitle(), 
     mParent(nsnull),
     mOwnerRule(nsnull),
--- a/layout/style/nsCSSStyleSheet.h
+++ b/layout/style/nsCSSStyleSheet.h
@@ -94,16 +94,18 @@ private:
   void AddSheet(nsCSSStyleSheet* aSheet);
   void RemoveSheet(nsCSSStyleSheet* aSheet);
 
   void RebuildNameSpaces();
 
   // Create a new namespace map
   nsresult CreateNamespaceMap();
 
+  size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
+
   nsAutoTArray<nsCSSStyleSheet*, 8> mSheets;
   nsCOMPtr<nsIURI>       mSheetURI; // for error reports, etc.
   nsCOMPtr<nsIURI>       mOriginalSheetURI;  // for GetHref.  Can be null.
   nsCOMPtr<nsIURI>       mBaseURI; // for resolving relative URIs
   nsCOMPtr<nsIPrincipal> mPrincipal;
   nsCOMArray<mozilla::css::Rule> mOrderedRules;
   nsAutoPtr<nsXMLNameSpaceMap> mNameSpaceMap;
   // Linked list of child sheets.  This is al fundamentally broken, because
@@ -261,16 +263,18 @@ public:
 
   // nsIDOMCSSStyleSheet interface
   NS_DECL_NSIDOMCSSSTYLESHEET
 
   // Function used as a callback to rebuild our inner's child sheet
   // list after we clone a unique inner for ourselves.
   static bool RebuildChildList(mozilla::css::Rule* aRule, void* aBuilder);
 
+  size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
+
 private:
   nsCSSStyleSheet(const nsCSSStyleSheet& aCopy,
                   nsCSSStyleSheet* aParentToUse,
                   mozilla::css::ImportRule* aOwnerRuleToUse,
                   nsIDocument* aDocumentToUse,
                   nsIDOMNode* aOwningNodeToUse);
 
   nsCSSStyleSheet(const nsCSSStyleSheet& aCopy) MOZ_DELETE;
--- a/layout/style/nsCSSValue.cpp
+++ b/layout/style/nsCSSValue.cpp
@@ -1109,16 +1109,151 @@ nsCSSValue::AppendToString(nsCSSProperty
     case eCSSUnit_Hertz:        aResult.AppendLiteral("Hz");   break;
     case eCSSUnit_Kilohertz:    aResult.AppendLiteral("kHz");  break;
 
     case eCSSUnit_Seconds:      aResult.Append(PRUnichar('s'));    break;
     case eCSSUnit_Milliseconds: aResult.AppendLiteral("ms");   break;
   }
 }
 
+size_t
+nsCSSValue::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const
+{
+  size_t n = 0;
+
+  switch (GetUnit()) {
+    // No value: nothing extra to measure.
+    case eCSSUnit_Null:
+    case eCSSUnit_Auto:
+    case eCSSUnit_Inherit:
+    case eCSSUnit_Initial:
+    case eCSSUnit_None:
+    case eCSSUnit_Normal:
+    case eCSSUnit_System_Font:
+    case eCSSUnit_All:
+    case eCSSUnit_Dummy:
+    case eCSSUnit_DummyInherit:
+      break;
+
+    // String
+    case eCSSUnit_String:
+    case eCSSUnit_Ident:
+    case eCSSUnit_Families:
+    case eCSSUnit_Attr:
+    case eCSSUnit_Local_Font:
+    case eCSSUnit_Font_Format:
+    case eCSSUnit_Element:
+      n += mValue.mString->SizeOfIncludingThisIfUnshared(aMallocSizeOf);
+      break;
+
+    // Array
+    case eCSSUnit_Array:
+    case eCSSUnit_Counter:
+    case eCSSUnit_Counters:
+    case eCSSUnit_Cubic_Bezier:
+    case eCSSUnit_Steps:
+    case eCSSUnit_Function:
+    case eCSSUnit_Calc:
+    case eCSSUnit_Calc_Plus:
+    case eCSSUnit_Calc_Minus:
+    case eCSSUnit_Calc_Times_L:
+    case eCSSUnit_Calc_Times_R:
+    case eCSSUnit_Calc_Divided:
+      break;
+
+    // URL
+    case eCSSUnit_URL:
+      n += mValue.mURL->SizeOfIncludingThis(aMallocSizeOf);
+      break;
+
+    // Image
+    case eCSSUnit_Image:
+      // Not yet measured.  Measurement may be added later if DMD finds it
+      // worthwhile.
+      break;
+
+    // Gradient
+    case eCSSUnit_Gradient:
+      n += mValue.mGradient->SizeOfIncludingThis(aMallocSizeOf);
+      break;
+
+    // Pair
+    case eCSSUnit_Pair:
+      n += mValue.mPair->SizeOfIncludingThis(aMallocSizeOf);
+      break;
+
+    // Triplet
+    case eCSSUnit_Triplet:
+      n += mValue.mTriplet->SizeOfIncludingThis(aMallocSizeOf);
+      break;
+
+    // Rect
+    case eCSSUnit_Rect:
+      n += mValue.mRect->SizeOfIncludingThis(aMallocSizeOf);
+      break;
+
+    // List
+    case eCSSUnit_List:
+      n += mValue.mList->SizeOfIncludingThis(aMallocSizeOf);
+      break;
+
+    // ListDep: not measured because it's non-owning.
+    case eCSSUnit_ListDep:
+      break;
+
+    // PairList
+    case eCSSUnit_PairList:
+      n += mValue.mPairList->SizeOfIncludingThis(aMallocSizeOf);
+      break;
+
+    // PairListDep: not measured because it's non-owning.
+    case eCSSUnit_PairListDep:
+      break;
+
+    // Int: nothing extra to measure.
+    case eCSSUnit_Integer:
+    case eCSSUnit_Enumerated:
+    case eCSSUnit_EnumColor:
+      break;
+
+    // Color: nothing extra to measure.
+    case eCSSUnit_Color:
+      break;
+
+    // Float: nothing extra to measure.
+    case eCSSUnit_Percent:
+    case eCSSUnit_Number:
+    case eCSSUnit_PhysicalMillimeter:
+    case eCSSUnit_EM:
+    case eCSSUnit_XHeight:
+    case eCSSUnit_Char:
+    case eCSSUnit_RootEM:
+    case eCSSUnit_Point:
+    case eCSSUnit_Inch:
+    case eCSSUnit_Millimeter:
+    case eCSSUnit_Centimeter:
+    case eCSSUnit_Pica:
+    case eCSSUnit_Pixel:
+    case eCSSUnit_Degree:
+    case eCSSUnit_Grad:
+    case eCSSUnit_Radian:
+    case eCSSUnit_Hertz:
+    case eCSSUnit_Kilohertz:
+    case eCSSUnit_Seconds:
+    case eCSSUnit_Milliseconds:
+      break;
+
+    default:
+      NS_ABORT_IF_FALSE(false, "bad nsCSSUnit");
+      break;
+  }
+
+  return n;
+}
+
 // --- nsCSSValueList -----------------
 
 nsCSSValueList::~nsCSSValueList()
 {
   MOZ_COUNT_DTOR(nsCSSValueList);
   NS_CSS_DELETE_LIST_MEMBER(nsCSSValueList, this, mNext);
 }
 
@@ -1170,16 +1305,38 @@ nsCSSValueList::operator==(const nsCSSVa
   const nsCSSValueList *p1 = this, *p2 = &aOther;
   for ( ; p1 && p2; p1 = p1->mNext, p2 = p2->mNext) {
     if (p1->mValue != p2->mValue)
       return false;
   }
   return !p1 && !p2; // true if same length, false otherwise
 }
 
+size_t
+nsCSSValueList::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
+{
+  size_t n = 0;
+  const nsCSSValueList* v = this;
+  while (v) {
+    n += aMallocSizeOf(v);
+    n += v->mValue.SizeOfExcludingThis(aMallocSizeOf);
+    v = v->mNext;
+  }
+  return n;
+}
+
+size_t
+nsCSSValueList_heap::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
+{
+  size_t n = aMallocSizeOf(this);
+  n += mValue.SizeOfExcludingThis(aMallocSizeOf);
+  n += mNext ? mNext->SizeOfIncludingThis(aMallocSizeOf) : 0;
+  return n;
+}
+
 // --- nsCSSRect -----------------
 
 nsCSSRect::nsCSSRect(void)
 {
   MOZ_COUNT_CTOR(nsCSSRect);
 }
 
 nsCSSRect::nsCSSRect(const nsCSSRect& aCopy)
@@ -1234,16 +1391,27 @@ nsCSSRect::AppendToString(nsCSSProperty 
 void nsCSSRect::SetAllSidesTo(const nsCSSValue& aValue)
 {
   mTop = aValue;
   mRight = aValue;
   mBottom = aValue;
   mLeft = aValue;
 }
 
+size_t
+nsCSSRect_heap::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
+{
+  size_t n = aMallocSizeOf(this);
+  n += mTop   .SizeOfExcludingThis(aMallocSizeOf);
+  n += mRight .SizeOfExcludingThis(aMallocSizeOf);
+  n += mBottom.SizeOfExcludingThis(aMallocSizeOf);
+  n += mLeft  .SizeOfExcludingThis(aMallocSizeOf);
+  return n;
+}
+
 PR_STATIC_ASSERT(NS_SIDE_TOP == 0 && NS_SIDE_RIGHT == 1 &&
                  NS_SIDE_BOTTOM == 2 && NS_SIDE_LEFT == 3);
 
 /* static */ const nsCSSRect::side_type nsCSSRect::sides[4] = {
   &nsCSSRect::mTop,
   &nsCSSRect::mRight,
   &nsCSSRect::mBottom,
   &nsCSSRect::mLeft,
@@ -1257,33 +1425,61 @@ nsCSSValuePair::AppendToString(nsCSSProp
 {
   mXValue.AppendToString(aProperty, aResult);
   if (mYValue.GetUnit() != eCSSUnit_Null) {
     aResult.Append(PRUnichar(' '));
     mYValue.AppendToString(aProperty, aResult);
   }
 }
 
-// --- nsCSSValueTriple -----------------
+size_t
+nsCSSValuePair::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const
+{
+  size_t n = 0;
+  n += mXValue.SizeOfExcludingThis(aMallocSizeOf);
+  n += mYValue.SizeOfExcludingThis(aMallocSizeOf);
+  return n;
+}
+
+size_t
+nsCSSValuePair_heap::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
+{
+  size_t n = aMallocSizeOf(this);
+  n += mXValue.SizeOfExcludingThis(aMallocSizeOf);
+  n += mYValue.SizeOfExcludingThis(aMallocSizeOf);
+  return n;
+}
+
+// --- nsCSSValueTriplet -----------------
 
 void
 nsCSSValueTriplet::AppendToString(nsCSSProperty aProperty,
                                nsAString& aResult) const
 {
     mXValue.AppendToString(aProperty, aResult);
     if (mYValue.GetUnit() != eCSSUnit_Null) {
         aResult.Append(PRUnichar(' '));
         mYValue.AppendToString(aProperty, aResult);
         if (mZValue.GetUnit() != eCSSUnit_Null) {
             aResult.Append(PRUnichar(' '));
             mZValue.AppendToString(aProperty, aResult);
         }
     }
 }
 
+size_t
+nsCSSValueTriplet_heap::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
+{
+  size_t n = aMallocSizeOf(this);
+  n += mXValue.SizeOfExcludingThis(aMallocSizeOf);
+  n += mYValue.SizeOfExcludingThis(aMallocSizeOf);
+  n += mZValue.SizeOfExcludingThis(aMallocSizeOf);
+  return n;
+}
+
 // --- nsCSSValuePairList -----------------
 
 nsCSSValuePairList::~nsCSSValuePairList()
 {
   MOZ_COUNT_DTOR(nsCSSValuePairList);
   NS_CSS_DELETE_LIST_MEMBER(nsCSSValuePairList, this, mNext);
 }
 
@@ -1337,16 +1533,50 @@ nsCSSValuePairList::operator==(const nsC
   for ( ; p1 && p2; p1 = p1->mNext, p2 = p2->mNext) {
     if (p1->mXValue != p2->mXValue ||
         p1->mYValue != p2->mYValue)
       return false;
   }
   return !p1 && !p2; // true if same length, false otherwise
 }
 
+size_t
+nsCSSValuePairList::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
+{
+  size_t n = 0;
+  const nsCSSValuePairList* v = this;
+  while (v) {
+    n += aMallocSizeOf(v);
+    n += v->mXValue.SizeOfExcludingThis(aMallocSizeOf);
+    n += v->mYValue.SizeOfExcludingThis(aMallocSizeOf);
+    v = v->mNext;
+  }
+  return n;
+}
+
+size_t
+nsCSSValuePairList_heap::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
+{
+  size_t n = aMallocSizeOf(this);
+  n += mXValue.SizeOfExcludingThis(aMallocSizeOf);
+  n += mYValue.SizeOfExcludingThis(aMallocSizeOf);
+  n += mNext ? mNext->SizeOfIncludingThis(aMallocSizeOf) : 0;
+  return n;
+}
+
+size_t
+nsCSSValue::Array::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
+{
+  size_t n = aMallocSizeOf(this);
+  for (size_t i = 0; i < mCount; i++) {
+    n += mArray[i].SizeOfExcludingThis(aMallocSizeOf);
+  }
+  return n;
+}
+
 nsCSSValue::URL::URL(nsIURI* aURI, nsStringBuffer* aString,
                      nsIURI* aReferrer, nsIPrincipal* aOriginPrincipal)
   : mURI(aURI),
     mString(aString),
     mReferrer(aReferrer),
     mOriginPrincipal(aOriginPrincipal),
     mURIResolved(true)
 {
@@ -1413,16 +1643,34 @@ nsCSSValue::URL::GetURI() const
     NS_NewURI(getter_AddRefs(newURI),
               NS_ConvertUTF16toUTF8(GetBufferValue(mString)), nsnull, mURI);
     newURI.swap(mURI);
   }
 
   return mURI;
 }
 
+size_t
+nsCSSValue::URL::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
+{
+  size_t n = aMallocSizeOf(this);
+
+  // This string is unshared.
+  n += mString->SizeOfIncludingThisMustBeUnshared(aMallocSizeOf);
+
+  // Measurement of the following members may be added later if DMD finds it is
+  // worthwhile:
+  // - mURI
+  // - mReferrer
+  // - mOriginPrincipal
+
+  return n;
+}
+
+
 nsCSSValue::Image::Image(nsIURI* aURI, nsStringBuffer* aString,
                          nsIURI* aReferrer, nsIPrincipal* aOriginPrincipal,
                          nsIDocument* aDocument)
   : URL(aURI, aString, aReferrer, aOriginPrincipal)
 {
   if (aDocument->GetOriginalDocument()) {
     aDocument = aDocument->GetOriginalDocument();
   }
@@ -1453,28 +1701,52 @@ nsCSSValueGradientStop::nsCSSValueGradie
   MOZ_COUNT_CTOR(nsCSSValueGradientStop);
 }
 
 nsCSSValueGradientStop::~nsCSSValueGradientStop()
 {
   MOZ_COUNT_DTOR(nsCSSValueGradientStop);
 }
 
+size_t
+nsCSSValueGradientStop::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const
+{
+  size_t n = 0;
+  n += mLocation.SizeOfExcludingThis(aMallocSizeOf);
+  n += mColor   .SizeOfExcludingThis(aMallocSizeOf);
+  return n;
+}
+
 nsCSSValueGradient::nsCSSValueGradient(bool aIsRadial,
                                        bool aIsRepeating)
   : mIsRadial(aIsRadial),
     mIsRepeating(aIsRepeating),
     mIsToCorner(false),
     mBgPos(eCSSUnit_None),
     mAngle(eCSSUnit_None),
     mRadialShape(eCSSUnit_None),
     mRadialSize(eCSSUnit_None)
 {
 }
 
+size_t
+nsCSSValueGradient::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
+{
+  size_t n = aMallocSizeOf(this);
+  n += mBgPos      .SizeOfExcludingThis(aMallocSizeOf);
+  n += mAngle      .SizeOfExcludingThis(aMallocSizeOf);
+  n += mRadialShape.SizeOfExcludingThis(aMallocSizeOf);
+  n += mRadialSize .SizeOfExcludingThis(aMallocSizeOf);
+  n += mStops      .SizeOfExcludingThis(aMallocSizeOf);
+  for (PRUint32 i = 0; i < mStops.Length(); i++) {
+    n += mStops[i].SizeOfExcludingThis(aMallocSizeOf);
+  }
+  return n;
+}
+
 // --- nsCSSCornerSizes -----------------
 
 nsCSSCornerSizes::nsCSSCornerSizes(void)
 {
   MOZ_COUNT_CTOR(nsCSSCornerSizes);
 }
 
 nsCSSCornerSizes::nsCSSCornerSizes(const nsCSSCornerSizes& aCopy)
--- a/layout/style/nsCSSValue.h
+++ b/layout/style/nsCSSValue.h
@@ -449,16 +449,18 @@ public:
   // Checks if this is a function value with the specified function id.
   bool EqualsFunction(nsCSSKeyword aFunctionId) const;
 
   // Returns an already addrefed buffer.  Can return null on allocation
   // failure.
   static already_AddRefed<nsStringBuffer>
     BufferFromString(const nsString& aValue);
 
+  size_t SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
+
   struct URL {
     // Methods are not inline because using an nsIPrincipal means requiring
     // caps, which leads to REQUIRES hell, since this header is included all
     // over.
 
     // For both constructors aString must not be null.
     // For both constructors aOriginPrincipal must not be null.
     // Construct with a base URI; this will create the actual URI lazily from
@@ -476,16 +478,18 @@ public:
     // URIEquals only compares URIs and principals (unlike operator==, which
     // also compares the original strings).  URIEquals also assumes that the
     // mURI member of both URL objects is non-null.  Do NOT call this method
     // unless you're sure this is the case.
     bool URIEquals(const URL& aOther) const;
 
     nsIURI* GetURI() const;
 
+    size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
+
   private:
     // If mURIResolved is false, mURI stores the base URI.
     // If mURIResolved is true, mURI stores the URI we resolve to; this may be
     // null if the URI is invalid.
     mutable nsCOMPtr<nsIURI> mURI;
   public:
     nsStringBuffer* mString; // Could use nsRefPtr, but it'd add useless
                              // null-checks; this is never null.
@@ -539,17 +543,17 @@ protected:
     nsCSSValueGradient* mGradient;
     nsCSSValuePair_heap* mPair;
     nsCSSRect_heap* mRect;
     nsCSSValueTriplet_heap* mTriplet;
     nsCSSValueList_heap* mList;
     nsCSSValueList* mListDependent;
     nsCSSValuePairList_heap* mPairList;
     nsCSSValuePairList* mPairListDependent;
-  }         mValue;
+  } mValue;
 };
 
 struct nsCSSValue::Array {
 
   // return |Array| with reference count of zero
   static Array* Create(size_t aItemCount) {
     return new (aItemCount) Array(aItemCount);
   }
@@ -637,16 +641,18 @@ private:
   ~Array()
   {
     MOZ_COUNT_DTOR(nsCSSValue::Array);
     CSSVALUE_LIST_FOR_EXTRA_VALUES(val) {
       val->~nsCSSValue();
     }
   }
 
+  size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
+
 #undef CSSVALUE_LIST_FOR_EXTRA_VALUES
 
 private:
   Array(const Array& aOther) MOZ_DELETE;
   Array& operator=(const Array& aOther) MOZ_DELETE;
 };
 
 // Prefer nsCSSValue::Array for lists of fixed size.
@@ -657,32 +663,36 @@ struct nsCSSValueList {
   nsCSSValueList* Clone() const;  // makes a deep copy
   void CloneInto(nsCSSValueList* aList) const; // makes a deep copy into aList
   void AppendToString(nsCSSProperty aProperty, nsAString& aResult) const;
 
   bool operator==(nsCSSValueList const& aOther) const;
   bool operator!=(const nsCSSValueList& aOther) const
   { return !(*this == aOther); }
 
+  size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
+
   nsCSSValue      mValue;
   nsCSSValueList* mNext;
 
 private:
   nsCSSValueList(const nsCSSValueList& aCopy) // makes a shallow copy
     : mValue(aCopy.mValue), mNext(nsnull)
   {
     MOZ_COUNT_CTOR(nsCSSValueList);
   }
 };
 
 // nsCSSValueList_heap differs from nsCSSValueList only in being
 // refcounted.  It should not be necessary to use this class directly;
 // it's an implementation detail of nsCSSValue.
 struct nsCSSValueList_heap : public nsCSSValueList {
   NS_INLINE_DECL_REFCOUNTING(nsCSSValueList_heap)
+
+  size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
 };
 
 // This has to be here so that the relationship between nsCSSValueList
 // and nsCSSValueList_heap is visible.
 inline nsCSSValueList*
 nsCSSValue::GetListValue()
 {
   if (mUnit == eCSSUnit_List)
@@ -751,16 +761,18 @@ struct nsCSSRect {
   static const side_type sides[4];
 };
 
 // nsCSSRect_heap differs from nsCSSRect only in being
 // refcounted.  It should not be necessary to use this class directly;
 // it's an implementation detail of nsCSSValue.
 struct nsCSSRect_heap : public nsCSSRect {
   NS_INLINE_DECL_REFCOUNTING(nsCSSRect_heap)
+
+  size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
 };
 
 // This has to be here so that the relationship between nsCSSRect
 // and nsCSSRect_heap is visible.
 inline nsCSSRect&
 nsCSSValue::GetRectValue()
 {
   NS_ABORT_IF_FALSE(mUnit == eCSSUnit_Rect, "not a rect value");
@@ -821,30 +833,34 @@ struct nsCSSValuePair {
 
   bool HasValue() const {
     return mXValue.GetUnit() != eCSSUnit_Null ||
            mYValue.GetUnit() != eCSSUnit_Null;
   }
 
   void AppendToString(nsCSSProperty aProperty, nsAString& aResult) const;
 
+  size_t SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
+
   nsCSSValue mXValue;
   nsCSSValue mYValue;
 };
 
 // nsCSSValuePair_heap differs from nsCSSValuePair only in being
 // refcounted.  It should not be necessary to use this class directly;
 // it's an implementation detail of nsCSSValue.
 struct nsCSSValuePair_heap : public nsCSSValuePair {
-    // forward constructor
-    nsCSSValuePair_heap(const nsCSSValue& aXValue, const nsCSSValue& aYValue)
-        : nsCSSValuePair(aXValue, aYValue)
-    {}
+  // forward constructor
+  nsCSSValuePair_heap(const nsCSSValue& aXValue, const nsCSSValue& aYValue)
+      : nsCSSValuePair(aXValue, aYValue)
+  {}
 
-    NS_INLINE_DECL_REFCOUNTING(nsCSSValuePair_heap)
+  NS_INLINE_DECL_REFCOUNTING(nsCSSValuePair_heap)
+
+  size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
 };
 
 struct nsCSSValueTriplet {
     nsCSSValueTriplet()
     {
         MOZ_COUNT_CTOR(nsCSSValueTriplet);
     }
     nsCSSValueTriplet(nsCSSUnit aUnit)
@@ -911,16 +927,18 @@ struct nsCSSValueTriplet {
 // it's an implementation detail of nsCSSValue.
 struct nsCSSValueTriplet_heap : public nsCSSValueTriplet {
   // forward constructor
   nsCSSValueTriplet_heap(const nsCSSValue& aXValue, const nsCSSValue& aYValue, const nsCSSValue& aZValue)
     : nsCSSValueTriplet(aXValue, aYValue, aZValue)
   {}
 
   NS_INLINE_DECL_REFCOUNTING(nsCSSValueTriplet_heap)
+
+  size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
 };
 
 // This has to be here so that the relationship between nsCSSValuePair
 // and nsCSSValuePair_heap is visible.
 inline nsCSSValuePair&
 nsCSSValue::GetPairValue()
 {
   NS_ABORT_IF_FALSE(mUnit == eCSSUnit_Pair, "not a pair value");
@@ -955,16 +973,18 @@ struct nsCSSValuePairList {
 
   nsCSSValuePairList* Clone() const; // makes a deep copy
   void AppendToString(nsCSSProperty aProperty, nsAString& aResult) const;
 
   bool operator==(const nsCSSValuePairList& aOther) const;
   bool operator!=(const nsCSSValuePairList& aOther) const
   { return !(*this == aOther); }
 
+  size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
+
   nsCSSValue          mXValue;
   nsCSSValue          mYValue;
   nsCSSValuePairList* mNext;
 
 private:
   nsCSSValuePairList(const nsCSSValuePairList& aCopy) // makes a shallow copy
     : mXValue(aCopy.mXValue), mYValue(aCopy.mYValue), mNext(nsnull)
   {
@@ -972,16 +992,18 @@ private:
   }
 };
 
 // nsCSSValuePairList_heap differs from nsCSSValuePairList only in being
 // refcounted.  It should not be necessary to use this class directly;
 // it's an implementation detail of nsCSSValue.
 struct nsCSSValuePairList_heap : public nsCSSValuePairList {
   NS_INLINE_DECL_REFCOUNTING(nsCSSValuePairList_heap)
+
+  size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
 };
 
 // This has to be here so that the relationship between nsCSSValuePairList
 // and nsCSSValuePairList_heap is visible.
 inline nsCSSValuePairList*
 nsCSSValue::GetPairListValue()
 {
   if (mUnit == eCSSUnit_PairList)
@@ -1019,16 +1041,18 @@ public:
     return (mLocation == aOther.mLocation &&
             mColor == aOther.mColor);
   }
 
   bool operator!=(const nsCSSValueGradientStop& aOther) const
   {
     return !(*this == aOther);
   }
+
+  size_t SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
 };
 
 struct nsCSSValueGradient {
   nsCSSValueGradient(bool aIsRadial, bool aIsRepeating);
 
   // true if gradient is radial, false if it is linear
   bool mIsRadial;
   bool mIsRepeating;
@@ -1067,16 +1091,18 @@ struct nsCSSValueGradient {
 
   bool operator!=(const nsCSSValueGradient& aOther) const
   {
     return !(*this == aOther);
   }
 
   NS_INLINE_DECL_REFCOUNTING(nsCSSValueGradient)
 
+  size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
+
 private:
   nsCSSValueGradient(const nsCSSValueGradient& aOther) MOZ_DELETE;
   nsCSSValueGradient& operator=(const nsCSSValueGradient& aOther) MOZ_DELETE;
 };
 
 struct nsCSSCornerSizes {
   nsCSSCornerSizes(void);
   nsCSSCornerSizes(const nsCSSCornerSizes& aCopy);
--- a/layout/style/nsIStyleSheet.h
+++ b/layout/style/nsIStyleSheet.h
@@ -104,13 +104,15 @@ public:
   // style sheet owner info
   virtual nsIStyleSheet* GetParentSheet() const = 0;  // may be null
   virtual nsIDocument* GetOwningDocument() const = 0; // may be null
   virtual void SetOwningDocument(nsIDocument* aDocument) = 0;
 
 #ifdef DEBUG
   virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const = 0;
 #endif
+
+  virtual size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIStyleSheet, NS_ISTYLE_SHEET_IID)
 
 #endif /* nsIStyleSheet_h___ */
--- a/layout/style/nsLayoutStylesheetCache.cpp
+++ b/layout/style/nsLayoutStylesheetCache.cpp
@@ -36,22 +36,40 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsLayoutStylesheetCache.h"
 
 #include "nsAppDirectoryServiceDefs.h"
 #include "mozilla/css/Loader.h"
 #include "nsIFile.h"
 #include "nsLayoutCID.h"
+#include "nsIMemoryReporter.h"
 #include "nsNetUtil.h"
 #include "nsIObserverService.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIXULRuntime.h"
 #include "nsCSSStyleSheet.h"
 
+NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(LayoutStyleSheetCacheMallocSizeOf,
+                                     "layout/style-sheet-cache")
+
+static PRInt64
+GetStylesheetCacheSize()
+{
+  return nsLayoutStylesheetCache::SizeOfIncludingThis(
+           LayoutStyleSheetCacheMallocSizeOf);
+}
+
+NS_MEMORY_REPORTER_IMPLEMENT(Sheets,
+                             "explicit/layout/style-sheet-cache",
+                             KIND_HEAP,
+                             nsIMemoryReporter::UNITS_BYTES,
+                             GetStylesheetCacheSize,
+                             "Memory used for some built-in style sheets.")
+
 NS_IMPL_ISUPPORTS1(nsLayoutStylesheetCache, nsIObserver)
 
 nsresult
 nsLayoutStylesheetCache::Observe(nsISupports* aSubject,
                             const char* aTopic,
                             const PRUnichar* aData)
 {
   if (!strcmp(aTopic, "profile-before-change")) {
@@ -167,16 +185,48 @@ nsLayoutStylesheetCache::FullScreenOverr
 
 void
 nsLayoutStylesheetCache::Shutdown()
 {
   NS_IF_RELEASE(gCSSLoader);
   NS_IF_RELEASE(gStyleCache);
 }
 
+size_t
+nsLayoutStylesheetCache::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf)
+{
+  if (nsLayoutStylesheetCache::gStyleCache) {
+    return nsLayoutStylesheetCache::gStyleCache->
+      SizeOfIncludingThisHelper(aMallocSizeOf);
+  }
+  return 0;
+}
+
+size_t
+nsLayoutStylesheetCache::SizeOfIncludingThisHelper(nsMallocSizeOfFun aMallocSizeOf) const
+{
+  size_t n = aMallocSizeOf(this);
+
+  #define MEASURE(s) n += s ? s->SizeOfIncludingThis(aMallocSizeOf) : 0;
+
+  MEASURE(mScrollbarsSheet);
+  MEASURE(mFormsSheet);
+  MEASURE(mUserContentSheet);
+  MEASURE(mUserChromeSheet);
+  MEASURE(mUASheet);
+  MEASURE(mQuirkSheet);
+  MEASURE(mFullScreenOverrideSheet);
+
+  // Measurement of the following members may be added later if DMD finds it is
+  // worthwhile:
+  // - gCSSLoader
+
+  return n;
+}
+
 nsLayoutStylesheetCache::nsLayoutStylesheetCache()
 {
   nsCOMPtr<nsIObserverService> obsSvc =
     mozilla::services::GetObserverService();
   NS_ASSERTION(obsSvc, "No global observer service?");
 
   if (obsSvc) {
     obsSvc->AddObserver(this, "profile-before-change", false);
@@ -203,16 +253,24 @@ nsLayoutStylesheetCache::nsLayoutStylesh
   NS_ASSERTION(mQuirkSheet, "Could not load quirk.css");
 
   NS_NewURI(getter_AddRefs(uri), "resource://gre-resources/full-screen-override.css");
   if (uri) {
     LoadSheet(uri, mFullScreenOverrideSheet, true);
   }
   NS_ASSERTION(mFullScreenOverrideSheet, "Could not load full-screen-override.css");
 
+  mSheetsReporter = new NS_MEMORY_REPORTER_NAME(Sheets);
+  (void)::NS_RegisterMemoryReporter(mSheetsReporter);
+}
+
+nsLayoutStylesheetCache::~nsLayoutStylesheetCache()
+{
+  (void)::NS_UnregisterMemoryReporter(mSheetsReporter);
+  mSheetsReporter = nsnull;
 }
 
 void
 nsLayoutStylesheetCache::EnsureGlobal()
 {
   if (gStyleCache) return;
 
   gStyleCache = new nsLayoutStylesheetCache();
--- a/layout/style/nsLayoutStylesheetCache.h
+++ b/layout/style/nsLayoutStylesheetCache.h
@@ -47,46 +47,54 @@ class nsCSSStyleSheet;
 class nsIURI;
 
 namespace mozilla {
 namespace css {
 class Loader;
 }
 }
 
+class nsIMemoryReporter;
+
 class nsLayoutStylesheetCache
  : public nsIObserver
 {
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
 
   static nsCSSStyleSheet* ScrollbarsSheet();
   static nsCSSStyleSheet* FormsSheet();
   static nsCSSStyleSheet* UserContentSheet();
   static nsCSSStyleSheet* UserChromeSheet();
   static nsCSSStyleSheet* UASheet();
   static nsCSSStyleSheet* QuirkSheet();
   static nsCSSStyleSheet* FullScreenOverrideSheet();
 
   static void Shutdown();
 
+  static size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf);
+
 private:
   nsLayoutStylesheetCache();
-  ~nsLayoutStylesheetCache() {}
+  ~nsLayoutStylesheetCache();
 
   static void EnsureGlobal();
   void InitFromProfile();
   static void LoadSheetFile(nsIFile* aFile, nsRefPtr<nsCSSStyleSheet> &aSheet);
   static void LoadSheet(nsIURI* aURI, nsRefPtr<nsCSSStyleSheet> &aSheet,
                         bool aEnableUnsafeRules);
 
+  size_t SizeOfIncludingThisHelper(nsMallocSizeOfFun aMallocSizeOf) const;
+
   static nsLayoutStylesheetCache* gStyleCache;
   static mozilla::css::Loader* gCSSLoader;
   nsRefPtr<nsCSSStyleSheet> mScrollbarsSheet;
   nsRefPtr<nsCSSStyleSheet> mFormsSheet;
   nsRefPtr<nsCSSStyleSheet> mUserContentSheet;
   nsRefPtr<nsCSSStyleSheet> mUserChromeSheet;
   nsRefPtr<nsCSSStyleSheet> mUASheet;
   nsRefPtr<nsCSSStyleSheet> mQuirkSheet;
   nsRefPtr<nsCSSStyleSheet> mFullScreenOverrideSheet;
+
+  nsIMemoryReporter* mSheetsReporter;
 };
 
 #endif
--- a/xpcom/base/nsIMemoryReporter.idl
+++ b/xpcom/base/nsIMemoryReporter.idl
@@ -351,29 +351,29 @@ namespace mozilla {
  * You might be wondering why we have a macro that creates multiple functions
  * distinguished only by |name|, instead of a single MemoryReporterMallocSizeOf
  * function.  It's mostly to help with DMD integration, though it sometimes
  * also helps with debugging and temporary ad hoc profiling.  The |name| chosen
  * doesn't matter greatly, but it's best to make it similar to the path used by
  * the relevant memory reporter(s).
  */
 #define NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(fn, name)                        \
-  size_t fn(const void *ptr)                                                  \
+  static size_t fn(const void *ptr)                                           \
   {                                                                           \
       size_t usable = moz_malloc_size_of(ptr);                                \
       VALGRIND_DMD_REPORT(ptr, usable, name);                                 \
       return usable;                                                          \
   }
 
 /*
  * Like NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN, but the created function sends an
  * "unreport" message to DMD.
  */
 #define NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN_UN(fn)                           \
-  size_t fn(const void *ptr)                                                  \
+  static size_t fn(const void *ptr)                                           \
   {                                                                           \
       size_t usable = moz_malloc_size_of(ptr);                                \
       VALGRIND_DMD_UNREPORT(ptr);                                             \
       return usable;                                                          \
   }
 
 #ifdef MOZ_DMD