[iOS] Upstream JSLock changes
authordbates@webkit.org <dbates@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 22 Oct 2013 20:40:34 +0000 (20:40 +0000)
committerdbates@webkit.org <dbates@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 22 Oct 2013 20:40:34 +0000 (20:40 +0000)
https://bugs.webkit.org/show_bug.cgi?id=123107

Reviewed by Geoffrey Garen.

* runtime/JSLock.cpp:
(JSC::JSLock::unlock):
(JSC::JSLock::dropAllLocks): Modified to take a SpinLock, used only on iOS.
(JSC::JSLock::dropAllLocksUnconditionally): Modified to take a SpinLock, used only on iOS. Also
use pre-increment instead of post-increment when we're not using the return value of the instruction.
(JSC::JSLock::grabAllLocks): Modified to take a SpinLock, used only on iOS. Also change
places where we were using post-increment/post-decrement to use pre-increment/pre-decrement,
since we don't use the return value of such instructions.
(JSC::JSLock::DropAllLocks::DropAllLocks): Modified to support releasing all locks unconditionally.
Take a spin lock before releasing all locks on iOS. Also, use nullptr instead of 0.
(JSC::JSLock::DropAllLocks::~DropAllLocks): Take a spin lock before acquiring all locks on iOS.
* runtime/JSLock.h: Remove extraneous argument name "exec" from DropAllLocks as the data type of
the argument is sufficiently descriptive of its purpose.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@157809 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/runtime/JSLock.cpp
Source/JavaScriptCore/runtime/JSLock.h

index d29a832..f29c7f7 100644 (file)
@@ -1,3 +1,24 @@
+2013-10-22  Daniel Bates  <dabates@apple.com>
+
+        [iOS] Upstream JSLock changes
+        https://bugs.webkit.org/show_bug.cgi?id=123107
+
+        Reviewed by Geoffrey Garen.
+
+        * runtime/JSLock.cpp:
+        (JSC::JSLock::unlock):
+        (JSC::JSLock::dropAllLocks): Modified to take a SpinLock, used only on iOS.
+        (JSC::JSLock::dropAllLocksUnconditionally): Modified to take a SpinLock, used only on iOS. Also
+        use pre-increment instead of post-increment when we're not using the return value of the instruction.
+        (JSC::JSLock::grabAllLocks): Modified to take a SpinLock, used only on iOS. Also change
+        places where we were using post-increment/post-decrement to use pre-increment/pre-decrement,
+        since we don't use the return value of such instructions.
+        (JSC::JSLock::DropAllLocks::DropAllLocks): Modified to support releasing all locks unconditionally.
+        Take a spin lock before releasing all locks on iOS. Also, use nullptr instead of 0.
+        (JSC::JSLock::DropAllLocks::~DropAllLocks): Take a spin lock before acquiring all locks on iOS.
+        * runtime/JSLock.h: Remove extraneous argument name "exec" from DropAllLocks as the data type of
+        the argument is sufficiently descriptive of its purpose.
+
 2013-10-22  Julien Brianceau  <jbriance@cisco.com>
 
         [arm] Add missing setupArgumentsWithExecState() prototypes to fix build.
