blob: 6e477be893af20ad450d3bb9206b25adf1ce2240 [file] [log] [blame]
ap@webkit.org01aff702008-08-20 07:23:06 +00001/*
mark.lam@apple.comfa09f022014-02-08 00:55:15 +00002 * Copyright (C) 2005, 2008, 2012, 2014 Apple Inc. All rights reserved.
ap@webkit.org01aff702008-08-20 07:23:06 +00003 *
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.
8 *
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.
13 *
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
18 *
19 */
20
21#include "config.h"
22#include "JSLock.h"
23
ggaren@apple.coma8b38542011-01-10 23:43:56 +000024#include "Heap.h"
ggaren@apple.com5169fc92008-11-17 22:11:26 +000025#include "CallFrame.h"
mhahnenberg@apple.come16f8092012-06-27 23:08:26 +000026#include "JSGlobalObject.h"
oliver@apple.com9d4f0ec2011-03-14 18:16:36 +000027#include "JSObject.h"
fpizlo@apple.comfb7eff22014-02-11 01:45:50 +000028#include "JSCInlines.h"
sbarati@apple.coma4ce86b2016-01-11 06:49:49 +000029#include "SamplingProfiler.h"
mark.lam@apple.com49d3b252015-07-20 18:12:56 +000030#include <thread>
ap@webkit.org01aff702008-08-20 07:23:06 +000031
cwzwarich@webkit.org3f782f62008-09-08 01:28:33 +000032namespace JSC {
ap@webkit.org01aff702008-08-20 07:23:06 +000033
fpizlo@apple.comaa671292015-08-15 00:14:52 +000034StaticLock GlobalJSLock::s_sharedInstanceMutex;
ap@webkit.org01aff702008-08-20 07:23:06 +000035
mhahnenberg@apple.come16f8092012-06-27 23:08:26 +000036GlobalJSLock::GlobalJSLock()
ap@webkit.org01aff702008-08-20 07:23:06 +000037{
fpizlo@apple.comaa671292015-08-15 00:14:52 +000038 s_sharedInstanceMutex.lock();
ap@webkit.org01aff702008-08-20 07:23:06 +000039}
40
mhahnenberg@apple.come16f8092012-06-27 23:08:26 +000041GlobalJSLock::~GlobalJSLock()
ap@webkit.org01aff702008-08-20 07:23:06 +000042{
fpizlo@apple.comaa671292015-08-15 00:14:52 +000043 s_sharedInstanceMutex.unlock();
ap@webkit.org01aff702008-08-20 07:23:06 +000044}
45
mhahnenberg@apple.come16f8092012-06-27 23:08:26 +000046JSLockHolder::JSLockHolder(ExecState* exec)
mark.lam@apple.comafd06072014-02-26 01:03:37 +000047 : m_vm(&exec->vm())
ap@webkit.org01aff702008-08-20 07:23:06 +000048{
mhahnenberg@apple.com765a7de2013-04-15 23:17:51 +000049 init();
ap@webkit.org01aff702008-08-20 07:23:06 +000050}
51
ggaren@apple.com9a9a4b52013-04-18 19:32:17 +000052JSLockHolder::JSLockHolder(VM* vm)
53 : m_vm(vm)
ap@webkit.org01aff702008-08-20 07:23:06 +000054{
mhahnenberg@apple.com765a7de2013-04-15 23:17:51 +000055 init();
ap@webkit.org01aff702008-08-20 07:23:06 +000056}
57
ggaren@apple.com9a9a4b52013-04-18 19:32:17 +000058JSLockHolder::JSLockHolder(VM& vm)
59 : m_vm(&vm)
ggaren@apple.com2ccf7a92010-08-03 20:34:17 +000060{
mhahnenberg@apple.com765a7de2013-04-15 23:17:51 +000061 init();
62}
63
64void JSLockHolder::init()
65{
mark.lam@apple.comafd06072014-02-26 01:03:37 +000066 m_vm->apiLock().lock();
ggaren@apple.com2ccf7a92010-08-03 20:34:17 +000067}
68
mhahnenberg@apple.come16f8092012-06-27 23:08:26 +000069JSLockHolder::~JSLockHolder()
ap@webkit.org01aff702008-08-20 07:23:06 +000070{
ggaren@apple.com9a9a4b52013-04-18 19:32:17 +000071 RefPtr<JSLock> apiLock(&m_vm->apiLock());
cdumez@apple.comd839ea12015-07-04 19:42:18 +000072 m_vm = nullptr;
mhahnenberg@apple.com765a7de2013-04-15 23:17:51 +000073 apiLock->unlock();
mhahnenberg@apple.come16f8092012-06-27 23:08:26 +000074}
ap@webkit.org01aff702008-08-20 07:23:06 +000075
ggaren@apple.com9a9a4b52013-04-18 19:32:17 +000076JSLock::JSLock(VM* vm)
mark.lam@apple.com49d3b252015-07-20 18:12:56 +000077 : m_ownerThreadID(std::thread::id())
mark.lam@apple.comafd06072014-02-26 01:03:37 +000078 , m_lockCount(0)
commit-queue@webkit.orge9ad9762012-11-13 17:17:07 +000079 , m_lockDropDepth(0)
mark.lam@apple.comafd06072014-02-26 01:03:37 +000080 , m_hasExclusiveThread(false)
ggaren@apple.com9a9a4b52013-04-18 19:32:17 +000081 , m_vm(vm)
joepeck@webkit.org6e829912014-07-24 23:56:34 +000082 , m_entryAtomicStringTable(nullptr)
mhahnenberg@apple.come16f8092012-06-27 23:08:26 +000083{
mhahnenberg@apple.come16f8092012-06-27 23:08:26 +000084}
ap@webkit.org01aff702008-08-20 07:23:06 +000085
mhahnenberg@apple.come16f8092012-06-27 23:08:26 +000086JSLock::~JSLock()
87{
88}
89
ggaren@apple.com9a9a4b52013-04-18 19:32:17 +000090void JSLock::willDestroyVM(VM* vm)
mhahnenberg@apple.com765a7de2013-04-15 23:17:51 +000091{
ggaren@apple.com9a9a4b52013-04-18 19:32:17 +000092 ASSERT_UNUSED(vm, m_vm == vm);
joepeck@webkit.org6e829912014-07-24 23:56:34 +000093 m_vm = nullptr;
mhahnenberg@apple.com765a7de2013-04-15 23:17:51 +000094}
95
mark.lam@apple.com49d3b252015-07-20 18:12:56 +000096void JSLock::setExclusiveThread(std::thread::id threadId)
mark.lam@apple.comafd06072014-02-26 01:03:37 +000097{
mark.lam@apple.com49d3b252015-07-20 18:12:56 +000098 RELEASE_ASSERT(!m_lockCount && m_ownerThreadID == std::thread::id());
99 m_hasExclusiveThread = (threadId != std::thread::id());
mark.lam@apple.comafd06072014-02-26 01:03:37 +0000100 m_ownerThreadID = threadId;
101}
102
mhahnenberg@apple.come16f8092012-06-27 23:08:26 +0000103void JSLock::lock()
104{
mark.lam@apple.com6f2215d2014-02-10 22:27:10 +0000105 lock(1);
106}
107
108void JSLock::lock(intptr_t lockCount)
109{
110 ASSERT(lockCount > 0);
mark.lam@apple.com7794f5e2014-02-10 19:39:30 +0000111 if (currentThreadIsHoldingLock()) {
mark.lam@apple.com6f2215d2014-02-10 22:27:10 +0000112 m_lockCount += lockCount;
mark.lam@apple.com7794f5e2014-02-10 19:39:30 +0000113 return;
ap@webkit.org01aff702008-08-20 07:23:06 +0000114 }
mhahnenberg@apple.come16f8092012-06-27 23:08:26 +0000115
mark.lam@apple.comafd06072014-02-26 01:03:37 +0000116 if (!m_hasExclusiveThread) {
117 m_lock.lock();
mark.lam@apple.com49d3b252015-07-20 18:12:56 +0000118 m_ownerThreadID = std::this_thread::get_id();
mark.lam@apple.comafd06072014-02-26 01:03:37 +0000119 }
mark.lam@apple.com7794f5e2014-02-10 19:39:30 +0000120 ASSERT(!m_lockCount);
mark.lam@apple.com6f2215d2014-02-10 22:27:10 +0000121 m_lockCount = lockCount;
msaboff@apple.comaa9f4ab2014-01-31 23:53:52 +0000122
mhahnenberg@apple.com085d24e2014-03-04 21:38:05 +0000123 didAcquireLock();
124}
125
126void JSLock::didAcquireLock()
127{
128 // FIXME: What should happen to the per-thread identifier table if we don't have a VM?
mhahnenberg@apple.comac9e2dc2014-02-15 01:27:53 +0000129 if (!m_vm)
130 return;
131
mark.lam@apple.com5e1200e2014-02-13 06:50:09 +0000132 RELEASE_ASSERT(!m_vm->stackPointerAtVMEntry());
133 void* p = &p; // A proxy for the current stack pointer.
134 m_vm->setStackPointerAtVMEntry(p);
mark.lam@apple.com7794f5e2014-02-10 19:39:30 +0000135
mark.lam@apple.comafd06072014-02-26 01:03:37 +0000136 WTFThreadData& threadData = wtfThreadData();
mark.lam@apple.com7794f5e2014-02-10 19:39:30 +0000137 m_vm->setLastStackTop(threadData.savedLastStackTop());
mhahnenberg@apple.com085d24e2014-03-04 21:38:05 +0000138
joepeck@webkit.org6e829912014-07-24 23:56:34 +0000139 ASSERT(!m_entryAtomicStringTable);
barraclough@apple.com0cde90d2014-03-20 21:05:49 +0000140 m_entryAtomicStringTable = threadData.setCurrentAtomicStringTable(m_vm->atomicStringTable());
joepeck@webkit.org6e829912014-07-24 23:56:34 +0000141 ASSERT(m_entryAtomicStringTable);
142
mark.lam@apple.com6aba4362015-02-26 19:44:08 +0000143 m_vm->heap.machineThreads().addCurrentThread();
sbarati@apple.coma4ce86b2016-01-11 06:49:49 +0000144
145#if ENABLE(SAMPLING_PROFILER)
146 // Note: this must come after addCurrentThread().
147 if (SamplingProfiler* samplingProfiler = m_vm->samplingProfiler())
148 samplingProfiler->noticeJSLockAcquisition();
149#endif
ap@webkit.org01aff702008-08-20 07:23:06 +0000150}
151
mhahnenberg@apple.come16f8092012-06-27 23:08:26 +0000152void JSLock::unlock()
ap@webkit.org01aff702008-08-20 07:23:06 +0000153{
mark.lam@apple.com6f2215d2014-02-10 22:27:10 +0000154 unlock(1);
155}
ap@webkit.org01aff702008-08-20 07:23:06 +0000156
mark.lam@apple.com6f2215d2014-02-10 22:27:10 +0000157void JSLock::unlock(intptr_t unlockCount)
158{
159 RELEASE_ASSERT(currentThreadIsHoldingLock());
160 ASSERT(m_lockCount >= unlockCount);
161
msaboff@apple.com847d1cb2015-03-04 05:33:37 +0000162 // Maintain m_lockCount while calling willReleaseLock() so that its callees know that
163 // they still have the lock.
164 if (unlockCount == m_lockCount)
165 willReleaseLock();
166
mark.lam@apple.com6f2215d2014-02-10 22:27:10 +0000167 m_lockCount -= unlockCount;
ap@webkit.org01aff702008-08-20 07:23:06 +0000168
msaboff@apple.comaa9f4ab2014-01-31 23:53:52 +0000169 if (!m_lockCount) {
mark.lam@apple.comafd06072014-02-26 01:03:37 +0000170
171 if (!m_hasExclusiveThread) {
mark.lam@apple.com49d3b252015-07-20 18:12:56 +0000172 m_ownerThreadID = std::thread::id();
mark.lam@apple.comafd06072014-02-26 01:03:37 +0000173 m_lock.unlock();
174 }
msaboff@apple.comaa9f4ab2014-01-31 23:53:52 +0000175 }
ap@webkit.org01aff702008-08-20 07:23:06 +0000176}
177
mhahnenberg@apple.com085d24e2014-03-04 21:38:05 +0000178void JSLock::willReleaseLock()
179{
mark.lam@apple.com416a13e2016-05-19 21:02:44 +0000180 RefPtr<VM> vm = m_vm;
181 if (vm) {
182 vm->drainMicrotasks();
utatane.tea@gmail.comff51b692015-07-17 22:40:40 +0000183
mark.lam@apple.com416a13e2016-05-19 21:02:44 +0000184 vm->heap.releaseDelayedReleasedObjects();
185 vm->setStackPointerAtVMEntry(nullptr);
msaboff@apple.com84946d42015-02-06 01:12:00 +0000186 }
mhahnenberg@apple.com085d24e2014-03-04 21:38:05 +0000187
joepeck@webkit.org6e829912014-07-24 23:56:34 +0000188 if (m_entryAtomicStringTable) {
189 wtfThreadData().setCurrentAtomicStringTable(m_entryAtomicStringTable);
190 m_entryAtomicStringTable = nullptr;
191 }
mhahnenberg@apple.com085d24e2014-03-04 21:38:05 +0000192}
193
ap@webkit.org01aff702008-08-20 07:23:06 +0000194void JSLock::lock(ExecState* exec)
195{
ggaren@apple.com9a9a4b52013-04-18 19:32:17 +0000196 exec->vm().apiLock().lock();
ap@webkit.org01aff702008-08-20 07:23:06 +0000197}
198
199void JSLock::unlock(ExecState* exec)
200{
ggaren@apple.com9a9a4b52013-04-18 19:32:17 +0000201 exec->vm().apiLock().unlock();
ap@webkit.org01aff702008-08-20 07:23:06 +0000202}
203
204bool JSLock::currentThreadIsHoldingLock()
205{
mark.lam@apple.com49d3b252015-07-20 18:12:56 +0000206 ASSERT(!m_hasExclusiveThread || (exclusiveThread() == std::this_thread::get_id()));
mark.lam@apple.comafd06072014-02-26 01:03:37 +0000207 if (m_hasExclusiveThread)
208 return !!m_lockCount;
mark.lam@apple.com49d3b252015-07-20 18:12:56 +0000209 return m_ownerThreadID == std::this_thread::get_id();
ap@webkit.org01aff702008-08-20 07:23:06 +0000210}
211
mhahnenberg@apple.come16f8092012-06-27 23:08:26 +0000212// This function returns the number of locks that were dropped.
mark.lam@apple.com2ff16d22014-02-11 04:48:01 +0000213unsigned JSLock::dropAllLocks(DropAllLocks* dropper)
mhahnenberg@apple.com6d9f86d2012-06-22 21:42:46 +0000214{
mark.lam@apple.comafd06072014-02-26 01:03:37 +0000215 if (m_hasExclusiveThread) {
mark.lam@apple.com49d3b252015-07-20 18:12:56 +0000216 ASSERT(exclusiveThread() == std::this_thread::get_id());
mark.lam@apple.comafd06072014-02-26 01:03:37 +0000217 return 0;
218 }
219
mark.lam@apple.com7794f5e2014-02-10 19:39:30 +0000220 if (!currentThreadIsHoldingLock())
dbates@webkit.org96fcf222013-10-22 20:40:34 +0000221 return 0;
222
mark.lam@apple.com2ff16d22014-02-11 04:48:01 +0000223 ++m_lockDropDepth;
224
mark.lam@apple.com2ff16d22014-02-11 04:48:01 +0000225 dropper->setDropDepth(m_lockDropDepth);
dbates@webkit.org96fcf222013-10-22 20:40:34 +0000226
mark.lam@apple.comc6c31832014-02-08 08:27:13 +0000227 WTFThreadData& threadData = wtfThreadData();
mark.lam@apple.com5e1200e2014-02-13 06:50:09 +0000228 threadData.setSavedStackPointerAtVMEntry(m_vm->stackPointerAtVMEntry());
mark.lam@apple.comc6c31832014-02-08 08:27:13 +0000229 threadData.setSavedLastStackTop(m_vm->lastStackTop());
mark.lam@apple.comc6c31832014-02-08 08:27:13 +0000230
mark.lam@apple.com7794f5e2014-02-10 19:39:30 +0000231 unsigned droppedLockCount = m_lockCount;
mark.lam@apple.com6f2215d2014-02-10 22:27:10 +0000232 unlock(droppedLockCount);
233
mark.lam@apple.com7794f5e2014-02-10 19:39:30 +0000234 return droppedLockCount;
mhahnenberg@apple.com6d9f86d2012-06-22 21:42:46 +0000235}
236
mark.lam@apple.com2ff16d22014-02-11 04:48:01 +0000237void JSLock::grabAllLocks(DropAllLocks* dropper, unsigned droppedLockCount)
mhahnenberg@apple.come16f8092012-06-27 23:08:26 +0000238{
mark.lam@apple.comafd06072014-02-26 01:03:37 +0000239 ASSERT(!m_hasExclusiveThread || !droppedLockCount);
240
dbates@webkit.org96fcf222013-10-22 20:40:34 +0000241 // If no locks were dropped, nothing to do!
mark.lam@apple.comcbebdc42014-02-09 00:46:17 +0000242 if (!droppedLockCount)
dbates@webkit.org96fcf222013-10-22 20:40:34 +0000243 return;
244
mark.lam@apple.com7794f5e2014-02-10 19:39:30 +0000245 ASSERT(!currentThreadIsHoldingLock());
mark.lam@apple.com6f2215d2014-02-10 22:27:10 +0000246 lock(droppedLockCount);
dbates@webkit.org96fcf222013-10-22 20:40:34 +0000247
mark.lam@apple.com2ff16d22014-02-11 04:48:01 +0000248 while (dropper->dropDepth() != m_lockDropDepth) {
249 unlock(droppedLockCount);
250 std::this_thread::yield();
251 lock(droppedLockCount);
252 }
mark.lam@apple.com2ff16d22014-02-11 04:48:01 +0000253
dbates@webkit.org96fcf222013-10-22 20:40:34 +0000254 --m_lockDropDepth;
mark.lam@apple.comc6c31832014-02-08 08:27:13 +0000255
256 WTFThreadData& threadData = wtfThreadData();
mark.lam@apple.com5e1200e2014-02-13 06:50:09 +0000257 m_vm->setStackPointerAtVMEntry(threadData.savedStackPointerAtVMEntry());
mark.lam@apple.comc6c31832014-02-08 08:27:13 +0000258 m_vm->setLastStackTop(threadData.savedLastStackTop());
mhahnenberg@apple.come16f8092012-06-27 23:08:26 +0000259}
260
mhahnenberg@apple.com085d24e2014-03-04 21:38:05 +0000261JSLock::DropAllLocks::DropAllLocks(VM* vm)
mark.lam@apple.comcbebdc42014-02-09 00:46:17 +0000262 : m_droppedLockCount(0)
mhahnenberg@apple.com085d24e2014-03-04 21:38:05 +0000263 // If the VM is in the middle of being destroyed then we don't want to resurrect it
264 // by allowing DropAllLocks to ref it. By this point the JSLock has already been
265 // released anyways, so it doesn't matter that DropAllLocks is a no-op.
266 , m_vm(vm->refCount() ? vm : nullptr)
mhahnenberg@apple.come16f8092012-06-27 23:08:26 +0000267{
dbates@webkit.org96fcf222013-10-22 20:40:34 +0000268 if (!m_vm)
269 return;
barraclough@apple.com0cde90d2014-03-20 21:05:49 +0000270 wtfThreadData().resetCurrentAtomicStringTable();
ggaren@apple.com1af6f962015-06-05 22:03:50 +0000271 RELEASE_ASSERT(!m_vm->apiLock().currentThreadIsHoldingLock() || !m_vm->isCollectorBusy());
mark.lam@apple.com2ff16d22014-02-11 04:48:01 +0000272 m_droppedLockCount = m_vm->apiLock().dropAllLocks(this);
mhahnenberg@apple.come16f8092012-06-27 23:08:26 +0000273}
274
mhahnenberg@apple.com085d24e2014-03-04 21:38:05 +0000275JSLock::DropAllLocks::DropAllLocks(ExecState* exec)
276 : DropAllLocks(exec ? &exec->vm() : nullptr)
mhahnenberg@apple.come16f8092012-06-27 23:08:26 +0000277{
ap@webkit.org01aff702008-08-20 07:23:06 +0000278}
279
akling@apple.com710fc6a2014-03-03 05:10:15 +0000280JSLock::DropAllLocks::DropAllLocks(VM& vm)
mhahnenberg@apple.com085d24e2014-03-04 21:38:05 +0000281 : DropAllLocks(&vm)
akling@apple.com710fc6a2014-03-03 05:10:15 +0000282{
akling@apple.com710fc6a2014-03-03 05:10:15 +0000283}
284
ap@webkit.org01aff702008-08-20 07:23:06 +0000285JSLock::DropAllLocks::~DropAllLocks()
286{
dbates@webkit.org96fcf222013-10-22 20:40:34 +0000287 if (!m_vm)
288 return;
mark.lam@apple.com2ff16d22014-02-11 04:48:01 +0000289 m_vm->apiLock().grabAllLocks(this, m_droppedLockCount);
barraclough@apple.com0cde90d2014-03-20 21:05:49 +0000290 wtfThreadData().setCurrentAtomicStringTable(m_vm->atomicStringTable());
ap@webkit.org01aff702008-08-20 07:23:06 +0000291}
292
cwzwarich@webkit.org3f782f62008-09-08 01:28:33 +0000293} // namespace JSC