WordLock doesn't need per-thread data
https://bugs.webkit.org/show_bug.cgi?id=185119

Reviewed by Yusuke Suzuki.

The stack is per-thread data, so we can stack-allocate our ThreadData.

This eliminates malloc() and high-level WTF threading primitives from
WordLock, making WordLock more portable to non-WTF code, including
bmalloc.

(NOTE: This patch makes the bug fixed in r231148 100% reproducible.)

* wtf/WordLock.cpp:
(WTF::WordLock::lockSlow): Allocate ThreadData on the stack.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@231151 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WTF/ChangeLog b/Source/WTF/ChangeLog
index 666e6df..3da61f6 100644
--- a/Source/WTF/ChangeLog
+++ b/Source/WTF/ChangeLog
@@ -1,3 +1,21 @@
+2018-04-29  Geoffrey Garen  <ggaren@apple.com>
+
+        WordLock doesn't need per-thread data
+        https://bugs.webkit.org/show_bug.cgi?id=185119
+
+        Reviewed by Yusuke Suzuki.
+
+        The stack is per-thread data, so we can stack-allocate our ThreadData.
+
+        This eliminates malloc() and high-level WTF threading primitives from
+        WordLock, making WordLock more portable to non-WTF code, including
+        bmalloc.
+
+        (NOTE: This patch makes the bug fixed in r231148 100% reproducible.)
+
+        * wtf/WordLock.cpp:
+        (WTF::WordLock::lockSlow): Allocate ThreadData on the stack.
+
 2018-04-28  Geoffrey Garen  <ggaren@apple.com>
 
         Fixed a very unlikely race condition in WTF::WordLock
diff --git a/Source/WTF/wtf/WordLock.cpp b/Source/WTF/wtf/WordLock.cpp
index cfe0905..febb3b6 100644
--- a/Source/WTF/wtf/WordLock.cpp
+++ b/Source/WTF/wtf/WordLock.cpp
@@ -26,9 +26,7 @@
 #include "config.h"
 #include "WordLock.h"
 
-#include "ThreadSpecific.h"
 #include "Threading.h"
-#include "ThreadingPrimitives.h"
 #include <condition_variable>
 #include <mutex>
 #include <thread>
@@ -60,20 +58,6 @@
     ThreadData* queueTail { nullptr };
 };
 
-ThreadSpecific<ThreadData, CanBeGCThread::True>* threadData;
-
-ThreadData* myThreadData()
-{
-    static std::once_flag initializeOnce;
-    std::call_once(
-        initializeOnce,
-        [] {
-            threadData = new ThreadSpecific<ThreadData, CanBeGCThread::True>();
-        });
-
-    return *threadData;
-}
-
 } // anonymous namespace
 
 NEVER_INLINE void WordLock::lockSlow()
@@ -106,12 +90,8 @@
 
         // Need to put ourselves on the queue. Create the queue if one does not exist. This requries
         // owning the queue for a little bit. The lock that controls the queue is itself a spinlock.
-        // But before we acquire the queue spinlock, we make sure that we have a ThreadData for this
-        // thread.
-        ThreadData* me = myThreadData();
-        ASSERT(!me->shouldPark);
-        ASSERT(!me->nextInQueue);
-        ASSERT(!me->queueTail);
+
+        ThreadData me;
 
         // Reload the current word value, since some time may have passed.
         currentWordValue = m_word.load();
@@ -125,15 +105,15 @@
             continue;
         }
         
-        me->shouldPark = true;
+        me.shouldPark = true;
 
         // We own the queue. Nobody can enqueue or dequeue until we're done. Also, it's not possible
         // to release the WordLock while we hold the queue lock.
         ThreadData* queueHead = bitwise_cast<ThreadData*>(currentWordValue & ~queueHeadMask);
         if (queueHead) {
             // Put this thread at the end of the queue.
-            queueHead->queueTail->nextInQueue = me;
-            queueHead->queueTail = me;
+            queueHead->queueTail->nextInQueue = &me;
+            queueHead->queueTail = &me;
 
             // Release the queue lock.
             currentWordValue = m_word.load();
@@ -143,8 +123,8 @@
             m_word.store(currentWordValue & ~isQueueLockedBit);
         } else {
             // Make this thread be the queue-head.
-            queueHead = me;
-            me->queueTail = me;
+            queueHead = &me;
+            me.queueTail = &me;
 
             // Release the queue lock and install ourselves as the head. No need for a CAS loop, since
             // we own the queue lock.
@@ -164,14 +144,14 @@
         // releasing thread holds me's parkingLock.
 
         {
-            std::unique_lock<std::mutex> locker(me->parkingLock);
-            while (me->shouldPark)
-                me->parkingCondition.wait(locker);
+            std::unique_lock<std::mutex> locker(me.parkingLock);
+            while (me.shouldPark)
+                me.parkingCondition.wait(locker);
         }
 
-        ASSERT(!me->shouldPark);
-        ASSERT(!me->nextInQueue);
-        ASSERT(!me->queueTail);
+        ASSERT(!me.shouldPark);
+        ASSERT(!me.nextInQueue);
+        ASSERT(!me.queueTail);
         
         // Now we can loop around and try to acquire the lock again.
     }