index ef0204a..7604075 100644 (file)
@@ -126,9 +126,9 @@ void JSLock::lock()
 
 void JSLock::unlock()
 {
+    SpinLockHolder holder(&m_spinLock);
     ASSERT(currentThreadIsHoldingLock());
 
-    SpinLockHolder holder(&m_spinLock);
     m_lockCount--;
 
     if (!m_lockCount)
@@ -192,51 +192,135 @@ bool JSLock::currentThreadIsHoldingLock()
 //
 
 // This function returns the number of locks that were dropped.
-unsigned JSLock::dropAllLocks()
+unsigned JSLock::dropAllLocks(SpinLock& spinLock)
 {
+#if PLATFORM(IOS)
+    ASSERT_UNUSED(spinLock, spinLock.IsHeld());
+    // Check if this thread is currently holding the lock.
+    // FIXME: Maybe we want to require this, guard with an ASSERT?
+    unsigned lockCount = m_lockCount;
+    if (!lockCount || m_ownerThread != WTF::currentThread())
+        return 0;
+
+    // Don't drop the locks if they've already been dropped once.
+    // (If the prior drop came from another thread, and it resumed first,
+    // it could trash our register file).
+    if (m_lockDropDepth)
+        return 0;
+
+    // m_lockDropDepth is only incremented if any locks were dropped.
+    ++m_lockDropDepth;
+    m_lockCount = 0;
+    m_lock.unlock();
+    return lockCount;
+#else
     if (m_lockDropDepth++)
         return 0;
 
-    return dropAllLocksUnconditionally();
+    return dropAllLocksUnconditionally(spinLock);
+#endif
 }
 
-unsigned JSLock::dropAllLocksUnconditionally()
+unsigned JSLock::dropAllLocksUnconditionally(SpinLock& spinLock)
 {
+#if PLATFORM(IOS)
+    ASSERT_UNUSED(spinLock, spinLock.IsHeld());
+    // Check if this thread is currently holding the lock.
+    // FIXME: Maybe we want to require this, guard with an ASSERT?
     unsigned lockCount = m_lockCount;
-    for (unsigned i = 0; i < lockCount; i++)
+    if (!lockCount || m_ownerThread != WTF::currentThread())
+        return 0;
+
+    // m_lockDropDepth is only incremented if any locks were dropped.
+    ++m_lockDropDepth;
+    m_lockCount = 0;
+    m_lock.unlock();
+    return lockCount;
+#else
+    UNUSED_PARAM(spinLock);
+    unsigned lockCount = m_lockCount;
+    for (unsigned i = 0; i < lockCount; ++i)
         unlock();
 
     return lockCount;
+#endif
 }
 
-void JSLock::grabAllLocks(unsigned lockCount)
+void JSLock::grabAllLocks(unsigned lockCount, SpinLock& spinLock)
 {
-    for (unsigned i = 0; i < lockCount; i++)
+#if PLATFORM(IOS)
+    ASSERT(spinLock.IsHeld());
+    // If no locks were dropped, nothing to do!
+    if (!lockCount)
+        return;
+
+    ThreadIdentifier currentThread = WTF::currentThread();
+    // Check if this thread is currently holding the lock.
+    // FIXME: Maybe we want to prohibit this, guard against with an ASSERT?
+    if (m_ownerThread == currentThread && m_lockCount) {
+        m_lockCount += lockCount;
+        --m_lockDropDepth;
+        return;
+    }
+
+    spinLock.Unlock();
+    m_lock.lock();
+    spinLock.Lock();
+
+    m_ownerThread = currentThread;
+    ASSERT(!m_lockCount);
+    m_lockCount = lockCount;
+    --m_lockDropDepth;
+#else
+    UNUSED_PARAM(spinLock);
+    for (unsigned i = 0; i < lockCount; ++i)
         lock();
 
-    m_lockDropDepth--;
+    --m_lockDropDepth;
+#endif
 }
 
-JSLock::DropAllLocks::DropAllLocks(ExecState* exec)
+JSLock::DropAllLocks::DropAllLocks(ExecState* exec, AlwaysDropLocksTag alwaysDropLocks)
     : m_lockCount(0)
-    , m_vm(exec ? &exec->vm() : 0)
+    , m_vm(exec ? &exec->vm() : nullptr)
 {
-    if (m_vm)
-        m_lockCount = m_vm->apiLock().dropAllLocks();
+    if (!m_vm)
+        return;
+    SpinLock& spinLock = m_vm->apiLock().m_spinLock;
+#if PLATFORM(IOS)
+    SpinLockHolder holder(&spinLock);
+#endif
+    if (alwaysDropLocks)
+        m_lockCount = m_vm->apiLock().dropAllLocksUnconditionally(spinLock);
+    else
+        m_lockCount = m_vm->apiLock().dropAllLocks(spinLock);
 }
 
-JSLock::DropAllLocks::DropAllLocks(VM* vm)
+JSLock::DropAllLocks::DropAllLocks(VM* vm, AlwaysDropLocksTag alwaysDropLocks)
     : m_lockCount(0)
     , m_vm(vm)
 {
-    if (m_vm)
-        m_lockCount = m_vm->apiLock().dropAllLocks();
+    if (!m_vm)
+        return;
+    SpinLock& spinLock = m_vm->apiLock().m_spinLock;
+#if PLATFORM(IOS)
+    SpinLockHolder holder(&spinLock);
+#endif
+    if (alwaysDropLocks)
+        m_lockCount = m_vm->apiLock().dropAllLocksUnconditionally(spinLock);
+    else
+        m_lockCount = m_vm->apiLock().dropAllLocks(spinLock);
 }
 
 JSLock::DropAllLocks::~DropAllLocks()
 {
-    if (m_vm)
-        m_vm->apiLock().grabAllLocks(m_lockCount);
+    if (!m_vm)
+        return;
+    SpinLock& spinLock = m_vm->apiLock().m_spinLock;
+#if PLATFORM(IOS)
+    SpinLockHolder holder(&spinLock);
+#endif
+    m_vm->apiLock().grabAllLocks(m_lockCount, spinLock);
 }
 
 } // namespace JSC
index 83bcc24..3002add 100644 (file)
@@ -95,17 +95,20 @@ namespace JSC {
 
         JS_EXPORT_PRIVATE bool currentThreadIsHoldingLock();
 
-        unsigned dropAllLocks();
-        unsigned dropAllLocksUnconditionally();
-        void grabAllLocks(unsigned lockCount);
+        unsigned dropAllLocks(SpinLock&);
+        unsigned dropAllLocksUnconditionally(SpinLock&);
+        void grabAllLocks(unsigned lockCount, SpinLock&);
 
         void willDestroyVM(VM*);
 
         class DropAllLocks {
             WTF_MAKE_NONCOPYABLE(DropAllLocks);
         public:
-            JS_EXPORT_PRIVATE DropAllLocks(ExecState* exec);
-            JS_EXPORT_PRIVATE DropAllLocks(VM*);
+            // By default, we release all locks conditionally. Some clients, such as Mobile Safari,
+            // may require that we release all locks unconditionally.
+            enum AlwaysDropLocksTag { DontAlwaysDropLocks = 0, AlwaysDropLocks };
+            JS_EXPORT_PRIVATE DropAllLocks(ExecState*, AlwaysDropLocksTag = DontAlwaysDropLocks);
+            JS_EXPORT_PRIVATE DropAllLocks(VM*, AlwaysDropLocksTag = DontAlwaysDropLocks);
             JS_EXPORT_PRIVATE ~DropAllLocks();
             
         private: