Bug 993546 - refactor malloc-wrapping memory reporter implementations; r=njn
authorNathan Froyd <froydnj@mozilla.com>
Tue, 08 Apr 2014 13:51:20 -0400
changeset 197046 00b716b32cdaa58bf6a631bf1130c0862ac2acfb
parent 197045 b2a9790f3753adc83dc669009ee99fa01556aaed
child 197047 b62c590540b0a0b82924413a0f2bcf0022cc8713
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnjn
bugs993546
milestone31.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 993546 - refactor malloc-wrapping memory reporter implementations; r=njn
extensions/spellcheck/hunspell/src/hunspell_alloc_hooks.h
extensions/spellcheck/hunspell/src/mozHunspell.cpp
extensions/spellcheck/hunspell/src/mozHunspell.h
extensions/spellcheck/hunspell/src/mozHunspellAllocator.h
gfx/thebes/gfxAndroidPlatform.cpp
xpcom/base/nsIMemoryReporter.idl
xpcom/build/nsXPComInit.cpp
--- a/extensions/spellcheck/hunspell/src/hunspell_alloc_hooks.h
+++ b/extensions/spellcheck/hunspell/src/hunspell_alloc_hooks.h
@@ -43,68 +43,16 @@
  * during the configure step.
  *
  * Currently, the memory allocated using operator new/new[] is not being
  * tracked, but that's OK, since almost all of the memory used by Hunspell is
  * allocated using C memory allocation functions.
  */
 
 #include "mozilla/mozalloc.h"
-
-extern void HunspellReportMemoryAllocation(void*);
-extern void HunspellReportMemoryDeallocation(void*);
-
-inline void* hunspell_malloc(size_t size)
-{
-  void* result = moz_malloc(size);
-  HunspellReportMemoryAllocation(result);
-  return result;
-}
-#define malloc(size) hunspell_malloc(size)
-
-inline void* hunspell_calloc(size_t count, size_t size)
-{
-  void* result = moz_calloc(count, size);
-  HunspellReportMemoryAllocation(result);
-  return result;
-}
-#define calloc(count, size) hunspell_calloc(count, size)
-
-inline void hunspell_free(void* ptr)
-{
-  HunspellReportMemoryDeallocation(ptr);
-  moz_free(ptr);
-}
-#define free(ptr) hunspell_free(ptr)
+#include "mozHunspellAllocator.h"
 
-inline void* hunspell_realloc(void* ptr, size_t size)
-{
-  HunspellReportMemoryDeallocation(ptr);
-  void* result = moz_realloc(ptr, size);
-  if (result) {
-    HunspellReportMemoryAllocation(result);
-  } else {
-    // realloc failed;  undo the HunspellReportMemoryDeallocation from above
-    HunspellReportMemoryAllocation(ptr);
-  }
-  return result;
-}
-#define realloc(ptr, size) hunspell_realloc(ptr, size)
-
-inline char* hunspell_strdup(const char* str)
-{
-  char* result = moz_strdup(str);
-  HunspellReportMemoryAllocation(result);
-  return result;
-}
-#define strdup(str) hunspell_strdup(str)
-
-#if defined(HAVE_STRNDUP)
-inline char* hunspell_strndup(const char* str, size_t size)
-{
-  char* result = moz_strndup(str, size);
-  HunspellReportMemoryAllocation(result);
-  return result;
-}
-#define strndup(str, size) hunspell_strndup(str, size)
-#endif
+#define malloc(size) HunspellAllocator::CountingMalloc(size)
+#define calloc(count, size) HunspellAllocator::CountingCalloc(count, size)
+#define free(ptr) HunspellAllocator::CountingFree(ptr)
+#define realloc(ptr, size) HunspellAllocator::CountingRealloc(ptr, size)
 
 #endif
