blob: 16aa369f48507061c06361518ae15d2bc68fb6dd [file] [log] [blame]
ap@webkit.org01aff702008-08-20 07:23:06 +00001/*
fpizlo@apple.com47d0cf72018-01-25 19:32:00 +00002 * Copyright (C) 2005-2018 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"
fpizlo@apple.combb9f63b2017-02-22 01:05:13 +000029#include "MachineStackMarker.h"
sbarati@apple.coma4ce86b2016-01-11 06:49:49 +000030#include "SamplingProfiler.h"
ysuzuki@apple.com2f875392019-03-21 19:14:12 +000031#include "WasmCapabilities.h"
keith_miller@apple.com5fe2e702017-04-26 23:55:05 +000032#include "WasmMachineThreads.h"
mark.lam@apple.com49d3b252015-07-20 18:12:56 +000033#include <thread>
mark.lam@apple.com6c4490c2018-10-11 19:19:18 +000034#include <wtf/StackPointer.h>
keith_miller@apple.comea98d8d2017-06-01 18:28:48 +000035#include <wtf/Threading.h>
36#include <wtf/threads/Signals.h>
ap@webkit.org01aff702008-08-20 07:23:06 +000037
ysuzuki@apple.com9f880612019-06-19 01:19:41 +000038#if USE(WEB_THREAD)
39#include <wtf/ios/WebCoreThread.h>
40#endif
41
cwzwarich@webkit.org3f782f62008-09-08 01:28:33 +000042namespace JSC {
ap@webkit.org01aff702008-08-20 07:23:06 +000043
utatane.tea@gmail.come71a8722018-04-05 17:22:21 +000044Lock GlobalJSLock::s_sharedInstanceMutex;
ap@webkit.org01aff702008-08-20 07:23:06 +000045
mhahnenberg@apple.come16f8092012-06-27 23:08:26 +000046GlobalJSLock::GlobalJSLock()
ap@webkit.org01aff702008-08-20 07:23:06 +000047{
fpizlo@apple.comaa671292015-08-15 00:14:52 +000048 s_sharedInstanceMutex.lock();
ap@webkit.org01aff702008-08-20 07:23:06 +000049}
50
mhahnenberg@apple.come16f8092012-06-27 23:08:26 +000051GlobalJSLock::~GlobalJSLock()
ap@webkit.org01aff702008-08-20 07:23:06 +000052{
fpizlo@apple.comaa671292015-08-15 00:14:52 +000053 s_sharedInstanceMutex.unlock();
ap@webkit.org01aff702008-08-20 07:23:06 +000054}
55
ysuzuki@apple.com52e98bb2019-10-22 09:24:48 +000056JSLockHolder::JSLockHolder(JSGlobalObject* globalObject)
57 : JSLockHolder(globalObject->vm())
ap@webkit.org01aff702008-08-20 07:23:06 +000058{
ap@webkit.org01aff702008-08-20 07:23:06 +000059}
60
ggaren@apple.com9a9a4b52013-04-18 19:32:17 +000061JSLockHolder::JSLockHolder(VM* vm)
ysuzuki@apple.com9f880612019-06-19 01:19:41 +000062 : JSLockHolder(*vm)
ap@webkit.org01aff702008-08-20 07:23:06 +000063{
ap@webkit.org01aff702008-08-20 07:23:06 +000064}
65
ggaren@apple.com9a9a4b52013-04-18 19:32:17 +000066JSLockHolder::JSLockHolder(VM& vm)
67 : m_vm(&vm)
ggaren@apple.com2ccf7a92010-08-03 20:34:17 +000068{
mark.lam@apple.comafd06072014-02-26 01:03:37 +000069 m_vm->apiLock().lock();
ggaren@apple.com2ccf7a92010-08-03 20:34:17 +000070}
71
mhahnenberg@apple.come16f8092012-06-27 23:08:26 +000072JSLockHolder::~JSLockHolder()
ap@webkit.org01aff702008-08-20 07:23:06 +000073{
tsavell@apple.com899b2dd2019-10-04 15:35:03 +000074 RefPtr<JSLock> apiLock(&m_vm->apiLock());
75 m_vm = nullptr;
76 apiLock->unlock();
mhahnenberg@apple.come16f8092012-06-27 23:08:26 +000077}
ap@webkit.org01aff702008-08-20 07:23:06 +000078
ggaren@apple.com9a9a4b52013-04-18 19:32:17 +000079JSLock::JSLock(VM* vm)
mark.lam@apple.com8bae0712017-03-01 20:15:08 +000080 : m_lockCount(0)
commit-queue@webkit.orge9ad9762012-11-13 17:17:07 +000081 , m_lockDropDepth(0)
ggaren@apple.com9a9a4b52013-04-18 19:32:17 +000082 , m_vm(vm)
darin@apple.com0ce67df2019-06-17 01:48:13 +000083 , m_entryAtomStringTable(nullptr)
mhahnenberg@apple.come16f8092012-06-27 23:08:26 +000084{
mhahnenberg@apple.come16f8092012-06-27 23:08:26 +000085}
ap@webkit.org01aff702008-08-20 07:23:06 +000086
mhahnenberg@apple.come16f8092012-06-27 23:08:26 +000087JSLock::~JSLock()
88{
89}
90
ggaren@apple.com9a9a4b52013-04-18 19:32:17 +000091void JSLock::willDestroyVM(VM* vm)
mhahnenberg@apple.com765a7de2013-04-15 23:17:51 +000092{
ggaren@apple.com9a9a4b52013-04-18 19:32:17 +000093 ASSERT_UNUSED(vm, m_vm == vm);
joepeck@webkit.org6e829912014-07-24 23:56:34 +000094 m_vm = nullptr;
mhahnenberg@apple.com765a7de2013-04-15 23:17:51 +000095}
96
mhahnenberg@apple.come16f8092012-06-27 23:08:26 +000097void JSLock::lock()
98{
mark.lam@apple.com6f2215d2014-02-10 22:27:10 +000099 lock(1);
100}
101
102void JSLock::lock(intptr_t lockCount)
103{
104 ASSERT(lockCount > 0);
ysuzuki@apple.com9f880612019-06-19 01:19:41 +0000105#if USE(WEB_THREAD)
106 if (m_isWebThreadAware) {
107 ASSERT(WebCoreWebThreadIsEnabled && WebCoreWebThreadIsEnabled());
108 WebCoreWebThreadLock();
109 }
110#endif
111
mark.lam@apple.com0a7ae132017-02-28 21:56:44 +0000112 bool success = m_lock.tryLock();
113 if (UNLIKELY(!success)) {
114 if (currentThreadIsHoldingLock()) {
115 m_lockCount += lockCount;
116 return;
117 }
118 m_lock.lock();
ap@webkit.org01aff702008-08-20 07:23:06 +0000119 }
mhahnenberg@apple.come16f8092012-06-27 23:08:26 +0000120
utatane.tea@gmail.com1e94a262017-04-12 12:08:29 +0000121 m_ownerThread = &Thread::current();
mark.lam@apple.com8bae0712017-03-01 20:15:08 +0000122 WTF::storeStoreFence();
123 m_hasOwnerThread = true;
mark.lam@apple.com7794f5e2014-02-10 19:39:30 +0000124 ASSERT(!m_lockCount);
mark.lam@apple.com6f2215d2014-02-10 22:27:10 +0000125 m_lockCount = lockCount;
msaboff@apple.comaa9f4ab2014-01-31 23:53:52 +0000126
mhahnenberg@apple.com085d24e2014-03-04 21:38:05 +0000127 didAcquireLock();
128}
129
130void JSLock::didAcquireLock()
commit-queue@webkit.org0b186d52018-08-07 12:50:23 +0000131{
mhahnenberg@apple.com085d24e2014-03-04 21:38:05 +0000132 // 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 +0000133 if (!m_vm)
134 return;
fpizlo@apple.com8b6ca582016-11-02 22:01:04 +0000135
utatane.tea@gmail.com843c4ac2017-08-03 06:03:18 +0000136 Thread& thread = Thread::current();
darin@apple.com0ce67df2019-06-17 01:48:13 +0000137 ASSERT(!m_entryAtomStringTable);
138 m_entryAtomStringTable = thread.setCurrentAtomStringTable(m_vm->atomStringTable());
139 ASSERT(m_entryAtomStringTable);
fpizlo@apple.com8b6ca582016-11-02 22:01:04 +0000140
msaboff@apple.com94801be2018-06-20 00:45:06 +0000141 m_vm->setLastStackTop(thread.savedLastStackTop());
142 ASSERT(thread.stack().contains(m_vm->lastStackTop()));
143
fpizlo@apple.com8b6ca582016-11-02 22:01:04 +0000144 if (m_vm->heap.hasAccess())
145 m_shouldReleaseHeapAccess = false;
146 else {
147 m_vm->heap.acquireAccess();
148 m_shouldReleaseHeapAccess = true;
149 }
mhahnenberg@apple.comac9e2dc2014-02-15 01:27:53 +0000150
mark.lam@apple.com5e1200e2014-02-13 06:50:09 +0000151 RELEASE_ASSERT(!m_vm->stackPointerAtVMEntry());
mark.lam@apple.com6c4490c2018-10-11 19:19:18 +0000152 void* p = currentStackPointer();
mark.lam@apple.com5e1200e2014-02-13 06:50:09 +0000153 m_vm->setStackPointerAtVMEntry(p);
mark.lam@apple.com7794f5e2014-02-10 19:39:30 +0000154
sbarati@apple.com48116782019-04-12 23:26:43 +0000155 if (m_vm->heap.machineThreads().addCurrentThread()) {
156 if (isKernTCSMAvailable())
157 enableKernTCSM();
158 }
159
keith_miller@apple.com5fe2e702017-04-26 23:55:05 +0000160#if ENABLE(WEBASSEMBLY)
ysuzuki@apple.com2f875392019-03-21 19:14:12 +0000161 if (Wasm::isSupported())
ysuzuki@apple.coma0cd7892019-02-16 00:18:54 +0000162 Wasm::startTrackingCurrentThread();
keith_miller@apple.com5fe2e702017-04-26 23:55:05 +0000163#endif
sbarati@apple.coma4ce86b2016-01-11 06:49:49 +0000164
keith_miller@apple.comea98d8d2017-06-01 18:28:48 +0000165#if HAVE(MACH_EXCEPTIONS)
utatane.tea@gmail.comf8727772017-07-20 18:32:13 +0000166 registerThreadForMachExceptionHandling(Thread::current());
keith_miller@apple.comea98d8d2017-06-01 18:28:48 +0000167#endif
168
keith_miller@apple.comc670c532017-06-29 17:34:57 +0000169 // Note: everything below must come after addCurrentThread().
mark.lam@apple.comf842cd82017-03-09 19:08:46 +0000170 m_vm->traps().notifyGrabAllLocks();
fpizlo@apple.comd2bbe272017-08-02 01:50:16 +0000171
fpizlo@apple.comc206913b2017-08-07 21:31:49 +0000172 m_vm->firePrimitiveGigacageEnabledIfNecessary();
mark.lam@apple.comf842cd82017-03-09 19:08:46 +0000173
sbarati@apple.coma4ce86b2016-01-11 06:49:49 +0000174#if ENABLE(SAMPLING_PROFILER)
sbarati@apple.coma4ce86b2016-01-11 06:49:49 +0000175 if (SamplingProfiler* samplingProfiler = m_vm->samplingProfiler())
176 samplingProfiler->noticeJSLockAcquisition();
177#endif
ap@webkit.org01aff702008-08-20 07:23:06 +0000178}
179
mhahnenberg@apple.come16f8092012-06-27 23:08:26 +0000180void JSLock::unlock()
ap@webkit.org01aff702008-08-20 07:23:06 +0000181{
mark.lam@apple.com6f2215d2014-02-10 22:27:10 +0000182 unlock(1);
183}
ap@webkit.org01aff702008-08-20 07:23:06 +0000184
mark.lam@apple.com6f2215d2014-02-10 22:27:10 +0000185void JSLock::unlock(intptr_t unlockCount)
186{
187 RELEASE_ASSERT(currentThreadIsHoldingLock());
188 ASSERT(m_lockCount >= unlockCount);
189
msaboff@apple.com847d1cb2015-03-04 05:33:37 +0000190 // Maintain m_lockCount while calling willReleaseLock() so that its callees know that
191 // they still have the lock.
192 if (unlockCount == m_lockCount)
193 willReleaseLock();
194
mark.lam@apple.com6f2215d2014-02-10 22:27:10 +0000195 m_lockCount -= unlockCount;
ap@webkit.org01aff702008-08-20 07:23:06 +0000196
msaboff@apple.comaa9f4ab2014-01-31 23:53:52 +0000197 if (!m_lockCount) {
mark.lam@apple.com8bae0712017-03-01 20:15:08 +0000198 m_hasOwnerThread = false;
mark.lam@apple.com0a7ae132017-02-28 21:56:44 +0000199 m_lock.unlock();
msaboff@apple.comaa9f4ab2014-01-31 23:53:52 +0000200 }
ap@webkit.org01aff702008-08-20 07:23:06 +0000201}
202
mhahnenberg@apple.com085d24e2014-03-04 21:38:05 +0000203void JSLock::willReleaseLock()
commit-queue@webkit.org0b186d52018-08-07 12:50:23 +0000204{
mark.lam@apple.com416a13e2016-05-19 21:02:44 +0000205 RefPtr<VM> vm = m_vm;
206 if (vm) {
keith_miller@apple.coma1c17ed2020-01-17 04:09:32 +0000207 RELEASE_ASSERT_WITH_MESSAGE(!vm->hasCheckpointOSRSideState(), "Releasing JSLock but pending checkpoint side state still available");
mark.lam@apple.com416a13e2016-05-19 21:02:44 +0000208 vm->drainMicrotasks();
utatane.tea@gmail.comff51b692015-07-17 22:40:40 +0000209
keith_miller@apple.comefd353c2018-06-04 21:51:04 +0000210 if (!vm->topCallFrame)
211 vm->clearLastException();
212
mark.lam@apple.com416a13e2016-05-19 21:02:44 +0000213 vm->heap.releaseDelayedReleasedObjects();
214 vm->setStackPointerAtVMEntry(nullptr);
fpizlo@apple.com8b6ca582016-11-02 22:01:04 +0000215
216 if (m_shouldReleaseHeapAccess)
217 vm->heap.releaseAccess();
msaboff@apple.com84946d42015-02-06 01:12:00 +0000218 }
mhahnenberg@apple.com085d24e2014-03-04 21:38:05 +0000219
darin@apple.com0ce67df2019-06-17 01:48:13 +0000220 if (m_entryAtomStringTable) {
221 Thread::current().setCurrentAtomStringTable(m_entryAtomStringTable);
222 m_entryAtomStringTable = nullptr;
joepeck@webkit.org6e829912014-07-24 23:56:34 +0000223 }
mhahnenberg@apple.com085d24e2014-03-04 21:38:05 +0000224}
225
ysuzuki@apple.com52e98bb2019-10-22 09:24:48 +0000226void JSLock::lock(JSGlobalObject* globalObject)
tsavell@apple.com899b2dd2019-10-04 15:35:03 +0000227{
ysuzuki@apple.com52e98bb2019-10-22 09:24:48 +0000228 globalObject->vm().apiLock().lock();
tsavell@apple.com899b2dd2019-10-04 15:35:03 +0000229}
230
ysuzuki@apple.com52e98bb2019-10-22 09:24:48 +0000231void JSLock::unlock(JSGlobalObject* globalObject)
tsavell@apple.com899b2dd2019-10-04 15:35:03 +0000232{
ysuzuki@apple.com52e98bb2019-10-22 09:24:48 +0000233 globalObject->vm().apiLock().unlock();
tsavell@apple.com899b2dd2019-10-04 15:35:03 +0000234}
235
mhahnenberg@apple.come16f8092012-06-27 23:08:26 +0000236// This function returns the number of locks that were dropped.
mark.lam@apple.com2ff16d22014-02-11 04:48:01 +0000237unsigned JSLock::dropAllLocks(DropAllLocks* dropper)
mhahnenberg@apple.com6d9f86d2012-06-22 21:42:46 +0000238{
mark.lam@apple.com7794f5e2014-02-10 19:39:30 +0000239 if (!currentThreadIsHoldingLock())
dbates@webkit.org96fcf222013-10-22 20:40:34 +0000240 return 0;
241
mark.lam@apple.com2ff16d22014-02-11 04:48:01 +0000242 ++m_lockDropDepth;
243
mark.lam@apple.com2ff16d22014-02-11 04:48:01 +0000244 dropper->setDropDepth(m_lockDropDepth);
dbates@webkit.org96fcf222013-10-22 20:40:34 +0000245
utatane.tea@gmail.com843c4ac2017-08-03 06:03:18 +0000246 Thread& thread = Thread::current();
247 thread.setSavedStackPointerAtVMEntry(m_vm->stackPointerAtVMEntry());
248 thread.setSavedLastStackTop(m_vm->lastStackTop());
mark.lam@apple.comc6c31832014-02-08 08:27:13 +0000249
mark.lam@apple.com7794f5e2014-02-10 19:39:30 +0000250 unsigned droppedLockCount = m_lockCount;
mark.lam@apple.com6f2215d2014-02-10 22:27:10 +0000251 unlock(droppedLockCount);
252
mark.lam@apple.com7794f5e2014-02-10 19:39:30 +0000253 return droppedLockCount;
mhahnenberg@apple.com6d9f86d2012-06-22 21:42:46 +0000254}
255
mark.lam@apple.com2ff16d22014-02-11 04:48:01 +0000256void JSLock::grabAllLocks(DropAllLocks* dropper, unsigned droppedLockCount)
mhahnenberg@apple.come16f8092012-06-27 23:08:26 +0000257{
dbates@webkit.org96fcf222013-10-22 20:40:34 +0000258 // If no locks were dropped, nothing to do!
mark.lam@apple.comcbebdc42014-02-09 00:46:17 +0000259 if (!droppedLockCount)
dbates@webkit.org96fcf222013-10-22 20:40:34 +0000260 return;
261
mark.lam@apple.com7794f5e2014-02-10 19:39:30 +0000262 ASSERT(!currentThreadIsHoldingLock());
mark.lam@apple.com6f2215d2014-02-10 22:27:10 +0000263 lock(droppedLockCount);
dbates@webkit.org96fcf222013-10-22 20:40:34 +0000264
mark.lam@apple.com2ff16d22014-02-11 04:48:01 +0000265 while (dropper->dropDepth() != m_lockDropDepth) {
266 unlock(droppedLockCount);
fpizlo@apple.comac12a7e2017-07-22 14:36:18 +0000267 Thread::yield();
mark.lam@apple.com2ff16d22014-02-11 04:48:01 +0000268 lock(droppedLockCount);
269 }
mark.lam@apple.com2ff16d22014-02-11 04:48:01 +0000270
dbates@webkit.org96fcf222013-10-22 20:40:34 +0000271 --m_lockDropDepth;
mark.lam@apple.comc6c31832014-02-08 08:27:13 +0000272
utatane.tea@gmail.com843c4ac2017-08-03 06:03:18 +0000273 Thread& thread = Thread::current();
274 m_vm->setStackPointerAtVMEntry(thread.savedStackPointerAtVMEntry());
275 m_vm->setLastStackTop(thread.savedLastStackTop());
mhahnenberg@apple.come16f8092012-06-27 23:08:26 +0000276}
277
mhahnenberg@apple.com085d24e2014-03-04 21:38:05 +0000278JSLock::DropAllLocks::DropAllLocks(VM* vm)
mark.lam@apple.comcbebdc42014-02-09 00:46:17 +0000279 : m_droppedLockCount(0)
mhahnenberg@apple.com085d24e2014-03-04 21:38:05 +0000280 // If the VM is in the middle of being destroyed then we don't want to resurrect it
281 // by allowing DropAllLocks to ref it. By this point the JSLock has already been
282 // released anyways, so it doesn't matter that DropAllLocks is a no-op.
rniwa@webkit.org954a92e2019-10-12 02:19:34 +0000283 , m_vm(vm->heap.isShuttingDown() ? nullptr : vm)
mhahnenberg@apple.come16f8092012-06-27 23:08:26 +0000284{
dbates@webkit.org96fcf222013-10-22 20:40:34 +0000285 if (!m_vm)
286 return;
fpizlo@apple.comea379af2016-10-21 02:17:35 +0000287 RELEASE_ASSERT(!m_vm->apiLock().currentThreadIsHoldingLock() || !m_vm->isCollectorBusyOnCurrentThread());
mark.lam@apple.com2ff16d22014-02-11 04:48:01 +0000288 m_droppedLockCount = m_vm->apiLock().dropAllLocks(this);
mhahnenberg@apple.come16f8092012-06-27 23:08:26 +0000289}
290
ysuzuki@apple.com52e98bb2019-10-22 09:24:48 +0000291JSLock::DropAllLocks::DropAllLocks(JSGlobalObject* globalObject)
292 : DropAllLocks(globalObject ? &globalObject->vm() : nullptr)
mhahnenberg@apple.come16f8092012-06-27 23:08:26 +0000293{
ap@webkit.org01aff702008-08-20 07:23:06 +0000294}
295
akling@apple.com710fc6a2014-03-03 05:10:15 +0000296JSLock::DropAllLocks::DropAllLocks(VM& vm)
mhahnenberg@apple.com085d24e2014-03-04 21:38:05 +0000297 : DropAllLocks(&vm)
akling@apple.com710fc6a2014-03-03 05:10:15 +0000298{
akling@apple.com710fc6a2014-03-03 05:10:15 +0000299}
300
ap@webkit.org01aff702008-08-20 07:23:06 +0000301JSLock::DropAllLocks::~DropAllLocks()
302{
dbates@webkit.org96fcf222013-10-22 20:40:34 +0000303 if (!m_vm)
304 return;
mark.lam@apple.com2ff16d22014-02-11 04:48:01 +0000305 m_vm->apiLock().grabAllLocks(this, m_droppedLockCount);
ap@webkit.org01aff702008-08-20 07:23:06 +0000306}
307
cwzwarich@webkit.org3f782f62008-09-08 01:28:33 +0000308} // namespace JSC