Bug 1010064 - Allow memory reports to be anonymized. r=bsmedberg.
authorNicholas Nethercote <nnethercote@mozilla.com>
Tue, 20 May 2014 23:06:54 -0700
changeset 189433 258916327d96add07d88990a8e13df3fd080f2d2
parent 189432 8eeb287c59fd0b7a8b3a0b66161b52c5833ac523
child 189434 87e3c9420691b0e27b7b5740b9650548dfce25cb
push id45061
push usernnethercote@mozilla.com
push dateThu, 19 Jun 2014 00:13:08 +0000
treeherdermozilla-inbound@258916327d96 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbsmedberg
bugs1010064
milestone33.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 1010064 - Allow memory reports to be anonymized. r=bsmedberg.
addon-sdk/source/lib/sdk/test/harness.js
content/base/src/nsContentUtils.cpp
content/base/src/nsDOMFile.cpp
content/base/src/nsFrameMessageManager.cpp
content/base/src/nsHostObjectProtocolHandler.cpp
content/canvas/src/CanvasRenderingContext2D.cpp
content/canvas/src/WebGLContextReporter.cpp
content/media/MediaDecoder.cpp
content/media/MediaStreamGraph.cpp
content/media/webaudio/AudioContext.cpp
content/media/webaudio/AudioContext.h
dom/base/nsScriptNameSpaceManager.cpp
dom/base/nsWindowMemoryReporter.cpp
dom/base/nsWindowMemoryReporter.h
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/PContent.ipdl
dom/settings/SettingsManager.js
dom/workers/WorkerPrivate.cpp
dom/workers/WorkerPrivate.h
extensions/spellcheck/hunspell/src/mozHunspell.h
gfx/gl/GfxTexturesReporter.h
gfx/layers/ipc/ISurfaceAllocator.h
gfx/layers/ipc/SharedBufferManagerParent.cpp
gfx/thebes/gfxASurface.cpp
gfx/thebes/gfxAndroidPlatform.cpp
gfx/thebes/gfxFont.cpp
gfx/thebes/gfxPlatformFontList.cpp
gfx/thebes/gfxWindowsPlatform.cpp
image/src/SurfaceCache.cpp
image/src/imgLoader.cpp
image/test/mochitest/test_bug601470.html
ipc/glue/SharedMemory.cpp
js/public/MemoryMetrics.h
js/src/vm/MemoryMetrics.cpp
js/xpconnect/src/XPCJSMemoryReporter.h
js/xpconnect/src/XPCJSRuntime.cpp
js/xpconnect/src/xpcpublic.h
layout/base/nsStyleSheetService.cpp
layout/style/nsLayoutStylesheetCache.cpp
mobile/android/chrome/content/MemoryObserver.js
modules/libpref/src/Preferences.cpp
netwerk/cache/nsCacheService.cpp
netwerk/cache2/CacheStorageService.cpp
netwerk/cookie/nsCookieService.cpp
netwerk/dns/nsDNSService2.cpp
netwerk/dns/nsEffectiveTLDService.cpp
netwerk/protocol/http/SpdyZlibReporter.cpp
netwerk/protocol/http/SpdyZlibReporter.h
startupcache/StartupCache.cpp
storage/src/mozStorageService.cpp
testing/mochitest/tests/SimpleTest/MemoryStats.js
toolkit/components/aboutmemory/content/aboutMemory.js
toolkit/components/aboutmemory/tests/test_aboutmemory.xul
toolkit/components/aboutmemory/tests/test_aboutmemory2.xul
toolkit/components/aboutmemory/tests/test_aboutmemory3.xul
toolkit/components/aboutmemory/tests/test_aboutmemory5.xul
toolkit/components/aboutmemory/tests/test_memoryReporters.xul
toolkit/components/aboutmemory/tests/test_memoryReporters2.xul
toolkit/components/aboutmemory/tests/test_sqliteMultiReporter.xul
toolkit/components/places/History.cpp
toolkit/components/telemetry/Telemetry.cpp
toolkit/components/url-classifier/nsUrlClassifierPrefixSet.cpp
xpcom/base/AvailableMemoryTracker.cpp
xpcom/base/SystemMemoryReporter.cpp
xpcom/base/nsCycleCollector.cpp
xpcom/base/nsIMemoryInfoDumper.idl
xpcom/base/nsIMemoryReporter.idl
xpcom/base/nsMemoryInfoDumper.cpp
xpcom/base/nsMemoryReporterManager.cpp
xpcom/base/nsMemoryReporterManager.h
xpcom/build/nsXPComInit.cpp
xpcom/components/nsCategoryManager.cpp
xpcom/components/nsComponentManager.cpp
xpcom/ds/nsObserverService.cpp
xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp
--- a/addon-sdk/source/lib/sdk/test/harness.js
+++ b/addon-sdk/source/lib/sdk/test/harness.js
@@ -156,17 +156,17 @@ function reportMemoryUsage() {
 
   return gcPromise().then((function () {
     var mgr = Cc["@mozilla.org/memory-reporter-manager;1"]
               .getService(Ci.nsIMemoryReporterManager);
     let count = 0;
     function logReporter(process, path, kind, units, amount, description) {
       print(((++count == 1) ? "\n" : "") + description + ": " + amount + "\n");
     }
-    mgr.getReportsForThisProcess(logReporter, null);
+    mgr.getReportsForThisProcess(logReporter, null, /* anonymize = */ false);
 
     var weakrefs = [info.weakref.get()
                     for each (info in memory.getObjects())];
     weakrefs = [weakref for each (weakref in weakrefs) if (weakref)];
     print("Tracked memory objects in testing sandbox: " + weakrefs.length + "\n");
   }));
 }
 
@@ -375,17 +375,17 @@ function getPotentialLeaks() {
         return;
 
       windows[matches[1]] = item;
     }
   }
 
   Cc["@mozilla.org/memory-reporter-manager;1"]
     .getService(Ci.nsIMemoryReporterManager)
-    .getReportsForThisProcess(logReporter, null);
+    .getReportsForThisProcess(logReporter, null, /* anonymize = */ false);
 
   return { compartments: compartments, windows: windows };
 }
 
 function nextIteration(tests) {
   if (tests) {
     results.passed += tests.passed;
     results.failed += tests.failed;
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -415,17 +415,17 @@ static PLDHashTable sEventListenerManage
 class DOMEventListenerManagersHashReporter MOZ_FINAL : public nsIMemoryReporter
 {
   MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
 
 public:
   NS_DECL_ISUPPORTS
 
   NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
-                            nsISupports* aData)
+                            nsISupports* aData, bool aAnonymize)
   {
     // We don't measure the |EventListenerManager| objects pointed to by the
     // entries because those references are non-owning.
     int64_t amount = sEventListenerManagersHash.ops
                    ? PL_DHashTableSizeOfExcludingThis(
                        &sEventListenerManagersHash, nullptr, MallocSizeOf)
                    : 0;
 
--- a/content/base/src/nsDOMFile.cpp
+++ b/content/base/src/nsDOMFile.cpp
@@ -637,17 +637,17 @@ MOZ_DEFINE_MALLOC_SIZE_OF(DOMMemoryFileD
 
 class nsDOMMemoryFileDataOwnerMemoryReporter MOZ_FINAL
   : public nsIMemoryReporter
 {
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
 
   NS_IMETHOD CollectReports(nsIMemoryReporterCallback *aCallback,
-                            nsISupports *aClosure)
+                            nsISupports *aClosure, bool aAnonymize)
   {
     typedef nsDOMMemoryFile::DataOwner DataOwner;
 
     StaticMutexAutoLock lock(DataOwner::sDataOwnerMutex);
 
     if (!DataOwner::sDataOwners) {
       return NS_OK;
     }
@@ -657,33 +657,32 @@ public:
 
     for (DataOwner *owner = DataOwner::sDataOwners->getFirst();
          owner; owner = owner->getNext()) {
 
       size_t size = DOMMemoryFileDataOwnerMallocSizeOf(owner->mData);
 
       if (size < LARGE_OBJECT_MIN_SIZE) {
         smallObjectsTotal += size;
-      }
-      else {
+      } else {
         SHA1Sum sha1;
         sha1.update(owner->mData, owner->mLength);
         uint8_t digest[SHA1Sum::HashSize]; // SHA1 digests are 20 bytes long.
         sha1.finish(digest);
 
         nsAutoCString digestString;
         for (size_t i = 0; i < sizeof(digest); i++) {
           digestString.AppendPrintf("%02x", digest[i]);
         }
 
         nsresult rv = aCallback->Callback(
           /* process */ NS_LITERAL_CSTRING(""),
           nsPrintfCString(
             "explicit/dom/memory-file-data/large/file(length=%llu, sha1=%s)",
-            owner->mLength, digestString.get()),
+            owner->mLength, aAnonymize ? "<anonymized>" : digestString.get()),
           KIND_HEAP, UNITS_BYTES, size,
           nsPrintfCString(
             "Memory used to back a memory file of length %llu bytes.  The file "
             "has a sha1 of %s.\n\n"
             "Note that the allocator may round up a memory file's length -- "
             "that is, an N-byte memory file may take up more than N bytes of "
             "memory.",
             owner->mLength, digestString.get()),
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -1325,17 +1325,17 @@ ReportReferentCount(const char* aManager
 
 #undef REPORT
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 MessageManagerReporter::CollectReports(nsIMemoryReporterCallback* aCb,
-                                       nsISupports* aClosure)
+                                       nsISupports* aClosure, bool aAnonymize)
 {
   nsresult rv;
 
   if (XRE_GetProcessType() == GeckoProcessType_Default) {
     nsCOMPtr<nsIMessageBroadcaster> globalmm =
       do_GetService("@mozilla.org/globalmessagemanager;1");
     if (globalmm) {
       nsRefPtr<nsFrameMessageManager> mm =
--- a/content/base/src/nsHostObjectProtocolHandler.cpp
+++ b/content/base/src/nsHostObjectProtocolHandler.cpp
@@ -32,17 +32,17 @@ static nsClassHashtable<nsCStringHashKey
 namespace mozilla {
 
 class HostObjectURLsReporter MOZ_FINAL : public nsIMemoryReporter
 {
  public:
   NS_DECL_ISUPPORTS
 
   NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
-                            nsISupports* aData)
+                            nsISupports* aData, bool aAnonymize)
   {
     return MOZ_COLLECT_REPORT(
       "host-object-urls", KIND_OTHER, UNITS_COUNT,
       gDataTable ? gDataTable->Count() : 0,
       "The number of host objects stored for access via URLs "
       "(e.g. blobs passed to URL.createObjectURL).");
   }
 };
@@ -50,21 +50,22 @@ class HostObjectURLsReporter MOZ_FINAL :
 NS_IMPL_ISUPPORTS(HostObjectURLsReporter, nsIMemoryReporter)
 
 class BlobURLsReporter MOZ_FINAL : public nsIMemoryReporter
 {
  public:
   NS_DECL_ISUPPORTS
 
   NS_IMETHOD CollectReports(nsIHandleReportCallback* aCallback,
-                            nsISupports* aData)
+                            nsISupports* aData, bool aAnonymize)
   {
     EnumArg env;
     env.mCallback = aCallback;
     env.mData = aData;
+    env.mAnonymize = aAnonymize;
 
     if (gDataTable) {
       gDataTable->EnumerateRead(CountCallback, &env);
       gDataTable->EnumerateRead(ReportCallback, &env);
     }
     return NS_OK;
   }
 
@@ -129,16 +130,17 @@ class BlobURLsReporter MOZ_FINAL : publi
       NS_ENSURE_SUCCESS_VOID(rv);
     }
   }
 
  private:
   struct EnumArg {
     nsIHandleReportCallback* mCallback;
     nsISupports* mData;
+    bool mAnonymize;
     nsDataHashtable<nsPtrHashKey<nsIDOMBlob>, uint32_t> mRefCounts;
   };
 
   // Determine number of URLs per blob, to handle the case where it's > 1.
   static PLDHashOperator CountCallback(nsCStringHashKey::KeyType aKey,
                                        DataInfo* aInfo,
                                        void* aUserArg)
   {
@@ -185,26 +187,38 @@ class BlobURLsReporter MOZ_FINAL : publi
 
       path = isMemoryFile ? "memory-blob-urls/" : "file-blob-urls/";
       if (NS_SUCCEEDED(aInfo->mPrincipal->GetURI(getter_AddRefs(principalURI))) &&
           principalURI != nullptr &&
           NS_SUCCEEDED(principalURI->GetSpec(owner)) &&
           !owner.IsEmpty()) {
         owner.ReplaceChar('/', '\\');
         path += "owner(";
-        path += owner;
+        if (envp->mAnonymize) {
+          path += "<anonymized>";
+        } else {
+          path += owner;
+        }
         path += ")";
       } else {
         path += "owner unknown";
       }
       path += "/";
-      path += aInfo->mStack;
+      if (envp->mAnonymize) {
+        path += "<anonymized-stack>";
+      } else {
+        path += aInfo->mStack;
+      }
       url = aKey;
       url.ReplaceChar('/', '\\');
-      path += url;
+      if (envp->mAnonymize) {
+        path += "<anonymized-url>";
+      } else {
+        path += url;
+      }
       if (refCount > 1) {
         nsAutoCString addrStr;
 
         addrStr = "0x";
         addrStr.AppendInt((uint64_t)(nsIDOMBlob*)blob, 16);
 
         path += " ";
         path.AppendInt(refCount);
--- a/content/canvas/src/CanvasRenderingContext2D.cpp
+++ b/content/canvas/src/CanvasRenderingContext2D.cpp
@@ -145,17 +145,17 @@ static int64_t gCanvasAzureMemoryUsed = 
 // of a canvas are stored.  Furthermore, this memory will be tracked by the
 // underlying surface implementations.  See bug 655638 for details.
 class Canvas2dPixelsReporter MOZ_FINAL : public nsIMemoryReporter
 {
 public:
   NS_DECL_ISUPPORTS
 
   NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
-                            nsISupports* aData)
+                            nsISupports* aData, bool aAnonymize)
   {
     return MOZ_COLLECT_REPORT(
       "canvas-2d-pixels", KIND_OTHER, UNITS_BYTES,
       gCanvasAzureMemoryUsed,
       "Memory used by 2D canvases. Each canvas requires "
       "(width * height * 4) bytes.");
   }
 };
--- a/content/canvas/src/WebGLContextReporter.cpp
+++ b/content/canvas/src/WebGLContextReporter.cpp
@@ -7,17 +7,17 @@
 #include "WebGLMemoryTracker.h"
 
 using namespace mozilla;
 
 NS_IMPL_ISUPPORTS(WebGLMemoryPressureObserver, nsIObserver)
 
 NS_IMETHODIMP
 WebGLMemoryTracker::CollectReports(nsIHandleReportCallback* aHandleReport,
-                                   nsISupports* aData)
+                                   nsISupports* aData, bool aAnonymize)
 {
 #define REPORT(_path, _kind, _units, _amount, _desc)                          \
     do {                                                                      \
       nsresult rv;                                                            \
       rv = aHandleReport->Callback(EmptyCString(), NS_LITERAL_CSTRING(_path), \
                                    _kind, _units, _amount,                    \
                                    NS_LITERAL_CSTRING(_desc), aData);         \
       NS_ENSURE_SUCCESS(rv, rv);                                              \
--- a/content/media/MediaDecoder.cpp
+++ b/content/media/MediaDecoder.cpp
@@ -1738,17 +1738,17 @@ bool
 MediaDecoder::IsAppleMP3Enabled()
 {
   return Preferences::GetBool("media.apple.mp3.enabled");
 }
 #endif
 
 NS_IMETHODIMP
 MediaMemoryTracker::CollectReports(nsIHandleReportCallback* aHandleReport,
-                                   nsISupports* aData)
+                                   nsISupports* aData, bool aAnonymize)
 {
   int64_t video = 0, audio = 0;
   size_t resources = 0;
   DecodersArray& decoders = Decoders();
   for (size_t i = 0; i < decoders.Length(); ++i) {
     MediaDecoder* decoder = decoders[i];
     video += decoder->SizeOfVideoQueue();
     audio += decoder->SizeOfAudioQueue();
--- a/content/media/MediaStreamGraph.cpp
+++ b/content/media/MediaStreamGraph.cpp
@@ -2746,17 +2746,17 @@ struct ArrayClearer
 {
   ArrayClearer(nsTArray<AudioNodeSizes>& aArray) : mArray(aArray) {}
   ~ArrayClearer() { mArray.Clear(); }
   nsTArray<AudioNodeSizes>& mArray;
 };
 
 NS_IMETHODIMP
 MediaStreamGraphImpl::CollectReports(nsIHandleReportCallback* aHandleReport,
-                                     nsISupports* aData)
+                                     nsISupports* aData, bool aAnonymize)
 {
   // Clears out the report array after we're done with it.
   ArrayClearer reportCleanup(mAudioStreamSizes);
 
   {
     MonitorAutoLock memoryReportLock(mMemoryReportMonitor);
     mNeedsMemoryReport = true;
 
@@ -2784,27 +2784,27 @@ MediaStreamGraphImpl::CollectReports(nsI
     NS_ENSURE_SUCCESS(rv, rv);                                              \
   } while (0)
 
   for (size_t i = 0; i < mAudioStreamSizes.Length(); i++) {
     const AudioNodeSizes& usage = mAudioStreamSizes[i];
     const char* const nodeType =  usage.mNodeType.get();
 
     nsPrintfCString domNodePath("explicit/webaudio/audio-node/%s/dom-nodes",
-                                  nodeType);
+                                nodeType);
     REPORT(domNodePath, usage.mDomNode,
            "Memory used by AudioNode DOM objects (Web Audio).");
 
     nsPrintfCString enginePath("explicit/webaudio/audio-node/%s/engine-objects",
-                                nodeType);
+                               nodeType);
     REPORT(enginePath, usage.mEngine,
            "Memory used by AudioNode engine objects (Web Audio).");
 
     nsPrintfCString streamPath("explicit/webaudio/audio-node/%s/stream-objects",
-                                nodeType);
+                               nodeType);
     REPORT(streamPath, usage.mStream,
            "Memory used by AudioNode stream objects (Web Audio).");
 
   }
 
 #undef REPORT
 
   return NS_OK;
--- a/content/media/webaudio/AudioContext.cpp
+++ b/content/media/webaudio/AudioContext.cpp
@@ -670,17 +670,17 @@ AudioContext::SizeOfIncludingThis(mozill
   }
   amount += mActiveNodes.SizeOfExcludingThis(nullptr, aMallocSizeOf);
   amount += mPannerNodes.SizeOfExcludingThis(nullptr, aMallocSizeOf);
   return amount;
 }
 
 NS_IMETHODIMP
 AudioContext::CollectReports(nsIHandleReportCallback* aHandleReport,
-                             nsISupports* aData)
+                             nsISupports* aData, bool aAnonymize)
 {
   int64_t amount = SizeOfIncludingThis(MallocSizeOf);
   return MOZ_COLLECT_REPORT("explicit/webaudio/audiocontext", KIND_HEAP, UNITS_BYTES,
                             amount, "Memory used by AudioContext objects (Web Audio).");
 }
 
 double
 AudioContext::ExtraCurrentTime() const
--- a/content/media/webaudio/AudioContext.h
+++ b/content/media/webaudio/AudioContext.h
@@ -244,17 +244,17 @@ private:
    */
   double ExtraCurrentTime() const;
 
   void RemoveFromDecodeQueue(WebAudioDecodeJob* aDecodeJob);
   void ShutdownDecoder();
 
   size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
   NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
-                            nsISupports* aData);
+                            nsISupports* aData, bool aAnonymize);
 
   friend struct ::mozilla::WebAudioDecodeJob;
 
 private:
   // Note that it's important for mSampleRate to be initialized before
   // mDestination, as mDestination's constructor needs to access it!
   const float mSampleRate;
   nsRefPtr<AudioDestinationNode> mDestination;
--- a/dom/base/nsScriptNameSpaceManager.cpp
+++ b/dom/base/nsScriptNameSpaceManager.cpp
@@ -811,17 +811,17 @@ SizeOfEntryExcludingThis(PLDHashEntryHdr
   GlobalNameMapEntry* entry = static_cast<GlobalNameMapEntry*>(aHdr);
   return entry->SizeOfExcludingThis(aMallocSizeOf);
 }
 
 MOZ_DEFINE_MALLOC_SIZE_OF(ScriptNameSpaceManagerMallocSizeOf)
 
 NS_IMETHODIMP
 nsScriptNameSpaceManager::CollectReports(
-  nsIHandleReportCallback* aHandleReport, nsISupports* aData)
+  nsIHandleReportCallback* aHandleReport, nsISupports* aData, bool aAnonymize)
 {
   return MOZ_COLLECT_REPORT(
     "explicit/script-namespace-manager", KIND_HEAP, UNITS_BYTES,
     SizeOfIncludingThis(ScriptNameSpaceManagerMallocSizeOf),
     "Memory used for the script namespace manager.");
 }
 
 size_t
--- a/dom/base/nsWindowMemoryReporter.cpp
+++ b/dom/base/nsWindowMemoryReporter.cpp
@@ -157,30 +157,34 @@ GetWindowURI(nsIDOMWindow *aWindow)
       }
     }
   }
 
   return uri.forget();
 }
 
 static void
-AppendWindowURI(nsGlobalWindow *aWindow, nsACString& aStr)
+AppendWindowURI(nsGlobalWindow *aWindow, nsACString& aStr, bool aAnonymize)
 {
   nsCOMPtr<nsIURI> uri = GetWindowURI(aWindow);
 
   if (uri) {
-    nsCString spec;
-    uri->GetSpec(spec);
+    if (aAnonymize && !aWindow->IsChromeWindow()) {
+      aStr.AppendPrintf("<anonymized-%d>", aWindow->WindowID());
+    } else {
+      nsCString spec;
+      uri->GetSpec(spec);
 
-    // A hack: replace forward slashes with '\\' so they aren't
-    // treated as path separators.  Users of the reporters
-    // (such as about:memory) have to undo this change.
-    spec.ReplaceChar('/', '\\');
+      // A hack: replace forward slashes with '\\' so they aren't
+      // treated as path separators.  Users of the reporters
+      // (such as about:memory) have to undo this change.
+      spec.ReplaceChar('/', '\\');
 
-    aStr += spec;
+      aStr += spec;
+    }
   } else {
     // If we're unable to find a URI, we're dealing with a chrome window with
     // no document in it (or somesuch), so we call this a "system window".
     aStr += NS_LITERAL_CSTRING("[system]");
   }
 }
 
 MOZ_DEFINE_MALLOC_SIZE_OF(WindowsMallocSizeOf)