--- a/extensions/spellcheck/hunspell/src/mozHunspell.cpp
+++ b/extensions/spellcheck/hunspell/src/mozHunspell.cpp
@@ -91,32 +91,24 @@ NS_INTERFACE_MAP_BEGIN(mozHunspell)
   NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(mozHunspell)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTION_3(mozHunspell,
                            mPersonalDictionary,
                            mEncoder,
                            mDecoder)
 
-int64_t mozHunspell::sAmount = 0;
-
-// WARNING: hunspell_alloc_hooks.h uses these two functions.
-void HunspellReportMemoryAllocation(void* ptr) {
-  mozHunspell::OnAlloc(ptr);
-}
-void HunspellReportMemoryDeallocation(void* ptr) {
-  mozHunspell::OnFree(ptr);
-}
+template<> mozilla::Atomic<size_t> mozilla::CountingAllocatorBase<HunspellAllocator>::sAmount(0);
 
 mozHunspell::mozHunspell()
   : mHunspell(nullptr)
 {
 #ifdef DEBUG
-  // There must be only one instance of this class, due to |sAmount|
-  // being static.
+  // There must be only one instance of this class: it reports memory based on
+  // a single static count in HunspellAllocator.
   static bool hasRun = false;
   MOZ_ASSERT(!hasRun);
   hasRun = true;
 #endif
 }
 
 nsresult
 mozHunspell::Init()
--- a/extensions/spellcheck/hunspell/src/mozHunspell.h
+++ b/extensions/spellcheck/hunspell/src/mozHunspell.h
@@ -68,16 +68,17 @@
 #include "nsCOMArray.h"
 #include "nsIMemoryReporter.h"
 #include "nsIObserver.h"
 #include "nsIUnicodeEncoder.h"
 #include "nsIUnicodeDecoder.h"
 #include "nsInterfaceHashtable.h"
 #include "nsWeakReference.h"
 #include "nsCycleCollectionParticipant.h"
+#include "mozHunspellAllocator.h"
 
 #define MOZ_HUNSPELL_CONTRACTID "@mozilla.org/spellchecker/engine;1"
 #define MOZ_HUNSPELL_CID         \
 /* 56c778e4-1bee-45f3-a689-886692a97fe7 */   \
 { 0x56c778e4, 0x1bee, 0x45f3, \
   { 0xa6, 0x89, 0x88, 0x66, 0x92, 0xa9, 0x7f, 0xe7 } }
 
 class mozHunspell : public mozISpellCheckingEngine,
@@ -96,27 +97,21 @@ public:
 
   nsresult Init();
 
   void LoadDictionaryList();
 
   // helper method for converting a word to the charset of the dictionary
   nsresult ConvertCharset(const char16_t* aStr, char ** aDst);
 
-  MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC(MallocSizeOfOnAlloc)
-  MOZ_DEFINE_MALLOC_SIZE_OF_ON_FREE(MallocSizeOfOnFree)
-
-  static void OnAlloc(void* ptr) { sAmount += MallocSizeOfOnAlloc(ptr); }
-  static void OnFree (void* ptr) { sAmount -= MallocSizeOfOnFree (ptr); }
-
   NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
                             nsISupports* aData)
   {
     return MOZ_COLLECT_REPORT(
-      "explicit/spell-check", KIND_HEAP, UNITS_BYTES, sAmount,
+      "explicit/spell-check", KIND_HEAP, UNITS_BYTES, HunspellAllocator::MemoryAllocated(),
       "Memory used by the spell-checking engine.");
   }
 
 protected:
 
   nsCOMPtr<mozIPersonalDictionary> mPersonalDictionary;
   nsCOMPtr<nsIUnicodeEncoder>      mEncoder;
   nsCOMPtr<nsIUnicodeDecoder>      mDecoder;
@@ -126,13 +121,11 @@ protected:
   nsString  mDictionary;
   nsString  mLanguage;
   nsCString mAffixFileName;
 
   // dynamic dirs used to search for dictionaries
   nsCOMArray<nsIFile> mDynamicDirectories;
 
   Hunspell  *mHunspell;
