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
--- 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