]>
git.saurik.com Git - apple/javascriptcore.git/blob - runtime/JSLock.cpp
   2  * Copyright (C) 2005, 2008, 2012, 2014 Apple Inc. All rights reserved. 
   4  * This library is free software; you can redistribute it and/or 
   5  * modify it under the terms of the GNU Library General Public 
   6  * License as published by the Free Software Foundation; either 
   7  * version 2 of the License, or (at your option) any later version. 
   9  * This library is distributed in the hope that it will be useful, 
  10  * but WITHOUT ANY WARRANTY; without even the implied warranty of 
  11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the NU 
  12  * Library General Public License for more details. 
  14  * You should have received a copy of the GNU Library General Public License 
  15  * along with this library; see the file COPYING.LIB.  If not, write to 
  16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 
  17  * Boston, MA 02110-1301, USA  
  25 #include "CallFrame.h" 
  26 #include "JSGlobalObject.h" 
  28 #include "JSCInlines.h" 
  33 std::mutex
* GlobalJSLock::s_sharedInstanceMutex
; 
  35 GlobalJSLock::GlobalJSLock() 
  37     s_sharedInstanceMutex
->lock(); 
  40 GlobalJSLock::~GlobalJSLock() 
  42     s_sharedInstanceMutex
->unlock(); 
  45 void GlobalJSLock::initialize() 
  47     s_sharedInstanceMutex 
= new std::mutex(); 
  50 JSLockHolder::JSLockHolder(ExecState
* exec
) 
  56 JSLockHolder::JSLockHolder(VM
* vm
) 
  62 JSLockHolder::JSLockHolder(VM
& vm
) 
  68 void JSLockHolder::init() 
  70     m_vm
->apiLock().lock(); 
  73 JSLockHolder::~JSLockHolder() 
  75     RefPtr
<JSLock
> apiLock(&m_vm
->apiLock()); 
  80 JSLock::JSLock(VM
* vm
) 
  81     : m_ownerThreadID(std::thread::id()) 
  84     , m_hasExclusiveThread(false) 
  86     , m_entryAtomicStringTable(nullptr) 
  94 void JSLock::willDestroyVM(VM
* vm
) 
  96     ASSERT_UNUSED(vm
, m_vm 
== vm
); 
 100 void JSLock::setExclusiveThread(std::thread::id threadId
) 
 102     RELEASE_ASSERT(!m_lockCount 
&& m_ownerThreadID 
== std::thread::id()); 
 103     m_hasExclusiveThread 
= (threadId 
!= std::thread::id()); 
 104     m_ownerThreadID 