-
-  static int64_t sAmount;
 };
 
 #endif
new file mode 100644
--- /dev/null
+++ b/extensions/spellcheck/hunspell/src/mozHunspellAllocator.h
@@ -0,0 +1,16 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 mozHunspellAllocator_h__
+#define mozHunspellAllocator_h__
+
+#include "nsIMemoryReporter.h"
+
+class HunspellAllocator : public mozilla::CountingAllocatorBase<HunspellAllocator>
+{
+};
+
+#endif
--- a/gfx/thebes/gfxAndroidPlatform.cpp
+++ b/gfx/thebes/gfxAndroidPlatform.cpp
@@ -35,87 +35,60 @@
 #include FT_MODULE_H
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::gfx;
 
 static FT_Library gPlatformFTLibrary = nullptr;
 
-class FreetypeReporter MOZ_FINAL : public nsIMemoryReporter
+class FreetypeReporter MOZ_FINAL : public nsIMemoryReporter,
+                                   public CountingAllocatorBase<FreetypeReporter>
 {
 public:
     NS_DECL_ISUPPORTS
 
-    FreetypeReporter()
+    static void* Malloc(FT_Memory, long size)
     {
-#ifdef DEBUG
-        // There must be only one instance of this class, due to |sAmount|
-        // being static.
-        static bool hasRun = false;
-        MOZ_ASSERT(!hasRun);
-        hasRun = true;
-#endif
+        return CountingMalloc(size);
     }
 
-    MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC(MallocSizeOfOnAlloc)
-    MOZ_DEFINE_MALLOC_SIZE_OF_ON_FREE(MallocSizeOfOnFree)
-
-    static void* CountingAlloc(FT_Memory, long size)
+    static void Free(FT_Memory, void* p)
     {
-        void *p = malloc(size);
-        sAmount += MallocSizeOfOnAlloc(p);
-        return p;
-    }
-
-    static void CountingFree(FT_Memory, void* p)
-    {
-        sAmount -= MallocSizeOfOnFree(p);
-        free(p);
+        return CountingFree(p);
     }
 
     static void*
-    CountingRealloc(FT_Memory, long cur_size, long new_size, void* p)
+    Realloc(FT_Memory, long cur_size, long new_size, void* p)
     {
-        sAmount -= MallocSizeOfOnFree(p);
-        void *pnew = realloc(p, new_size);
-        if (pnew) {
-            sAmount += MallocSizeOfOnAlloc(pnew);
-        } else {
-            // realloc failed;  undo the decrement from above
-            sAmount += MallocSizeOfOnAlloc(p);
-        }
-        return pnew;
+        return CountingRealloc(p, new_size);
     }
 
     NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
                               nsISupports* aData)
     {
         return MOZ_COLLECT_REPORT(
-            "explicit/freetype", KIND_HEAP, UNITS_BYTES, sAmount,
+            "explicit/freetype", KIND_HEAP, UNITS_BYTES, MemoryAllocated(),
             "Memory used by Freetype.");
     }
-
-private:
-    static int64_t sAmount;
 };
 
 NS_IMPL_ISUPPORTS1(FreetypeReporter, nsIMemoryReporter)
 
