Bug 1462138 - Part 1: Add a memory reporter for nsStringBundleService. r=erahm
authorKristen Wright <kwright@mozilla.com>
Fri, 18 May 2018 13:16:31 -0700
changeset 419811 ef08139f2c65053ab21a5f346a23f643bb3d856d
parent 419810 dabad83b031e02d828cf875aa5f511dd6aa78964
child 419812 0ae824c33c15469316e8139256b5dbaa7c442774
push id34049
push userbtara@mozilla.com
push dateFri, 25 May 2018 10:01:58 +0000
treeherdermozilla-central@bf4762f10b8d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerserahm
bugs1462138
milestone62.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 1462138 - Part 1: Add a memory reporter for nsStringBundleService. r=erahm Added memory reporter in nsStringBundleService. Added SizeOfIncluding/ExcludingThis functions in IStringBundle, StringBundle, ExtensibleStringBundle, PersistentProperties, StringBundleTextOverride.
intl/strres/nsIStringBundle.idl
intl/strres/nsIStringBundleOverride.idl
intl/strres/nsStringBundle.cpp
intl/strres/nsStringBundle.h
intl/strres/nsStringBundleService.h
intl/strres/nsStringBundleTextOverride.cpp
intl/strres/nsStringBundleTextOverride.h
xpcom/ds/nsIPersistentProperties2.idl
xpcom/ds/nsPersistentProperties.cpp
xpcom/ds/nsPersistentProperties.h
--- a/intl/strres/nsIStringBundle.idl
+++ b/intl/strres/nsIStringBundle.idl
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 #include "nsISimpleEnumerator.idl"
 
 %{C++
+#include "mozilla/MemoryReporting.h"
 
 // Define Contractid and CID
 // {D85A17C1-AA7C-11d2-9B8C-00805F8A16D9}
 #define NS_STRINGBUNDLESERVICE_CID \
 { 0xd85a17c1, 0xaa7c, 0x11d2, \
   { 0x9b, 0x8c, 0x0, 0x80, 0x5f, 0x8a, 0x16, 0xd9 } }
 
 #define NS_STRINGBUNDLE_CONTRACTID "@mozilla.org/intl/stringbundle;1"
@@ -52,21 +53,26 @@ interface nsIStringBundle : nsISupports
   // the names are most often 8-bit string literals (normally ASCII, though
   // u8"foo" literals will also work).
   [noscript, binaryname(FormatStringFromName)]
   AString formatStringFromNameCpp(in string aName,
                                   [array, size_is(length)] in wstring params,
                                   in unsigned long length);
 
   /*
-  Implements nsISimpleEnumerator, replaces nsIEnumerator 
+  Implements nsISimpleEnumerator, replaces nsIEnumerator
   */
   nsISimpleEnumerator getSimpleEnumeration();
   // Preloads string bundle data asynchronously
   void asyncPreload();
+
+%{C++
+  virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const = 0;
+  virtual size_t SizeOfIncludingThisIfUnshared(mozilla::MallocSizeOf aMallocSizeOf) const = 0;
+%}
 };
 
 [scriptable, uuid(D85A17C0-AA7C-11d2-9B8C-00805F8A16D9)]
 interface nsIStringBundleService : nsISupports
 {
   nsIStringBundle createBundle(in string aURLSpec);
   nsIStringBundle createExtensibleBundle(in string aRegistryKey);
 
@@ -78,16 +84,20 @@ interface nsIStringBundleService : nsISu
    *            can be separated by newline ('\n') characters.
    * @return the formatted message
    */
   AString formatStatusMessage(in nsresult aStatus, in wstring aStatusArg);
 
   /**
    * flushes the string bundle cache - useful when the locale changes or
    * when we need to get some extra memory back
-   * 
+   *
    * at some point, we might want to make this flush all the bundles,
    * because any bundles that are floating around when the locale changes
    * will suddenly contain bad data
    *
    */
   void flushBundles();
+
+  %{C++
+    virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const = 0;
+  %}
 };
--- a/intl/strres/nsIStringBundleOverride.idl
+++ b/intl/strres/nsIStringBundleOverride.idl
@@ -2,24 +2,32 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
 interface nsISimpleEnumerator;
 
+%{C++
+#include "mozilla/MemoryReporting.h"
+%}
+
 // to be implemented by an embeddor that wants to override some strings
 [scriptable, uuid(965eb278-5678-456b-82a7-20a0c86a803c)]
 interface nsIStringBundleOverride : nsISupports
 {
   /**
    * get the override value for a particular key in a particular
    * string bundle
    */
   AString getStringFromName(in AUTF8String url,
                             in ACString key);
 
   /**
    * get all override keys for a given string bundle
    */
   nsISimpleEnumerator enumerateKeysInBundle(in AUTF8String url);
+
+%{C++
+  virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const = 0;
+%}
 };
