Bug 1460838 - Avoid static initializers in mozjemalloc with MSVC. r=njn
authorMike Hommey <mh+mozilla@glandium.org>
Thu, 24 May 2018 11:23:10 +0900
changeset 419627 b1f8ccb26696d4f347e1ea5fd41576564fe2ab9b
parent 419626 037424ee08ef146c214a9d2d873bc90137cc1309
child 419628 3025063ca800a38bf0f3b30e577806f67cf3dbe8
push id34040
push userebalazs@mozilla.com
push dateThu, 24 May 2018 09:37:05 +0000
treeherdermozilla-central@c411ccb6bb4a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnjn
bugs1460838
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 1460838 - Avoid static initializers in mozjemalloc with MSVC. r=njn
memory/build/Mutex.h
memory/build/mozjemalloc.cpp
--- a/memory/build/Mutex.h
+++ b/memory/build/Mutex.h
@@ -88,40 +88,36 @@ struct Mutex
 // initialization, which SRWLock provides.
 // Ideally, we'd use the same type of locks everywhere, but SRWLocks
 // everywhere incur a performance penalty. See bug 1418389.
 #if defined(XP_WIN)
 struct StaticMutex
 {
   SRWLOCK mMutex;
 
-  constexpr StaticMutex()
-    : mMutex(SRWLOCK_INIT)
-  {
-  }
-
   inline void Lock() { AcquireSRWLockExclusive(&mMutex); }
 
   inline void Unlock() { ReleaseSRWLockExclusive(&mMutex); }
 };
+
+// Normally, we'd use a constexpr constructor, but MSVC likes to create
+// static initializers anyways.
+#define STATIC_MUTEX_INIT SRWLOCK_INIT
+
 #else
-struct StaticMutex : public Mutex
-{
+typedef Mutex StaticMutex;
+
 #if defined(XP_DARWIN)
 #define STATIC_MUTEX_INIT OS_SPINLOCK_INIT
 #elif defined(XP_LINUX) && !defined(ANDROID)
 #define STATIC_MUTEX_INIT PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
 #else
 #define STATIC_MUTEX_INIT PTHREAD_MUTEX_INITIALIZER
 #endif
-  constexpr StaticMutex()
-    : Mutex{ STATIC_MUTEX_INIT }
-  {
-  }
-};
+
 #endif
 
 template<typename T>
 struct MOZ_RAII AutoLock
 {
   explicit AutoLock(T& aMutex MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
     : mMutex(aMutex)
   {
--- a/memory/build/mozjemalloc.cpp
+++ b/memory/build/mozjemalloc.cpp
@@ -533,19 +533,30 @@ static size_t opt_dirty_max = DIRTY_MAX_
 #if defined(MALLOC_DECOMMIT) && defined(MALLOC_DOUBLE_PURGE)
 #error MALLOC_DECOMMIT and MALLOC_DOUBLE_PURGE are mutually exclusive.
 #endif
 
 static void*
 base_alloc(size_t aSize);
 
 // Set to true once the allocator has been initialized.
-static Atomic<bool> malloc_initialized(false);
-
-static StaticMutex gInitLock;
+#if defined(_MSC_VER) && !defined(__clang__)
+// MSVC may create a static initializer for an Atomic<bool>, which may actually
+// run after `malloc_init` has been called once, which triggers multiple
+// initializations.
+// We work around the problem by not using an Atomic<bool> at all. There is a
+// theoretical problem with using `malloc_initialized` non-atomically, but
+// practically, this is only true if `malloc_init` is never called before
+// threads are created.
+static bool malloc_initialized;
+#else
+static Atomic<bool> malloc_initialized;
+#endif
+
+static StaticMutex gInitLock = { STATIC_MUTEX_INIT };
 
 // ***************************************************************************
 // Statistics data structures.
 
 struct arena_stats_t
 {
   // Number of bytes currently mapped.
   size_t mapped;