-int64_t FreetypeReporter::sAmount = 0;
+template<> Atomic<size_t> CountingAllocatorBase<FreetypeReporter>::sAmount(0);
 
 static FT_MemoryRec_ sFreetypeMemoryRecord;
 
 gfxAndroidPlatform::gfxAndroidPlatform()
 {
     // A custom allocator.  It counts allocations, enabling memory reporting.
     sFreetypeMemoryRecord.user    = nullptr;
-    sFreetypeMemoryRecord.alloc   = FreetypeReporter::CountingAlloc;
-    sFreetypeMemoryRecord.free    = FreetypeReporter::CountingFree;
-    sFreetypeMemoryRecord.realloc = FreetypeReporter::CountingRealloc;
+    sFreetypeMemoryRecord.alloc   = FreetypeReporter::Malloc;
+    sFreetypeMemoryRecord.free    = FreetypeReporter::Free;
+    sFreetypeMemoryRecord.realloc = FreetypeReporter::Realloc;
 
     // These two calls are equivalent to FT_Init_FreeType(), but allow us to
     // provide a custom memory allocator.
     FT_New_Library(&sFreetypeMemoryRecord, &gPlatformFTLibrary);
     FT_Add_Default_Modules(gPlatformFTLibrary);
 
     RegisterStrongMemoryReporter(new FreetypeReporter());
 
--- a/xpcom/base/nsIMemoryReporter.idl
+++ b/xpcom/base/nsIMemoryReporter.idl
@@ -396,16 +396,17 @@ interface nsIMemoryReporterManager : nsI
                  out double jsMilliseconds, out double nonJSMilliseconds);
 };
 
 %{C++
 
 #include "js/TypeDecls.h"
 #include "nsStringGlue.h"
 #include "nsTArray.h"
+#include "mozilla/Atomics.h"
 
 class nsPIDOMWindow;
 
 // nsIHandleReportCallback is a better name, but keep nsIMemoryReporterCallback
 // around for backwards compatibility.
 typedef nsIMemoryReporterCallback nsIHandleReportCallback;
 
 namespace mozilla {
@@ -525,16 +526,126 @@ void RunReportersForThisProcess();
       return moz_malloc_size_of(aPtr);                                        \
   }
 #define MOZ_DEFINE_MALLOC_SIZE_OF_ON_FREE(fn)                                 \
   static size_t fn(const void* aPtr)                                          \
   {                                                                           \
       return moz_malloc_size_of(aPtr);                                        \
   }
 
+namespace mozilla {
+
+// This CRTP class handles several details of wrapping allocators and should
+// be preferred to manually counting with MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC
+// and MOZ_DEFINE_MALLOC_SIZE_OF_ON_FREE.  The typical use is in a memory
+// reporter for a particular third party library:
+//
+//   class MyMemoryReporter : public CountingAllocatorBase<MyMemoryReporter>
+//   {
+//     ...
+//     NS_IMETHODIMP
+//     CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData)
+//     {
+//        return MOZ_COLLECT_REPORTER(
+//          "explicit/path/to/somewhere", KIND_HEAP, UNITS_BYTES,
+//          MemoryAllocated(),
+//          "A description of what we are reporting."
+//     }
+//   };
+//
+//   ...somewhere later in the code...
+//   SetThirdPartyMemoryFunctions(MyMemoryReporter::CountingAlloc,
+//                                MyMemoryReporter::CountingFree);
+template<typename T>
+class CountingAllocatorBase
+{
+public:
+  CountingAllocatorBase()
+  {
+#ifdef DEBUG
+    // There must be only one instance of this class, due to |sAmount| being
+    // static.
+    static bool hasRun = false;
+    MOZ_ASSERT(!hasRun);
+    hasRun = true;
+#endif
+  }
+
+  static size_t
+  MemoryAllocated()
+  {
+    return sAmount;
+  }
+
+  static void*
+  CountingMalloc(size_t size)
+  {
+    void* p = malloc(size);
+    sAmount += MallocSizeOfOnAlloc(p);
+    return p;
+  }
+
+  static void*
+  CountingCalloc(size_t nmemb, size_t size)
+  {
+    void* p = calloc(nmemb, size);
+    sAmount += MallocSizeOfOnAlloc(p);
+    return p;
+  }
+
+  static void*
+  CountingRealloc(void* p, size_t size)
+  {
+    size_t oldsize = MallocSizeOfOnFree(p);
+    void *pnew = realloc(p, size);
+    if (pnew) {
+      size_t newsize = MallocSizeOfOnAlloc(pnew);
+      sAmount += newsize - oldsize;
+    } else if (size == 0) {
+      // We asked for a 0-sized (re)allocation of some existing pointer
+      // and received NULL in return.  0-sized allocations are permitted
+      // to either return NULL or to allocate a unique object per call (!).
+      // For a malloc implementation that chooses the second strategy,
+      // that allocation may fail (unlikely, but possible).
+      //
+      // Given a NULL return value and an allocation size of 0, then, we
+      // don't know if that means the original pointer was freed or if
+      // the allocation of the unique object failed.  If the original
+      // pointer was freed, then we have nothing to do here.  If the
+      // allocation of the unique object failed, the original pointer is
+      // still valid and we ought to undo the decrement from above.
+      // However, we have no way of knowing how the underlying realloc
+      // implementation is behaving.  Assuming that the original pointer
+      // was freed is the safest course of action.  We do, however, need
+      // to note that we freed memory.
+      sAmount -= oldsize;
+    } else {
+      // realloc failed.  The amount allocated hasn't changed.
+    }
+    return pnew;
+  }
+
+  static void
+  CountingFree(void* p)
+  {
+    sAmount -= MallocSizeOfOnFree(p);
+    free(p);
+  }
+
+private:
+  // |sAmount| can be (implicitly) accessed by multiple threads, so it
+  // must be thread-safe.
+  static Atomic<size_t> sAmount;
+
+  MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC(MallocSizeOfOnAlloc)
+  MOZ_DEFINE_MALLOC_SIZE_OF_ON_FREE(MallocSizeOfOnFree)
+};
+
+}
+
 // This macro assumes the presence of appropriate |aHandleReport| and |aData|
 // variables.
 #define MOZ_COLLECT_REPORT(path, kind, units, amount, description)            \
   aHandleReport->Callback(EmptyCString(), NS_LITERAL_CSTRING(path),           \
                           kind, units, amount,                                \
                           NS_LITERAL_CSTRING(description), aData)
 
 %}