--- a/intl/strres/nsStringBundle.cpp
+++ b/intl/strres/nsStringBundle.cpp
@@ -59,16 +59,39 @@ NS_IMETHODIMP
 nsStringBundle::AsyncPreload()
 {
   return NS_IdleDispatchToCurrentThread(
     NewIdleRunnableMethod("nsStringBundle::LoadProperties",
                           this,
                           &nsStringBundle::LoadProperties));
 }
 
+size_t
+nsStringBundle::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
+{
+  size_t n = 0;
+  if (mProps) {
+    n += mProps->SizeOfIncludingThis(aMallocSizeOf);
+  }
+  if (mOverrideStrings) {
+    n += mOverrideStrings->SizeOfIncludingThis(aMallocSizeOf);
+  }
+  return aMallocSizeOf(this) + n;
+}
+
+size_t
+nsStringBundle::SizeOfIncludingThisIfUnshared(MallocSizeOf aMallocSizeOf) const
+{
+  if (mRefCnt == 1) {
+    return SizeOfIncludingThis(aMallocSizeOf);
+  } else {
+    return 0;
+  }
+}
+
 nsresult
 nsStringBundle::LoadProperties()
 {
   // this is different than mLoaded, because we only want to attempt
   // to load once
   // we only want to load once, but if we've tried once and failed,
   // continue to throw an error!
   if (mAttemptedLoad) {
@@ -378,16 +401,41 @@ nsExtensibleStringBundle::AsyncPreload()
   }
   return rv;
 }
 
 nsExtensibleStringBundle::~nsExtensibleStringBundle()
 {
 }
 
+size_t
+nsExtensibleStringBundle::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
+{
+  size_t n = 0;
+  const uint32_t sz = mBundles.Count();
+  for (uint32_t i = 0; i < sz; ++i) {
+    nsIStringBundle* bundle = mBundles[i];
+    if (bundle) {
+      n += bundle->SizeOfIncludingThis(aMallocSizeOf);
+    }
+  }
+  n += mBundles.ShallowSizeOfExcludingThis(aMallocSizeOf);
+  return aMallocSizeOf(this) + n;
+}
+
+size_t
+nsExtensibleStringBundle::SizeOfIncludingThisIfUnshared(MallocSizeOf aMallocSizeOf) const
+{
+  if (mRefCnt == 1) {
+    return SizeOfIncludingThis(aMallocSizeOf);
+  } else {
+    return 0;
+  }
+}
+
 nsresult
 nsExtensibleStringBundle::GetStringFromID(int32_t aID, nsAString& aResult)
 {
   nsAutoCString idStr;
   idStr.AppendInt(aID, 10);
   return GetStringFromName(idStr.get(), aResult);
 }
 
@@ -485,20 +533,22 @@ nsStringBundleService::nsStringBundleSer
 {
   mErrorService = do_GetService(kErrorServiceCID);
   NS_ASSERTION(mErrorService, "Couldn't get error service");
 }
 
 NS_IMPL_ISUPPORTS(nsStringBundleService,
                   nsIStringBundleService,
                   nsIObserver,
-                  nsISupportsWeakReference)
+                  nsISupportsWeakReference,
+                  nsIMemoryReporter)
 
 nsStringBundleService::~nsStringBundleService()
 {
+  UnregisterWeakMemoryReporter(this);
   flushBundleCache();
 }
 
 nsresult
 nsStringBundleService::Init()
 {
   nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
   if (os) {
@@ -509,19 +559,32 @@ nsStringBundleService::Init()
     os->AddObserver(this, "intl:app-locales-changed", true);
   }
 
   // instantiate the override service, if there is any.
   // at some point we probably want to make this a category, and
   // support multiple overrides
   mOverrideStrings = do_GetService(NS_STRINGBUNDLETEXTOVERRIDE_CONTRACTID);
 
+  RegisterWeakMemoryReporter(this);
+
   return NS_OK;
 }
 
