Bug 1257019 - Add move construction to js::Mutex<T>. r=terrence
☠☠ backed out by b0e2c28119d8 ☠ ☠
authorNick Fitzgerald <fitzgen@gmail.com>
Thu, 17 Mar 2016 14:53:00 -0400
changeset 289573 1364b664788acdf0c2df71106b1223ded167df51
parent 289572 8c8ed5ea5eaf988f640dfa38470ef37edaaa0ed4
child 289574 a41a84351d7c358b094f508e44edef6fb96fe17c
push id18283
push usercbook@mozilla.com
push dateMon, 21 Mar 2016 15:02:44 +0000
treeherderfx-team@af22a2e633c0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersterrence
bugs1257019
milestone48.0a1
Bug 1257019 - Add move construction to js::Mutex<T>. r=terrence
js/src/jsapi-tests/testThreadingMutex.cpp
js/src/threading/Mutex.h
js/src/threading/posix/Mutex.cpp
js/src/threading/windows/Mutex.cpp
--- a/js/src/jsapi-tests/testThreadingMutex.cpp
+++ b/js/src/jsapi-tests/testThreadingMutex.cpp
@@ -29,8 +29,22 @@ END_TEST(testThreadingLockGuard)
 BEGIN_TEST(testThreadingUnlockGuard)
 {
     js::Mutex mutex;
     js::LockGuard<js::Mutex> guard(mutex);
     js::UnlockGuard<js::Mutex> unguard(guard);
     return true;
 }
 END_TEST(testThreadingUnlockGuard)
+
+BEGIN_TEST(testThreadingMoveMutex)
+{
+    js::Mutex mutex;
+    mutex.lock();
+    mutex.unlock();
+
+    js::Mutex another(mozilla::Move(mutex));
+    another.lock();
+    another.unlock();
+
+    return true;
+}
+END_TEST(testThreadingMoveMutex)
--- a/js/src/threading/Mutex.h
+++ b/js/src/threading/Mutex.h
@@ -2,50 +2,56 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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/. */
 
 #ifndef threading_Mutex_h
 #define threading_Mutex_h
 
+#include <new>
+#include <string.h>
+
+#include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/Move.h"
 
 namespace js {
 
 class Mutex
 {
 public:
   struct PlatformData;
 
   Mutex();
   ~Mutex();
 
   void lock();
   void unlock();
 
+  Mutex(Mutex&& rhs)
+    : platformData_(rhs.platformData_)
+  {
+    MOZ_ASSERT(this != &rhs, "self move disallowed!");
+    rhs.platformData_ = nullptr;
+  }
+
+  Mutex& operator=(Mutex&& rhs) {
+    this->~Mutex();
+    new (this) Mutex(mozilla::Move(rhs));
+    return *this;
+  }
+
 private:
   Mutex(const Mutex&) = delete;
   void operator=(const Mutex&) = delete;
-  Mutex(Mutex&&) = delete;
-  void operator=(Mutex&&) = delete;
-
-  PlatformData* platformData();
 
-// Linux and maybe other platforms define the storage size of pthread_mutex_t in
-// bytes. However, we must define it as an array of void pointers to ensure
-// proper alignment.
-#if defined(__APPLE__) && defined(__MACH__) && defined(__i386__)
-  void* platformData_[11];
-#elif defined(__APPLE__) && defined(__MACH__) && defined(__amd64__)
-  void* platformData_[8];
-#elif defined(__linux__)
-  void* platformData_[40 / sizeof(void*)];
-#elif defined(_WIN32)
-  void* platformData_[6];
-#else
-  void* platformData_[64 / sizeof(void*)];
-#endif
+  PlatformData* platformData() {
+    MOZ_ASSERT(platformData_);
+    return platformData_;
+  };
+
+  PlatformData* platformData_;
 };
 
 } // namespace js
 
 #endif // threading_Mutex_h
