]>
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());