+size_t
+nsStringBundleService::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
+{
+  size_t n = mBundleMap.ShallowSizeOfExcludingThis(aMallocSizeOf);
+  for (auto iter = mBundleMap.ConstIter(); !iter.Done(); iter.Next()) {
+    n += iter.Data()->mBundle->SizeOfIncludingThis(aMallocSizeOf);
+    n += iter.Data()->mHashKey.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
+  }
+  return aMallocSizeOf(this) + n;
+}
+
 NS_IMETHODIMP
 nsStringBundleService::Observe(nsISupports* aSubject,
                                const char* aTopic,
                                const char16_t* aSomeData)
 {
   if (strcmp("memory-pressure", aTopic) == 0 ||
       strcmp("profile-do-change", aTopic) == 0 ||
       strcmp("chrome-flush-caches", aTopic) == 0 ||
@@ -565,17 +628,16 @@ nsStringBundleService::getStringBundle(c
 
   if (cacheEntry) {
     // cache hit!
     // remove it from the list, it will later be reinserted
     // at the head of the list
     cacheEntry->remove();
 
   } else {
-
     // hasn't been cached, so insert it into the hash table
     RefPtr<nsStringBundle> bundle = new nsStringBundle(aURLSpec, mOverrideStrings);
     cacheEntry = insertIntoCache(bundle.forget(), key);
   }
 
   // at this point the cacheEntry should exist in the hashtable,
   // but is not in the LRU cache.
   // put the cache entry at the front of the list
--- a/intl/strres/nsStringBundle.h
+++ b/intl/strres/nsStringBundle.h
@@ -22,16 +22,19 @@ public:
     nsStringBundle(const char* aURLSpec, nsIStringBundleOverride*);
     nsresult LoadProperties();
 
     NS_DECL_THREADSAFE_ISUPPORTS
     NS_DECL_NSISTRINGBUNDLE
 
     nsCOMPtr<nsIPersistentProperties> mProps;
 
+    size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
+    size_t SizeOfIncludingThisIfUnshared(mozilla::MallocSizeOf aMallocSizeOf) const override;
+
 protected:
     virtual ~nsStringBundle();
 
     nsresult GetCombinedEnumeration(nsIStringBundleOverride* aOverrideString,
                                     nsISimpleEnumerator** aResult);
 private:
     nsCString              mPropertiesURL;
     nsCOMPtr<nsIStringBundleOverride> mOverrideStrings;
@@ -57,16 +60,18 @@ class nsExtensibleStringBundle final : p
 {
   NS_DECL_ISUPPORTS
   NS_DECL_NSISTRINGBUNDLE
 
   nsresult Init(const char * aCategory, nsIStringBundleService *);
 
 public:
   nsExtensibleStringBundle();
+  size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
+  size_t SizeOfIncludingThisIfUnshared(mozilla::MallocSizeOf aMallocSizeOf) const override;
 
 private:
   virtual ~nsExtensibleStringBundle();
 
   nsCOMArray<nsIStringBundle> mBundles;
   bool mLoaded;
 };
 
--- a/intl/strres/nsStringBundleService.h
+++ b/intl/strres/nsStringBundleService.h
@@ -10,34 +10,52 @@
 #include "nsDataHashtable.h"
 #include "nsHashKeys.h"
 #include "nsIPersistentProperties2.h"
 #include "nsIStringBundle.h"
 #include "nsIObserver.h"
 #include "nsWeakReference.h"
 #include "nsIErrorService.h"
 #include "nsIStringBundleOverride.h"
+#include "nsIMemoryReporter.h"
 
 #include "mozilla/LinkedList.h"
 
 struct bundleCacheEntry_t;
 
 class nsStringBundleService : public nsIStringBundleService,
                               public nsIObserver,
-                              public nsSupportsWeakReference
+                              public nsSupportsWeakReference,
+                              public nsIMemoryReporter
 {
+  MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf);
+
 public:
   nsStringBundleService();
 
   nsresult Init();
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSISTRINGBUNDLESERVICE
   NS_DECL_NSIOBSERVER
 
+  NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
+                            nsISupports* aData, bool anonymize) override
+  {
+    size_t amt = SizeOfIncludingThis(MallocSizeOf);
+
+    MOZ_COLLECT_REPORT(
+      "explicit/string-bundle-service", KIND_HEAP, UNITS_BYTES,
+      amt,
+      "Memory used for StringBundleService bundles");
+    return NS_OK;
+  };
+
+  size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
+
 private:
   virtual ~nsStringBundleService();
 
   void getStringBundle(const char *aUrl, nsIStringBundle** aResult);
   nsresult FormatWithBundle(nsIStringBundle* bundle, nsresult aStatus,
                             uint32_t argCount, char16_t** argArray,
                             nsAString& result);
 
--- a/intl/strres/nsStringBundleTextOverride.cpp
+++ b/intl/strres/nsStringBundleTextOverride.cpp
@@ -207,16 +207,22 @@ nsStringBundleTextOverride::GetStringFro
     nsAutoCString combinedURL(aURL + NS_LITERAL_CSTRING("#") + key);
 
     // persistent properties uses ":" as a delimiter, so escape that character
     combinedURL.ReplaceSubstring(":", "%3A");
 
     return mValues->GetStringProperty(combinedURL, aResult);
 }
 
+size_t
+nsStringBundleTextOverride::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
+{
+  return aMallocSizeOf(this) + (mValues ? mValues->SizeOfIncludingThis(aMallocSizeOf) : 0);
+}
+
 NS_IMETHODIMP
 nsStringBundleTextOverride::EnumerateKeysInBundle(const nsACString& aURL,
                                                   nsISimpleEnumerator** aResult)
 {
     // enumerate all strings, and let the enumerator know
     nsCOMPtr<nsISimpleEnumerator> enumerator;
     mValues->Enumerate(getter_AddRefs(enumerator));
 
--- a/intl/strres/nsStringBundleTextOverride.h
+++ b/intl/strres/nsStringBundleTextOverride.h
@@ -27,15 +27,17 @@ class nsStringBundleTextOverride : publi
   public:
     nsStringBundleTextOverride() { }
 
     nsresult Init();
 
     NS_DECL_ISUPPORTS
     NS_DECL_NSISTRINGBUNDLEOVERRIDE
 
+    size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
+
   private:
     nsCOMPtr<nsIPersistentProperties> mValues;
 
     virtual ~nsStringBundleTextOverride() {}
 };
 
 #endif
--- a/xpcom/ds/nsIPersistentProperties2.idl
+++ b/xpcom/ds/nsIPersistentProperties2.idl
@@ -4,16 +4,20 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsIProperties.idl"
 
 interface nsIInputStream;
 interface nsIOutputStream;
 interface nsISimpleEnumerator;
 
+%{C++
+#include "mozilla/MemoryReporting.h"
+%}
+
 [scriptable, uuid(283EE646-1AEF-11D4-98B3-00C04fA0CE9A)]
 interface nsIPropertyElement : nsISupports {
   attribute AUTF8String key;
   attribute AString value;
 };
 
 [scriptable, uuid(706867af-0400-4faa-beb1-0dae87308784)]
 interface nsIPersistentProperties : nsIProperties
@@ -43,21 +47,24 @@ interface nsIPersistentProperties : nsIP
   AString getStringProperty(in AUTF8String key);
 
   /**
    * shortcut to nsIProperty's set() which sets a string value
    * directly (and thus faster). If the given property already exists,
    * then the old value will be returned
    */
   AString setStringProperty(in AUTF8String key, in AString value);
+
+%{C++
+  virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const = 0;
+%}
 };
 
 
 %{C++
 
 #define NS_IPERSISTENTPROPERTIES_CID \
 { 0x2245e573, 0x9464, 0x11d2, \
   { 0x9b, 0x8b, 0x0, 0x80, 0x5f, 0x8a, 0x16, 0xd9 } }
 
 #define NS_PERSISTENTPROPERTIES_CONTRACTID "@mozilla.org/persistent-properties;1"
 
 %}
-
--- a/xpcom/ds/nsPersistentProperties.cpp
+++ b/xpcom/ds/nsPersistentProperties.cpp
@@ -439,16 +439,26 @@ nsPersistentProperties::nsPersistentProp
   , mArena()
 {
 }
 
 nsPersistentProperties::~nsPersistentProperties()
 {
 }
 
+size_t
+nsPersistentProperties::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
+{
+  // The memory used by mTable is accounted for in mArena.
+  size_t n = 0;
+  n += mArena.SizeOfExcludingThis(aMallocSizeOf);
+  n += mTable.ShallowSizeOfExcludingThis(aMallocSizeOf);
+  return aMallocSizeOf(this) + n;
+}
+
 nsresult
 nsPersistentProperties::Create(nsISupports* aOuter, REFNSIID aIID,
                                void** aResult)
 {
   if (aOuter) {
     return NS_ERROR_NO_AGGREGATION;
   }
   RefPtr<nsPersistentProperties> props = new nsPersistentProperties();
--- a/xpcom/ds/nsPersistentProperties.h
+++ b/xpcom/ds/nsPersistentProperties.h
@@ -23,16 +23,18 @@ public:
 
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIPROPERTIES
   NS_DECL_NSIPERSISTENTPROPERTIES
 
   static MOZ_MUST_USE nsresult
   Create(nsISupports* aOuter, REFNSIID aIID, void** aResult);
 
+  size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
+
 private:
   ~nsPersistentProperties();
 
 protected:
   nsCOMPtr<nsIUnicharInputStream> mIn;
 
   PLDHashTable mTable;
   mozilla::ArenaAllocator<2048,4> mArena;