@@ -231,17 +235,18 @@ ReportCount(const nsCString& aBasePath, 
 static nsresult
 CollectWindowReports(nsGlobalWindow *aWindow,
                      amIAddonManager *addonManager,
                      nsWindowSizes *aWindowTotalSizes,
                      nsTHashtable<nsUint64HashKey> *aGhostWindowIDs,
                      WindowPaths *aWindowPaths,
                      WindowPaths *aTopWindowPaths,
                      nsIMemoryReporterCallback *aCb,
-                     nsISupports *aClosure)
+                     nsISupports *aClosure,
+                     bool aAnonymize)
 {
   nsAutoCString windowPath("explicit/");
 
   // Avoid calling aWindow->GetTop() if there's no outer window.  It will work
   // just fine, but will spew a lot of warnings.
   nsGlobalWindow *top = nullptr;
   nsCOMPtr<nsIURI> location;
   if (aWindow->GetOuterWindow()) {
@@ -255,26 +260,28 @@ CollectWindowReports(nsGlobalWindow *aWi
   if (!location) {
     location = GetWindowURI(aWindow);
   }
 
   if (addonManager && location) {
     bool ok;
     nsAutoCString id;
     if (NS_SUCCEEDED(addonManager->MapURIToAddonID(location, id, &ok)) && ok) {
+      // Add-on names are not privacy-sensitive, so we can use them with
+      // impunity.
       windowPath += NS_LITERAL_CSTRING("add-ons/") + id +
                     NS_LITERAL_CSTRING("/");
     }
   }
 
   windowPath += NS_LITERAL_CSTRING("window-objects/");
 
   if (top) {
     windowPath += NS_LITERAL_CSTRING("top(");
-    AppendWindowURI(top, windowPath);
+    AppendWindowURI(top, windowPath, aAnonymize);
     windowPath += NS_LITERAL_CSTRING(", id=");
     windowPath.AppendInt(top->WindowID());
     windowPath += NS_LITERAL_CSTRING(")");
 
     aTopWindowPaths->Put(aWindow->WindowID(), windowPath);
 
     windowPath += aWindow->IsFrozen() ? NS_LITERAL_CSTRING("/cached/")
                                       : NS_LITERAL_CSTRING("/active/");
@@ -282,17 +289,17 @@ CollectWindowReports(nsGlobalWindow *aWi
     if (aGhostWindowIDs->Contains(aWindow->WindowID())) {
       windowPath += NS_LITERAL_CSTRING("top(none)/ghost/");
     } else {
       windowPath += NS_LITERAL_CSTRING("top(none)/detached/");
     }
   }
 
   windowPath += NS_LITERAL_CSTRING("window(");
-  AppendWindowURI(aWindow, windowPath);
+  AppendWindowURI(aWindow, windowPath, aAnonymize);
   windowPath += NS_LITERAL_CSTRING(")");
 
   // Use |windowPath|, but replace "explicit/" with "event-counts/".
   nsCString censusWindowPath(windowPath);
   censusWindowPath.Replace(0, strlen("explicit"), "event-counts");
 
   // Remember the path for later.
   aWindowPaths->Put(aWindow->WindowID(), windowPath);
@@ -441,106 +448,107 @@ GetWindows(const uint64_t& aId, nsGlobal
 {
   ((WindowArray *)aClosure)->AppendElement(aWindow);
 
   return PL_DHASH_NEXT;
 }
 
 struct ReportGhostWindowsEnumeratorData
 {
-  nsIMemoryReporterCallback* callback;
-  nsISupports* closure;
-  nsresult rv;
+  nsIMemoryReporterCallback* mCallback;
+  nsISupports* mData;
+  bool mAnonymize;
+  nsresult mRv;
 };
 
 static PLDHashOperator
-ReportGhostWindowsEnumerator(nsUint64HashKey* aIDHashKey, void* aClosure)
+ReportGhostWindowsEnumerator(nsUint64HashKey* aIDHashKey, void* aData)
 {
   ReportGhostWindowsEnumeratorData *data =
-    static_cast<ReportGhostWindowsEnumeratorData*>(aClosure);
+    static_cast<ReportGhostWindowsEnumeratorData*>(aData);
 
   nsGlobalWindow::WindowByIdTable* windowsById =
     nsGlobalWindow::GetWindowsTable();
   if (!windowsById) {
     NS_WARNING("Couldn't get window-by-id hashtable?");
     return PL_DHASH_NEXT;
   }
 
   nsGlobalWindow* window = windowsById->Get(aIDHashKey->GetKey());
   if (!window) {
     NS_WARNING("Could not look up window?");
     return PL_DHASH_NEXT;
   }
 
   nsAutoCString path;
   path.AppendLiteral("ghost-windows/");
-  AppendWindowURI(window, path);
+  AppendWindowURI(window, path, data->mAnonymize);
 
-  nsresult rv = data->callback->Callback(
+  nsresult rv = data->mCallback->Callback(
     /* process = */ EmptyCString(),
     path,
     nsIMemoryReporter::KIND_OTHER,
     nsIMemoryReporter::UNITS_COUNT,
     /* amount = */ 1,
     /* description = */ NS_LITERAL_CSTRING("A ghost window."),
-    data->closure);
+    data->mData);
 
-  if (NS_FAILED(rv) && NS_SUCCEEDED(data->rv)) {
-    data->rv = rv;
+  if (NS_FAILED(rv) && NS_SUCCEEDED(data->mRv)) {
+    data->mRv = rv;
   }
 
   return PL_DHASH_NEXT;
 }
 
 NS_IMETHODIMP
 nsWindowMemoryReporter::CollectReports(nsIMemoryReporterCallback* aCb,
-                                       nsISupports* aClosure)
+                                       nsISupports* aClosure, bool aAnonymize)
 {
   nsGlobalWindow::WindowByIdTable* windowsById =
     nsGlobalWindow::GetWindowsTable();
   NS_ENSURE_TRUE(windowsById, NS_OK);
 
   // 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);
 
   // Get the IDs of all the "ghost" windows, and call aCb->Callback() for each
   // one.
   nsTHashtable<nsUint64HashKey> ghostWindows;
   CheckForGhostWindows(&ghostWindows);
   ReportGhostWindowsEnumeratorData reportGhostWindowsEnumData =
-    { aCb, aClosure, NS_OK };
+    { aCb, aClosure, aAnonymize, NS_OK };
   ghostWindows.EnumerateEntries(ReportGhostWindowsEnumerator,
                                 &reportGhostWindowsEnumData);
-  nsresult rv = reportGhostWindowsEnumData.rv;
+  nsresult rv = reportGhostWindowsEnumData.mRv;
   NS_ENSURE_SUCCESS(rv, rv);
 
   WindowPaths windowPaths;
   WindowPaths topWindowPaths;
 
   // Collect window memory usage.
   nsWindowSizes windowTotalSizes(nullptr);
   nsCOMPtr<amIAddonManager> addonManager;
   if (XRE_GetProcessType() == GeckoProcessType_Default) {
     // Only try to access the service from the main process.
     addonManager = do_GetService("@mozilla.org/addons/integration;1");
   }
   for (uint32_t i = 0; i < windows.Length(); i++) {
     rv = CollectWindowReports(windows[i], addonManager,
                               &windowTotalSizes, &ghostWindows,
                               &windowPaths, &topWindowPaths, aCb,
-                              aClosure);
+                              aClosure, aAnonymize);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   // Report JS memory usage.  We do this from here because the JS memory
   // reporter needs to be passed |windowPaths|.
   rv = xpc::JSReporter::CollectReports(&windowPaths, &topWindowPaths,
-                                       aCb, aClosure);
+                                       aCb, aClosure, aAnonymize);
   NS_ENSURE_SUCCESS(rv, rv);
 
 #define REPORT(_path, _amount, _desc)                                         \
   do {                                                                        \
     nsresult rv;                                                              \
     rv = aCb->Callback(EmptyCString(), NS_LITERAL_CSTRING(_path),             \
                        KIND_OTHER, UNITS_BYTES, _amount,                      \
                        NS_LITERAL_CSTRING(_desc), aClosure);                  \
--- a/dom/base/nsWindowMemoryReporter.h
+++ b/dom/base/nsWindowMemoryReporter.h
@@ -168,17 +168,18 @@ private:
   class GhostWindowsReporter MOZ_FINAL : public nsIMemoryReporter
   {
   public:
     NS_DECL_ISUPPORTS
 
     static int64_t DistinguishedAmount();
 
     NS_IMETHOD
-    CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData)
+    CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData,
+                   bool aAnonymize)
     {
       return MOZ_COLLECT_REPORT(
         "ghost-windows", KIND_OTHER, UNITS_COUNT, DistinguishedAmount(),
 "The number of ghost windows present (the number of nodes underneath "
 "explicit/window-objects/top(none)/ghost, modulo race conditions).  A ghost "
 "window is not shown in any tab, does not share a domain with any non-detached "
 "windows, and has met these criteria for at least "
 "memory.ghost_window_timeout_seconds, or has survived a round of "
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -185,28 +185,32 @@ namespace mozilla {
 namespace dom {
 
 class MemoryReportRequestChild : public PMemoryReportRequestChild,
                                  public nsIRunnable
 {
 public:
     NS_DECL_ISUPPORTS
 
-    MemoryReportRequestChild(uint32_t aGeneration, const nsAString& aDMDDumpIdent);
+    MemoryReportRequestChild(uint32_t aGeneration, bool aAnonymize,
+                             const nsAString& aDMDDumpIdent);
     virtual ~MemoryReportRequestChild();
     NS_IMETHOD Run();
 private:
     uint32_t mGeneration;
+    bool     mAnonymize;
     nsString mDMDDumpIdent;
 };
 
 NS_IMPL_ISUPPORTS(MemoryReportRequestChild, nsIRunnable)
 
-MemoryReportRequestChild::MemoryReportRequestChild(uint32_t aGeneration, const nsAString& aDMDDumpIdent)
-: mGeneration(aGeneration), mDMDDumpIdent(aDMDDumpIdent)
+MemoryReportRequestChild::MemoryReportRequestChild(
+    uint32_t aGeneration, bool aAnonymize, const nsAString& aDMDDumpIdent)
+  : mGeneration(aGeneration), mAnonymize(aAnonymize),
+    mDMDDumpIdent(aDMDDumpIdent)
 {
     MOZ_COUNT_CTOR(MemoryReportRequestChild);
 }
 
 MemoryReportRequestChild::~MemoryReportRequestChild()
 {
     MOZ_COUNT_DTOR(MemoryReportRequestChild);
 }
@@ -667,21 +671,23 @@ ContentChild::InitXPCOM()
     sysMsgObserver->Init();
 
 #ifndef MOZ_NUWA_PROCESS
     InitOnContentProcessCreated();
 #endif
 }
 
 PMemoryReportRequestChild*
-ContentChild::AllocPMemoryReportRequestChild(const uint32_t& generation,
-                                             const bool &minimizeMemoryUsage,
+ContentChild::AllocPMemoryReportRequestChild(const uint32_t& aGeneration,
+                                             const bool &aAnonymize,
+                                             const bool &aMinimizeMemoryUsage,
                                              const nsString& aDMDDumpIdent)
 {
-    MemoryReportRequestChild *actor = new MemoryReportRequestChild(generation, aDMDDumpIdent);
+    MemoryReportRequestChild *actor =
+        new MemoryReportRequestChild(aGeneration, aAnonymize, aDMDDumpIdent);
     actor->AddRef();
     return actor;
 }
 
 // This is just a wrapper for InfallibleTArray<MemoryReport> that implements
 // nsISupports, so it can be passed to nsIMemoryReporter::CollectReports.
 class MemoryReportsWrapper MOZ_FINAL : public nsISupports {
 public:
@@ -719,25 +725,27 @@ private:
 };
 NS_IMPL_ISUPPORTS(
   MemoryReportCallback
 , nsIMemoryReporterCallback
 )
 
 bool
 ContentChild::RecvPMemoryReportRequestConstructor(
-    PMemoryReportRequestChild* child,
-    const uint32_t& generation,
-    const bool& minimizeMemoryUsage,
+    PMemoryReportRequestChild* aChild,
+    const uint32_t& aGeneration,
+    const bool& aAnonymize,
+    const bool& aMinimizeMemoryUsage,
     const nsString& aDMDDumpIdent)
 {
-    MemoryReportRequestChild *actor = static_cast<MemoryReportRequestChild*>(child);
+    MemoryReportRequestChild *actor =
+        static_cast<MemoryReportRequestChild*>(aChild);
     nsresult rv;
 
-    if (minimizeMemoryUsage) {
+    if (aMinimizeMemoryUsage) {
         nsCOMPtr<nsIMemoryReporterManager> mgr = do_GetService("@mozilla.org/memory-reporter-manager;1");
         rv = mgr->MinimizeMemoryUsage(actor);
         // mgr will eventually call actor->Run()
     } else {
         rv = actor->Run();
     }
 
     return !NS_WARN_IF(NS_FAILED(rv));
@@ -754,17 +762,18 @@ NS_IMETHODIMP MemoryReportRequestChild::
     child->GetProcessName(process);
     child->AppendProcessId(process);
 
     // Run the reporters.  The callback will turn each measurement into a
     // MemoryReport.
     nsRefPtr<MemoryReportsWrapper> wrappedReports =
         new MemoryReportsWrapper(&reports);
     nsRefPtr<MemoryReportCallback> cb = new MemoryReportCallback(process);
-    mgr->GetReportsForThisProcessExtended(cb, wrappedReports, mDMDDumpIdent);
+    mgr->GetReportsForThisProcessExtended(cb, wrappedReports, mAnonymize,
+                                          mDMDDumpIdent);
 
     bool sent = Send__delete__(this, mGeneration, reports);
     return sent ? NS_OK : NS_ERROR_FAILURE;
 }
 
 bool
 ContentChild::RecvAudioChannelNotify()
 {
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -147,26 +147,28 @@ public:
 
     virtual PHalChild* AllocPHalChild() MOZ_OVERRIDE;
     virtual bool DeallocPHalChild(PHalChild*) MOZ_OVERRIDE;
 
     virtual PIndexedDBChild* AllocPIndexedDBChild() MOZ_OVERRIDE;
     virtual bool DeallocPIndexedDBChild(PIndexedDBChild* aActor) MOZ_OVERRIDE;
 
     virtual PMemoryReportRequestChild*
-    AllocPMemoryReportRequestChild(const uint32_t& generation,
-                                   const bool &minimizeMemoryUsage,
-                                   const nsString &aDMDDumpIdent) MOZ_OVERRIDE;
+    AllocPMemoryReportRequestChild(const uint32_t& aGeneration,
+                                   const bool& aAnonymize,
+                                   const bool& aMinimizeMemoryUsage,
+                                   const nsString& aDMDDumpIdent) MOZ_OVERRIDE;
     virtual bool
     DeallocPMemoryReportRequestChild(PMemoryReportRequestChild* actor) MOZ_OVERRIDE;
 
     virtual bool
-    RecvPMemoryReportRequestConstructor(PMemoryReportRequestChild* child,
-                                        const uint32_t& generation,
-                                        const bool &minimizeMemoryUsage,
+    RecvPMemoryReportRequestConstructor(PMemoryReportRequestChild* aChild,
+                                        const uint32_t& aGeneration,
+                                        const bool& aAnonymize,
+                                        const bool &aMinimizeMemoryUsage,
                                         const nsString &aDMDDumpIdent) MOZ_OVERRIDE;
 
     virtual PCycleCollectWithLogsChild*
     AllocPCycleCollectWithLogsChild(const bool& aDumpAllTraces,
                                     const FileDescriptor& aGCLog,
                                     const FileDescriptor& aCCLog) MOZ_OVERRIDE;
     virtual bool
     DeallocPCycleCollectWithLogsChild(PCycleCollectWithLogsChild* aActor) MOZ_OVERRIDE;
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -449,27 +449,28 @@ public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSIMEMORYREPORTER
 };
 
 NS_IMPL_ISUPPORTS(ContentParentsMemoryReporter, nsIMemoryReporter)
 
 NS_IMETHODIMP
 ContentParentsMemoryReporter::CollectReports(nsIMemoryReporterCallback* cb,
-                                             nsISupports* aClosure)
+                                             nsISupports* aClosure,
+                                             bool aAnonymize)
 {
     nsAutoTArray<ContentParent*, 16> cps;
     ContentParent::GetAllEvenIfDead(cps);
 
     for (uint32_t i = 0; i < cps.Length(); i++) {
         ContentParent* cp = cps[i];
         MessageChannel* channel = cp->GetIPCChannel();
 
         nsString friendlyName;
-        cp->FriendlyName(friendlyName);
+        cp->FriendlyName(friendlyName, aAnonymize);
 
         cp->AddRef();
         nsrefcnt refcnt = cp->Release();
 
         const char* channelStr = "no channel";
         uint32_t numQueuedMessages = 0;
         if (channel) {
             if (channel->Unsound_IsClosed()) {
@@ -2418,31 +2419,32 @@ ContentParent::Observe(nsISupports* aSub
     }
     else if (!strcmp(aTopic, "child-memory-reporter-request")) {
         bool isNuwa = false;
 #ifdef MOZ_NUWA_PROCESS
         isNuwa = IsNuwaProcess();
 #endif
         if (!isNuwa) {
             unsigned generation;
-            int minimize, identOffset = -1;
+            int anonymize, minimize, identOffset = -1;
             nsDependentString msg(aData);
             NS_ConvertUTF16toUTF8 cmsg(msg);
 
             if (sscanf(cmsg.get(),
-                       "generation=%x minimize=%d DMDident=%n",
-                       &generation, &minimize, &identOffset) < 2
+                       "generation=%x anonymize=%d minimize=%d DMDident=%n",
+                       &generation, &anonymize, &minimize, &identOffset) < 3
                 || identOffset < 0) {
                 return NS_ERROR_INVALID_ARG;
             }
             // The pre-%n part of the string should be all ASCII, so the byte
             // offset in identOffset should be correct as a char offset.
             MOZ_ASSERT(cmsg[identOffset - 1] == '=');
             unused << SendPMemoryReportRequestConstructor(
-              generation, minimize, nsString(Substring(msg, identOffset)));
+              generation, anonymize, minimize,
+              nsString(Substring(msg, identOffset)));
         }
     }
     else if (!strcmp(aTopic, "child-gc-request")){
         unused << SendGarbageCollect();
     }
     else if (!strcmp(aTopic, "child-cc-request")){
         unused << SendCycleCollect();
     }
@@ -2673,28 +2675,30 @@ ContentParent::KillHard()
 
 bool
 ContentParent::IsPreallocated()
 {
     return mAppManifestURL == MAGIC_PREALLOCATED_APP_MANIFEST_URL;
 }
 
 void
-ContentParent::FriendlyName(nsAString& aName)
+ContentParent::FriendlyName(nsAString& aName, bool aAnonymize)
 {
     aName.Truncate();
 #ifdef MOZ_NUWA_PROCESS
     if (IsNuwaProcess()) {
         aName.AssignLiteral("(Nuwa)");
     } else
 #endif
     if (IsPreallocated()) {
         aName.AssignLiteral("(Preallocated)");
     } else if (mIsForBrowser) {
         aName.AssignLiteral("Browser");
+    } else if (aAnonymize) {
+        aName.AssignLiteral("<anonymized-name>");
     } else if (!mAppName.IsEmpty()) {
         aName = mAppName;
     } else if (!mAppManifestURL.IsEmpty()) {
         aName.AssignLiteral("Unknown app: ");
         aName.Append(mAppManifestURL);
     } else {
         aName.AssignLiteral("???");
     }
@@ -2772,18 +2776,19 @@ ContentParent::RecvPIndexedDBConstructor
     IndexedDBParent* actor = static_cast<IndexedDBParent*>(aActor);
     actor->mFactory = factory;
     actor->mASCIIOrigin = factory->GetASCIIOrigin();
 
     return true;
 }
 
 PMemoryReportRequestParent*
-ContentParent::AllocPMemoryReportRequestParent(const uint32_t& generation,
-                                               const bool &minimizeMemoryUsage,
+ContentParent::AllocPMemoryReportRequestParent(const uint32_t& aGeneration,
+                                               const bool &aAnonymize,
+                                               const bool &aMinimizeMemoryUsage,
                                                const nsString &aDMDDumpIdent)
 {
     MemoryReportRequestParent* parent = new MemoryReportRequestParent();
     return parent;
 }
 
 bool
 ContentParent::DeallocPMemoryReportRequestParent(PMemoryReportRequestParent* actor)
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -203,17 +203,17 @@ public:
     bool IsPreallocated();
 
     /**
      * Get a user-friendly name for this ContentParent.  We make no guarantees
      * about this name: It might not be unique, apps can spoof special names,
      * etc.  So please don't use this name to make any decisions about the
      * ContentParent based on the value returned here.
      */
-    void FriendlyName(nsAString& aName);
+    void FriendlyName(nsAString& aName, bool aAnonymize = false);
 
     virtual void OnChannelError() MOZ_OVERRIDE;
 
     virtual PIndexedDBParent* AllocPIndexedDBParent() MOZ_OVERRIDE;
     virtual bool
     RecvPIndexedDBConstructor(PIndexedDBParent* aActor) MOZ_OVERRIDE;
 
     virtual PCrashReporterParent*
@@ -413,18 +413,19 @@ private:
     virtual bool RecvGetRandomValues(const uint32_t& length,
                                      InfallibleTArray<uint8_t>* randomValues) MOZ_OVERRIDE;
 
     virtual bool DeallocPHalParent(PHalParent*) MOZ_OVERRIDE;
 
     virtual bool DeallocPIndexedDBParent(PIndexedDBParent* aActor) MOZ_OVERRIDE;
 
     virtual PMemoryReportRequestParent*
-    AllocPMemoryReportRequestParent(const uint32_t& generation,
-                                    const bool &minimizeMemoryUsage,
+    AllocPMemoryReportRequestParent(const uint32_t& aGeneration,
+                                    const bool &aAnonymize,
+                                    const bool &aMinimizeMemoryUsage,
                                     const nsString &aDMDDumpIdent) MOZ_OVERRIDE;
     virtual bool DeallocPMemoryReportRequestParent(PMemoryReportRequestParent* actor) MOZ_OVERRIDE;
 
     virtual PCycleCollectWithLogsParent*
     AllocPCycleCollectWithLogsParent(const bool& aDumpAllTraces,
                                      const FileDescriptor& aGCLog,
                                      const FileDescriptor& aCCLog) MOZ_OVERRIDE;
     virtual bool
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -345,17 +345,18 @@ both:
 child:
     /**
      * Enable system-level sandboxing features, if available.  Can
      * usually only be performed zero or one times.  The child may
      * abnormally exit if this fails; the details are OS-specific.
      */
     async SetProcessSandbox();
 
-    PMemoryReportRequest(uint32_t generation, bool minimizeMemoryUsage, nsString DMDDumpIdent);
+    PMemoryReportRequest(uint32_t generation, bool anonymize,
+                         bool minimizeMemoryUsage, nsString DMDDumpIdent);
 
     /**
      * Notify the AudioChannelService in the child processes.
      */
     async AudioChannelNotify();
 
     async SpeakerManagerNotify();
 
--- a/dom/settings/SettingsManager.js
+++ b/dom/settings/SettingsManager.js
@@ -380,28 +380,29 @@ SettingsManager.prototype = {
     if (aTopic == "inner-window-destroyed") {
       let wId = aSubject.QueryInterface(Ci.nsISupportsPRUint64).data;
       if (wId == this.innerWindowID) {
         this.cleanup();
       }
     }
   },
 
-  collectReports: function(aCallback, aData) {
+  collectReports: function(aCallback, aData, aAnonymize) {
     for (var topic in this._callbacks) {
       let length = this._callbacks[topic].length;
       if (length == 0) {
         continue;
       }
 
       let path;
       if (length < 20) {
         path = "settings-observers";
       } else {
-        path = "settings-observers-suspect/referent(topic=" + topic + ")";
+        path = "settings-observers-suspect/referent(topic=" +
+               (aAnonymize ? "<anonymized>" : topic) + ")";
       }
 
       aCallback.callback("", path,
                          Ci.nsIMemoryReporter.KIND_OTHER,
                          Ci.nsIMemoryReporter.UNITS_COUNT,
                          this._callbacks[topic].length,
                          "The number of settings observers for this topic.",
                          aData);
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -1753,16 +1753,18 @@ public:
                                             (void *)js::GetCompartmentZone(aCompartment));
     extras->jsPathPrefix += js::IsAtomsCompartment(aCompartment)
                             ? NS_LITERAL_CSTRING("compartment(web-worker-atoms)/")
                             : NS_LITERAL_CSTRING("compartment(web-worker)/");
 
     // This should never be used when reporting with workers (hence the "?!").
     extras->domPathPrefix.AssignLiteral("explicit/workers/?!/");
 
+    extras->location = nullptr;
+
     aCompartmentStats->extra = extras;
   }
 };
 
 class MessagePortRunnable MOZ_FINAL : public WorkerRunnable
 {
   uint64_t mMessagePortSerial;
   bool mConnect;
@@ -1970,65 +1972,71 @@ struct WorkerPrivate::TimeoutInfo
 class WorkerPrivate::MemoryReporter MOZ_FINAL : public nsIMemoryReporter
 {
   NS_DECL_THREADSAFE_ISUPPORTS
 
   friend class WorkerPrivate;
 
   SharedMutex mMutex;
   WorkerPrivate* mWorkerPrivate;
-  nsCString mRtPath;
   bool mAlreadyMappedToAddon;
 
 public:
   MemoryReporter(WorkerPrivate* aWorkerPrivate)
   : mMutex(aWorkerPrivate->mMutex), mWorkerPrivate(aWorkerPrivate),
     mAlreadyMappedToAddon(false)
   {
     aWorkerPrivate->AssertIsOnWorkerThread();
 
-    nsCString escapedDomain(aWorkerPrivate->Domain());
-    escapedDomain.ReplaceChar('/', '\\');
-
-    NS_ConvertUTF16toUTF8 escapedURL(aWorkerPrivate->ScriptURL());
-    escapedURL.ReplaceChar('/', '\\');
-
-    nsAutoCString addressString;
-    addressString.AppendPrintf("0x%p", static_cast<void*>(aWorkerPrivate));
-
-    mRtPath = NS_LITERAL_CSTRING("explicit/workers/workers(") +
-              escapedDomain + NS_LITERAL_CSTRING(")/worker(") +
-              escapedURL + NS_LITERAL_CSTRING(", ") + addressString +
-              NS_LITERAL_CSTRING(")/");
   }
 
   NS_IMETHOD
   CollectReports(nsIMemoryReporterCallback* aCallback,
-                 nsISupports* aClosure)
+                 nsISupports* aClosure, bool aAnonymize)
   {
     AssertIsOnMainThread();
 
-    // Assumes that WorkerJSRuntimeStats will hold a reference to mRtPath,
-    // and not a copy, as TryToMapAddon() may later modify the string again.
-    WorkerJSRuntimeStats rtStats(mRtPath);
+    // Assumes that WorkerJSRuntimeStats will hold a reference to |path|, and
+    // not a copy, as TryToMapAddon() may later modify if.
+    nsCString path;
+    WorkerJSRuntimeStats rtStats(path);
 
     {
       MutexAutoLock lock(mMutex);
 
-      TryToMapAddon();
+      path.AppendLiteral("explicit/workers/workers(");
+      if (aAnonymize && !mWorkerPrivate->Domain().IsEmpty()) {
+        path.AppendLiteral("<anonymized-domain>)/worker(<anonymized-url>");
+      } else {
+        nsCString escapedDomain(mWorkerPrivate->Domain());
+        if (escapedDomain.IsEmpty()) {
+          escapedDomain += "chrome";
+        } else {
+          escapedDomain.ReplaceChar('/', '\\');
+        }
+        path.Append(escapedDomain);
+        path.AppendLiteral(")/worker(");
+        NS_ConvertUTF16toUTF8 escapedURL(mWorkerPrivate->ScriptURL());
+        escapedURL.ReplaceChar('/', '\\');
+        path.Append(escapedURL);
+      }
+      path.AppendPrintf(", 0x%p)/", static_cast<void*>(mWorkerPrivate));
+
+      TryToMapAddon(path);
 
       if (!mWorkerPrivate ||
-          !mWorkerPrivate->BlockAndCollectRuntimeStats(&rtStats)) {
+          !mWorkerPrivate->BlockAndCollectRuntimeStats(&rtStats, aAnonymize)) {
         // Returning NS_OK here will effectively report 0 memory.
         return NS_OK;
       }
     }
 
-    return xpc::ReportJSRuntimeExplicitTreeStats(rtStats, mRtPath,
-                                                 aCallback, aClosure);
+    return xpc::ReportJSRuntimeExplicitTreeStats(rtStats, path,
+                                                 aCallback, aClosure,
+                                                 aAnonymize);
   }
 
 private:
   ~MemoryReporter()
   { }
 
   void
   Disable()
@@ -2037,17 +2045,17 @@ private:
     mMutex.AssertCurrentThreadOwns();
 
     NS_ASSERTION(mWorkerPrivate, "Disabled more than once!");
     mWorkerPrivate = nullptr;
   }
 
   // Only call this from the main thread and under mMutex lock.
   void
-  TryToMapAddon()
+  TryToMapAddon(nsACString &path)
   {
     AssertIsOnMainThread();
     mMutex.AssertCurrentThreadOwns();
 
     if (mAlreadyMappedToAddon || !mWorkerPrivate) {
       return;
     }
 
@@ -2073,17 +2081,17 @@ private:
         NS_FAILED(addonManager->MapURIToAddonID(scriptURI, addonId, &ok)) ||
         !ok) {
       return;
     }
 
     static const size_t explicitLength = strlen("explicit/");
     addonId.Insert(NS_LITERAL_CSTRING("add-ons/"), 0);
     addonId += "/";
-    mRtPath.Insert(addonId, explicitLength);
+    path.Insert(addonId, explicitLength);
   }
 };
 
 NS_IMPL_ISUPPORTS(WorkerPrivate::MemoryReporter, nsIMemoryReporter)
 
 WorkerPrivate::SyncLoopInfo::SyncLoopInfo(EventTarget* aEventTarget)
 : mEventTarget(aEventTarget), mCompleted(false), mResult(false)
 #ifdef DEBUG
@@ -4296,17 +4304,18 @@ WorkerPrivate::ScheduleDeletion(WorkerRa
       new TopLevelWorkerFinishedRunnable(this);
     if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
       NS_WARNING("Failed to dispatch runnable!");
     }
   }
 }
 
 bool
-WorkerPrivate::BlockAndCollectRuntimeStats(JS::RuntimeStats* aRtStats)
+WorkerPrivate::BlockAndCollectRuntimeStats(JS::RuntimeStats* aRtStats,
+                                           bool aAnonymize)
 {
   AssertIsOnMainThread();
   mMutex.AssertCurrentThreadOwns();
   NS_ASSERTION(aRtStats, "Null RuntimeStats!");
 
   NS_ASSERTION(!mMemoryReporterRunning, "How can we get reentered here?!");
 
   // This signals the worker that it should block itself as soon as possible.
@@ -4329,17 +4338,17 @@ WorkerPrivate::BlockAndCollectRuntimeSta
 
   bool succeeded = false;
 
   // If mMemoryReporter is still set then we can do the actual report. Otherwise
   // we're trying to shut down and we don't want to do anything but clean up.
   if (mMemoryReporter) {
     // Don't hold the lock while doing the actual report.
     MutexAutoUnlock unlock(mMutex);
-    succeeded = JS::CollectRuntimeStats(rt, aRtStats, nullptr);
+    succeeded = JS::CollectRuntimeStats(rt, aRtStats, nullptr, aAnonymize);
   }
 
   NS_ASSERTION(mMemoryReporterRunning, "This isn't possible!");
   NS_ASSERTION(mBlockedForMemoryReporter, "Somehow we got unblocked!");
 
   // Tell the worker that it can now continue its execution.
   mMemoryReporterRunning = false;
 
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -943,17 +943,17 @@ public:
     WorkerNeverRan = 0,
     WorkerRan
   };
 
   void
   ScheduleDeletion(WorkerRanOrNot aRanOrNot);
 
   bool
-  BlockAndCollectRuntimeStats(JS::RuntimeStats* aRtStats);
+  BlockAndCollectRuntimeStats(JS::RuntimeStats* aRtStats, bool aAnonymize);
 
 #ifdef JS_GC_ZEAL
   void
   UpdateGCZealInternal(JSContext* aCx, uint8_t aGCZeal, uint32_t aFrequency);
 #endif
 
   void
   GarbageCollectInternal(JSContext* aCx, bool aShrinking,
--- a/extensions/spellcheck/hunspell/src/mozHunspell.h
+++ b/extensions/spellcheck/hunspell/src/mozHunspell.h
@@ -98,17 +98,17 @@ 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);
 
   NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
-                            nsISupports* aData)
+                            nsISupports* aData, bool aAnonymize)
   {
     return MOZ_COLLECT_REPORT(
       "explicit/spell-check", KIND_HEAP, UNITS_BYTES, HunspellAllocator::MemoryAllocated(),
       "Memory used by the spell-checking engine.");
   }
 
 protected:
 
--- a/gfx/gl/GfxTexturesReporter.h
+++ b/gfx/gl/GfxTexturesReporter.h
@@ -37,17 +37,17 @@ public:
     };
 
     // When memory is used/freed for tile textures, call this method to update
     // the value reported by this memory reporter.
     static void UpdateAmount(MemoryUse action, GLenum format, GLenum type,
                              int32_t tileWidth, int32_t tileHeight);
 
     NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
-                              nsISupports* aData)
+                              nsISupports* aData, bool aAnonymize)
     {
         return MOZ_COLLECT_REPORT(
             "gfx-textures", KIND_OTHER, UNITS_BYTES, sAmount,
             "Memory used for storing GL textures.");
     }
 
 private:
     static int64_t sAmount;
--- a/gfx/layers/ipc/ISurfaceAllocator.h
+++ b/gfx/layers/ipc/ISurfaceAllocator.h
@@ -205,17 +205,17 @@ public:
   }
 
   static void WillFree(void* aPointer)
   {
     sAmount -= MallocSizeOfOnFree(aPointer);
   }
 
   NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
-                            nsISupports* aData)
+                            nsISupports* aData, bool aAnonymize)
   {
     return MOZ_COLLECT_REPORT(
       "explicit/gfx/heap-textures", KIND_HEAP, UNITS_BYTES, sAmount,
       "Heap memory shared between threads by texture clients and hosts.");
   }
 
 private:
   static mozilla::Atomic<size_t> sAmount;
--- a/gfx/layers/ipc/SharedBufferManagerParent.cpp
+++ b/gfx/layers/ipc/SharedBufferManagerParent.cpp
@@ -36,17 +36,17 @@ Atomic<uint32_t> SharedBufferManagerPare
 
 #ifdef MOZ_WIDGET_GONK
 class GrallocReporter MOZ_FINAL : public nsIMemoryReporter
 {
 public:
   NS_DECL_ISUPPORTS
 
   NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
-                            nsISupports* aData)
+                            nsISupports* aData, bool aAnonymize)
   {
     map<base::ProcessId, SharedBufferManagerParent*>::iterator it;
     for (it = SharedBufferManagerParent::sManagers.begin(); it != SharedBufferManagerParent::sManagers.end(); it++) {
       base::ProcessId pid = it->first;
       SharedBufferManagerParent *mgr = it->second;
 
       std::map<int, android::sp<android::GraphicBuffer> >::iterator buf_it;
       for (buf_it = mgr->mBuffers.begin(); buf_it != mgr->mBuffers.end(); buf_it++) {
--- a/gfx/thebes/gfxASurface.cpp
+++ b/gfx/thebes/gfxASurface.cpp
@@ -581,17 +581,17 @@ PR_STATIC_ASSERT(uint32_t(CAIRO_SURFACE_
 static int64_t gSurfaceMemoryUsed[size_t(gfxSurfaceType::Max)] = { 0 };
 
 class SurfaceMemoryReporter MOZ_FINAL : public nsIMemoryReporter
 {
 public:
     NS_DECL_ISUPPORTS
 
     NS_IMETHOD CollectReports(nsIMemoryReporterCallback *aCb,
-                              nsISupports *aClosure)
+                              nsISupports *aClosure, bool aAnonymize)
     {
         const size_t len = ArrayLength(sSurfaceMemoryReporterAttrs);
         for (size_t i = 0; i < len; i++) {
             int64_t amount = gSurfaceMemoryUsed[i];
 
             if (amount != 0) {
                 const char *path = sSurfaceMemoryReporterAttrs[i].path;
                 const char *desc = sSurfaceMemoryReporterAttrs[i].description;
--- a/gfx/thebes/gfxAndroidPlatform.cpp
+++ b/gfx/thebes/gfxAndroidPlatform.cpp
@@ -58,17 +58,17 @@ public:
 
     static void*
     Realloc(FT_Memory, long cur_size, long new_size, void* p)
     {
         return CountingRealloc(p, new_size);
     }
 
     NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
-                              nsISupports* aData)
+                              nsISupports* aData, bool aAnonymize)
     {
         return MOZ_COLLECT_REPORT(
             "explicit/freetype", KIND_HEAP, UNITS_BYTES, MemoryAllocated(),
             "Memory used by Freetype.");
     }
 };
 
 NS_IMPL_ISUPPORTS(FreetypeReporter, nsIMemoryReporter)
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -1735,19 +1735,18 @@ gfxFontFamily::AddSizeOfIncludingThis(Ma
  * shaped-word caches to free up memory.
  */
 
 MOZ_DEFINE_MALLOC_SIZE_OF(FontCacheMallocSizeOf)
 
 NS_IMPL_ISUPPORTS(gfxFontCache::MemoryReporter, nsIMemoryReporter)
 
 NS_IMETHODIMP
-gfxFontCache::MemoryReporter::CollectReports
-    (nsIMemoryReporterCallback* aCb,
-     nsISupports* aClosure)
+gfxFontCache::MemoryReporter::CollectReports(
+    nsIMemoryReporterCallback* aCb, nsISupports* aClosure, bool aAnonymize)
 {
     FontCacheSizes sizes;
 
     gfxFontCache::GetCache()->AddSizeOfIncludingThis(&FontCacheMallocSizeOf,
                                                      &sizes);
 
     aCb->Callback(EmptyCString(),
                   NS_LITERAL_CSTRING("explicit/gfx/font-cache"),
--- a/gfx/thebes/gfxPlatformFontList.cpp
+++ b/gfx/thebes/gfxPlatformFontList.cpp
@@ -123,39 +123,41 @@ gfxFontListPrefObserver::Observe(nsISupp
     return NS_OK;
 }
 
 MOZ_DEFINE_MALLOC_SIZE_OF(FontListMallocSizeOf)
 
 NS_IMPL_ISUPPORTS(gfxPlatformFontList::MemoryReporter, nsIMemoryReporter)
 
 NS_IMETHODIMP
-gfxPlatformFontList::MemoryReporter::CollectReports
-    (nsIMemoryReporterCallback* aCb,
-     nsISupports* aClosure)
+gfxPlatformFontList::MemoryReporter::CollectReports(
+    nsIMemoryReporterCallback* aCb, nsISupports* aClosure, bool aAnonymize)
 {
     FontListSizes sizes;
     sizes.mFontListSize = 0;
     sizes.mFontTableCacheSize = 0;
     sizes.mCharMapsSize = 0;
 
     gfxPlatformFontList::PlatformFontList()->AddSizeOfIncludingThis(&FontListMallocSizeOf,
                                                                     &sizes);
 
-    aCb->Callback(EmptyCString(),
-                  NS_LITERAL_CSTRING("explicit/gfx/font-list"),
-                  KIND_HEAP, UNITS_BYTES, sizes.mFontListSize,
-                  NS_LITERAL_CSTRING("Memory used to manage the list of font families and faces."),
-                  aClosure);
+    nsresult rv;
+    rv = aCb->Callback(EmptyCString(),
+                       NS_LITERAL_CSTRING("explicit/gfx/font-list"),
+                       KIND_HEAP, UNITS_BYTES, sizes.mFontListSize,
+                       NS_LITERAL_CSTRING("Memory used to manage the list of font families and faces."),
+                       aClosure);
+    NS_ENSURE_SUCCESS(rv, rv);
 
-    aCb->Callback(EmptyCString(),
-                  NS_LITERAL_CSTRING("explicit/gfx/font-charmaps"),
-                  KIND_HEAP, UNITS_BYTES, sizes.mCharMapsSize,
-                  NS_LITERAL_CSTRING("Memory used to record the character coverage of individual fonts."),
-                  aClosure);
+    rv = aCb->Callback(EmptyCString(),
+                       NS_LITERAL_CSTRING("explicit/gfx/font-charmaps"),
+                       KIND_HEAP, UNITS_BYTES, sizes.mCharMapsSize,
+                       NS_LITERAL_CSTRING("Memory used to record the character coverage of individual fonts."),
+                       aClosure);
+    NS_ENSURE_SUCCESS(rv, rv);
 
     if (sizes.mFontTableCacheSize) {
         aCb->Callback(EmptyCString(),
                       NS_LITERAL_CSTRING("explicit/gfx/font-tables"),
                       KIND_HEAP, UNITS_BYTES, sizes.mFontTableCacheSize,
                       NS_LITERAL_CSTRING("Memory used for cached font metrics and layout tables."),
                       aClosure);
     }
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -82,17 +82,17 @@ static const int kSupportedFeatureLevels
     D3D10_FEATURE_LEVEL_9_3 };
 
 class GfxD2DSurfaceReporter MOZ_FINAL : public nsIMemoryReporter
 {
 public:
     NS_DECL_ISUPPORTS
 
     NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
-                              nsISupports* aData)
+                              nsISupports* aData, bool aAnonymize)
     {
         nsresult rv;
 
         int64_t amount = cairo_d2d_get_image_surface_cache_usage();
         rv = MOZ_COLLECT_REPORT(
             "gfx-d2d-surface-cache", KIND_OTHER, UNITS_BYTES, amount,
             "Memory used by the Direct2D internal surface cache.");
         NS_ENSURE_SUCCESS(rv, rv);
@@ -114,17 +114,17 @@ NS_IMPL_ISUPPORTS(GfxD2DSurfaceReporter,
 #endif
 
 class GfxD2DVramReporter MOZ_FINAL : public nsIMemoryReporter
 {
 public:
     NS_DECL_ISUPPORTS
 
     NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
-                              nsISupports* aData)
+                              nsISupports* aData, bool aAnonymize)
     {
         nsresult rv;
 
         rv = MOZ_COLLECT_REPORT(
             "gfx-d2d-vram-draw-target", KIND_OTHER, UNITS_BYTES,
             Factory::GetD2DVRAMUsageDrawTarget(),
             "Video memory used by D2D DrawTargets.");
         NS_ENSURE_SUCCESS(rv, rv);
@@ -170,30 +170,30 @@ class GPUAdapterReporter : public nsIMem
         return result;
     }
 
 public:
     NS_DECL_ISUPPORTS
 
     NS_IMETHOD
     CollectReports(nsIMemoryReporterCallback* aCb,
-                   nsISupports* aClosure)
+                   nsISupports* aClosure, bool aAnonymize)
     {
         HANDLE ProcessHandle = GetCurrentProcess();
 
         int64_t dedicatedBytesUsed = 0;
         int64_t sharedBytesUsed = 0;
         int64_t committedBytesUsed = 0;
         IDXGIAdapter *DXGIAdapter;
 
         HMODULE gdi32Handle;
         PFND3DKMTQS queryD3DKMTStatistics;
 
         // GPU memory reporting is not available before Windows 7
-        if (!IsWin7OrLater()) 
+        if (!IsWin7OrLater())
             return NS_OK;
 
         if (gdi32Handle = LoadLibrary(TEXT("gdi32.dll")))
             queryD3DKMTStatistics = (PFND3DKMTQS)GetProcAddress(gdi32Handle, "D3DKMTQueryStatistics");
 
         if (queryD3DKMTStatistics && GetDXGIAdapter(&DXGIAdapter)) {
             // Most of this block is understood thanks to wj32's work on Process Hacker
 
--- a/image/src/SurfaceCache.cpp
+++ b/image/src/SurfaceCache.cpp
@@ -361,17 +361,18 @@ public:
                                         CachedSurface*    aSurface,
                                         void*             aCache)
   {
     static_cast<SurfaceCacheImpl*>(aCache)->StopTracking(aSurface);
     return PL_DHASH_NEXT;
   }
 
   NS_IMETHOD
-  CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData)
+  CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData,
+                 bool aAnonymize)
   {
     return MOZ_COLLECT_REPORT(
       "imagelib-surface-cache", KIND_OTHER, UNITS_BYTES,
       SizeOfSurfacesEstimate(),
       "Memory used by the imagelib temporary surface cache.");
   }
 
   // XXX(seth): This is currently only an estimate and, since we don't know
--- a/image/src/imgLoader.cpp
+++ b/image/src/imgLoader.cpp
@@ -51,27 +51,29 @@ using namespace mozilla::image;
 MOZ_DEFINE_MALLOC_SIZE_OF(ImagesMallocSizeOf)
 
 class imgMemoryReporter MOZ_FINAL : public nsIMemoryReporter
 {
 public:
   NS_DECL_ISUPPORTS
 
   NS_IMETHOD CollectReports(nsIMemoryReporterCallback *aHandleReport,
-                            nsISupports *aData)
+                            nsISupports *aData, bool aAnonymize)
   {
     nsresult rv;
     ImageSizes chrome;
     ImageSizes content;
 
     for (uint32_t i = 0; i < mKnownLoaders.Length(); i++) {
       mKnownLoaders[i]->mChromeCache.EnumerateRead(EntryImageSizes, &chrome);
       mKnownLoaders[i]->mCache.EnumerateRead(EntryImageSizes, &content);
     }
 
+    // Note that we only need to anonymize content image URIs.
+
     rv = ReportInfoArray(aHandleReport, aData, chrome.mRasterUsedImageInfo,
                          "images/chrome/raster/used");
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = ReportInfoArray(aHandleReport, aData, chrome.mRasterUnusedImageInfo,
                          "images/chrome/raster/unused");
     NS_ENSURE_SUCCESS(rv, rv);
 
@@ -79,29 +81,29 @@ public:
                          "images/chrome/vector/used/documents");
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = ReportInfoArray(aHandleReport, aData, chrome.mVectorUnusedImageDocInfo,
                          "images/chrome/vector/unused/documents");
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = ReportInfoArray(aHandleReport, aData, content.mRasterUsedImageInfo,
-                         "images/content/raster/used");
+                         "images/content/raster/used", aAnonymize);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = ReportInfoArray(aHandleReport, aData, content.mRasterUnusedImageInfo,
-                         "images/content/raster/unused");
+                         "images/content/raster/unused", aAnonymize);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = ReportInfoArray(aHandleReport, aData, content.mVectorUsedImageDocInfo,
-                         "images/content/vector/used/documents");
+                         "images/content/vector/used/documents", aAnonymize);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = ReportInfoArray(aHandleReport, aData, content.mVectorUnusedImageDocInfo,
-                         "images/content/vector/unused/documents");
+                         "images/content/vector/unused/documents", aAnonymize);
     NS_ENSURE_SUCCESS(rv, rv);
 
     return NS_OK;
   }
 
   static int64_t ImagesContentUsedUncompressedDistinguishedAmount()
   {
     size_t n = 0;
@@ -196,37 +198,43 @@ private:
                        Sizes aSizes);
 
   // This is used to report all images of a single kind, e.g. all
   // "chrome/raster/used" images.
   template <typename Sizes>
   nsresult ReportInfoArray(nsIMemoryReporterCallback *aHandleReport,
                            nsISupports *aData,
                            const nsTArray<ImageInfo<Sizes> > &aInfoArray,
-                           const char *aPathPartStr)
+                           const char *aPathPartStr, bool aAnonymize = false)
   {
     nsresult rv;
     Sizes totalSizes;
     Sizes nonNotableSizes;
 
     nsCString pathPart(aPathPartStr);
     nsCString explicitPathPrefix(aPathPartStr);
     explicitPathPrefix.Insert("explicit/", 0);
 
     // Report notable images, and compute total and non-notable aggregate sizes.
     for (uint32_t i = 0; i < aInfoArray.Length(); i++) {
       ImageInfo<Sizes> info = aInfoArray[i];
-      // info.mURI can be a data: URI, and thus extremely long. Truncate if
-      // necessary.
-      static const size_t max = 256;
-      if (info.mURI.Length() > max) {
-        info.mURI.Truncate(max);
-        info.mURI.AppendLiteral(" (truncated)");
+
+      if (aAnonymize) {
+        info.mURI.Truncate();
+        info.mURI.AppendPrintf("<anonymized-%u>", i);
+      } else {
+        // info.mURI can be a data: URI, and thus extremely long. Truncate if
+        // necessary.
+        static const size_t max = 256;
+        if (info.mURI.Length() > max) {
+          info.mURI.Truncate(max);
+          info.mURI.AppendLiteral(" (truncated)");
+        }
+        info.mURI.ReplaceChar('/', '\\');
       }
-      info.mURI.ReplaceChar('/', '\\');
 
       totalSizes.add(info.mSizes);
 
       if (!info.mSizes.isNotable()) {
         nonNotableSizes.add(info.mSizes);
       } else {
         // Report the notable image.
         rv = ReportSizes(aHandleReport, aData, explicitPathPrefix,
--- a/image/test/mochitest/test_bug601470.html
+++ b/image/test/mochitest/test_bug601470.html
@@ -25,17 +25,17 @@ window.onload = function() {
   var mgr = SpecialPowers.Cc["@mozilla.org/memory-reporter-manager;1"]
     .getService(SpecialPowers.Ci.nsIMemoryReporterManager);
 
   var amount = 0;
   var handleReport = function(aProcess, aPath, aKind, aUnits, aAmount, aDesc) {
     amount += aAmount;
   }
 
-  mgr.getReportsForThisProcess(handleReport, null);
+  mgr.getReportsForThisProcess(handleReport, null, /* anonymize = */ false);
 
   ok(amount > 0, "we should be using a nonzero amount of memory");
   ok(true, "yay, didn't crash!");
 
   SimpleTest.finish();
 }
 
 </script>
--- a/ipc/glue/SharedMemory.cpp
+++ b/ipc/glue/SharedMemory.cpp
@@ -18,17 +18,18 @@ static Atomic<size_t> gShmemAllocated;
 static Atomic<size_t> gShmemMapped;
 
 class ShmemReporter MOZ_FINAL : public nsIMemoryReporter
 {
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
 
   NS_IMETHOD
-  CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData)
+  CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData,
+                 bool aAnonymize)
   {
     nsresult rv;
     rv = MOZ_COLLECT_REPORT(
       "shmem-allocated", KIND_OTHER, UNITS_BYTES, gShmemAllocated,
       "Memory shared with other processes that is accessible (but not "
       "necessarily mapped).");
     NS_ENSURE_SUCCESS(rv, rv);
 
--- a/js/public/MemoryMetrics.h
+++ b/js/public/MemoryMetrics.h
@@ -630,17 +630,17 @@ class ObjectPrivateVisitor
     GetISupportsFun getISupports_;
 
     explicit ObjectPrivateVisitor(GetISupportsFun getISupports)
       : getISupports_(getISupports)
     {}
 };
 
 extern JS_PUBLIC_API(bool)
-CollectRuntimeStats(JSRuntime *rt, RuntimeStats *rtStats, ObjectPrivateVisitor *opv);
+CollectRuntimeStats(JSRuntime *rt, RuntimeStats *rtStats, ObjectPrivateVisitor *opv, bool anonymize);
 
 extern JS_PUBLIC_API(size_t)
 SystemCompartmentCount(JSRuntime *rt);
 
 extern JS_PUBLIC_API(size_t)
 UserCompartmentCount(JSRuntime *rt);
 
 extern JS_PUBLIC_API(size_t)
--- a/js/src/vm/MemoryMetrics.cpp
+++ b/js/src/vm/MemoryMetrics.cpp
@@ -191,17 +191,24 @@ NotableScriptSourceInfo &NotableScriptSo
 
 typedef HashSet<ScriptSource *, DefaultHasher<ScriptSource *>, SystemAllocPolicy> SourceSet;
 
 struct StatsClosure
 {
     RuntimeStats *rtStats;
     ObjectPrivateVisitor *opv;
     SourceSet seenSources;
-    StatsClosure(RuntimeStats *rt, ObjectPrivateVisitor *v) : rtStats(rt), opv(v) {}
+    bool anonymize;
+
+    StatsClosure(RuntimeStats *rt, ObjectPrivateVisitor *v, bool anon)
+      : rtStats(rt),
+        opv(v),
+        anonymize(anon)
+    {}
+
     bool init() {
         return seenSources.init();
     }
 };
 
 static void
 DecommittedArenasChunkCallback(JSRuntime *rt, void *data, gc::Chunk *chunk)
 {
@@ -282,19 +289,23 @@ StatsArenaCallback(JSRuntime *rt, void *
 }
 
 static CompartmentStats *
 GetCompartmentStats(JSCompartment *comp)
 {
     return static_cast<CompartmentStats *>(comp->compartmentStats);
 }
 
+// FineGrained is used for normal memory reporting.  CoarseGrained is used by
+// AddSizeOfTab(), which aggregates all the measurements into a handful of
+// high-level numbers, which means that fine-grained reporting would be a waste
+// of effort.
 enum Granularity {
-    FineGrained,    // Corresponds to CollectRuntimeStats()
-    CoarseGrained   // Corresponds to AddSizeOfTab()
+    FineGrained,
+    CoarseGrained
 };
 
 // The various kinds of hashing are expensive, and the results are unused when
 // doing coarse-grained measurements. Skipping them more than doubles the
 // profile speed for complex pages such as gmail.com.
 template <Granularity granularity>
 static void
 StatsCellCallback(JSRuntime *rt, void *data, void *thing, JSGCTraceKind traceKind,
@@ -331,17 +342,20 @@ StatsCellCallback(JSRuntime *rt, void *d
 
         JS::StringInfo info;
         info.gcHeap = thingSize;
         info.mallocHeap = str->sizeOfExcludingThis(rtStats->mallocSizeOf_);
         info.numCopies = 1;
 
         zStats->stringInfo.add(info);
 
-        if (granularity == FineGrained) {
+        // The primary use case for anonymization is automated crash submission
+        // (to help detect OOM crashes). In that case, we don't want to pay the
+        // memory cost required to do notable string detection.
+        if (granularity == FineGrained && !closure->anonymize) {
             ZoneStats::StringsHashMap::AddPtr p = zStats->allStrings->lookupForAdd(str);
             if (!p) {
                 // Ignore failure -- we just won't record the string as notable.
                 (void)zStats->allStrings->add(p, str, info);
             } else {
                 p->value().add(info);
             }
         }
@@ -527,17 +541,18 @@ FindNotableScriptSources(JS::RuntimeSize
     // Delete |allScriptSources| now, rather than waiting for zStats's
     // destruction, to reduce peak memory consumption during reporting.
     js_delete(runtime.allScriptSources);
     runtime.allScriptSources = nullptr;
     return true;
 }
 
 JS_PUBLIC_API(bool)
-JS::CollectRuntimeStats(JSRuntime *rt, RuntimeStats *rtStats, ObjectPrivateVisitor *opv)
+JS::CollectRuntimeStats(JSRuntime *rt, RuntimeStats *rtStats, ObjectPrivateVisitor *opv,
+                        bool anonymize)
 {
     if (!rtStats->compartmentStatsVector.reserve(rt->numCompartments))
         return false;
 
     if (!rtStats->zoneStatsVector.reserve(rt->gc.zones.length()))
         return false;
 
     rtStats->gcHeapChunkTotal =
@@ -545,21 +560,24 @@ JS::CollectRuntimeStats(JSRuntime *rt, R
 
     rtStats->gcHeapUnusedChunks =
         size_t(JS_GetGCParameter(rt, JSGC_UNUSED_CHUNKS)) * gc::ChunkSize;
 
     IterateChunks(rt, &rtStats->gcHeapDecommittedArenas,
                   DecommittedArenasChunkCallback);
 
     // Take the per-compartment measurements.
-    StatsClosure closure(rtStats, opv);
+    StatsClosure closure(rtStats, opv, anonymize);
     if (!closure.init())
         return false;
-    IterateZonesCompartmentsArenasCells(rt, &closure, StatsZoneCallback, StatsCompartmentCallback,
-                                        StatsArenaCallback, StatsCellCallback<FineGrained>);
+    IterateZonesCompartmentsArenasCells(rt, &closure,
+                                        StatsZoneCallback,
+                                        StatsCompartmentCallback,
+                                        StatsArenaCallback,
+                                        StatsCellCallback<FineGrained>);
 
     // Take the "explicit/js/runtime/" measurements.
     rt->addSizeOfIncludingThis(rtStats->mallocSizeOf_, &rtStats->runtime);
 
     if (!FindNotableScriptSources(rtStats->runtime))
         return false;
 
     ZoneStatsVector &zs = rtStats->zoneStatsVector;
@@ -669,18 +687,19 @@ AddSizeOfTab(JSRuntime *rt, HandleObject
     JS::Zone *zone = GetObjectZone(obj);
 
     if (!rtStats.compartmentStatsVector.reserve(zone->compartments.length()))
         return false;
 
     if (!rtStats.zoneStatsVector.reserve(1))
         return false;
 
-    // Take the per-compartment measurements.
-    StatsClosure closure(&rtStats, opv);
+    // Take the per-compartment measurements. No need to anonymize because
+    // these measurements will be aggregated.
+    StatsClosure closure(&rtStats, opv, /* anonymize = */ false);
     if (!closure.init())
         return false;
     IterateZoneCompartmentsArenasCells(rt, zone, &closure, StatsZoneCallback,
                                        StatsCompartmentCallback, StatsArenaCallback,
                                        StatsCellCallback<CoarseGrained>);
 
     JS_ASSERT(rtStats.zoneStatsVector.length() == 1);
     rtStats.zTotals.addSizes(rtStats.zoneStatsVector[0]);
--- a/js/xpconnect/src/XPCJSMemoryReporter.h
+++ b/js/xpconnect/src/XPCJSMemoryReporter.h
@@ -19,14 +19,15 @@ typedef nsDataHashtable<nsUint64HashKey,
 // because it's invoked by nsWindowMemoryReporter in order to get |windowPaths|
 // in CollectReports.
 class JSReporter
 {
 public:
     static nsresult CollectReports(WindowPaths *windowPaths,
                                    WindowPaths *topWindowPaths,
                                    nsIMemoryReporterCallback *cb,
-                                   nsISupports *closure);
+                                   nsISupports *closure,
+                                   bool anonymize);
 };
 
 }
 
 #endif
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -1452,16 +1452,17 @@ XPCJSRuntime::CustomOutOfMemoryCallback(
     nsCOMPtr<nsIMemoryInfoDumper> dumper =
         do_GetService("@mozilla.org/memory-info-dumper;1");
     if (!dumper) {
         return;
     }
 
     // If this fails, it fails silently.
     dumper->DumpMemoryInfoToTempDir(NS_LITERAL_STRING("due-to-JS-OOM"),
+                                    /* anonymize = */ false,
                                     /* minimizeMemoryUsage = */ false);
 }
 
 void
 XPCJSRuntime::CustomLargeAllocationFailureCallback()
 {
     nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
     if (os) {
@@ -1676,37 +1677,68 @@ XPCJSRuntime::~XPCJSRuntime()
     for (uint32_t i = 0; i < XPCCCX_STRING_CACHE_SIZE; ++i) {
         MOZ_ASSERT(mScratchStrings[i].empty(), "Short lived string still in use");
     }
 #endif
 
     Preferences::UnregisterCallback(ReloadPrefsCallback, JS_OPTIONS_DOT_STR, this);
 }
 
+// If |*anonymizeID| is non-zero and this is a user compartment, the name will
+// be anonymized.
 static void
-GetCompartmentName(JSCompartment *c, nsCString &name, bool replaceSlashes)
+GetCompartmentName(JSCompartment *c, nsCString &name, int *anonymizeID,
+                   bool replaceSlashes)
 {
     if (js::IsAtomsCompartment(c)) {
         name.AssignLiteral("atoms");
+    } else if (*anonymizeID && !js::IsSystemCompartment(c)) {
+        name.AppendPrintf("<anonymized-%d>", *anonymizeID);
+        *anonymizeID += 1;
     } else if (JSPrincipals *principals = JS_GetCompartmentPrincipals(c)) {
         nsJSPrincipals::get(principals)->GetScriptLocation(name);
 
         // If the compartment's location (name) differs from the principal's
         // script location, append the compartment's location to allow
         // differentiation of multiple compartments owned by the same principal
         // (e.g. components owned by the system or null principal).
         CompartmentPrivate *compartmentPrivate = GetCompartmentPrivate(c);
         if (compartmentPrivate) {
             const nsACString& location = compartmentPrivate->GetLocation();
             if (!location.IsEmpty() && !location.Equals(name)) {
                 name.AppendLiteral(", ");
                 name.Append(location);
             }
         }
 
+        // We might have a file:// URL that includes paths from the local
+        // filesystem, which should be omitted if we're anonymizing.
+        if (*anonymizeID) {
+            static const char *filePrefix = "file://";
+            int filePos = name.Find(filePrefix);
+            if (filePos >= 0) {
+                int pathPos = filePos + strlen(filePrefix);
+                int lastSlashPos = -1;
+                for (int i = pathPos; i < int(name.Length()); i++) {
+                    if (name[i] == '/' || name[i] == '\\') {
+                        lastSlashPos = i;
+                    }
+                }
+                if (lastSlashPos != -1) {
+                    name.ReplaceASCII(pathPos, lastSlashPos - pathPos,
+                                      "<anonymized>");
+                } else {
+                    // Something went wrong. Anonymize the entire path to be
+                    // safe.
+                    name.Truncate(pathPos);
+                    name += "<anonymized?!>";
+                }
+            }
+        }
+
         // A hack: replace forward slashes with '\\' so they aren't
         // treated as path separators.  Users of the reporters
         // (such as about:memory) have to undo this change.
         if (replaceSlashes)
             name.ReplaceChar('/', '\\');
     } else {
         name.AssignLiteral("null-principal");
     }
@@ -1742,17 +1774,17 @@ JSMainRuntimeCompartmentsUserDistinguish
 }
 
 class JSMainRuntimeTemporaryPeakReporter MOZ_FINAL : public nsIMemoryReporter
 {
   public:
     NS_DECL_ISUPPORTS
 
     NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
-                              nsISupports* aData)
+                              nsISupports* aData, bool aAnonymize)
     {
         return MOZ_COLLECT_REPORT("js-main-runtime-temporary-peak",
             KIND_OTHER, UNITS_BYTES,
             JSMainRuntimeTemporaryPeakDistinguishedAmount(),
             "Peak transient data size in the main JSRuntime (the current size "
             "of which is reported as "
             "'explicit/js-non-window/runtime/temporary').");
     }
@@ -1845,17 +1877,19 @@ NS_IMPL_ISUPPORTS(JSMainRuntimeTemporary
 MOZ_DEFINE_MALLOC_SIZE_OF(JSMallocSizeOf)
 
 namespace xpc {
 
 static nsresult
 ReportZoneStats(const JS::ZoneStats &zStats,
                 const xpc::ZoneStatsExtras &extras,
                 nsIMemoryReporterCallback *cb,
-                nsISupports *closure, size_t *gcTotalOut = nullptr)
+                nsISupports *closure,
+                bool anonymize,
+                size_t *gcTotalOut = nullptr)
 {
     const nsAutoCString& pathPrefix = extras.pathPrefix;
     size_t gcTotal = 0, sundriesGCHeap = 0, sundriesMallocHeap = 0;
 
     MOZ_ASSERT(!gcTotalOut == zStats.isTotals);
 
     ZCREPORT_GC_BYTES(pathPrefix + NS_LITERAL_CSTRING("gc-heap-arena-admin"),
         zStats.gcHeapArenaAdmin,
@@ -1901,16 +1935,21 @@ ReportZoneStats(const JS::ZoneStats &zSt
     #define MAYBE_OVERALLOCATED \
         "Sometimes over-allocated to simplify string concatenation."
 
     for (size_t i = 0; i < zStats.notableStrings.length(); i++) {
         const JS::NotableStringInfo& info = zStats.notableStrings[i];
 
         MOZ_ASSERT(!zStats.isTotals);
 
+        // We don't do notable string detection when anonymizing, because
+        // there's a good chance its for crash submission, and the memory
+        // required for notable string detection is high.
+        MOZ_ASSERT(!anonymize);
+
         nsDependentCString notableString(info.buffer);
 
         // Viewing about:memory generates many notable strings which contain
         // "string(length=".  If we report these as notable, then we'll create
         // even more notable strings the next time we open about:memory (unless
         // there's a GC in the meantime), and so on ad infinitum.
         //
         // To avoid cluttering up about:memory like this, we stick notable
@@ -1944,17 +1983,17 @@ ReportZoneStats(const JS::ZoneStats &zSt
         if (info.mallocHeap > 0) {
             REPORT_BYTES(path + NS_LITERAL_CSTRING("malloc-heap"),
                 KIND_HEAP, info.mallocHeap,
                 "Non-inline string characters. " MAYBE_OVERALLOCATED);
         }
     }
 
     nsCString nonNotablePath = pathPrefix;
-    nonNotablePath += zStats.isTotals
+    nonNotablePath += (zStats.isTotals || anonymize)
                     ? NS_LITERAL_CSTRING("strings/")
                     : NS_LITERAL_CSTRING("strings/string(<non-notable strings>)/");
 
     if (zStats.stringInfo.gcHeap > 0) {
         REPORT_GC_BYTES(nonNotablePath + NS_LITERAL_CSTRING("gc-heap"),
             zStats.stringInfo.gcHeap,
             "Strings. " MAYBE_INLINE);
     }
@@ -2268,27 +2307,29 @@ ReportScriptSourceStats(const ScriptSour
     return NS_OK;
 }
 
 static nsresult
 ReportJSRuntimeExplicitTreeStats(const JS::RuntimeStats &rtStats,
                                  const nsACString &rtPath,
                                  amIAddonManager* addonManager,
                                  nsIMemoryReporterCallback *cb,
-                                 nsISupports *closure, size_t *rtTotalOut)
+                                 nsISupports *closure,
+                                 bool anonymize,
+                                 size_t *rtTotalOut)
 {
     nsresult rv;
 
     size_t gcTotal = 0;
 
     for (size_t i = 0; i < rtStats.zoneStatsVector.length(); i++) {
         const JS::ZoneStats &zStats = rtStats.zoneStatsVector[i];
         const xpc::ZoneStatsExtras *extras =
           static_cast<const xpc::ZoneStatsExtras*>(zStats.extra);
-        rv = ReportZoneStats(zStats, *extras, cb, closure, &gcTotal);
+        rv = ReportZoneStats(zStats, *extras, cb, closure, anonymize, &gcTotal);
         NS_ENSURE_SUCCESS(rv, rv);
     }
 
     for (size_t i = 0; i < rtStats.compartmentStatsVector.length(); i++) {
         JS::CompartmentStats cStats = rtStats.compartmentStatsVector[i];
         const xpc::CompartmentStatsExtras *extras =
             static_cast<const xpc::CompartmentStatsExtras*>(cStats.extra);
         rv = ReportCompartmentStats(cStats, *extras, addonManager, cb, closure,
@@ -2351,19 +2392,24 @@ ReportJSRuntimeExplicitTreeStats(const J
         const JS::NotableScriptSourceInfo& scriptSourceInfo =
             rtStats.runtime.notableScriptSources[i];
 
         // Escape / to \ before we put the filename into the memory reporter
         // path, because we don't want any forward slashes in the string to
         // count as path separators. Consumers of memory reporters (e.g.
         // about:memory) will convert them back to / after doing path
         // splitting.
-        nsDependentCString filename(scriptSourceInfo.filename_);
-        nsCString escapedFilename(filename);
-        escapedFilename.ReplaceSubstring("/", "\\");
+        nsCString escapedFilename;
+        if (anonymize) {
+            escapedFilename.AppendPrintf("<anonymized-source-%d>", int(i));
+        } else {
+            nsDependentCString filename(scriptSourceInfo.filename_);
+            escapedFilename.Append(filename);
+            escapedFilename.ReplaceSubstring("/", "\\");
+        }
 
         nsCString notablePath = rtPath +
             nsPrintfCString("runtime/script-sources/source(scripts=%d, %s)/",
                             scriptSourceInfo.numScripts, escapedFilename.get());
 
         rv = ReportScriptSourceStats(scriptSourceInfo, notablePath,
                                      cb, closure, rtTotal);
         NS_ENSURE_SUCCESS(rv, rv);
@@ -2469,66 +2515,68 @@ ReportJSRuntimeExplicitTreeStats(const J
 
     return NS_OK;
 }
 
 nsresult
 ReportJSRuntimeExplicitTreeStats(const JS::RuntimeStats &rtStats,
                                  const nsACString &rtPath,
                                  nsIMemoryReporterCallback *cb,
-                                 nsISupports *closure, size_t *rtTotalOut)
+                                 nsISupports *closure,
+                                 bool anonymize,
+                                 size_t *rtTotalOut)
 {
     nsCOMPtr<amIAddonManager> am;
     if (XRE_GetProcessType() == GeckoProcessType_Default) {
         // Only try to access the service from the main process.
         am = do_GetService("@mozilla.org/addons/integration;1");
     }
-    return ReportJSRuntimeExplicitTreeStats(rtStats, rtPath, am.get(), cb,
-                                            closure, rtTotalOut);
+    return ReportJSRuntimeExplicitTreeStats(rtStats, rtPath, am.get(),
+                                            cb, closure, anonymize, rtTotalOut);
 }
 
 
 } // namespace xpc
 
 class JSMainRuntimeCompartmentsReporter MOZ_FINAL : public nsIMemoryReporter
 {
   public:
     NS_DECL_ISUPPORTS
 
-    typedef js::Vector<nsCString, 0, js::SystemAllocPolicy> Paths;
-
-    static void CompartmentCallback(JSRuntime *rt, void* data, JSCompartment *c) {
+    struct Data {
+        int anonymizeID;
+        js::Vector<nsCString, 0, js::SystemAllocPolicy> paths;
+    };
+
+    static void CompartmentCallback(JSRuntime *rt, void* vdata, JSCompartment *c) {
         // silently ignore OOM errors
-        Paths *paths = static_cast<Paths *>(data);
+        Data *data = static_cast<Data *>(vdata);
         nsCString path;
-        GetCompartmentName(c, path, true);
+        GetCompartmentName(c, path, &data->anonymizeID, /* replaceSlashes = */ true);
         path.Insert(js::IsSystemCompartment(c)
                     ? NS_LITERAL_CSTRING("js-main-runtime-compartments/system/")
                     : NS_LITERAL_CSTRING("js-main-runtime-compartments/user/"),
                     0);
-        paths->append(path);
+        data->paths.append(path);
     }
 
     NS_IMETHOD CollectReports(nsIMemoryReporterCallback *cb,
-                              nsISupports *closure)
+                              nsISupports *closure, bool anonymize)
     {
         // First we collect the compartment paths.  Then we report them.  Doing
         // the two steps interleaved is a bad idea, because calling |cb|
         // from within CompartmentCallback() leads to all manner of assertions.
 
-        // Collect.
-
-        Paths paths;
+        Data data;
+        data.anonymizeID = anonymize ? 1 : 0;
         JS_IterateCompartments(nsXPConnect::GetRuntimeInstance()->Runtime(),
-                               &paths, CompartmentCallback);
-
-        // Report.
-        for (size_t i = 0; i < paths.length(); i++)
-            // These ones don't need a description, hence the "".
-            REPORT(nsCString(paths[i]), KIND_OTHER, UNITS_COUNT, 1,
+                               &data, CompartmentCallback);
+
+        for (size_t i = 0; i < data.paths.length(); i++)
+            REPORT(nsCString(data.paths[i]), KIND_OTHER, UNITS_COUNT, 1,
                 "A live compartment in the main JSRuntime.");
 
         return NS_OK;
     }
 };
 
 NS_IMPL_ISUPPORTS(JSMainRuntimeCompartmentsReporter, nsIMemoryReporter)
 
@@ -2588,24 +2636,26 @@ StartsWithExplicit(nsACString& s)
 }
 #endif
 
 class XPCJSRuntimeStats : public JS::RuntimeStats
 {
     WindowPaths *mWindowPaths;
     WindowPaths *mTopWindowPaths;
     bool mGetLocations;
+    int mAnonymizeID;
 
   public:
     XPCJSRuntimeStats(WindowPaths *windowPaths, WindowPaths *topWindowPaths,
-                      bool getLocations)
+                      bool getLocations, bool anonymize)
       : JS::RuntimeStats(JSMallocSizeOf),
         mWindowPaths(windowPaths),
         mTopWindowPaths(topWindowPaths),
-        mGetLocations(getLocations)
+        mGetLocations(getLocations),
+        mAnonymizeID(anonymize ? 1 : 0)
     {}
 
     ~XPCJSRuntimeStats() {
         for (size_t i = 0; i != compartmentStatsVector.length(); ++i)
             delete static_cast<xpc::CompartmentStatsExtras*>(compartmentStatsVector[i].extra);
 
 
         for (size_t i = 0; i != zoneStatsVector.length(); ++i)
@@ -2641,17 +2691,17 @@ class XPCJSRuntimeStats : public JS::Run
         zStats->extra = extras;
     }
 
     virtual void initExtraCompartmentStats(JSCompartment *c,
                                            JS::CompartmentStats *cstats) MOZ_OVERRIDE
     {
         xpc::CompartmentStatsExtras *extras = new xpc::CompartmentStatsExtras;
         nsCString cName;
-        GetCompartmentName(c, cName, true);
+        GetCompartmentName(c, cName, &mAnonymizeID, /* replaceSlashes = */ true);
         if (mGetLocations) {
             CompartmentPrivate *cp = GetCompartmentPrivate(c);
             if (cp)
               cp->GetLocationURI(CompartmentPrivate::LocationHintAddon,
                                  getter_AddRefs(extras->location));
             // Note: cannot use amIAddonManager implementation at this point,
             // as it is a JS service and the JS heap is currently not idle.
             // Otherwise, we could have computed the add-on id at this point.
@@ -2712,36 +2762,41 @@ class XPCJSRuntimeStats : public JS::Run
         cstats->extra = extras;
     }
 };
 
 nsresult
 JSReporter::CollectReports(WindowPaths *windowPaths,
                            WindowPaths *topWindowPaths,
                            nsIMemoryReporterCallback *cb,
-                           nsISupports *closure)
+                           nsISupports *closure,
+                           bool anonymize)
 {
     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.
 
     nsCOMPtr<amIAddonManager> addonManager;
     if (XRE_GetProcessType() == GeckoProcessType_Default) {
         // Only try to access the service from the main process.
         addonManager = do_GetService("@mozilla.org/addons/integration;1");
     }
     bool getLocations = !!addonManager;
-    XPCJSRuntimeStats rtStats(windowPaths, topWindowPaths, getLocations);
+    XPCJSRuntimeStats rtStats(windowPaths, topWindowPaths, getLocations,
+                              anonymize);
     OrphanReporter orphanReporter(XPCConvert::GetISupportsFromJSObject);
-    if (!JS::CollectRuntimeStats(xpcrt->Runtime(), &rtStats, &orphanReporter))
+    if (!JS::CollectRuntimeStats(xpcrt->Runtime(), &rtStats, &orphanReporter,
+                                 anonymize))
+    {
         return NS_ERROR_FAILURE;
+    }
 
     size_t xpconnect = xpcrt->SizeOfIncludingThis(JSMallocSizeOf);
 
     XPCWrappedNativeScope::ScopeSizeInfo sizeInfo(JSMallocSizeOf);
     XPCWrappedNativeScope::AddSizeOfAllScopesIncludingThis(&sizeInfo);
 
     mozJSComponentLoader* loader = mozJSComponentLoader::Get();
     size_t jsComponentLoaderSize = loader ? loader->SizeOfIncludingThis(JSMallocSizeOf) : 0;
@@ -2749,30 +2804,30 @@ JSReporter::CollectReports(WindowPaths *
     // This is the second step (see above).  First we report stuff in the
     // "explicit" tree, then we report other stuff.
 
     nsresult rv;
     size_t rtTotal = 0;
     rv = xpc::ReportJSRuntimeExplicitTreeStats(rtStats,
                                                NS_LITERAL_CSTRING("explicit/js-non-window/"),
                                                addonManager, cb, closure,
-                                               &rtTotal);
+                                               anonymize, &rtTotal);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Report the sums of the compartment numbers.
     xpc::CompartmentStatsExtras cExtrasTotal;
     cExtrasTotal.jsPathPrefix.AssignLiteral("js-main-runtime/compartments/");
     cExtrasTotal.domPathPrefix.AssignLiteral("window-objects/dom/");
     rv = ReportCompartmentStats(rtStats.cTotals, cExtrasTotal, addonManager,
                                 cb, closure);
     NS_ENSURE_SUCCESS(rv, rv);
 
     xpc::ZoneStatsExtras zExtrasTotal;
     zExtrasTotal.pathPrefix.AssignLiteral("js-main-runtime/zones/");
-    rv = ReportZoneStats(rtStats.zTotals, zExtrasTotal, cb, closure);
+    rv = ReportZoneStats(rtStats.zTotals, zExtrasTotal, cb, closure, anonymize);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Report the sum of the runtime/ numbers.
     REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime/runtime"),
         KIND_OTHER, rtTotal,
         "The sum of all measurements under 'explicit/js-non-window/runtime/'.");
 
     // Report the numbers for memory outside of compartments.
@@ -2918,17 +2973,20 @@ AccumulateTelemetryCallback(int id, uint
     }
 }
 
 static void
 CompartmentNameCallback(JSRuntime *rt, JSCompartment *comp,
                         char *buf, size_t bufsize)
 {
     nsCString name;
-    GetCompartmentName(comp, name, false);
+    // This is called via the JSAPI and isn't involved in memory reporting, so
+    // we don't need to anonymize compartment names.
+    int anonymizeID = 0;
+    GetCompartmentName(comp, name, &anonymizeID, /* replaceSlashes = */ false);
     if (name.Length() >= bufsize)
         name.Truncate(bufsize - 1);
     memcpy(buf, name.get(), name.Length() + 1);
 }
 
 static bool
 PreserveWrapper(JSContext *cx, JSObject *obj)
 {
--- a/js/xpconnect/src/xpcpublic.h
+++ b/js/xpconnect/src/xpcpublic.h
@@ -395,17 +395,19 @@ private:
 // This reports all the stats in |rtStats| that belong in the "explicit" tree,
 // (which isn't all of them).
 // @see ZoneStatsExtras
 // @see CompartmentStatsExtras
 nsresult
 ReportJSRuntimeExplicitTreeStats(const JS::RuntimeStats &rtStats,
                                  const nsACString &rtPath,
                                  nsIMemoryReporterCallback *cb,
-                                 nsISupports *closure, size_t *rtTotal = nullptr);
+                                 nsISupports *closure,
+                                 bool anonymize,
+                                 size_t *rtTotal = nullptr);
 
 /**
  * Throws an exception on cx and returns false.
  */
 bool
 Throw(JSContext *cx, nsresult rv);
 
 /**
--- a/layout/base/nsStyleSheetService.cpp
+++ b/layout/base/nsStyleSheetService.cpp
@@ -284,17 +284,17 @@ SizeOfElementIncludingThis(nsIStyleSheet
 {
   return aElement->SizeOfIncludingThis(aMallocSizeOf);
 }
 
 MOZ_DEFINE_MALLOC_SIZE_OF(StyleSheetServiceMallocSizeOf)
 
 NS_IMETHODIMP
 nsStyleSheetService::CollectReports(nsIHandleReportCallback* aHandleReport,
-                                    nsISupports* aData)
+                                    nsISupports* aData, bool aAnonymize)
 {
   return MOZ_COLLECT_REPORT(
     "explicit/layout/style-sheet-service", KIND_HEAP, UNITS_BYTES,
     SizeOfIncludingThis(StyleSheetServiceMallocSizeOf),
     "Memory used for style sheets held by the style sheet service.");
 }
 
 size_t
--- a/layout/style/nsLayoutStylesheetCache.cpp
+++ b/layout/style/nsLayoutStylesheetCache.cpp
@@ -243,17 +243,17 @@ nsLayoutStylesheetCache::Shutdown()
   NS_IF_RELEASE(gCSSLoader);
   NS_IF_RELEASE(gStyleCache);
 }
 
 MOZ_DEFINE_MALLOC_SIZE_OF(LayoutStylesheetCacheMallocSizeOf)
 
 NS_IMETHODIMP
 nsLayoutStylesheetCache::CollectReports(nsIHandleReportCallback* aHandleReport,
-                                        nsISupports* aData)
+                                        nsISupports* aData, bool aAnonymize)
 {
   return MOZ_COLLECT_REPORT(
     "explicit/layout/style-sheet-cache", KIND_HEAP, UNITS_BYTES,
     SizeOfIncludingThis(LayoutStylesheetCacheMallocSizeOf),
     "Memory used for some built-in style sheets.");
 }
 
 
--- a/mobile/android/chrome/content/MemoryObserver.js
+++ b/mobile/android/chrome/content/MemoryObserver.js
@@ -61,11 +61,12 @@ var MemoryObserver = {
 
   gc: function() {
     window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils).garbageCollect();
     Cu.forceGC();
   },
 
   dumpMemoryStats: function(aLabel) {
     let memDumper = Cc["@mozilla.org/memory-info-dumper;1"].getService(Ci.nsIMemoryInfoDumper);
-    memDumper.dumpMemoryInfoToTempDir(aLabel, /* minimize = */ false);
+    memDumper.dumpMemoryInfoToTempDir(aLabel, /* anonymize = */ false,
+                                      /* minimize = */ false);
   },
 };
--- a/modules/libpref/src/Preferences.cpp
+++ b/modules/libpref/src/Preferences.cpp
@@ -288,17 +288,18 @@ PreferenceServiceReporter::CountReferent
 
   return PL_DHASH_NEXT;
 }
 
 MOZ_DEFINE_MALLOC_SIZE_OF(PreferenceServiceMallocSizeOf)
 
 NS_IMETHODIMP
 PreferenceServiceReporter::CollectReports(nsIMemoryReporterCallback* aCb,
-                                          nsISupports* aClosure)
+                                          nsISupports* aClosure,
+                                          bool aAnonymize)
 {
 #define REPORT(_path, _kind, _units, _amount, _desc)                          \
     do {                                                                      \
       nsresult rv;                                                            \
       rv = aCb->Callback(EmptyCString(), _path, _kind,                        \
                          _units, _amount, NS_LITERAL_CSTRING(_desc),          \
                          aClosure);                                           \
       NS_ENSURE_SUCCESS(rv, rv);                                              \
--- a/netwerk/cache/nsCacheService.cpp
+++ b/netwerk/cache/nsCacheService.cpp
@@ -3263,17 +3263,17 @@ nsCacheService::LeavePrivateBrowsing()
         gService->mMemoryDevice->EvictPrivateEntries();
     }
 }
 
 MOZ_DEFINE_MALLOC_SIZE_OF(DiskCacheDeviceMallocSizeOf)
 
 NS_IMETHODIMP
 nsCacheService::CollectReports(nsIHandleReportCallback* aHandleReport,
-                               nsISupports* aData)
+                               nsISupports* aData, bool aAnonymize)
 {
     size_t disk = 0;
     if (mDiskDevice) {
         nsCacheServiceAutoLock
             lock(LOCK_TELEM(NSCACHESERVICE_DISKDEVICEHEAPSIZE));
         disk = mDiskDevice->SizeOfIncludingThis(DiskCacheDeviceMallocSizeOf);
     }
 
--- a/netwerk/cache2/CacheStorageService.cpp
+++ b/netwerk/cache2/CacheStorageService.cpp
@@ -1740,17 +1740,19 @@ PLDHashOperator ReportStorageMemory(cons
                                     void* aClosure)
 {
   CacheStorageService::Self()->Lock().AssertCurrentThreadOwns();
 
   size_t size = aTable->SizeOfIncludingThis(&CollectEntryMemory,
                                             CacheStorageService::MallocSizeOf,
                                             aTable);
 
-  ReportStorageMemoryData& data = *static_cast<ReportStorageMemoryData*>(aClosure);
+  ReportStorageMemoryData& data =
+    *static_cast<ReportStorageMemoryData*>(aClosure);
+  // These key names are not privacy-sensitive.
   data.mHandleReport->Callback(
     EmptyCString(),
     nsPrintfCString("explicit/network/cache2/%s-storage(%s)",
       aTable->Type() == CacheEntryTable::MEMORY_ONLY ? "memory" : "disk",
       aKey.BeginReading()),
     nsIMemoryReporter::KIND_HEAP,
     nsIMemoryReporter::UNITS_BYTES,
     size,
@@ -1758,17 +1760,18 @@ PLDHashOperator ReportStorageMemory(cons
     data.mData);
 
   return PL_DHASH_NEXT;
 }
 
 } // anon
 
 NS_IMETHODIMP
-CacheStorageService::CollectReports(nsIMemoryReporterCallback* aHandleReport, nsISupports* aData)
+CacheStorageService::CollectReports(nsIMemoryReporterCallback* aHandleReport,
+                                    nsISupports* aData, bool aAnonymize)
 {
   nsresult rv;
 
   rv = MOZ_COLLECT_REPORT(
     "explicit/network/cache2/io", KIND_HEAP, UNITS_BYTES,
     CacheFileIOManager::SizeOfIncludingThis(MallocSizeOf),
     "Memory used by the cache IO manager.");
   if (NS_WARN_IF(NS_FAILED(rv)))
--- a/netwerk/cookie/nsCookieService.cpp
+++ b/netwerk/cookie/nsCookieService.cpp
@@ -4355,15 +4355,15 @@ nsCookieService::SizeOfIncludingThis(moz
 
   return n;
 }
 
 MOZ_DEFINE_MALLOC_SIZE_OF(CookieServiceMallocSizeOf)
 
 NS_IMETHODIMP
 nsCookieService::CollectReports(nsIHandleReportCallback* aHandleReport,
-                                nsISupports* aData)
+                                nsISupports* aData, bool aAnonymize)
 {
   return MOZ_COLLECT_REPORT(
     "explicit/cookie-service", KIND_HEAP, UNITS_BYTES,
     SizeOfIncludingThis(CookieServiceMallocSizeOf),
     "Memory used by the cookie service.");
 }
--- a/netwerk/dns/nsDNSService2.cpp
+++ b/netwerk/dns/nsDNSService2.cpp
@@ -958,16 +958,16 @@ nsDNSService::SizeOfIncludingThis(mozill
                                            mallocSizeOf);
     return n;
 }
 
 MOZ_DEFINE_MALLOC_SIZE_OF(DNSServiceMallocSizeOf)
 
 NS_IMETHODIMP
 nsDNSService::CollectReports(nsIHandleReportCallback* aHandleReport,
-                             nsISupports* aData)
+                             nsISupports* aData, bool aAnonymize)
 {
     return MOZ_COLLECT_REPORT(
         "explicit/network/dns-service", KIND_HEAP, UNITS_BYTES,
         SizeOfIncludingThis(DNSServiceMallocSizeOf),
         "Memory used for the DNS service.");
 }
 
--- a/netwerk/dns/nsEffectiveTLDService.cpp
+++ b/netwerk/dns/nsEffectiveTLDService.cpp
@@ -106,17 +106,17 @@ nsEffectiveTLDService::~nsEffectiveTLDSe
   UnregisterWeakMemoryReporter(this);
   gService = nullptr;
 }
 
 MOZ_DEFINE_MALLOC_SIZE_OF(EffectiveTLDServiceMallocSizeOf)
 
 NS_IMETHODIMP
 nsEffectiveTLDService::CollectReports(nsIHandleReportCallback* aHandleReport,
-                                      nsISupports* aData)
+                                      nsISupports* aData, bool aAnonymize)
 {
   return MOZ_COLLECT_REPORT(
     "explicit/xpcom/effective-TLD-service", KIND_HEAP, UNITS_BYTES,
     SizeOfIncludingThis(EffectiveTLDServiceMallocSizeOf),
     "Memory used by the effective TLD service.");
 }
 
 size_t
--- a/netwerk/protocol/http/SpdyZlibReporter.cpp
+++ b/netwerk/protocol/http/SpdyZlibReporter.cpp
@@ -23,16 +23,17 @@ SpdyZlibReporter::Alloc(void*, uInt item
 /* static */ void
 SpdyZlibReporter::Free(void*, void* p)
 {
   sAmount -= MallocSizeOfOnFree(p);
   moz_free(p);
 }
 
 NS_IMETHODIMP
-SpdyZlibReporter::CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData)
+SpdyZlibReporter::CollectReports(nsIHandleReportCallback* aHandleReport,
+                                 nsISupports* aData, bool aAnonymize)
 {
   return MOZ_COLLECT_REPORT(
     "explicit/network/spdy-zlib-buffers", KIND_HEAP, UNITS_BYTES, sAmount,
     "Memory allocated for SPDY zlib send and receive buffers.");
 }
 
 } // namespace mozilla
--- a/netwerk/protocol/http/SpdyZlibReporter.h
+++ b/netwerk/protocol/http/SpdyZlibReporter.h
@@ -39,12 +39,13 @@ private:
   // 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);
+  CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData,
+                 bool aAnonymize);
 };
 
 } // namespace mozilla
--- a/startupcache/StartupCache.cpp
+++ b/startupcache/StartupCache.cpp
@@ -51,17 +51,17 @@
 
 namespace mozilla {
 namespace scache {
 
 MOZ_DEFINE_MALLOC_SIZE_OF(StartupCacheMallocSizeOf)
 
 NS_IMETHODIMP
 StartupCache::CollectReports(nsIHandleReportCallback* aHandleReport,
-                             nsISupports* aData)
+                             nsISupports* aData, bool aAnonymize)
 {
 #define REPORT(_path, _kind, _amount, _desc)                                \
   do {                                                                      \
     nsresult rv =                                                           \
       aHandleReport->Callback(EmptyCString(),                               \
                               NS_LITERAL_CSTRING(_path),                    \
                               _kind, UNITS_BYTES, _amount,                  \
                               NS_LITERAL_CSTRING(_desc), aData);            \
--- a/storage/src/mozStorageService.cpp
+++ b/storage/src/mozStorageService.cpp
@@ -119,17 +119,17 @@ ReportConn(nsIHandleReportCallback *aHan
 // Warning: To get a Connection's measurements requires holding its lock.
 // There may be a delay getting the lock if another thread is accessing the
 // Connection.  This isn't very nice if CollectReports is called from the main
 // thread!  But at the time of writing this function is only called when
 // about:memory is loaded (not, for example, when telemetry pings occur) and
 // any delays in that case aren't so bad.
 NS_IMETHODIMP
 Service::CollectReports(nsIHandleReportCallback *aHandleReport,
-                        nsISupports *aData)
+                        nsISupports *aData, bool aAnonymize)
 {
   nsresult rv;
   size_t totalConnSize = 0;
   {
     nsTArray<nsRefPtr<Connection> > connections;
     getConnections(connections);
 
     for (uint32_t i = 0; i < connections.Length(); i++) {
@@ -138,16 +138,17 @@ Service::CollectReports(nsIHandleReportC
       // Someone may have closed the Connection, in which case we skip it.
       bool isReady;
       (void)conn->GetConnectionReady(&isReady);
       if (!isReady) {
           continue;
       }
 
       nsCString pathHead("explicit/storage/sqlite/");
+      // This filename isn't privacy-sensitive, and so is never anonymized.
       pathHead.Append(conn->getFilename());
       pathHead.Append('/');
 
       SQLiteMutexAutoLock lockedScope(conn->sharedDBMutex);
 
       NS_NAMED_LITERAL_CSTRING(stmtDesc,
         "Memory (approximate) used by all prepared statements used by "
         "connections to this database.");
--- a/testing/mochitest/tests/SimpleTest/MemoryStats.js
+++ b/testing/mochitest/tests/SimpleTest/MemoryStats.js
@@ -85,17 +85,17 @@ MemoryStats.dump = function (dumpFn,
         var basename = "about-memory-" + testNumber + ".json.gz";
         var dumpfile = MemoryStats.constructPathname(dumpOutputDirectory,
                                                      basename);
         dumpFn("TEST-INFO | " + testURL + " | MEMDUMP-START " + dumpfile);
         var md = MemoryStats._getService("@mozilla.org/memory-info-dumper;1",
                                          "nsIMemoryInfoDumper");
         md.dumpMemoryReportsToNamedFile(dumpfile, function () {
             dumpFn("TEST-INFO | " + testURL + " | MEMDUMP-END");
-        }, null);
+        }, null, /* anonymize = */ false);
 
     }
 
     if (dumpDMD && typeof(DMDReportAndDump) != undefined) {
         var basename = "dmd-" + testNumber + ".txt";
         var dumpfile = MemoryStats.constructPathname(dumpOutputDirectory,
                                                      basename);
         dumpFn("TEST-INFO | " + testURL + " | DMD-DUMP " + dumpfile);
--- a/toolkit/components/aboutmemory/content/aboutMemory.js
+++ b/toolkit/components/aboutmemory/content/aboutMemory.js
@@ -21,16 +21,17 @@
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 const CC = Components.Constructor;
 
 const KIND_NONHEAP           = Ci.nsIMemoryReporter.KIND_NONHEAP;
 const KIND_HEAP              = Ci.nsIMemoryReporter.KIND_HEAP;
 const KIND_OTHER             = Ci.nsIMemoryReporter.KIND_OTHER;
+
 const UNITS_BYTES            = Ci.nsIMemoryReporter.UNITS_BYTES;
 const UNITS_COUNT            = Ci.nsIMemoryReporter.UNITS_COUNT;
 const UNITS_COUNT_CUMULATIVE = Ci.nsIMemoryReporter.UNITS_COUNT_CUMULATIVE;
 const UNITS_PERCENTAGE       = Ci.nsIMemoryReporter.UNITS_PERCENTAGE;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
@@ -126,16 +127,19 @@ function onUnload()
 let gMain;
 
 // The <div> holding the footer.
 let gFooter;
 
 // The "verbose" checkbox.
 let gVerbose;
 
+// The "anonymize" checkbox.
+let gAnonymize;
+
 // Values for the second argument to updateMainAndFooter.
 let HIDE_FOOTER = 0;
 let SHOW_FOOTER = 1;
 
 function updateMainAndFooter(aMsg, aFooterAction, aClassName)
 {
   // Clear gMain by replacing it with an empty node.
   let tmp = gMain.cloneNode(false);
@@ -298,40 +302,46 @@ function onLoad()
   const DMDDisabledDesc = "DMD is not running. Please re-start with $DMD and " +
                           "the other relevant environment variables set " +
                           "appropriately.";
 
   let ops = appendElement(header, "div", "");
 
   let row1 = appendElement(ops, "div", "opsRow");
 
-  let labelDiv =
+  let labelDiv1 =
    appendElementWithText(row1, "div", "opsRowLabel", "Show memory reports");
-  let label = appendElementWithText(labelDiv, "label", "");
-  gVerbose = appendElement(label, "input", "");
+  let label1 = appendElementWithText(labelDiv1, "label", "");
+  gVerbose = appendElement(label1, "input", "");
   gVerbose.type = "checkbox";
   gVerbose.id = "verbose";   // used for testing
-
-  appendTextNode(label, "verbose");
+  appendTextNode(label1, "verbose");
 
   const kEllipsis = "\u2026";
 
   // The "measureButton" id is used for testing.
   appendButton(row1, CuDesc, doMeasure, "Measure", "measureButton");
   appendButton(row1, LdDesc, () => fileInput1.click(), "Load" + kEllipsis);
   appendButton(row1, DfDesc, () => fileInput2.click(),
                "Load and diff" + kEllipsis);
   appendButton(row1, RdDesc, updateAboutMemoryFromClipboard,
                "Read from clipboard");
 
   let row2 = appendElement(ops, "div", "opsRow");
 
-  appendElementWithText(row2, "div", "opsRowLabel", "Save memory reports");
+  let labelDiv2 =
+    appendElementWithText(row2, "div", "opsRowLabel", "Save memory reports");
   appendButton(row2, SvDesc, saveReportsToFile, "Measure and save" + kEllipsis);
 
+  // XXX njn: still not happy with the placement of this checkbox
+  let label2 = appendElementWithText(labelDiv2, "label", "");
+  gAnonymize = appendElement(label2, "input", "");
+  gAnonymize.type = "checkbox";
+  appendTextNode(label2, "anonymize");
+
   let row3 = appendElement(ops, "div", "opsRow");
 
   appendElementWithText(row3, "div", "opsRowLabel", "Free memory");
   appendButton(row3, GCDesc, doGC,  "GC");
   appendButton(row3, CCDesc, doCC,  "CC");
   appendButton(row3, MMDesc, doMMU, "Minimize memory usage");
 
   let row4 = appendElement(ops, "div", "opsRow");
@@ -488,18 +498,18 @@ function updateAboutMemoryFromReporters(
                       aDescription, /* presence = */ undefined);
       }
 
       let displayReportsAndFooter = function() {
         updateMainAndFooter("", SHOW_FOOTER);
         aDisplayReports();
       }
 
-      gMgr.getReports(handleReport, null,
-                      displayReportsAndFooter, null);
+      gMgr.getReports(handleReport, null, displayReportsAndFooter, null,
+                      gAnonymize.checked);
     }
 
     // Process the reports from the live memory reporters.
     appendAboutMemoryMain(processLiveMemoryReports,
                           gMgr.hasMozMallocUsableSize);
 
   } catch (ex) {
     handleException(ex);
@@ -1957,17 +1967,18 @@ function saveReportsToFile()
   let fpFinish = function(file) {
     let dumper = Cc["@mozilla.org/memory-info-dumper;1"]
                    .getService(Ci.nsIMemoryInfoDumper);
 
     let finishDumping = () => {
       updateMainAndFooter("Saved reports to " + file.path, HIDE_FOOTER);
     }
 
-    dumper.dumpMemoryReportsToNamedFile(file.path, finishDumping, null);
+    dumper.dumpMemoryReportsToNamedFile(file.path, finishDumping, null,
+                                        gAnonymize.checked);
   }
 
   let fpCallback = function(aResult) {
     if (aResult == Ci.nsIFilePicker.returnOK ||
         aResult == Ci.nsIFilePicker.returnReplace) {
       fpFinish(fp.file);
     }
   };
--- a/toolkit/components/aboutmemory/tests/test_aboutmemory.xul
+++ b/toolkit/components/aboutmemory/tests/test_aboutmemory.xul
@@ -38,17 +38,17 @@
   const OTHER   = Ci.nsIMemoryReporter.KIND_OTHER;
 
   const BYTES = Ci.nsIMemoryReporter.UNITS_BYTES;
   const COUNT = Ci.nsIMemoryReporter.UNITS_COUNT;
   const COUNT_CUMULATIVE = Ci.nsIMemoryReporter.UNITS_COUNT_CUMULATIVE;
   const PERCENTAGE = Ci.nsIMemoryReporter.UNITS_PERCENTAGE;
 
   let fakeReporters = [
-    { collectReports: function(aCbObj, aClosure) {
+    { collectReports: function(aCbObj, aClosure, aAnonymize) {
         function f(aP, aK, aU, aA) {
           aCbObj.callback("", aP, aK, aU, aA, "Desc.", aClosure);
         }
         f("heap-allocated",     OTHER,   BYTES, 500 * MB);
         f("heap-unallocated",   OTHER,   BYTES, 100 * MB);
         f("explicit/a",         HEAP,    BYTES, 222 * MB);
         f("explicit/b/a",       HEAP,    BYTES,  85 * MB);
         f("explicit/b/b",       HEAP,    BYTES,  75 * MB);
@@ -75,43 +75,43 @@
         f("other6/small",       OTHER,   COUNT, 1);
         // Check that a 0 / 0 is handled correctly.
         f("other7/zero",        OTHER,   BYTES, 0);
         // These compartments ones shouldn't be displayed.
         f("compartments/user/foo",   OTHER, COUNT, 1);
         f("compartments/system/foo", OTHER, COUNT, 1);
       }
     },
-    { collectReports: function(aCbObj, aClosure) {
+    { collectReports: function(aCbObj, aClosure, aAnonymize) {
         function f(aP, aK, aU, aA) {
           aCbObj.callback("", aP, aK, aU, aA, "Desc.", aClosure);
         }
         f("explicit/c/d",     NONHEAP, BYTES,  13 * MB);
         f("explicit/c/d",     NONHEAP, BYTES,  10 * MB); // dup
         f("explicit/c/other", NONHEAP, BYTES,  77 * MB);
         f("explicit/cc",      NONHEAP, BYTES,  13 * MB);
         f("explicit/cc",      NONHEAP, BYTES,  10 * MB); // dup
         f("explicit/d",       NONHEAP, BYTES, 499 * KB); // omitted
         f("explicit/e",       NONHEAP, BYTES, 100 * KB); // omitted
         f("explicit/f/g/h/i", HEAP,    BYTES,  10 * MB);
         f("explicit/f/g/h/j", HEAP,    BYTES,  10 * MB);
       }
     },
-    { collectReports: function(aCbObj, aClosure) {
+    { collectReports: function(aCbObj, aClosure, aAnonymize) {
         function f(aP, aK, aU, aA) {
           aCbObj.callback("", aP, aK, aU, aA, "Desc.", aClosure);
         }
         f("other3",           OTHER,   COUNT, 777);
         f("other2",           OTHER,   BYTES, 222 * MB);
         f("perc2",            OTHER,   PERCENTAGE, 10000);
         f("perc1",            OTHER,   PERCENTAGE, 4567);
         f("compartments/user/https:\\\\very-long-url.com\\very-long\\oh-so-long\\really-quite-long.html?a=2&b=3&c=4&d=5&e=abcdefghijklmnopqrstuvwxyz&f=123456789123456789123456789", OTHER, COUNT, 1);
       }
     },
-    { collectReports: function(aCbObj, aClosure) {
+    { collectReports: function(aCbObj, aClosure, aAnonymize) {
         function f(aP) {
           aCbObj.callback("", aP, OTHER, COUNT, 1, "Desc.", aClosure);
         }
         f("compartments/user/bar");
         f("compartments/system/bar");
       }
     }
   ];
@@ -134,17 +134,17 @@
     is(ex.result, Cr.NS_ERROR_NOT_AVAILABLE, "mgr.explicit exception");
   }
 
   // The main process always comes first when we display about:memory.  The
   // remaining processes are sorted by their |resident| values (starting with
   // the largest).  Processes without a |resident| memory reporter are saved
   // for the end.
   let fakeReporters2 = [
-    { collectReports: function(aCbObj, aClosure) {
+    { collectReports: function(aCbObj, aClosure, aAnonymize) {
         function f(aP1, aP2, aK, aU, aA) {
           aCbObj.callback(aP1, aP2, aK, aU, aA, "Desc.", aClosure);
         }
         f("2nd", "heap-allocated",  OTHER,   BYTES,1000* MB);
         f("2nd", "heap-unallocated",OTHER,   BYTES,100 * MB);
         f("2nd", "explicit/a/b/c",  HEAP,    BYTES,497 * MB);
         f("2nd", "explicit/a/b/c",  HEAP,    BYTES,  1 * MB); // dup: merge
         f("2nd", "explicit/a/b/c",  HEAP,    BYTES,  1 * MB); // dup: merge
--- a/toolkit/components/aboutmemory/tests/test_aboutmemory2.xul
+++ b/toolkit/components/aboutmemory/tests/test_aboutmemory2.xul
@@ -33,17 +33,17 @@
   const BYTES = Ci.nsIMemoryReporter.UNITS_BYTES;
 
   let hiPath  = "explicit/h/i";
   let hi2Path = "explicit/h/i2";
   let jkPath  = "explicit/j/k";
   let jk2Path = "explicit/j/k2";
 
   let fakeReporters = [
-    { collectReports: function(aCbObj, aClosure) {
+    { collectReports: function(aCbObj, aClosure, aAnonymize) {
         function f(aP, aK, aA) {
           aCbObj.callback("", aP, aK, BYTES, aA, "Desc.", aClosure);
         }
         f("heap-allocated",     OTHER,   250 * MB);
         f("explicit/a/b",       HEAP,     50 * MB);
         f("explicit/a/c/d",     HEAP,     25 * MB);
         f("explicit/a/c/e",     HEAP,     15 * MB);
         f("explicit/a/f",       HEAP,     30 * MB);
--- a/toolkit/components/aboutmemory/tests/test_aboutmemory3.xul
+++ b/toolkit/components/aboutmemory/tests/test_aboutmemory3.xul
@@ -28,17 +28,17 @@
   // Setup a minimal number of fake reporters.
   const KB = 1024;
   const MB = KB * KB;
   const HEAP  = Ci.nsIMemoryReporter.KIND_HEAP;
   const OTHER = Ci.nsIMemoryReporter.KIND_OTHER;
   const BYTES = Ci.nsIMemoryReporter.UNITS_BYTES;
 
   let fakeReporters = [
-    { collectReports: function(aCbObj, aClosure) {
+    { collectReports: function(aCbObj, aClosure, aAnonymize) {
         function f(aP, aK, aA, aD) {
           aCbObj.callback("", aP, aK, BYTES, aA, aD, aClosure);
         }
         f("heap-allocated",     OTHER,   250 * MB, "Heap allocated.");
         f("explicit/a/b",       HEAP,     50 * MB, "A b.");
         f("other/a",            OTHER,   0.2 * MB, "Other a.");
         f("other/b",            OTHER,   0.1 * MB, "Other b.");
       }
@@ -135,17 +135,18 @@
 
         fileInput1.dispatchEvent(e);
         check();
       }
 
       if (aDumpFirst) {
         let dumper = Cc["@mozilla.org/memory-info-dumper;1"].
                         getService(Ci.nsIMemoryInfoDumper);
-        dumper.dumpMemoryReportsToNamedFile(filePath, loadAndCheck, null);
+        dumper.dumpMemoryReportsToNamedFile(filePath, loadAndCheck, null,
+                                            /* anonymize = */ false);
       } else {
         loadAndCheck();
       }
 
     } else {
       let fileInput2 =
         frame.contentWindow.document.getElementById("fileInput2");
       fileInput2.value = filePath;    // this works because it's a chrome test
--- a/toolkit/components/aboutmemory/tests/test_aboutmemory5.xul
+++ b/toolkit/components/aboutmemory/tests/test_aboutmemory5.xul
@@ -80,17 +80,18 @@
 
     let filePath = getFilePath("memory-reports-dumped.json.gz");
 
     let e = document.createEvent('Event');
     e.initEvent('change', true, true);
 
     let dumper = Cc["@mozilla.org/memory-info-dumper;1"].
                     getService(Ci.nsIMemoryInfoDumper);
-    dumper.dumpMemoryReportsToNamedFile(filePath, loadAndCheck, null);
+    dumper.dumpMemoryReportsToNamedFile(filePath, loadAndCheck, null,
+                                        /* anonymize = */ false);
 
     function loadAndCheck() {
       // Load the file.
       let fileInput1 =
         frame.contentWindow.document.getElementById("fileInput1");
       fileInput1.value = filePath;    // this works because it's a chrome test
       fileInput1.dispatchEvent(e);
 
--- a/toolkit/components/aboutmemory/tests/test_memoryReporters.xul
+++ b/toolkit/components/aboutmemory/tests/test_memoryReporters.xul
@@ -11,16 +11,20 @@
        presentation of memory reports in about:memory. -->
 
   <!-- test results are displayed in the html:body -->
   <body xmlns="http://www.w3.org/1999/xhtml">
   <!-- In bug 773533, <marquee> elements crashed the JS memory reporter -->
   <marquee>Marquee</marquee>
   </body>
 
+  <!-- some URIs that should be anonymized in anonymous mode -->
+  <iframe id="amFrame"  height="200" src="http://example.org:80"></iframe>
+  <iframe id="amFrame"  height="200" src="https://example.com:443"></iframe>
+
   <!-- test code goes here -->
   <script type="application/javascript">
   <![CDATA[
 
   // Nb: this test is all JS and so should be done with an xpcshell test,
   // but bug 671753 is preventing the memory-reporter-manager from being
   // accessed from xpcshell.
 
@@ -62,17 +66,18 @@
   for (let i = 0; i < 10000; i++) {
     let str = (Math.random() > 0.5 ? "!" : "@") + ")(*&";
     shortStrings.push(str);
   }
 
   let mySandbox = Components.utils.Sandbox(document.nodePrincipal,
                     { sandboxName: "this-is-a-sandbox-name" });
 
-  function handleReport(aProcess, aPath, aKind, aUnits, aAmount, aDescription)
+  function handleReportNormal(aProcess, aPath, aKind, aUnits, aAmount,
+                              aDescription)
   {
     // Record the values of some notable reporters.
     if (aPath === "vsize") {
       vsizeAmounts.push(aAmount);
     } else if (aPath === "resident") {
       residentAmounts.push(aAmount);
     } else if (aPath === "js-main-runtime-gc-heap-committed/used/gc-things") {
       jsGcHeapAmounts.push(aAmount); 
@@ -100,16 +105,35 @@
       present.sandboxLocation = true;
     } else if (aPath.contains(bigStringPrefix)) {
       present.bigString = true;
     } else if (aPath.contains("!)(*&")) {
       present.smallString1 = true;
     } else if (aPath.contains("@)(*&")) {
       present.smallString2 = true;
     }
+
+    // Shouldn't get any anonymized paths.
+    if (aPath.contains('<anonymized')) {
+        present.anonymizedWhenUnnecessary = true;
+    }
+  }
+
+  function handleReportAnonymized(aProcess, aPath, aKind, aUnits, aAmount,
+                                  aDescription)
+  {
+    // Shouldn't get http: or https: in any paths.
+    if (aPath.contains('http:')) {
+        present.httpWhenAnonymized = true;
+    }
+
+    // file: URLs should have their path anonymized.
+    if (aPath.search('file:..[^<]') !== -1) {
+        present.unanonymizedFilePathWhenAnonymized = true;
+    }
   }
 
   let mgr = Cc["@mozilla.org/memory-reporter-manager;1"].
             getService(Ci.nsIMemoryReporterManager);
 
   // Access the distinguished amounts (mgr.explicit et al.) just to make sure
   // they don't crash.  We can't check their actual values because they're
   // non-deterministic.
@@ -166,17 +190,21 @@
   let otherSize = {};
   let totalSize = {};
   let jsMilliseconds = {};
   let nonJSMilliseconds = {};
   mgr.sizeOfTab(window, jsObjectsSize, jsStringsSize, jsOtherSize,
                 domSize, styleSize, otherSize, totalSize,
                 jsMilliseconds, nonJSMilliseconds);
 
-  mgr.getReportsForThisProcess(handleReport, null);
+  mgr.getReportsForThisProcess(handleReportNormal, null,
+                               /* anonymize = */ false);
+
+  mgr.getReportsForThisProcess(handleReportAnonymized, null,
+                               /* anonymize = */ true);
 
   function checkSpecialReport(aName, aAmounts, aCanBeUnreasonable)
   {
     ok(aAmounts.length == 1, aName + " has " + aAmounts.length + " report");
     let n = aAmounts[0];
     // Check the size is reasonable -- i.e. not ridiculously large or small.
     ok((100 * 1000 <= n && n <= 10 * 1000 * 1000 * 1000) || aCanBeUnreasonable,
        aName + "'s size is reasonable");
@@ -197,16 +225,20 @@
   ok(present.images,                      "images is present");
   ok(present.xptiWorkingSet,              "xpti-working-set is present");
   ok(present.atomTable,                   "atom-table is present");
   ok(present.sandboxLocation,             "sandbox locations are present");
   ok(present.bigString,                   "large string is present");
   ok(present.smallString1,                "small string 1 is present");
   ok(present.smallString2,                "small string 2 is present");
 
+  ok(!present.anonymizedWhenUnnecessary,  "anonymized paths are not present when unnecessary");
+  ok(!present.httpWhenAnonymized,         "http URLs are anonymized when necessary");
+  ok(!present.unanonymizedFilePathWhenAnonymized,
+                                          "file URLs are anonymized when necessary");
 
   // Reporter registration tests
 
   // collectReports() calls to the test reporter.
   let called = 0;
 
   // The test memory reporter, testing the various report units.
   // Also acts as a report collector, verifying the reported values match the
@@ -240,17 +272,17 @@
         expected: () => called
       },
       "test-memory-reporter-percentage": {
         units: PERCENTAGE,
         amount: () => 9999
       }
     },
     // nsIMemoryReporter
-    collectReports: function(callback, data) {
+    collectReports: function(callback, data, anonymize) {
       for (let path of Object.keys(this.tests)) {
         try {
           let test = this.tests[path];
           callback.callback(
             "", // Process. Should be "" initially.
             path,
             OTHER,
             test.units,
@@ -289,25 +321,27 @@
 
   // General memory reporter + registerStrongReporter tests.
   function test_register_strong() {
     let reporterAndCallback = new MemoryReporterAndCallback();
     // Registration works.
     mgr.registerStrongReporter(reporterAndCallback);
 
     // Check the generated reports.
-    mgr.getReportsForThisProcess(reporterAndCallback, null);
+    mgr.getReportsForThisProcess(reporterAndCallback, null,
+                                 /* anonymize = */ false);
     reporterAndCallback.finish();
 
     // Unregistration works.
     mgr.unregisterStrongReporter(reporterAndCallback);
 
     // The reporter was unregistered, hence there shouldn't be any reports from
     // the test reporter.
-    mgr.getReportsForThisProcess(reporterAndCallback, null);
+    mgr.getReportsForThisProcess(reporterAndCallback, null,
+                                 /* anonymize = */ false);
     reporterAndCallback.finish(0);
   }
 
   test_register_strong();
 
   // Check strong reporters a second time, to make sure a reporter can be
   // re-registered.
   test_register_strong();
--- a/toolkit/components/aboutmemory/tests/test_memoryReporters2.xul
+++ b/toolkit/components/aboutmemory/tests/test_memoryReporters2.xul
@@ -62,17 +62,17 @@
     }
 
     let processReports = function() {
       // First, test a failure case:  calling getReports() before the previous
       // getReports() has finished should silently abort.  (And the arguments
       // won't be used.)
       mgr.getReports(
         () => ok(false, "handleReport called for nested getReports() call"),
-        null, null, null
+        null, null, null, /* anonymize = */ false
       );
 
       // Close the remote processes.
       for (let i = 0; i < numRemotes; i++) {
         remotes[i].close();
       }
 
       // Check the results.
@@ -92,13 +92,14 @@
       }
       ok(numEmptyProcesses == 1, "correct empty process name count");
       ok(numNonEmptyProcesses == numRemotes,
                                  "correct non-empty process name count");
 
       SimpleTest.finish();
     }
 
-    mgr.getReports(handleReport, null, processReports, null);
+    mgr.getReports(handleReport, null, processReports, null,
+                   /* anonymize = */ false);
   }
 
   ]]></script>
 </window>
--- a/toolkit/components/aboutmemory/tests/test_sqliteMultiReporter.xul
+++ b/toolkit/components/aboutmemory/tests/test_sqliteMultiReporter.xul
@@ -35,17 +35,17 @@
                 getService(Ci.mozIStorageService);
   let db = storage.openDatabase(file);
   db.close();
 
   // Invoke all the reporters.  The SQLite multi-reporter is among
   // them.  It shouldn't crash.
   let mgr = Cc["@mozilla.org/memory-reporter-manager;1"].
             getService(Ci.nsIMemoryReporterManager);
-  mgr.getReportsForThisProcess(function(){}, null);
+  mgr.getReportsForThisProcess(function(){}, null, /* anonymize = */ false);
 
   // If we haven't crashed, we've passed, but the test harness requires that
   // we explicitly check something.
   ok(true, "didn't crash");
 
   ]]>
   </script>
 </window>
--- a/toolkit/components/places/History.cpp
+++ b/toolkit/components/places/History.cpp
@@ -2229,17 +2229,17 @@ History::SizeOfEntryExcludingThis(KeyCla
 {
   return aEntry->array.SizeOfExcludingThis(aMallocSizeOf);
 }
 
 MOZ_DEFINE_MALLOC_SIZE_OF(HistoryMallocSizeOf)
 
 NS_IMETHODIMP
 History::CollectReports(nsIHandleReportCallback* aHandleReport,
-                        nsISupports* aData)
+                        nsISupports* aData, bool aAnonymize)
 {
   return MOZ_COLLECT_REPORT(
     "explicit/history-links-hashtable", KIND_HEAP, UNITS_BYTES,
     SizeOfIncludingThis(HistoryMallocSizeOf),
     "Memory used by the hashtable that records changes to the visited state "
     "of links.");
 }
 
--- a/toolkit/components/telemetry/Telemetry.cpp
+++ b/toolkit/components/telemetry/Telemetry.cpp
@@ -659,17 +659,17 @@ private:
 };
 
 TelemetryImpl*  TelemetryImpl::sTelemetry = nullptr;
 
 MOZ_DEFINE_MALLOC_SIZE_OF(TelemetryMallocSizeOf)
 
 NS_IMETHODIMP
 TelemetryImpl::CollectReports(nsIHandleReportCallback* aHandleReport,
-                              nsISupports* aData)
+                              nsISupports* aData, bool aAnonymize)
 {
   return MOZ_COLLECT_REPORT(
     "explicit/telemetry", KIND_HEAP, UNITS_BYTES,
     SizeOfIncludingThis(TelemetryMallocSizeOf),
     "Memory used by the telemetry system.");
 }
 
 // A initializer to initialize histogram collection
--- a/toolkit/components/url-classifier/nsUrlClassifierPrefixSet.cpp
+++ b/toolkit/components/url-classifier/nsUrlClassifierPrefixSet.cpp
@@ -244,17 +244,17 @@ nsUrlClassifierPrefixSet::Contains(uint3
 
   return NS_OK;
 }
 
 MOZ_DEFINE_MALLOC_SIZE_OF(UrlClassifierMallocSizeOf)
 
 NS_IMETHODIMP
 nsUrlClassifierPrefixSet::CollectReports(nsIHandleReportCallback* aHandleReport,
-                                         nsISupports* aData)
+                                         nsISupports* aData, bool aAnonymize)
 {
   return aHandleReport->Callback(
     EmptyCString(), mMemoryReportPath, KIND_HEAP, UNITS_BYTES,
     SizeOfIncludingThis(UrlClassifierMallocSizeOf),
     NS_LITERAL_CSTRING("Memory used by the prefix set for a URL classifier."),
     aData);
 }
 
--- a/xpcom/base/AvailableMemoryTracker.cpp
+++ b/xpcom/base/AvailableMemoryTracker.cpp
@@ -339,17 +339,17 @@ LowMemoryEventsPhysicalDistinguishedAmou
 }
 
 class LowEventsReporter MOZ_FINAL : public nsIMemoryReporter
 {
 public:
   NS_DECL_ISUPPORTS
 
   NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
-                            nsISupports* aData)
+                            nsISupports* aData, bool aAnonymize)
   {
     nsresult rv;
 
     // We only do virtual-memory tracking on 32-bit builds.
     if (sizeof(void*) == 4) {
       rv = MOZ_COLLECT_REPORT(
         "low-memory-events/virtual", KIND_OTHER, UNITS_COUNT_CUMULATIVE,
         LowMemoryEventsVirtualDistinguishedAmount(),
--- a/xpcom/base/SystemMemoryReporter.cpp
+++ b/xpcom/base/SystemMemoryReporter.cpp
@@ -131,18 +131,23 @@ public:
       }                                                                       \
     }                                                                         \
   } while (0)
 
 #define REPORT(_path, _amount, _desc) \
   REPORT_WITH_CLEANUP(_path, UNITS_BYTES, _amount, _desc, (void)0)
 
   NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
-                            nsISupports* aData)
+                            nsISupports* aData, bool aAnonymize)
   {
+    // There is lots of privacy-sensitive data in /proc. Just skip this
+    // reporter entirely when anonymization is required.
+    if (aAnonymize)
+      return NS_OK;
+
     if (!Preferences::GetBool("memory.system_memory_reporter")) {
       return NS_OK;
     }
 
     // Read relevant fields from /proc/meminfo.
     int64_t memTotal = 0, memFree = 0;
     nsresult rv = ReadMemInfo(&memTotal, &memFree);
 
--- a/xpcom/base/nsCycleCollector.cpp
+++ b/xpcom/base/nsCycleCollector.cpp
@@ -3264,17 +3264,17 @@ nsCycleCollector::CollectWhite()
 ////////////////////////
 // Memory reporting
 ////////////////////////
 
 MOZ_DEFINE_MALLOC_SIZE_OF(CycleCollectorMallocSizeOf)
 
 NS_IMETHODIMP
 nsCycleCollector::CollectReports(nsIHandleReportCallback* aHandleReport,
-                                 nsISupports* aData)
+                                 nsISupports* aData, bool aAnonymize)
 {
   size_t objectSize, graphNodesSize, graphEdgesSize, weakMapsSize,
          purpleBufferSize;
   SizeOfIncludingThis(CycleCollectorMallocSizeOf,
                       &objectSize,
                       &graphNodesSize, &graphEdgesSize,
                       &weakMapsSize,
                       &purpleBufferSize);
--- a/xpcom/base/nsIMemoryInfoDumper.idl
+++ b/xpcom/base/nsIMemoryInfoDumper.idl
@@ -39,25 +39,31 @@ interface nsIDumpGCAndCCLogsCallback : n
               in bool aIsParent);
 
   /**
    * Called when GC/CC logging has finished, after all calls to |onDump|.
    */
   void onFinish();
 };
 
-[scriptable, builtinclass, uuid(a156fda4-aea0-4da2-9daa-9858430fade9)]
+[scriptable, builtinclass, uuid(48541b74-47ee-4a62-9557-7f4b809bda5c)]
 interface nsIMemoryInfoDumper : nsISupports
 {
   /**
    * This dumps gzipped memory reports for this process and its child
    * processes.  If a file of the given name exists, it will be overwritten.
    *
    * @param aFilename The output file.
    *
+   * @param aFinishDumping The callback called on completion.
+   *
+   * @param aFinishDumpingData The environment for the callback.
+   *
+   * @param aAnonymize Should the reports be anonymized?
+   *
    * Sample output:
    *
    * {
    *   "hasMozMallocUsableSize":true,
    *   "reports": [
    *     {"process":"Main Process (pid 12345)", "path":"explicit/foo/bar",
    *      "kind":1, "units":0, "amount":2000000, "description":"Foo bar."},
    *     {"process":"Main Process (pid 12345)", "path":"heap-allocated",
@@ -118,17 +124,18 @@ interface nsIMemoryInfoDumper : nsISuppo
    *         }
    *       }
    *     }
    *   }
    * }
    */
   void dumpMemoryReportsToNamedFile(in AString aFilename,
                                     in nsIFinishDumpingCallback aFinishDumping,
-                                    in nsISupports aFinishDumpingData);
+                                    in nsISupports aFinishDumpingData,
+                                    in boolean aAnonymize);
 
   /**
    * Similar to dumpMemoryReportsToNamedFile, this method dumps gzipped memory
    * reports for this process and its child processes to files in the tmp
    * directory called memory-reports-<identifier>-<pid>.json.gz (or something
    * similar, such as memory-reports-<identifier>-<pid>-1.json.gz; no existing
    * file will be overwritten).
    *
@@ -139,23 +146,26 @@ interface nsIMemoryInfoDumper : nsISuppo
    * @param aIdentifier this identifier will appear in the filename of our
    *   about:memory dump and those of our children.
    *
    *   If the identifier is empty, the implementation may set it arbitrarily
    *   and use that new value for its own dump and the dumps of its child
    *   processes.  For example, the implementation may set |aIdentifier| to the
    *   number of seconds since the epoch.
    *
+   * @param aAnonymize Should the reports be anonymized?
+   *
    * @param aMinimizeMemoryUsage indicates whether we should run a series of
    *   gc/cc's in an attempt to reduce our memory usage before collecting our
    *   memory report.
    */
   void dumpMemoryInfoToTempDir(
     in AString aIdentifier,
-    in bool aMinimizeMemoryUsage);
+    in boolean aAnonymize,
+    in boolean aMinimizeMemoryUsage);
 
   /**
    * Dump GC and CC logs to files in the OS's temp directory (or in
    * $MOZ_CC_LOG_DIRECTORY, if that environment variable is specified).
    *
    * @param aIdentifier If aIdentifier is non-empty, this string will appear in
    *   the filenames of the logs we create (both for this process and, if
    *   aDumpChildProcesses is true, for our child processes).
--- a/xpcom/base/nsIMemoryReporter.idl
+++ b/xpcom/base/nsIMemoryReporter.idl
@@ -142,34 +142,57 @@ interface nsIMemoryReporterCallback : ns
  *   an OS-level allocation (e.g. mmap/VirtualAlloc/vm_allocate) or a
  *   heap-level allocation (e.g. malloc/calloc/operator new).  Reporters in
  *   this tree must have kind HEAP or NONHEAP, units BYTES.
  *
  * It is preferred, but not required, that report descriptions use complete
  * sentences (i.e. start with a capital letter and end with a period, or
  * similar).
  */
-[scriptable, uuid(0884cd0f-5829-4381-979b-0f53904030ed)]
+[scriptable, uuid(92a36db1-46bd-4fe6-988e-47db47236d8b)]
 interface nsIMemoryReporter : nsISupports
 {
   /*
    * Run the reporter.
+   *
+   * If |anonymize| is true, the memory reporter should anonymize any
+   * privacy-sensitive details in memory report paths, by replacing them with a
+   * string such as "<anonymized>". Anonymized memory reports may be sent
+   * automatically via crash reports or telemetry.
+   *
+   * The following things are considered privacy-sensitive.
+   *
+   * - Content domains and URLs, and information derived from them.
+   * - Content data, such as strings.
+   * - Details about content code, such as filenames, function names or stack
+   *   traces.
+   * - Details about or data from the user's system, such as filenames.
+   * - Running apps.
+   *
+   * In short, anything that could identify parts of the user's browsing
+   * history is considered privacy-sensitive.
+   *
+   * The following thing are not considered privacy-sensitive.
+   *
+   * - Chrome domains and URLs.
+   * - Information about installed extensions.
    */
   void collectReports(in nsIMemoryReporterCallback callback,
-                      in nsISupports data);
+                      in nsISupports data,
+                      in boolean anonymize);
 
   /*
-   * Kinds.  See the |kind| comment in nsIMemoryReporterCallback.
+   * Kinds. See the |kind| comment in nsIMemoryReporterCallback.
    */
   const int32_t KIND_NONHEAP = 0;
   const int32_t KIND_HEAP    = 1;
   const int32_t KIND_OTHER   = 2;
 
   /*
-   * Units.  See the |units| comment in nsIMemoryReporterCallback.
+   * Units. See the |units| comment in nsIMemoryReporterCallback.
    */
   const int32_t UNITS_BYTES = 0;
   const int32_t UNITS_COUNT = 1;
   const int32_t UNITS_COUNT_CUMULATIVE = 2;
   const int32_t UNITS_PERCENTAGE = 3;
 };
 
 [scriptable, function, uuid(548b3909-c04d-4ca6-8466-b8bee3837457)]
@@ -231,52 +254,59 @@ interface nsIMemoryReporterManager : nsI
    *
    * |finishReporting| is called even if, for example, some child processes
    * fail to report back.  However, calls to this method will silently and
    * immediately abort -- and |finishReporting| will not be called -- if a
    * previous getReports() call is still in flight, i.e. if it has not yet
    * finished invoking |finishReporting|.  The silent abort is because the
    * in-flight request will finish soon, and the caller would very likely just
    * catch and ignore any error anyway.
+   *
+   * If |anonymize| is true, it indicates that the memory reporters should
+   * anonymize any privacy-sensitive data (see above).
    */
   void getReports(in nsIMemoryReporterCallback handleReport,
                   in nsISupports handleReportData,
                   in nsIFinishReportingCallback finishReporting,
-                  in nsISupports finishReportingData);
+                  in nsISupports finishReportingData,
+                  in boolean anonymize);
 
   /*
    * As above, but: If |minimizeMemoryUsage| is true, then each process will
    * minimize its memory usage (see the |minimizeMemoryUsage| method) before
    * gathering its report.  If DMD is enabled and |DMDDumpIdent| is non-empty
    * then write a DMD report to a file in the usual temporary directory (see
    * |dumpMemoryInfoToTempDir| in |nsIMemoryInfoDumper|.)
    */
   [noscript] void
     getReportsExtended(in nsIMemoryReporterCallback handleReport,
                        in nsISupports handleReportData,
                        in nsIFinishReportingCallback finishReporting,
                        in nsISupports finishReportingData,
+                       in boolean anonymize,
                        in boolean minimizeMemoryUsage,
                        in AString DMDDumpIdent);
 
   /*
    * Get memory reports in the current process only.  |handleReport| is called
    * for each report.
    */
   void getReportsForThisProcess(in nsIMemoryReporterCallback handleReport,
-                                in nsISupports handleReportData);
+                                in nsISupports handleReportData,
+                                in boolean anonymize);
 
   /*
    * As above, but if DMD is enabled and |DMDDumpIdent| is non-empty
    * then write a DMD report to a file in the usual temporary directory (see
    * |dumpMemoryInfoToTempDir| in |nsIMemoryInfoDumper|.)
    */
   [noscript] void
     getReportsForThisProcessExtended(in nsIMemoryReporterCallback handleReport,
                                      in nsISupports handleReportData,
+                                     in boolean anonymize,
                                      in AString DMDDumpIdent);
 
   /*
    * The memory reporter manager, for the most part, treats reporters
    * registered with it as a black box.  However, there are some
    * "distinguished" amounts (as could be reported by a memory reporter) that
    * the manager provides as attributes, because they are sufficiently
    * interesting that we want external code (e.g. telemetry) to be able to rely
@@ -547,19 +577,20 @@ namespace mozilla {
 // 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)
+//     CollectReports(nsIHandleReportCallback* aHandleReport,
+//                    nsISupports* aData, bool aAnonymize)
 //     {
-//        return MOZ_COLLECT_REPORTER(
+//        return MOZ_COLLECT_REPORT(
 //          "explicit/path/to/somewhere", KIND_HEAP, UNITS_BYTES,
 //          MemoryAllocated(),
 //          "A description of what we are reporting."
 //     }
 //   };
 //
 //   ...somewhere later in the code...
 //   SetThirdPartyMemoryFunctions(MyMemoryReporter::CountingAlloc,
--- a/xpcom/base/nsMemoryInfoDumper.cpp
+++ b/xpcom/base/nsMemoryInfoDumper.cpp
@@ -51,32 +51,35 @@ using namespace mozilla;
 using namespace mozilla::dom;
 
 namespace {
 
 class DumpMemoryInfoToTempDirRunnable : public nsRunnable
 {
 public:
   DumpMemoryInfoToTempDirRunnable(const nsAString& aIdentifier,
-                                  bool aMinimizeMemoryUsage)
+                                  bool aAnonymize, bool aMinimizeMemoryUsage)
     : mIdentifier(aIdentifier)
+    , mAnonymize(aAnonymize)
     , mMinimizeMemoryUsage(aMinimizeMemoryUsage)
   {
   }
 
   NS_IMETHOD Run()
   {
     nsCOMPtr<nsIMemoryInfoDumper> dumper =
       do_GetService("@mozilla.org/memory-info-dumper;1");
-    dumper->DumpMemoryInfoToTempDir(mIdentifier, mMinimizeMemoryUsage);
+    dumper->DumpMemoryInfoToTempDir(mIdentifier, mAnonymize,
+                                    mMinimizeMemoryUsage);
     return NS_OK;
   }
 
 private:
   const nsString mIdentifier;
+  const bool mAnonymize;
   const bool mMinimizeMemoryUsage;
 };
 
 class GCAndCCLogDumpRunnable MOZ_FINAL
   : public nsRunnable
   , public nsIDumpGCAndCCLogsCallback
 {
 public:
@@ -152,21 +155,22 @@ namespace {
 // constant, so these have to be set at runtime.
 static uint8_t sDumpAboutMemorySignum;         // SIGRTMIN
 static uint8_t sDumpAboutMemoryAfterMMUSignum; // SIGRTMIN + 1
 static uint8_t sGCAndCCDumpSignum;             // SIGRTMIN + 2
 
 void doMemoryReport(const uint8_t aRecvSig)
 {
   // Dump our memory reports (but run this on the main thread!).
-  bool doMMUFirst = aRecvSig == sDumpAboutMemoryAfterMMUSignum;
+  bool minimize = aRecvSig == sDumpAboutMemoryAfterMMUSignum;
   LOG("SignalWatcher(sig %d) dispatching memory report runnable.", aRecvSig);
   nsRefPtr<DumpMemoryInfoToTempDirRunnable> runnable =
     new DumpMemoryInfoToTempDirRunnable(/* identifier = */ EmptyString(),
-                                        doMMUFirst);
+                                        /* anonymize = */ false,
+                                        minimize);
   NS_DispatchToMainThread(runnable);
 }
 
 void doGCCCDump(const uint8_t aRecvSig)
 {
   LOG("SignalWatcher(sig %d) dispatching GC/CC log runnable.", aRecvSig);
   // Dump GC and CC logs (from the main thread).
   nsRefPtr<GCAndCCLogDumpRunnable> runnable =
@@ -181,21 +185,22 @@ void doGCCCDump(const uint8_t aRecvSig)
 #endif // MOZ_SUPPORTS_RT_SIGNALS }
 
 #if defined(MOZ_SUPPORTS_FIFO) // {
 namespace {
 
 void
 doMemoryReport(const nsCString& aInputStr)
 {
-  bool doMMUMemoryReport = aInputStr.EqualsLiteral("minimize memory report");
+  bool minimize = aInputStr.EqualsLiteral("minimize memory report");
   LOG("FifoWatcher(command:%s) dispatching memory report runnable.", aInputStr.get());
   nsRefPtr<DumpMemoryInfoToTempDirRunnable> runnable =
     new DumpMemoryInfoToTempDirRunnable(/* identifier = */ EmptyString(),
-                                        doMMUMemoryReport);
+                                        /* anonymize = */ false,
+                                        minimize);
   NS_DispatchToMainThread(runnable);
 }
 
 void
 doGCCCDump(const nsCString& aInputStr)
 {
   bool doAllTracesGCCCDump = aInputStr.EqualsLiteral("gc log");
   LOG("FifoWatcher(command:%s) dispatching GC/CC log runnable.", aInputStr.get());
@@ -588,16 +593,17 @@ private:
   nsCString mrFilename;
   nsString mIdentifier;
 };
 
 NS_IMPL_ISUPPORTS(TempDirMemoryFinishCallback, nsIFinishReportingCallback)
 
 NS_IMETHODIMP
 nsMemoryInfoDumper::DumpMemoryInfoToTempDir(const nsAString& aIdentifier,
+                                            bool aAnonymize,
                                             bool aMinimizeMemoryUsage)
 {
   nsString identifier(aIdentifier);
   EnsureNonEmptyIdentifier(identifier);
 
 #ifdef MOZ_DMD
   // Clear DMD's reportedness state before running the memory reporters, to
   // avoid spurious twice-reported warnings.
@@ -653,16 +659,17 @@ nsMemoryInfoDumper::DumpMemoryInfoToTemp
   // Process reporters.
   nsCOMPtr<nsIMemoryReporterManager> mgr =
     do_GetService("@mozilla.org/memory-reporter-manager;1");
   nsRefPtr<DumpReportCallback> dumpReport = new DumpReportCallback(mrWriter);
   nsRefPtr<nsIFinishReportingCallback> finishReport =
     new TempDirMemoryFinishCallback(mrWriter, mrTmpFile, mrFilename, identifier);
   rv = mgr->GetReportsExtended(dumpReport, nullptr,
                                finishReport, nullptr,
+                               aAnonymize,
                                aMinimizeMemoryUsage,
                                identifier);
   return rv;
 }
 
 #ifdef MOZ_DMD
 nsresult
 nsMemoryInfoDumper::DumpDMD(const nsAString& aIdentifier)
@@ -821,17 +828,18 @@ private:
 };
 
 NS_IMPL_ISUPPORTS(FinishReportingCallback, nsIFinishReportingCallback)
 
 NS_IMETHODIMP
 nsMemoryInfoDumper::DumpMemoryReportsToNamedFile(
   const nsAString& aFilename,
   nsIFinishDumpingCallback* aFinishDumping,
-  nsISupports* aFinishDumpingData)
+  nsISupports* aFinishDumpingData,
+  bool aAnonymize)
 {
   MOZ_ASSERT(!aFilename.IsEmpty());
 
   // Create the file.
 
   nsCOMPtr<nsIFile> mrFile;
   nsresult rv = NS_NewLocalFile(aFilename, false, getter_AddRefs(mrFile));
   if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -870,12 +878,13 @@ nsMemoryInfoDumper::DumpMemoryReportsToN
   }
 
   // Process reports and finish up.
   nsRefPtr<DumpReportCallback> dumpReport = new DumpReportCallback(mrWriter);
   nsRefPtr<FinishReportingCallback> finishReporting =
     new FinishReportingCallback(aFinishDumping, aFinishDumpingData);
   nsCOMPtr<nsIMemoryReporterManager> mgr =
     do_GetService("@mozilla.org/memory-reporter-manager;1");
-  return mgr->GetReports(dumpReport, nullptr, finishReporting, mrWriter);
+  return mgr->GetReports(dumpReport, nullptr, finishReporting, mrWriter,
+                         aAnonymize);
 }
 
 #undef DUMP
--- a/xpcom/base/nsMemoryReporterManager.cpp
+++ b/xpcom/base/nsMemoryReporterManager.cpp
@@ -117,17 +117,17 @@ ResidentUniqueDistinguishedAmount(int64_
 }
 
 class ResidentUniqueReporter MOZ_FINAL : public nsIMemoryReporter
 {
 public:
   NS_DECL_ISUPPORTS
 
   NS_METHOD CollectReports(nsIHandleReportCallback* aHandleReport,
-                           nsISupports* aData)
+                           nsISupports* aData, bool aAnonymize)
   {
     int64_t amount = 0;
     nsresult rv = ResidentUniqueDistinguishedAmount(&amount);
     NS_ENSURE_SUCCESS(rv, rv);
 
     return MOZ_COLLECT_REPORT(
       "resident-unique", KIND_OTHER, UNITS_BYTES, amount,
 "Memory mapped by the process that is present in physical memory and not "
@@ -514,17 +514,17 @@ PrivateDistinguishedAmount(int64_t* aN)
 
 #ifdef HAVE_VSIZE_MAX_CONTIGUOUS_REPORTER
 class VsizeMaxContiguousReporter MOZ_FINAL : public nsIMemoryReporter
 {
 public:
   NS_DECL_ISUPPORTS
 
   NS_METHOD CollectReports(nsIHandleReportCallback* aHandleReport,
-                           nsISupports* aData)
+                           nsISupports* aData, bool aAnonymize)
   {
     int64_t amount;
     nsresult rv = VsizeMaxContiguousDistinguishedAmount(&amount);
     NS_ENSURE_SUCCESS(rv, rv);
     return MOZ_COLLECT_REPORT(
       "vsize-max-contiguous", KIND_OTHER, UNITS_BYTES, amount,
       "Size of the maximum contiguous block of available virtual "
       "memory.");
@@ -535,17 +535,17 @@ NS_IMPL_ISUPPORTS(VsizeMaxContiguousRepo
 
 #ifdef HAVE_PRIVATE_REPORTER
 class PrivateReporter MOZ_FINAL : public nsIMemoryReporter
 {
 public:
   NS_DECL_ISUPPORTS
 
   NS_METHOD CollectReports(nsIHandleReportCallback* aHandleReport,
-                           nsISupports* aData)
+                           nsISupports* aData, bool aAnonymize)
   {
     int64_t amount;
     nsresult rv = PrivateDistinguishedAmount(&amount);
     NS_ENSURE_SUCCESS(rv, rv);
     return MOZ_COLLECT_REPORT(
       "private", KIND_OTHER, UNITS_BYTES, amount,
 "Memory that cannot be shared with other processes, including memory that is "
 "committed and marked MEM_PRIVATE, data that is not mapped, and executable "
@@ -557,17 +557,17 @@ NS_IMPL_ISUPPORTS(PrivateReporter, nsIMe
 
 #ifdef HAVE_VSIZE_AND_RESIDENT_REPORTERS
 class VsizeReporter MOZ_FINAL : public nsIMemoryReporter
 {
 public:
   NS_DECL_ISUPPORTS
 
   NS_METHOD CollectReports(nsIHandleReportCallback* aHandleReport,
-                           nsISupports* aData)
+                           nsISupports* aData, bool aAnonymize)
   {
     int64_t amount;
     nsresult rv = VsizeDistinguishedAmount(&amount);
     NS_ENSURE_SUCCESS(rv, rv);
 
     return MOZ_COLLECT_REPORT(
       "vsize", KIND_OTHER, UNITS_BYTES, amount,
 "Memory mapped by the process, including code and data segments, the heap, "
@@ -582,17 +582,17 @@ public:
 NS_IMPL_ISUPPORTS(VsizeReporter, nsIMemoryReporter)
 
 class ResidentReporter MOZ_FINAL : public nsIMemoryReporter
 {
 public:
   NS_DECL_ISUPPORTS
 
   NS_METHOD CollectReports(nsIHandleReportCallback* aHandleReport,
-                           nsISupports* aData)
+                           nsISupports* aData, bool aAnonymize)
   {
     int64_t amount;
     nsresult rv = ResidentDistinguishedAmount(&amount);
     NS_ENSURE_SUCCESS(rv, rv);
 
     return MOZ_COLLECT_REPORT(
       "resident", KIND_OTHER, UNITS_BYTES, amount,
 "Memory mapped by the process that is present in physical memory, also known "
@@ -614,17 +614,17 @@ NS_IMPL_ISUPPORTS(ResidentReporter, nsIM
 #define HAVE_PAGE_FAULT_REPORTERS 1
 
 class PageFaultsSoftReporter MOZ_FINAL : public nsIMemoryReporter
 {
 public:
   NS_DECL_ISUPPORTS
 
   NS_METHOD CollectReports(nsIHandleReportCallback* aHandleReport,
-                           nsISupports* aData)
+                           nsISupports* aData, bool aAnonymize)
   {
     struct rusage usage;
     int err = getrusage(RUSAGE_SELF, &usage);
     if (err != 0) {
       return NS_ERROR_FAILURE;
     }
     int64_t amount = usage.ru_minflt;
 
@@ -656,17 +656,17 @@ PageFaultsHardDistinguishedAmount(int64_
 }
 
 class PageFaultsHardReporter MOZ_FINAL : public nsIMemoryReporter
 {
 public:
   NS_DECL_ISUPPORTS
 
   NS_METHOD CollectReports(nsIHandleReportCallback* aHandleReport,
-                           nsISupports* aData)
+                           nsISupports* aData, bool aAnonymize)
   {
     int64_t amount = 0;
     nsresult rv = PageFaultsHardDistinguishedAmount(&amount);
     NS_ENSURE_SUCCESS(rv, rv);
 
     return MOZ_COLLECT_REPORT(
       "page-faults-hard", KIND_OTHER, UNITS_COUNT_CUMULATIVE, amount,
 "The number of hard page faults (also known as 'major page faults') that have "
@@ -703,17 +703,17 @@ HeapOverheadRatio(jemalloc_stats_t* aSta
 }
 
 class JemallocHeapReporter MOZ_FINAL : public nsIMemoryReporter
 {
 public:
   NS_DECL_ISUPPORTS
 
   NS_METHOD CollectReports(nsIHandleReportCallback* aHandleReport,
-                           nsISupports* aData)
+                           nsISupports* aData, bool aAnonymize)
   {
     jemalloc_stats_t stats;
     jemalloc_stats(&stats);
 
     nsresult rv;
 
     rv = MOZ_COLLECT_REPORT(
       "heap-allocated", KIND_OTHER, UNITS_BYTES, stats.allocated,
@@ -807,17 +807,17 @@ NS_IMPL_ISUPPORTS(JemallocHeapReporter, 
 class AtomTablesReporter MOZ_FINAL : public nsIMemoryReporter
 {
   MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
 
 public:
   NS_DECL_ISUPPORTS
 
   NS_METHOD CollectReports(nsIHandleReportCallback* aHandleReport,
-                           nsISupports* aData)
+                           nsISupports* aData, bool aAnonymize)
   {
     return MOZ_COLLECT_REPORT(
       "explicit/atom-tables", KIND_HEAP, UNITS_BYTES,
       NS_SizeOfAtomTablesIncludingThis(MallocSizeOf),
       "Memory used by the dynamic and static atoms tables.");
   }
 };
 NS_IMPL_ISUPPORTS(AtomTablesReporter, nsIMemoryReporter)
@@ -828,17 +828,17 @@ namespace mozilla {
 namespace dmd {
 
 class DMDReporter MOZ_FINAL : public nsIMemoryReporter
 {
 public:
   NS_DECL_ISUPPORTS
 
   NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
-                            nsISupports* aData)
+                            nsISupports* aData, bool aAnonymize)
   {
     dmd::Sizes sizes;
     dmd::SizeOf(&sizes);
 
 #define REPORT(_path, _amount, _desc)                                         \
   do {                                                                        \
     nsresult rv;                                                              \
     rv = aHandleReport->Callback(EmptyCString(), NS_LITERAL_CSTRING(_path),   \
@@ -986,30 +986,33 @@ nsMemoryReporterManager::DecrementNumChi
                        mNumChildProcesses);
 }
 
 NS_IMETHODIMP
 nsMemoryReporterManager::GetReports(
   nsIHandleReportCallback* aHandleReport,
   nsISupports* aHandleReportData,
   nsIFinishReportingCallback* aFinishReporting,
-  nsISupports* aFinishReportingData)
+  nsISupports* aFinishReportingData,
+  bool aAnonymize)
 {
   return GetReportsExtended(aHandleReport, aHandleReportData,
                             aFinishReporting, aFinishReportingData,
+                            aAnonymize,
                             /* minimize = */ false,
                             /* DMDident = */ nsString());
 }
 
 NS_IMETHODIMP
 nsMemoryReporterManager::GetReportsExtended(
   nsIHandleReportCallback* aHandleReport,
   nsISupports* aHandleReportData,
   nsIFinishReportingCallback* aFinishReporting,
   nsISupports* aFinishReportingData,
+  bool aAnonymize,
   bool aMinimize,
   const nsAString& aDMDDumpIdent)
 {
   nsresult rv;
 
   // Memory reporters are not necessarily threadsafe, so this function must
   // be called from the main thread.
   if (!NS_IsMainThread()) {
@@ -1032,41 +1035,43 @@ nsMemoryReporterManager::GetReportsExten
   if (mNumChildProcesses > 0) {
     // Request memory reports from child processes.  We do this *before*
     // collecting reports for this process so each process can collect
     // reports in parallel.
     nsCOMPtr<nsIObserverService> obs =
       do_GetService("@mozilla.org/observer-service;1");
     NS_ENSURE_STATE(obs);
 
-    nsPrintfCString genStr("generation=%x minimize=%d DMDident=",
-                           generation, aMinimize ? 1 : 0);
+    nsPrintfCString genStr("generation=%x anonymize=%d minimize=%d DMDident=",
+                           generation, aAnonymize ? 1 : 0, aMinimize ? 1 : 0);
     nsAutoString msg = NS_ConvertUTF8toUTF16(genStr);
     msg += aDMDDumpIdent;
 
     obs->NotifyObservers(nullptr, "child-memory-reporter-request",
                          msg.get());
 
     nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID);
     NS_ENSURE_TRUE(timer, NS_ERROR_FAILURE);
     rv = timer->InitWithFuncCallback(TimeoutCallback,
                                      this, kTimeoutLengthMS,
                                      nsITimer::TYPE_ONE_SHOT);
     NS_ENSURE_SUCCESS(rv, rv);
 
     mGetReportsState = new GetReportsState(generation,
+                                           aAnonymize,
                                            timer,
                                            mNumChildProcesses,
                                            aHandleReport,
                                            aHandleReportData,
                                            aFinishReporting,
                                            aFinishReportingData,
                                            aDMDDumpIdent);
   } else {
     mGetReportsState = new GetReportsState(generation,
+                                           aAnonymize,
                                            nullptr,
                                            /* mNumChildProcesses = */ 0,
                                            aHandleReport,
                                            aHandleReportData,
                                            aFinishReporting,
                                            aFinishReportingData,
                                            aDMDDumpIdent);
   }
@@ -1081,17 +1086,17 @@ nsMemoryReporterManager::GetReportsExten
 
 nsresult
 nsMemoryReporterManager::StartGettingReports()
 {
   GetReportsState* s = mGetReportsState;
 
   // Get reports for this process.
   GetReportsForThisProcessExtended(s->mHandleReport, s->mHandleReportData,
-                                   s->mDMDDumpIdent);
+                                   s->mAnonymize, s->mDMDDumpIdent);
   s->mParentDone = true;
 
   // If there are no remaining child processes, we can finish up immediately.
   return (s->mNumChildProcessesCompleted >= s->mNumChildProcesses)
     ? FinishReporting()
     : NS_OK;
 }
 
@@ -1111,28 +1116,26 @@ WeakEnumerator(nsPtrHashKey<nsIMemoryRep
   MemoryReporterArray* allReporters = static_cast<MemoryReporterArray*>(aData);
   allReporters->AppendElement(aElem->GetKey());
   return PL_DHASH_NEXT;
 }
 
 NS_IMETHODIMP
 nsMemoryReporterManager::GetReportsForThisProcess(
   nsIHandleReportCallback* aHandleReport,
-  nsISupports* aHandleReportData)
+  nsISupports* aHandleReportData, bool aAnonymize)
 {
-  return GetReportsForThisProcessExtended(aHandleReport,
-                                          aHandleReportData,
-                                          nsString());
+  return GetReportsForThisProcessExtended(aHandleReport, aHandleReportData,
+                                          aAnonymize, nsString());
 }
 
 NS_IMETHODIMP
 nsMemoryReporterManager::GetReportsForThisProcessExtended(
-  nsIHandleReportCallback* aHandleReport,
-  nsISupports* aHandleReportData,
-  const nsAString& aDMDDumpIdent)
+  nsIHandleReportCallback* aHandleReport, nsISupports* aHandleReportData,
+  bool aAnonymize, const nsAString& aDMDDumpIdent)
 {
   // Memory reporters are not necessarily threadsafe, so this function must
   // be called from the main thread.
   if (!NS_IsMainThread()) {
     MOZ_CRASH();
   }
 
 #ifdef MOZ_DMD
@@ -1145,17 +1148,18 @@ nsMemoryReporterManager::GetReportsForTh
 
   MemoryReporterArray allReporters;
   {
     mozilla::MutexAutoLock autoLock(mMutex);
     mStrongReporters->EnumerateEntries(StrongEnumerator, &allReporters);
     mWeakReporters->EnumerateEntries(WeakEnumerator, &allReporters);
   }
   for (uint32_t i = 0; i < allReporters.Length(); i++) {
-    allReporters[i]->CollectReports(aHandleReport, aHandleReportData);
+    allReporters[i]->CollectReports(aHandleReport, aHandleReportData,
+                                    aAnonymize);
   }
 
 #ifdef MOZ_DMD
   if (!aDMDDumpIdent.IsEmpty()) {
     return nsMemoryInfoDumper::DumpDMD(aDMDDumpIdent);
   }
 #endif
 
@@ -1492,17 +1496,21 @@ nsMemoryReporterManager::GetExplicit(int
   // non-explicit, non-NONHEAP measurements (except for "heap-allocated").
   // That's lots of wasted work, and we used to have a GetExplicitNonHeap()
   // method which did this more efficiently, but it ended up being more
   // trouble than it was worth.
 
   nsRefPtr<ExplicitCallback> handleReport = new ExplicitCallback();
   nsRefPtr<Int64Wrapper> wrappedExplicitSize = new Int64Wrapper();
 
-  GetReportsForThisProcess(handleReport, wrappedExplicitSize);
+  // Anonymization doesn't matter here, because we're only summing all the
+  // reported values. Enable it anyway because it's slightly faster, since it
+  // doesn't have to get URLs, find notable strings, etc.
+  GetReportsForThisProcess(handleReport, wrappedExplicitSize,
+                           /* anonymize = */ true);
 
   *aAmount = wrappedExplicitSize->mValue;
 
   return NS_OK;
 #endif // HAVE_JEMALLOC_STATS
 }
 
 NS_IMETHODIMP
@@ -1974,16 +1982,16 @@ NS_IMPL_ISUPPORTS(DoNothingCallback, nsI
 void
 RunReportersForThisProcess()
 {
   nsCOMPtr<nsIMemoryReporterManager> mgr =
     do_GetService("@mozilla.org/memory-reporter-manager;1");
 
   nsRefPtr<DoNothingCallback> doNothing = new DoNothingCallback();
 
-  mgr->GetReportsForThisProcess(doNothing, nullptr);
+  mgr->GetReportsForThisProcess(doNothing, nullptr, /* anonymize = */ false);
 }
 
 } // namespace dmd
 } // namespace mozilla
 
 #endif  // defined(MOZ_DMD)
 
--- a/xpcom/base/nsMemoryReporterManager.h
+++ b/xpcom/base/nsMemoryReporterManager.h
@@ -188,34 +188,36 @@ private:
   WeakReportersTable* mSavedWeakReporters;
 
   uint32_t mNumChildProcesses;
   uint32_t mNextGeneration;
 
   struct GetReportsState
   {
     uint32_t                             mGeneration;
+    bool                                 mAnonymize;
     nsCOMPtr<nsITimer>                   mTimer;
     uint32_t                             mNumChildProcesses;
     uint32_t                             mNumChildProcessesCompleted;
     bool                                 mParentDone;
     nsCOMPtr<nsIHandleReportCallback>    mHandleReport;
     nsCOMPtr<nsISupports>                mHandleReportData;
     nsCOMPtr<nsIFinishReportingCallback> mFinishReporting;
     nsCOMPtr<nsISupports>                mFinishReportingData;
     nsString                             mDMDDumpIdent;
 
-    GetReportsState(uint32_t aGeneration, nsITimer* aTimer,
+    GetReportsState(uint32_t aGeneration, bool aAnonymize, nsITimer* aTimer,
                     uint32_t aNumChildProcesses,
                     nsIHandleReportCallback* aHandleReport,
                     nsISupports* aHandleReportData,
                     nsIFinishReportingCallback* aFinishReporting,
                     nsISupports* aFinishReportingData,
                     const nsAString& aDMDDumpIdent)
       : mGeneration(aGeneration)
+      , mAnonymize(aAnonymize)
       , mTimer(aTimer)
       , mNumChildProcesses(aNumChildProcesses)
       , mNumChildProcessesCompleted(0)
       , mParentDone(false)
       , mHandleReport(aHandleReport)
       , mHandleReportData(aHandleReportData)
       , mFinishReporting(aFinishReporting)
       , mFinishReportingData(aFinishReportingData)
--- a/xpcom/build/nsXPComInit.cpp
+++ b/xpcom/build/nsXPComInit.cpp
@@ -368,17 +368,18 @@ public:
 
     static void Free(const void*, void* p)
     {
         return CountingFree(p);
     }
 
 private:
     NS_IMETHODIMP
-    CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData)
+    CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData,
+                   bool aAnonymize)
     {
         return MOZ_COLLECT_REPORT(
             "explicit/icu", KIND_HEAP, UNITS_BYTES, MemoryAllocated(),
             "Memory used by ICU, a Unicode and globalization support library.");
     }
 };
 
 NS_IMPL_ISUPPORTS(ICUReporter, nsIMemoryReporter)
@@ -388,17 +389,18 @@ NS_IMPL_ISUPPORTS(ICUReporter, nsIMemory
 class OggReporter MOZ_FINAL : public nsIMemoryReporter,
                               public CountingAllocatorBase<OggReporter>
 {
 public:
     NS_DECL_ISUPPORTS
 
 private:
     NS_IMETHODIMP
-    CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData)
+    CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData,
+                   bool aAnonymize)
     {
         return MOZ_COLLECT_REPORT(
             "explicit/media/libogg", KIND_HEAP, UNITS_BYTES, MemoryAllocated(),
             "Memory allocated through libogg for Ogg, Theora, and related media files.");
     }
 };
 
 NS_IMPL_ISUPPORTS(OggReporter, nsIMemoryReporter)
@@ -409,17 +411,18 @@ NS_IMPL_ISUPPORTS(OggReporter, nsIMemory
 class VPXReporter MOZ_FINAL : public nsIMemoryReporter,
                               public CountingAllocatorBase<VPXReporter>
 {
 public:
     NS_DECL_ISUPPORTS
 
 private:
     NS_IMETHODIMP
-    CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData)
+    CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData,
+                   bool aAnonymize)
     {
         return MOZ_COLLECT_REPORT(
             "explicit/media/libvpx", KIND_HEAP, UNITS_BYTES, MemoryAllocated(),
             "Memory allocated through libvpx for WebM media files.");
     }
 };
 
 NS_IMPL_ISUPPORTS(VPXReporter, nsIMemoryReporter)
@@ -431,17 +434,18 @@ NS_IMPL_ISUPPORTS(VPXReporter, nsIMemory
 class NesteggReporter MOZ_FINAL : public nsIMemoryReporter
                                 , public CountingAllocatorBase<NesteggReporter>
 {
 public:
     NS_DECL_ISUPPORTS
 
 private:
     NS_IMETHODIMP
-    CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData)
+    CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData,
+                   bool aAnonymize)
     {
         return MOZ_COLLECT_REPORT(
             "explicit/media/libnestegg", KIND_HEAP, UNITS_BYTES, MemoryAllocated(),
             "Memory allocated through libnestegg for WebM media files.");
     }
 };
 
 NS_IMPL_ISUPPORTS(NesteggReporter, nsIMemoryReporter)
--- a/xpcom/components/nsCategoryManager.cpp
+++ b/xpcom/components/nsCategoryManager.cpp
@@ -474,17 +474,17 @@ nsCategoryManager::get_category(const ch
   }
   return node;
 }
 
 MOZ_DEFINE_MALLOC_SIZE_OF(CategoryManagerMallocSizeOf)
 
 NS_IMETHODIMP
 nsCategoryManager::CollectReports(nsIHandleReportCallback* aHandleReport,
-                                  nsISupports* aData)
+                                  nsISupports* aData, bool aAnonymize)
 {
   return MOZ_COLLECT_REPORT(
     "explicit/xpcom/category-manager", KIND_HEAP, UNITS_BYTES,
     SizeOfIncludingThis(CategoryManagerMallocSizeOf),
     "Memory used for the XPCOM category manager.");
 }
 
 static size_t
--- a/xpcom/components/nsComponentManager.cpp
+++ b/xpcom/components/nsComponentManager.cpp
@@ -1684,17 +1684,17 @@ SizeOfContractIDsEntryExcludingThis(nsCS
     // (which measures them in SizeOfFactoriesEntryExcludingThis).
     return aKey.SizeOfExcludingThisMustBeUnshared(aMallocSizeOf);
 }
 
 MOZ_DEFINE_MALLOC_SIZE_OF(ComponentManagerMallocSizeOf)
 
 NS_IMETHODIMP
 nsComponentManagerImpl::CollectReports(nsIHandleReportCallback* aHandleReport,
-                                       nsISupports* aData)
+                                       nsISupports* aData, bool aAnonymize)
 {
     return MOZ_COLLECT_REPORT(
         "explicit/xpcom/component-manager", KIND_HEAP, UNITS_BYTES,
         SizeOfIncludingThis(ComponentManagerMallocSizeOf),
         "Memory used for the XPCOM component manager.");
 }
 
 size_t
--- a/xpcom/ds/nsObserverService.cpp
+++ b/xpcom/ds/nsObserverService.cpp
@@ -103,21 +103,22 @@ nsObserverService::CountReferents(nsObse
         referentCount->suspectObservers.AppendElement(suspect);
     }
 
     return PL_DHASH_NEXT;
 }
 
 NS_IMETHODIMP
 nsObserverService::CollectReports(nsIHandleReportCallback* aHandleReport,
-                                  nsISupports* aData)
+                                  nsISupports* aData, bool aAnonymize)
 {
     ObserverServiceReferentCount referentCount;
     mObserverTopicTable.EnumerateEntries(CountReferents, &referentCount);
 
+    // These aren't privacy-sensitive and so don't need anonymizing.
     nsresult rv;
     for (uint32_t i = 0; i < referentCount.suspectObservers.Length(); i++) {
         SuspectObserver& suspect = referentCount.suspectObservers[i];
         nsPrintfCString suspectPath("observer-service-suspect/"
                                     "referent(topic=%s)",
                                     suspect.topic);
         rv = aHandleReport->Callback(/* process */ EmptyCString(),
             suspectPath, KIND_OTHER, UNITS_COUNT, suspect.referentCount,
--- a/xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp
+++ b/xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp
@@ -40,17 +40,17 @@ XPTInterfaceInfoManager::SizeOfIncluding
     n += mWorkingSet.mNameTable.SizeOfExcludingThis(nullptr, aMallocSizeOf);
     return n;
 }
 
 MOZ_DEFINE_MALLOC_SIZE_OF(XPTIMallocSizeOf)
 
 NS_IMETHODIMP
 XPTInterfaceInfoManager::CollectReports(nsIHandleReportCallback* aHandleReport,
-                                        nsISupports* aData)
+                                        nsISupports* aData, bool aAnonymize)
 {
     size_t amount = SizeOfIncludingThis(XPTIMallocSizeOf);
 
     // Measure gXPTIStructArena here, too.  This is a bit grotty because it
     // doesn't belong to the XPTIInterfaceInfoManager, but there's no
     // obviously better place to measure it.
     amount += XPT_SizeOfArena(gXPTIStructArena, XPTIMallocSizeOf);