--- a/xpcom/build/nsXPComInit.cpp
+++ b/xpcom/build/nsXPComInit.cpp
@@ -336,225 +336,91 @@ NS_GetDebug(nsIDebug** result)
 
 EXPORT_XPCOM_API(nsresult)
 NS_InitXPCOM(nsIServiceManager* *result,
                              nsIFile* binDirectory)
 {
     return NS_InitXPCOM2(result, binDirectory, nullptr);
 }
 
-class ICUReporter MOZ_FINAL : public nsIMemoryReporter
+class ICUReporter MOZ_FINAL : public nsIMemoryReporter,
+                              public CountingAllocatorBase<ICUReporter>
 {
 public:
     NS_DECL_ISUPPORTS
 
-    ICUReporter()
-    {
-#ifdef DEBUG
-        // There must be only one instance of this class, due to |sAmount|
-        // being static.
-        static bool hasRun = false;
-        MOZ_ASSERT(!hasRun);
-        hasRun = true;
-#endif
-        sAmount = 0;
-    }
-
     static void* Alloc(const void*, size_t size)
     {
-        void* p = malloc(size);
-        sAmount += MallocSizeOfOnAlloc(p);
-        return p;
+        return CountingMalloc(size);
     }
 
     static void* Realloc(const void*, void* p, size_t size)
     {
-        sAmount -= MallocSizeOfOnFree(p);
-        void *pnew = realloc(p, size);
-        if (pnew) {
-            sAmount += MallocSizeOfOnAlloc(pnew);
-        } else {
-            // realloc failed;  undo the decrement from above
-            sAmount += MallocSizeOfOnAlloc(p);
-        }
-        return pnew;
+        return CountingRealloc(p, size);
     }
 
     static void Free(const void*, void* p)
     {
-        sAmount -= MallocSizeOfOnFree(p);
-        free(p);
+        return CountingFree(p);
     }
 
 private:
-    // |sAmount| can be (implicitly) accessed by multiple JSRuntimes, so it
-    // must be thread-safe.
-    static Atomic<size_t> sAmount;
-
-    MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
-    MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC(MallocSizeOfOnAlloc)
-    MOZ_DEFINE_MALLOC_SIZE_OF_ON_FREE(MallocSizeOfOnFree)
-
     NS_IMETHODIMP
     CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData)
     {
         return MOZ_COLLECT_REPORT(
-            "explicit/icu", KIND_HEAP, UNITS_BYTES, sAmount,
+            "explicit/icu", KIND_HEAP, UNITS_BYTES, MemoryAllocated(),
             "Memory used by ICU, a Unicode and globalization support library.");
     }
 };
 
 NS_IMPL_ISUPPORTS1(ICUReporter, nsIMemoryReporter)
 