--- a/js/src/threading/posix/Mutex.cpp
+++ b/js/src/threading/posix/Mutex.cpp
@@ -1,46 +1,47 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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 "mozilla/Assertions.h"
+#include <pthread.h>
 
-#include <pthread.h>
+#include "js/Utility.h"
 
 #include "threading/Mutex.h"
 #include "threading/posix/MutexPlatformData.h"
 
 js::Mutex::Mutex()
 {
+  AutoEnterOOMUnsafeRegion oom;
+  platformData_ = js_new<PlatformData>();
+  if (!platformData_)
+    oom.crash("js::Mutex::Mutex");
+
   int r = pthread_mutex_init(&platformData()->ptMutex, NULL);
   MOZ_RELEASE_ASSERT(r == 0);
 }
 
 js::Mutex::~Mutex()
 {
+  if (!platformData_)
+    return;
+
   int r = pthread_mutex_destroy(&platformData()->ptMutex);
   MOZ_RELEASE_ASSERT(r == 0);
+  js_delete(platformData());
 }
 
 void
 js::Mutex::lock()
 {
   int r = pthread_mutex_lock(&platformData()->ptMutex);
   MOZ_RELEASE_ASSERT(r == 0);
 }
 
 void
 js::Mutex::unlock()
 {
   int r = pthread_mutex_unlock(&platformData()->ptMutex);
   MOZ_RELEASE_ASSERT(r == 0);
 }
-
-js::Mutex::PlatformData*
-js::Mutex::platformData()
-{
-  static_assert(sizeof(platformData_) >= sizeof(PlatformData),
-                "platformData_ is too small");
-  return reinterpret_cast<PlatformData*>(platformData_);
-}
--- a/js/src/threading/windows/Mutex.cpp
+++ b/js/src/threading/windows/Mutex.cpp
@@ -1,19 +1,20 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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 "mozilla/Assertions.h"
 #include "mozilla/DebugOnly.h"
 
 #include "jswin.h"
 
+#include "js/Utility.h"
+
 #include "threading/Mutex.h"
 #include "threading/windows/MutexPlatformData.h"
 
 namespace {
 
 // We build with a toolkit that supports WinXP, so we have to probe
 // for modern features at runtime. This is necessary because Vista and
 // later automatically allocate and subsequently leak a debug info
@@ -38,46 +39,47 @@ struct MutexNativeImports
 };
 
 static MutexNativeImports NativeImports;
 
 } // (anonymous namespace)
 
 js::Mutex::Mutex()
 {
+  AutoEnterOOMUnsafeRegion oom;
+  platformData_ = js_new<PlatformData>();
+  if (!platformData_)
+    oom.crash("js::Mutex::Mutex");
+
   // This number was adopted from NSPR.
   const static DWORD LockSpinCount = 1500;
   BOOL r;
   if (NativeImports.hasInitializeCriticalSectionEx()) {
     r = NativeImports.InitializeCriticalSectionEx(&platformData()->criticalSection,
                                                   LockSpinCount,
                                                   CRITICAL_SECTION_NO_DEBUG_INFO);
   } else {
     r = InitializeCriticalSectionAndSpinCount(&platformData()->criticalSection,
                                               LockSpinCount);
   }
   MOZ_RELEASE_ASSERT(r);
 }
 
 js::Mutex::~Mutex()
 {
+  if (!platformData_)
+    return;
+
   DeleteCriticalSection(&platformData()->criticalSection);
+  js_delete(platformData());
 }
 
 void
 js::Mutex::lock()
 {
   EnterCriticalSection(&platformData()->criticalSection);
 }
 
 void
 js::Mutex::unlock()
 {
   LeaveCriticalSection(&platformData()->criticalSection);
 }
-
-js::Mutex::PlatformData*
-js::Mutex::platformData()
-{
-  static_assert(sizeof(platformData_) >= sizeof(PlatformData),
-                "platformData_ is too small");
-  return reinterpret_cast<PlatformData*>(platformData_);
-}