Bug 1454594 - Avoid running unordered_map static initializers. r?botond draft
authorKartikaya Gupta <kgupta@mozilla.com>
Wed, 18 Apr 2018 17:32:38 -0400
changeset 785029 d63786f44703fb8797a31078156207a6a9982143
parent 784524 0e45c13b34e815cb42a9f08bb44142d1a81e186e
push id107098
push userkgupta@mozilla.com
push dateThu, 19 Apr 2018 12:52:47 +0000
reviewersbotond
bugs1454594
milestone61.0a1
Bug 1454594 - Avoid running unordered_map static initializers. r?botond We wrap the std::unordered_map in a StaticAutoPtr so that there's no initialization cost, and also so that we have a smaller memory footprint in processes that aren't using WebRender+APZ. MozReview-Commit-ID: 9QCKiv0IzB8
gfx/layers/apz/public/APZSampler.h
gfx/layers/apz/public/APZUpdater.h
gfx/layers/apz/src/APZSampler.cpp
gfx/layers/apz/src/APZUpdater.cpp
--- a/gfx/layers/apz/public/APZSampler.h
+++ b/gfx/layers/apz/public/APZSampler.h
@@ -7,16 +7,17 @@
 #ifndef mozilla_layers_APZSampler_h
 #define mozilla_layers_APZSampler_h
 
 #include <unordered_map>
 
 #include "base/platform_thread.h" // for PlatformThreadId
 #include "mozilla/layers/AsyncCompositionManager.h" // for AsyncTransform
 #include "mozilla/StaticMutex.h"