-/* static */ Atomic<size_t> ICUReporter::sAmount;
+/* static */ template<> Atomic<size_t> CountingAllocatorBase<ICUReporter>::sAmount(0);
 
-class OggReporter MOZ_FINAL : public nsIMemoryReporter
+class OggReporter MOZ_FINAL : public nsIMemoryReporter,
+                              public CountingAllocatorBase<OggReporter>
 {
 public:
     NS_DECL_ISUPPORTS
 
-    OggReporter()
-    {
-#ifdef DEBUG
-        // There must be only one instance of this class, due to |sAmount|
-        // being static.
-        static bool hasRun = false;
-        MOZ_ASSERT(!hasRun);
-        hasRun = true;
-#endif
-        sAmount = 0;
-    }
-
-    static void* Alloc(size_t size)
-    {
-        void* p = malloc(size);
-        sAmount += MallocSizeOfOnAlloc(p);
-        return p;
-    }
-
-    static void* Realloc(void* p, size_t size)
-    {
-        sAmount -= MallocSizeOfOnFree(p);
-        void *pnew = realloc(p, size);
-        if (pnew) {
-            sAmount += MallocSizeOfOnAlloc(pnew);
-        } else {
-            // realloc failed;  undo the decrement from above
-            sAmount += MallocSizeOfOnAlloc(p);
-        }
-        return pnew;
-    }
-
-    static void* Calloc(size_t nmemb, size_t size)
-    {
-        void* p = calloc(nmemb, size);
-        sAmount += MallocSizeOfOnAlloc(p);
-        return p;
-    }
-
-    static void Free(void* p)
-    {
-        sAmount -= MallocSizeOfOnFree(p);
-        free(p);
-    }
-
 private:
-    // |sAmount| can be (implicitly) accessed by multiple threads, so it
-    // must be thread-safe.
-    static Atomic<size_t> sAmount;
-
-    MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
-    MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC(MallocSizeOfOnAlloc)
-    MOZ_DEFINE_MALLOC_SIZE_OF_ON_FREE(MallocSizeOfOnFree)
-
     NS_IMETHODIMP
     CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData)
     {
         return MOZ_COLLECT_REPORT(
-            "explicit/media/libogg", KIND_HEAP, UNITS_BYTES, sAmount,
+            "explicit/media/libogg", KIND_HEAP, UNITS_BYTES, MemoryAllocated(),
             "Memory allocated through libogg for Ogg, Theora, and related media files.");
     }
 };
 
 NS_IMPL_ISUPPORTS1(OggReporter, nsIMemoryReporter)
 
-/* static */ Atomic<size_t> OggReporter::sAmount;
+/* static */ template<> Atomic<size_t> CountingAllocatorBase<OggReporter>::sAmount(0);
 
 #ifdef MOZ_VPX
-class VPXReporter MOZ_FINAL : public nsIMemoryReporter
+class VPXReporter MOZ_FINAL : public nsIMemoryReporter,
+                              public CountingAllocatorBase<VPXReporter>
 {
 public:
     NS_DECL_ISUPPORTS
 
-    VPXReporter()
-    {
-#ifdef DEBUG
-        // There must be only one instance of this class, due to |sAmount|
-        // being static.
-        static bool hasRun = false;
-        MOZ_ASSERT(!hasRun);
-        hasRun = true;
-#endif
-        sAmount = 0;
-    }
-
-    static void* Alloc(size_t size)
-    {
-        void* p = malloc(size);
-        sAmount += MallocSizeOfOnAlloc(p);
-        return p;
-    }
-
-    static void* Realloc(void* p, size_t size)
-    {
-        sAmount -= MallocSizeOfOnFree(p);
-        void *pnew = realloc(p, size);
-        if (pnew) {
-            sAmount += MallocSizeOfOnAlloc(pnew);
-        } else {
-            // realloc failed;  undo the decrement from above
-            sAmount += MallocSizeOfOnAlloc(p);
-        }
-        return pnew;
-    }
-
-    static void* Calloc(size_t nmemb, size_t size)
-    {
-        void* p = calloc(nmemb, size);
-        sAmount += MallocSizeOfOnAlloc(p);
-        return p;
-    }
-
-    static void Free(void* p)
-    {
-        sAmount -= MallocSizeOfOnFree(p);
-        free(p);
-    }
-
 private:
-    // |sAmount| can be (implicitly) accessed by multiple threads, so it
-    // must be thread-safe.
-    static Atomic<size_t> sAmount;
-
-    MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
-    MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC(MallocSizeOfOnAlloc)
-    MOZ_DEFINE_MALLOC_SIZE_OF_ON_FREE(MallocSizeOfOnFree)
-
     NS_IMETHODIMP
     CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData)
     {
         return MOZ_COLLECT_REPORT(
-            "explicit/media/libvpx", KIND_HEAP, UNITS_BYTES, sAmount,
+            "explicit/media/libvpx", KIND_HEAP, UNITS_BYTES, MemoryAllocated(),
             "Memory allocated through libvpx for WebM media files.");
     }
 };
 
 NS_IMPL_ISUPPORTS1(VPXReporter, nsIMemoryReporter)
 
-/* static */ Atomic<size_t> VPXReporter::sAmount;
+/* static */ template<> Atomic<size_t> CountingAllocatorBase<VPXReporter>::sAmount(0);
 #endif /* MOZ_VPX */
 
 EXPORT_XPCOM_API(nsresult)
 NS_InitXPCOM2(nsIServiceManager* *result,
               nsIFile* binDirectory,
               nsIDirectoryServiceProvider* appFileLocationProvider)
 {
     mozPoisonValueInit();
@@ -701,27 +567,27 @@ NS_InitXPCOM2(nsIServiceManager* *result
     // JS engine should do this on its own inside JS_Init, and memory-reporting
     // code should call a JSAPI function to observe ICU memory usage.  But we
     // can't define the alloc/free functions in the JS engine, because it can't
     // depend on the XPCOM-based memory reporting goop.  So for now, we have
     // this oddness.
     mozilla::SetICUMemoryFunctions();
 
     // Do the same for libogg.
-    ogg_set_mem_functions(OggReporter::Alloc,
-                          OggReporter::Calloc,
-                          OggReporter::Realloc,
-                          OggReporter::Free);
+    ogg_set_mem_functions(OggReporter::CountingMalloc,
+                          OggReporter::CountingCalloc,
+                          OggReporter::CountingRealloc,
+                          OggReporter::CountingFree);
 
 #ifdef MOZ_VPX
     // And for VPX.
-    vpx_mem_set_functions(VPXReporter::Alloc,
-                          VPXReporter::Calloc,
-                          VPXReporter::Realloc,
-                          VPXReporter::Free,
+    vpx_mem_set_functions(VPXReporter::CountingMalloc,
+                          VPXReporter::CountingCalloc,
+                          VPXReporter::CountingRealloc,
+                          VPXReporter::CountingFree,
                           memcpy,
                           memset,
                           memmove);
 #endif
 
     // Initialize the JS engine.
     if (!JS_Init()) {
         NS_RUNTIMEABORT("JS_Init failed");