= threadId
; 
 112 void JSLock::lock(intptr_t lockCount
) 
 114     ASSERT(lockCount 
> 0); 
 115     if (currentThreadIsHoldingLock()) { 
 116         m_lockCount 
+= lockCount
; 
 120     if (!m_hasExclusiveThread
) { 
 122         m_ownerThreadID 
= std::this_thread::get_id(); 
 124     ASSERT(!m_lockCount
); 
 125     m_lockCount 
= lockCount
; 
 130 void JSLock::didAcquireLock() 
 132     // FIXME: What should happen to the per-thread identifier table if we don't have a VM? 
 136     RELEASE_ASSERT(!m_vm
->stackPointerAtVMEntry()); 
 137     void* p 
= &p
; // A proxy for the current stack pointer. 
 138     m_vm
->setStackPointerAtVMEntry(p
); 
 140     WTFThreadData
& threadData 
= wtfThreadData(); 
 141     m_vm
->setLastStackTop(threadData
.savedLastStackTop()); 
 143     ASSERT(!m_entryAtomicStringTable
); 
 144     m_entryAtomicStringTable 
= threadData
.setCurrentAtomicStringTable(m_vm
->atomicStringTable()); 
 145     ASSERT(m_entryAtomicStringTable
); 
 147     m_vm
->heap
.machineThreads().addCurrentThread(); 
 150 void JSLock::unlock() 
 155 void JSLock::unlock(intptr_t unlockCount
) 
 157     RELEASE_ASSERT(currentThreadIsHoldingLock()); 
 158     ASSERT(m_lockCount 
>= unlockCount
); 
 160     // Maintain m_lockCount while calling willReleaseLock() so that its callees know that 
 161     // they still have the lock. 
 162     if (unlockCount 
== m_lockCount
) 
 165     m_lockCount 
-= unlockCount
; 
 169         if (!m_hasExclusiveThread
) { 
 170             m_ownerThreadID 
= std::thread::id(); 
 176 void JSLock::willReleaseLock() 
 179         m_vm
->heap
.releaseDelayedReleasedObjects(); 
 180         m_vm
->setStackPointerAtVMEntry(nullptr); 
 183     if (m_entryAtomicStringTable
) { 
 184         wtfThreadData().setCurrentAtomicStringTable(m_entryAtomicStringTable
); 
 185         m_entryAtomicStringTable 
= nullptr; 
 189 void JSLock::lock(ExecState
* exec
) 
 191     exec
->vm().apiLock().lock(); 
 194 void JSLock::unlock(ExecState
* exec
) 
 196     exec
->vm().apiLock().unlock(); 
 199 bool JSLock::currentThreadIsHoldingLock() 
 201     ASSERT(!m_hasExclusiveThread 
|| (exclusiveThread() == std::this_thread::get_id())); 
 202     if (m_hasExclusiveThread
) 
 203         return !!m_lockCount
; 
 204     return m_ownerThreadID 
== std::this_thread::get_id(); 
 207 // This function returns the number of locks that were dropped. 
 208 unsigned JSLock::dropAllLocks(DropAllLocks
* dropper
) 
 210     if (m_hasExclusiveThread
) { 
 211         ASSERT(exclusiveThread() == std::this_thread::get_id()); 
 215     if (!currentThreadIsHoldingLock()) 
 220     dropper
->setDropDepth(m_lockDropDepth
); 
 222     WTFThreadData
& threadData 
= wtfThreadData(); 
 223     threadData
.setSavedStackPointerAtVMEntry(m_vm
->stackPointerAtVMEntry()); 
 224     threadData
.setSavedLastStackTop(m_vm
->lastStackTop()); 
 226     unsigned droppedLockCount 
= m_lockCount
; 
 227     unlock(droppedLockCount
); 
 229     return droppedLockCount
; 
 232 void JSLock::grabAllLocks(DropAllLocks
* dropper
, unsigned droppedLockCount
) 
 234     ASSERT(!m_hasExclusiveThread 
|| !droppedLockCount
); 
 236     // If no locks were dropped, nothing to do! 
 237     if (!droppedLockCount
) 
 240     ASSERT(!currentThreadIsHoldingLock()); 
 241     lock(droppedLockCount
); 
 243     while (dropper
->dropDepth() != m_lockDropDepth
) { 
 244         unlock(droppedLockCount
); 
 245         std::this_thread::yield(); 
 246         lock(droppedLockCount
); 
 251     WTFThreadData
& threadData 
= wtfThreadData(); 
 252     m_vm
->setStackPointerAtVMEntry(threadData
.savedStackPointerAtVMEntry()); 
 253     m_vm
->setLastStackTop(threadData
.savedLastStackTop()); 
 256 JSLock::DropAllLocks::DropAllLocks(VM
* vm
) 
 257     : m_droppedLockCount(0) 
 258     // If the VM is in the middle of being destroyed then we don't want to resurrect it 
 259     // by allowing DropAllLocks to ref it. By this point the JSLock has already been  
 260     // released anyways, so it doesn't matter that DropAllLocks is a no-op. 
 261     , m_vm(vm
->refCount() ? vm 
: nullptr) 
 265     wtfThreadData().resetCurrentAtomicStringTable(); 
 266     RELEASE_ASSERT(!m_vm
->apiLock().currentThreadIsHoldingLock() || !m_vm
->isCollectorBusy()); 
 267     m_droppedLockCount 
= m_vm
->apiLock().dropAllLocks(this); 
 270 JSLock::DropAllLocks::DropAllLocks(ExecState
* exec
) 
 271     : DropAllLocks(exec 
? &exec
->vm() : nullptr) 
 275 JSLock::DropAllLocks::DropAllLocks(VM
& vm
) 
 280 JSLock::DropAllLocks::~DropAllLocks() 
 284     m_vm
->apiLock().grabAllLocks(this, m_droppedLockCount
); 
 285     wtfThreadData().setCurrentAtomicStringTable(m_vm
->atomicStringTable());