+#include "mozilla/StaticPtr.h"
 #include "nsTArray.h"
 #include "Units.h"
 
 namespace mozilla {
 
 class TimeStamp;
 
 namespace wr {
@@ -105,19 +106,22 @@ protected:
   bool UsingWebRenderSamplerThread() const;
   static already_AddRefed<APZSampler> GetSampler(const wr::WrWindowId& aWindowId);
 
 private:
   RefPtr<APZCTreeManager> mApz;
 
   // Used to manage the mapping from a WR window id to APZSampler. These are only
   // used if WebRender is enabled. Both sWindowIdMap and mWindowId should only
-  // be used while holding the sWindowIdLock.
+  // be used while holding the sWindowIdLock. Note that we use a StaticAutoPtr
+  // wrapper on sWindowIdMap to avoid a static initializer for the unordered_map.
+  // This also avoids the initializer/memory allocation in cases where we're
+  // not using WebRender.
   static StaticMutex sWindowIdLock;
-  static std::unordered_map<uint64_t, APZSampler*> sWindowIdMap;
+  static StaticAutoPtr<std::unordered_map<uint64_t, APZSampler*>> sWindowIdMap;
   Maybe<wr::WrWindowId> mWindowId;
 
   // If WebRender is enabled, this holds the thread id of the render backend
   // thread (which is the sampler thread) for the compositor associated with
   // this APZSampler instance.
   // This is written to once during init and never cleared, and so reading it
   // from multiple threads during normal operation (after initialization)
   // without locking should be fine.
--- a/gfx/layers/apz/public/APZUpdater.h
+++ b/gfx/layers/apz/public/APZUpdater.h
@@ -10,16 +10,17 @@
 #include <deque>
 #include <unordered_map>
 
 #include "base/platform_thread.h"   // for PlatformThreadId
 #include "LayersTypes.h"
 #include "mozilla/layers/APZTestData.h"
 #include "mozilla/layers/WebRenderScrollData.h"
 #include "mozilla/StaticMutex.h"
+#include "mozilla/StaticPtr.h"
 #include "mozilla/webrender/WebRenderTypes.h"
 #include "nsThreadUtils.h"
 #include "Units.h"
 
 namespace mozilla {
 
 namespace wr {
 struct WrWindowId;
@@ -179,19 +180,22 @@ private:
   // Map from layers id to epoch state.
   // This data structure can only be touched on the updater thread.
   std::unordered_map<LayersId,
                      EpochState,
                      LayersId::HashFn> mEpochData;
 
   // Used to manage the mapping from a WR window id to APZUpdater. These are only
   // used if WebRender is enabled. Both sWindowIdMap and mWindowId should only
-  // be used while holding the sWindowIdLock.
+  // be used while holding the sWindowIdLock. Note that we use a StaticAutoPtr
+  // wrapper on sWindowIdMap to avoid a static initializer for the unordered_map.
+  // This also avoids the initializer/memory allocation in cases where we're
+  // not using WebRender.
   static StaticMutex sWindowIdLock;
-  static std::unordered_map<uint64_t, APZUpdater*> sWindowIdMap;
+  static StaticAutoPtr<std::unordered_map<uint64_t, APZUpdater*>> sWindowIdMap;
   Maybe<wr::WrWindowId> mWindowId;
 
   // If WebRender and async scene building are enabled, this holds the thread id
   // of the scene builder thread (which is the updater thread) for the
   // compositor associated with this APZUpdater instance. It may be populated
   // even if async scene building is not enabled, but in that case we don't
   // care about the contents.
   // This is written to once during init and never cleared, and so reading it
--- a/gfx/layers/apz/src/APZSampler.cpp
+++ b/gfx/layers/apz/src/APZSampler.cpp
@@ -14,17 +14,17 @@
 #include "mozilla/layers/SynchronousTask.h"
 #include "TreeTraversal.h"
 #include "mozilla/webrender/WebRenderAPI.h"
 
 namespace mozilla {
 namespace layers {
 
 StaticMutex APZSampler::sWindowIdLock;
-std::unordered_map<uint64_t, APZSampler*> APZSampler::sWindowIdMap;
+StaticAutoPtr<std::unordered_map<uint64_t, APZSampler*>> APZSampler::sWindowIdMap;
 
 
 APZSampler::APZSampler(const RefPtr<APZCTreeManager>& aApz)
   : mApz(aApz)
 #ifdef DEBUG
   , mSamplerThreadQueried(false)
 #endif
   , mSampleTimeLock("APZSampler::mSampleTimeLock")
@@ -34,27 +34,31 @@ APZSampler::APZSampler(const RefPtr<APZC
 }
 
 APZSampler::~APZSampler()
 {
   mApz->SetSampler(nullptr);
 
   StaticMutexAutoLock lock(sWindowIdLock);
   if (mWindowId) {
-    sWindowIdMap.erase(wr::AsUint64(*mWindowId));
+    MOZ_ASSERT(sWindowIdMap);
+    sWindowIdMap->erase(wr::AsUint64(*mWindowId));
   }
 }
 
 void
 APZSampler::SetWebRenderWindowId(const wr::WindowId& aWindowId)
 {
   StaticMutexAutoLock lock(sWindowIdLock);
   MOZ_ASSERT(!mWindowId);
   mWindowId = Some(aWindowId);
-  sWindowIdMap[wr::AsUint64(aWindowId)] = this;
+  if (!sWindowIdMap) {
+    sWindowIdMap = new std::unordered_map<uint64_t, APZSampler*>();
+  }
+  (*sWindowIdMap)[wr::AsUint64(aWindowId)] = this;
 }
 
 /*static*/ void
 APZSampler::SetSamplerThread(const wr::WrWindowId& aWindowId)
 {
   if (RefPtr<APZSampler> sampler = GetSampler(aWindowId)) {
     // Ensure nobody tried to use the updater thread before this point.
     MOZ_ASSERT(!sampler->mSamplerThreadQueried);
@@ -237,19 +241,21 @@ APZSampler::UsingWebRenderSamplerThread(
   return mSamplerThreadId.isSome();
 }
 
 /*static*/ already_AddRefed<APZSampler>
 APZSampler::GetSampler(const wr::WrWindowId& aWindowId)
 {
   RefPtr<APZSampler> sampler;
   StaticMutexAutoLock lock(sWindowIdLock);
-  auto it = sWindowIdMap.find(wr::AsUint64(aWindowId));
-  if (it != sWindowIdMap.end()) {
-    sampler = it->second;
+  if (sWindowIdMap) {
+    auto it = sWindowIdMap->find(wr::AsUint64(aWindowId));
+    if (it != sWindowIdMap->end()) {
+      sampler = it->second;
+    }
   }
   return sampler.forget();
 }
 
 } // namespace layers
 } // namespace mozilla
 
 void
--- a/gfx/layers/apz/src/APZUpdater.cpp
+++ b/gfx/layers/apz/src/APZUpdater.cpp
@@ -14,17 +14,17 @@
 #include "mozilla/layers/SynchronousTask.h"
 #include "mozilla/layers/WebRenderScrollDataWrapper.h"
 #include "mozilla/webrender/WebRenderAPI.h"
 
 namespace mozilla {
 namespace layers {
 
 StaticMutex APZUpdater::sWindowIdLock;
-std::unordered_map<uint64_t, APZUpdater*> APZUpdater::sWindowIdMap;
+StaticAutoPtr<std::unordered_map<uint64_t, APZUpdater*>> APZUpdater::sWindowIdMap;
 
 
 APZUpdater::APZUpdater(const RefPtr<APZCTreeManager>& aApz)
   : mApz(aApz)
 #ifdef DEBUG
   , mUpdaterThreadQueried(false)
 #endif
   , mQueueLock("APZUpdater::QueueLock")
@@ -34,34 +34,38 @@ APZUpdater::APZUpdater(const RefPtr<APZC
 }
 
 APZUpdater::~APZUpdater()
 {
   mApz->SetUpdater(nullptr);
 
   StaticMutexAutoLock lock(sWindowIdLock);
   if (mWindowId) {
+    MOZ_ASSERT(sWindowIdMap);
     // Ensure that ClearTree was called and the task got run
-    MOZ_ASSERT(sWindowIdMap.find(wr::AsUint64(*mWindowId)) == sWindowIdMap.end());
+    MOZ_ASSERT(sWindowIdMap->find(wr::AsUint64(*mWindowId)) == sWindowIdMap->end());
   }
 }
 
 bool
 APZUpdater::HasTreeManager(const RefPtr<APZCTreeManager>& aApz)
 {
   return aApz.get() == mApz.get();
 }
 
 void
 APZUpdater::SetWebRenderWindowId(const wr::WindowId& aWindowId)
 {
   StaticMutexAutoLock lock(sWindowIdLock);
   MOZ_ASSERT(!mWindowId);
   mWindowId = Some(aWindowId);
-  sWindowIdMap[wr::AsUint64(aWindowId)] = this;
+  if (!sWindowIdMap) {
+    sWindowIdMap = new std::unordered_map<uint64_t, APZUpdater*>();
+  }
+  (*sWindowIdMap)[wr::AsUint64(aWindowId)] = this;
 }
 
 /*static*/ void
 APZUpdater::SetUpdaterThread(const wr::WrWindowId& aWindowId)
 {
   if (RefPtr<APZUpdater> updater = GetUpdater(aWindowId)) {
     // Ensure nobody tried to use the updater thread before this point.
     MOZ_ASSERT(!updater->mUpdaterThreadQueried);
@@ -142,17 +146,18 @@ APZUpdater::ClearTree(LayersId aRootLaye
       self->mApz->ClearTree();
 
       // Once ClearTree is called on the APZCTreeManager, we are in a shutdown
       // phase. After this point it's ok if WebRender cannot get a hold of the
       // updater via the window id, and it's a good point to remove the mapping
       // and avoid leaving a dangling pointer to this object.
       StaticMutexAutoLock lock(sWindowIdLock);
       if (self->mWindowId) {
-        sWindowIdMap.erase(wr::AsUint64(*(self->mWindowId)));
+        MOZ_ASSERT(sWindowIdMap);
+        sWindowIdMap->erase(wr::AsUint64(*(self->mWindowId)));
       }
     }
   ));
 }
 
 void
 APZUpdater::UpdateFocusState(LayersId aRootLayerTreeId,
                              LayersId aOriginatingLayersId,
@@ -411,19 +416,21 @@ APZUpdater::UsingWebRenderUpdaterThread(
   return mUpdaterThreadId.isSome();
 }
 
 /*static*/ already_AddRefed<APZUpdater>
 APZUpdater::GetUpdater(const wr::WrWindowId& aWindowId)
 {
   RefPtr<APZUpdater> updater;
   StaticMutexAutoLock lock(sWindowIdLock);
-  auto it = sWindowIdMap.find(wr::AsUint64(aWindowId));
-  if (it != sWindowIdMap.end()) {
-    updater = it->second;
+  if (sWindowIdMap) {
+    auto it = sWindowIdMap->find(wr::AsUint64(aWindowId));
+    if (it != sWindowIdMap->end()) {
+      updater = it->second;
+    }
   }
   return updater.forget();
 }
 
 void
 APZUpdater::ProcessQueue()
 {
   { // scope lock to check for emptiness