Bug 1290156 - Remove the DEBUG-only lockOwner member from GlobalHelperThreadState; r=terrence

The checks that the `lockOwner` member was used for are now redundant given that
`js::Mutex` uses `PTHREAD_MUTEX_ERRORCHECK` in `DEBUG` builds.

In methods where we asserted `isLocked()`, we now pass in an
`AutoLockHelperThreadState` reference for compile-time proof of lock
holding. This is mostly a mechanical change.
This commit is contained in:
Nick Fitzgerald 2016-08-01 18:39:44 -07:00
parent 7862c33d73
commit 9f15a50ddf
10 changed files with 179 additions and 263 deletions

View File

@ -76,17 +76,17 @@ ModuleGenerator::~ModuleGenerator()
if (outstanding_) {
AutoLockHelperThreadState lock;
while (true) {
IonCompileTaskPtrVector& worklist = HelperThreadState().wasmWorklist();
IonCompileTaskPtrVector& worklist = HelperThreadState().wasmWorklist(lock);
MOZ_ASSERT(outstanding_ >= worklist.length());
outstanding_ -= worklist.length();
worklist.clear();
IonCompileTaskPtrVector& finished = HelperThreadState().wasmFinishedList();
IonCompileTaskPtrVector& finished = HelperThreadState().wasmFinishedList(lock);
MOZ_ASSERT(outstanding_ >= finished.length());
outstanding_ -= finished.length();
finished.clear();
uint32_t numFailed = HelperThreadState().harvestFailedWasmJobs();
uint32_t numFailed = HelperThreadState().harvestFailedWasmJobs(lock);
MOZ_ASSERT(outstanding_ >= numFailed);
outstanding_ -= numFailed;
@ -199,12 +199,12 @@ ModuleGenerator::finishOutstandingTask()
while (true) {
MOZ_ASSERT(outstanding_ > 0);
if (HelperThreadState().wasmFailed())
if (HelperThreadState().wasmFailed(lock))
return false;
if (!HelperThreadState().wasmFinishedList().empty()) {
if (!HelperThreadState().wasmFinishedList(lock).empty()) {
outstanding_--;
task = HelperThreadState().wasmFinishedList().popCopy();
task = HelperThreadState().wasmFinishedList(lock).popCopy();
break;
}
@ -790,9 +790,9 @@ ModuleGenerator::startFuncDefs()
#ifdef DEBUG
{
AutoLockHelperThreadState lock;
MOZ_ASSERT(!HelperThreadState().wasmFailed());
MOZ_ASSERT(HelperThreadState().wasmWorklist().empty());
MOZ_ASSERT(HelperThreadState().wasmFinishedList().empty());
MOZ_ASSERT(!HelperThreadState().wasmFailed(lock));
MOZ_ASSERT(HelperThreadState().wasmWorklist(lock).empty());
MOZ_ASSERT(HelperThreadState().wasmFinishedList(lock).empty());
}
#endif
parallel_ = true;

View File

@ -294,7 +294,7 @@ GCRuntime::startBackgroundAllocTaskIfIdle()
// Join the previous invocation of the task. This will return immediately
// if the thread has never been started.
allocTask.joinWithLockHeld(helperLock);
allocTask.startWithLockHeld();
allocTask.startWithLockHeld(helperLock);
}
/* static */ TenuredCell*

View File

@ -714,7 +714,7 @@ js::Nursery::freeMallocedBuffers()
AutoLockHelperThreadState lock;
freeMallocedBuffersTask->joinWithLockHeld(lock);
freeMallocedBuffersTask->transferBuffersToFree(mallocedBuffers, lock);
started = freeMallocedBuffersTask->startWithLockHeld();
started = freeMallocedBuffersTask->startWithLockHeld(lock);
}
if (!started)

View File

@ -474,10 +474,9 @@ JitCompartment::ensureIonStubsExist(JSContext* cx)
}
void
jit::FinishOffThreadBuilder(JSRuntime* runtime, IonBuilder* builder)
jit::FinishOffThreadBuilder(JSRuntime* runtime, IonBuilder* builder,
const AutoLockHelperThreadState& locked)
{
MOZ_ASSERT(HelperThreadState().isLocked());
// Clean the references to the pending IonBuilder, if we just finished it.
if (builder->script()->baselineScript()->hasPendingIonBuilder() &&
builder->script()->baselineScript()->pendingIonBuilder() == builder)
@ -515,12 +514,12 @@ static inline void
FinishAllOffThreadCompilations(JSCompartment* comp)
{
AutoLockHelperThreadState lock;
GlobalHelperThreadState::IonBuilderVector& finished = HelperThreadState().ionFinishedList();
GlobalHelperThreadState::IonBuilderVector& finished = HelperThreadState().ionFinishedList(lock);
for (size_t i = 0; i < finished.length(); i++) {
IonBuilder* builder = finished[i];
if (builder->compartment == CompileCompartment::get(comp)) {
FinishOffThreadBuilder(nullptr, builder);
FinishOffThreadBuilder(nullptr, builder, lock);
HelperThreadState().remove(finished, &i);
}
}
@ -590,7 +589,7 @@ jit::LinkIonScript(JSContext* cx, HandleScript calleeScript)
{
AutoLockHelperThreadState lock;
FinishOffThreadBuilder(cx->runtime(), builder);
FinishOffThreadBuilder(cx->runtime(), builder, lock);
}
}
@ -2052,7 +2051,7 @@ AttachFinishedCompilations(JSContext* cx)
{
AutoLockHelperThreadState lock;
GlobalHelperThreadState::IonBuilderVector& finished = HelperThreadState().ionFinishedList();
GlobalHelperThreadState::IonBuilderVector& finished = HelperThreadState().ionFinishedList(lock);
// Incorporate any off thread compilations for the compartment which have
// finished, failed or have been cancelled.
@ -3539,4 +3538,3 @@ jit::JitSupportsAtomics()
// If you change these, please also change the comment in TempAllocator.
/* static */ const size_t TempAllocator::BallastSize = 16 * 1024;
/* static */ const size_t TempAllocator::PreferredLifoChunkSize = 32 * 1024;

View File

@ -153,7 +153,8 @@ CodeGenerator* GenerateCode(MIRGenerator* mir, LIRGraph* lir);
CodeGenerator* CompileBackEnd(MIRGenerator* mir);
void AttachFinishedCompilations(JSContext* cx);
void FinishOffThreadBuilder(JSRuntime* runtime, IonBuilder* builder);
void FinishOffThreadBuilder(JSRuntime* runtime, IonBuilder* builder,
const AutoLockHelperThreadState& lock);
void StopAllOffThreadCompilations(Zone* zone);
void StopAllOffThreadCompilations(JSCompartment* comp);

View File

@ -3289,18 +3289,19 @@ GCHelperState::setState(State state, const AutoLockGC&)
}
void
GCHelperState::startBackgroundThread(State newState, const AutoLockGC& lock)
GCHelperState::startBackgroundThread(State newState, const AutoLockGC& lock,
const AutoLockHelperThreadState& helperLock)
{
MOZ_ASSERT(!thread && state(lock) == IDLE && newState != IDLE);
setState(newState, lock);
{
AutoEnterOOMUnsafeRegion noOOM;
if (!HelperThreadState().gcHelperWorklist().append(this))
if (!HelperThreadState().gcHelperWorklist(helperLock).append(this))
noOOM.crash("Could not add to pending GC helpers list");
}
HelperThreadState().notifyAll(GlobalHelperThreadState::PRODUCER);
HelperThreadState().notifyAll(GlobalHelperThreadState::PRODUCER, helperLock);
}
void
@ -3348,7 +3349,7 @@ GCRuntime::queueZonesForBackgroundSweep(ZoneList& zones)
AutoLockHelperThreadState helperLock;
AutoLockGC lock(rt);
backgroundSweepZones.transferFrom(zones);
helperState.maybeStartBackgroundSweep(lock);
helperState.maybeStartBackgroundSweep(lock, helperLock);
}
void
@ -3375,12 +3376,13 @@ GCRuntime::freeAllLifoBlocksAfterMinorGC(LifoAlloc* lifo)
}
void
GCHelperState::maybeStartBackgroundSweep(const AutoLockGC& lock)
GCHelperState::maybeStartBackgroundSweep(const AutoLockGC& lock,
const AutoLockHelperThreadState& helperLock)
{
MOZ_ASSERT(CanUseExtraThreads());
if (state(lock) == IDLE)
startBackgroundThread(SWEEPING, lock);
startBackgroundThread(SWEEPING, lock, helperLock);
}
void
@ -4883,8 +4885,7 @@ SweepMiscTask::run()
void
GCRuntime::startTask(GCParallelTask& task, gcstats::Phase phase, AutoLockHelperThreadState& locked)
{
MOZ_ASSERT(HelperThreadState().isLocked());
if (!task.startWithLockHeld()) {
if (!task.startWithLockHeld(locked)) {
AutoUnlockHelperThreadState unlock(locked);
gcstats::AutoPhase ap(stats, phase);
task.runFromMainThread(rt);
@ -5598,7 +5599,7 @@ AutoTraceSession::~AutoTraceSession()
runtime->heapState_ = prevState;
// Notify any helper threads waiting for the trace session to end.
HelperThreadState().notifyAll(GlobalHelperThreadState::PRODUCER);
HelperThreadState().notifyAll(GlobalHelperThreadState::PRODUCER, lock);
} else {
runtime->heapState_ = prevState;
}

View File

@ -865,7 +865,8 @@ class GCHelperState
// Thread which work is being performed on, or null.
PRThread* thread;
void startBackgroundThread(State newState, const js::AutoLockGC&);
void startBackgroundThread(State newState, const AutoLockGC& lock,
const AutoLockHelperThreadState& helperLock);
void waitForBackgroundThread(js::AutoLockGC& lock);
State state(const AutoLockGC&);
@ -894,7 +895,8 @@ class GCHelperState
void work();
void maybeStartBackgroundSweep(const AutoLockGC& lock);
void maybeStartBackgroundSweep(const AutoLockGC& lock,
const AutoLockHelperThreadState& helperLock);
void startBackgroundShrink(const AutoLockGC& lock);
/* Must be called without the GC lock taken. */
@ -955,7 +957,7 @@ class GCParallelTask
// If multiple tasks are to be started or joined at once, it is more
// efficient to take the helper thread lock once and use these methods.
bool startWithLockHeld();
bool startWithLockHeld(AutoLockHelperThreadState& locked);
void joinWithLockHeld(AutoLockHelperThreadState& locked);
// Instead of dispatching to a helper, run the task on the main thread.

View File

@ -86,13 +86,13 @@ js::StartOffThreadWasmCompile(wasm::IonCompileTask* task)
AutoLockHelperThreadState lock;
// Don't append this task if another failed.
if (HelperThreadState().wasmFailed())
if (HelperThreadState().wasmFailed(lock))
return false;
if (!HelperThreadState().wasmWorklist().append(task))
if (!HelperThreadState().wasmWorklist(lock).append(task))
return false;
HelperThreadState().notifyOne(GlobalHelperThreadState::PRODUCER);
HelperThreadState().notifyOne(GlobalHelperThreadState::PRODUCER, lock);
return true;
}
@ -101,10 +101,10 @@ js::StartOffThreadIonCompile(JSContext* cx, jit::IonBuilder* builder)
{
AutoLockHelperThreadState lock;
if (!HelperThreadState().ionWorklist().append(builder))
if (!HelperThreadState().ionWorklist(lock).append(builder))
return false;
HelperThreadState().notifyOne(GlobalHelperThreadState::PRODUCER);
HelperThreadState().notifyOne(GlobalHelperThreadState::PRODUCER, lock);
return true;
}
@ -114,10 +114,10 @@ js::StartOffThreadIonCompile(JSContext* cx, jit::IonBuilder* builder)
* compilations which are started must eventually be finished.
*/
static void
FinishOffThreadIonCompile(jit::IonBuilder* builder)
FinishOffThreadIonCompile(jit::IonBuilder* builder, const AutoLockHelperThreadState& lock)
{
AutoEnterOOMUnsafeRegion oomUnsafe;
if (!HelperThreadState().ionFinishedList().append(builder))
if (!HelperThreadState().ionFinishedList(lock).append(builder))
oomUnsafe.crash("FinishOffThreadIonCompile");
}
@ -143,11 +143,11 @@ js::CancelOffThreadIonCompile(JSCompartment* compartment, JSScript* script, bool
return;
/* Cancel any pending entries for which processing hasn't started. */
GlobalHelperThreadState::IonBuilderVector& worklist = HelperThreadState().ionWorklist();
GlobalHelperThreadState::IonBuilderVector& worklist = HelperThreadState().ionWorklist(lock);
for (size_t i = 0; i < worklist.length(); i++) {
jit::IonBuilder* builder = worklist[i];
if (CompiledScriptMatches(compartment, script, builder->script())) {
FinishOffThreadIonCompile(builder);
FinishOffThreadIonCompile(builder, lock);
HelperThreadState().remove(worklist, &i);
}
}
@ -161,18 +161,18 @@ js::CancelOffThreadIonCompile(JSCompartment* compartment, JSScript* script, bool
helper.ionBuilder()->cancel();
if (helper.pause) {
helper.pause = false;
HelperThreadState().notifyAll(GlobalHelperThreadState::PAUSE);
HelperThreadState().notifyAll(GlobalHelperThreadState::PAUSE, lock);
}
HelperThreadState().wait(lock, GlobalHelperThreadState::CONSUMER);
}
}
/* Cancel code generation for any completed entries. */
GlobalHelperThreadState::IonBuilderVector& finished = HelperThreadState().ionFinishedList();
GlobalHelperThreadState::IonBuilderVector& finished = HelperThreadState().ionFinishedList(lock);
for (size_t i = 0; i < finished.length(); i++) {
jit::IonBuilder* builder = finished[i];
if (CompiledScriptMatches(compartment, script, builder->script())) {
jit::FinishOffThreadBuilder(nullptr, builder);
jit::FinishOffThreadBuilder(nullptr, builder, lock);
HelperThreadState().remove(finished, &i);
}
}
@ -185,7 +185,7 @@ js::CancelOffThreadIonCompile(JSCompartment* compartment, JSScript* script, bool
while (builder) {
jit::IonBuilder* next = builder->getNext();
if (CompiledScriptMatches(compartment, script, builder->script()))
jit::FinishOffThreadBuilder(runtime, builder);
jit::FinishOffThreadBuilder(runtime, builder, lock);
builder = next;
}
}
@ -308,7 +308,8 @@ js::CancelOffThreadParses(JSRuntime* rt)
return;
#ifdef DEBUG
GlobalHelperThreadState::ParseTaskVector& waitingOnGC = HelperThreadState().parseWaitingOnGC();
GlobalHelperThreadState::ParseTaskVector& waitingOnGC =
HelperThreadState().parseWaitingOnGC(lock);
for (size_t i = 0; i < waitingOnGC.length(); i++)
MOZ_ASSERT(!waitingOnGC[i]->runtimeMatches(rt));
#endif
@ -318,7 +319,7 @@ js::CancelOffThreadParses(JSRuntime* rt)
// everything due to zones being used off thread.
while (true) {
bool pending = false;
GlobalHelperThreadState::ParseTaskVector& worklist = HelperThreadState().parseWorklist();
GlobalHelperThreadState::ParseTaskVector& worklist = HelperThreadState().parseWorklist(lock);
for (size_t i = 0; i < worklist.length(); i++) {
ParseTask* task = worklist[i];
if (task->runtimeMatches(rt))
@ -338,7 +339,7 @@ js::CancelOffThreadParses(JSRuntime* rt)
}
// Clean up any parse tasks which haven't been finished by the main thread.
GlobalHelperThreadState::ParseTaskVector& finished = HelperThreadState().parseFinishedList();
GlobalHelperThreadState::ParseTaskVector& finished = HelperThreadState().parseFinishedList(lock);
while (true) {
bool found = false;
for (size_t i = 0; i < finished.length(); i++) {
@ -448,19 +449,19 @@ QueueOffThreadParseTask(JSContext* cx, ParseTask* task)
{
if (OffThreadParsingMustWaitForGC(cx->runtime())) {
AutoLockHelperThreadState lock;
if (!HelperThreadState().parseWaitingOnGC().append(task)) {
if (!HelperThreadState().parseWaitingOnGC(lock).append(task)) {
ReportOutOfMemory(cx);
return false;
}
} else {
AutoLockHelperThreadState lock;
if (!HelperThreadState().parseWorklist().append(task)) {
if (!HelperThreadState().parseWorklist(lock).append(task)) {
ReportOutOfMemory(cx);
return false;
}
task->activate(cx->runtime());
HelperThreadState().notifyOne(GlobalHelperThreadState::PRODUCER);
HelperThreadState().notifyOne(GlobalHelperThreadState::PRODUCER, lock);
}
return true;
@ -548,7 +549,8 @@ js::EnqueuePendingParseTasksAfterGC(JSRuntime* rt)
GlobalHelperThreadState::ParseTaskVector newTasks;
{
AutoLockHelperThreadState lock;
GlobalHelperThreadState::ParseTaskVector& waiting = HelperThreadState().parseWaitingOnGC();
GlobalHelperThreadState::ParseTaskVector& waiting =
HelperThreadState().parseWaitingOnGC(lock);
for (size_t i = 0; i < waiting.length(); i++) {
ParseTask* task = waiting[i];
@ -574,11 +576,11 @@ js::EnqueuePendingParseTasksAfterGC(JSRuntime* rt)
{
AutoEnterOOMUnsafeRegion oomUnsafe;
if (!HelperThreadState().parseWorklist().appendAll(newTasks))
if (!HelperThreadState().parseWorklist(lock).appendAll(newTasks))
oomUnsafe.crash("EnqueuePendingParseTasksAfterGC");
}
HelperThreadState().notifyAll(GlobalHelperThreadState::PRODUCER);
HelperThreadState().notifyAll(GlobalHelperThreadState::PRODUCER, lock);
}
static const uint32_t kDefaultHelperStackSize = 2048 * 1024;
@ -667,64 +669,38 @@ GlobalHelperThreadState::finishThreads()
void
GlobalHelperThreadState::lock()
{
MOZ_ASSERT(!isLocked());
AssertCurrentThreadCanLock(HelperThreadStateLock);
helperLock.lock();
#ifdef DEBUG
lockOwner = PR_GetCurrentThread();
#endif
}
void
GlobalHelperThreadState::unlock()
{
MOZ_ASSERT(isLocked());
#ifdef DEBUG
lockOwner = nullptr;
#endif
helperLock.unlock();
}
#ifdef DEBUG
bool
GlobalHelperThreadState::isLocked()
{
return lockOwner == PR_GetCurrentThread();
}
#endif
void
GlobalHelperThreadState::wait(AutoLockHelperThreadState& locked, CondVar which,
TimeDuration timeout /* = TimeDuration::Forever() */)
{
MOZ_ASSERT(isLocked());
#ifdef DEBUG
lockOwner = nullptr;
#endif
whichWakeup(which).wait_for(locked, timeout);
#ifdef DEBUG
lockOwner = PR_GetCurrentThread();
#endif
}
void
GlobalHelperThreadState::notifyAll(CondVar which)
GlobalHelperThreadState::notifyAll(CondVar which, const AutoLockHelperThreadState&)
{
MOZ_ASSERT(isLocked());
whichWakeup(which).notify_all();
}
void
GlobalHelperThreadState::notifyOne(CondVar which)
GlobalHelperThreadState::notifyOne(CondVar which, const AutoLockHelperThreadState&)
{
MOZ_ASSERT(isLocked());
whichWakeup(which).notify_one();
}
bool
GlobalHelperThreadState::hasActiveThreads()
GlobalHelperThreadState::hasActiveThreads(const AutoLockHelperThreadState&)
{
MOZ_ASSERT(isLocked());
if (!threads)
return false;
@ -742,7 +718,7 @@ GlobalHelperThreadState::waitForAllThreads()
CancelOffThreadIonCompile(nullptr, nullptr, /* discardLazyLinkList = */ false);
AutoLockHelperThreadState lock;
while (hasActiveThreads())
while (hasActiveThreads(lock))
wait(lock, CONSUMER);
}
@ -836,11 +812,10 @@ GlobalHelperThreadState::maxGCParallelThreads() const
}
bool
GlobalHelperThreadState::canStartWasmCompile()
GlobalHelperThreadState::canStartWasmCompile(const AutoLockHelperThreadState& lock)
{
// Don't execute an wasm job if an earlier one failed.
MOZ_ASSERT(isLocked());
if (wasmWorklist().empty() || numWasmFailedJobs)
if (wasmWorklist(lock).empty() || numWasmFailedJobs)
return false;
// Honor the maximum allowed threads to compile wasm jobs at once,
@ -871,39 +846,38 @@ IonBuilderHasHigherPriority(jit::IonBuilder* first, jit::IonBuilder* second)
}
bool
GlobalHelperThreadState::canStartIonCompile()
GlobalHelperThreadState::canStartIonCompile(const AutoLockHelperThreadState& lock)
{
return !ionWorklist().empty() &&
return !ionWorklist(lock).empty() &&
checkTaskThreadLimit<jit::IonBuilder*>(maxIonCompilationThreads());
}
jit::IonBuilder*
GlobalHelperThreadState::highestPriorityPendingIonCompile(bool remove /* = false */)
GlobalHelperThreadState::highestPriorityPendingIonCompile(const AutoLockHelperThreadState& lock,
bool remove /* = false */)
{
MOZ_ASSERT(isLocked());
if (ionWorklist().empty()) {
auto& worklist = ionWorklist(lock);
if (worklist.empty()) {
MOZ_ASSERT(!remove);
return nullptr;
}
// Get the highest priority IonBuilder which has not started compilation yet.
size_t index = 0;
for (size_t i = 1; i < ionWorklist().length(); i++) {
if (IonBuilderHasHigherPriority(ionWorklist()[i], ionWorklist()[index]))
for (size_t i = 1; i < worklist.length(); i++) {
if (IonBuilderHasHigherPriority(worklist[i], worklist[index]))
index = i;
}
jit::IonBuilder* builder = ionWorklist()[index];
jit::IonBuilder* builder = worklist[index];
if (remove)
ionWorklist().erase(&ionWorklist()[index]);
worklist.erase(&worklist[index]);
return builder;
}
HelperThread*
GlobalHelperThreadState::lowestPriorityUnpausedIonCompileAtThreshold()
GlobalHelperThreadState::lowestPriorityUnpausedIonCompileAtThreshold(
const AutoLockHelperThreadState& lock)
{
MOZ_ASSERT(isLocked());
// Get the lowest priority IonBuilder which has started compilation and
// isn't paused, unless there are still fewer than the maximum number of
// such builders permitted.
@ -922,10 +896,8 @@ GlobalHelperThreadState::lowestPriorityUnpausedIonCompileAtThreshold()
}
HelperThread*
GlobalHelperThreadState::highestPriorityPausedIonCompile()
GlobalHelperThreadState::highestPriorityPausedIonCompile(const AutoLockHelperThreadState& lock)
{
MOZ_ASSERT(isLocked());
// Get the highest priority IonBuilder which has started compilation but
// which was subsequently paused.
HelperThread* thread = nullptr;
@ -941,17 +913,16 @@ GlobalHelperThreadState::highestPriorityPausedIonCompile()
}
bool
GlobalHelperThreadState::pendingIonCompileHasSufficientPriority()
GlobalHelperThreadState::pendingIonCompileHasSufficientPriority(
const AutoLockHelperThreadState& lock)
{
MOZ_ASSERT(isLocked());
// Can't compile anything if there are no scripts to compile.
if (!canStartIonCompile())
if (!canStartIonCompile(lock))
return false;
// Count the number of threads currently compiling scripts, and look for
// the thread with the lowest priority.
HelperThread* lowestPriorityThread = lowestPriorityUnpausedIonCompileAtThreshold();
HelperThread* lowestPriorityThread = lowestPriorityUnpausedIonCompileAtThreshold(lock);
// If the number of threads building scripts is less than the maximum, the
// compilation can start immediately.
@ -961,7 +932,7 @@ GlobalHelperThreadState::pendingIonCompileHasSufficientPriority()
// If there is a builder in the worklist with higher priority than some
// builder currently being compiled, then that current compilation can be
// paused, so allow the compilation.
if (IonBuilderHasHigherPriority(highestPriorityPendingIonCompile(),
if (IonBuilderHasHigherPriority(highestPriorityPendingIonCompile(lock),
lowestPriorityThread->ionBuilder()))
return true;
@ -970,30 +941,29 @@ GlobalHelperThreadState::pendingIonCompileHasSufficientPriority()
}
bool
GlobalHelperThreadState::canStartParseTask()
GlobalHelperThreadState::canStartParseTask(const AutoLockHelperThreadState& lock)
{
MOZ_ASSERT(isLocked());
return !parseWorklist().empty() && checkTaskThreadLimit<ParseTask*>(maxParseThreads());
return !parseWorklist(lock).empty() && checkTaskThreadLimit<ParseTask*>(maxParseThreads());
}
bool
GlobalHelperThreadState::canStartCompressionTask()
GlobalHelperThreadState::canStartCompressionTask(const AutoLockHelperThreadState& lock)
{
return !compressionWorklist().empty() &&
return !compressionWorklist(lock).empty() &&
checkTaskThreadLimit<SourceCompressionTask*>(maxCompressionThreads());
}
bool
GlobalHelperThreadState::canStartGCHelperTask()
GlobalHelperThreadState::canStartGCHelperTask(const AutoLockHelperThreadState& lock)
{
return !gcHelperWorklist().empty() &&
return !gcHelperWorklist(lock).empty() &&
checkTaskThreadLimit<GCHelperState*>(maxGCHelperThreads());
}
bool
GlobalHelperThreadState::canStartGCParallelTask()
GlobalHelperThreadState::canStartGCParallelTask(const AutoLockHelperThreadState& lock)
{
return !gcParallelWorklist().empty() &&
return !gcParallelWorklist(lock).empty() &&
checkTaskThreadLimit<GCParallelTask*>(maxGCParallelThreads());
}
@ -1010,10 +980,8 @@ js::GCParallelTask::~GCParallelTask()
}
bool
js::GCParallelTask::startWithLockHeld()
js::GCParallelTask::startWithLockHeld(AutoLockHelperThreadState& lock)
{
MOZ_ASSERT(HelperThreadState().isLocked());
// Tasks cannot be started twice.
MOZ_ASSERT(state == NotStarted);
@ -1023,11 +991,11 @@ js::GCParallelTask::startWithLockHeld()
if (!HelperThreadState().threads)
return false;
if (!HelperThreadState().gcParallelWorklist().append(this))
if (!HelperThreadState().gcParallelWorklist(lock).append(this))
return false;
state = Dispatched;
HelperThreadState().notifyOne(GlobalHelperThreadState::PRODUCER);
HelperThreadState().notifyOne(GlobalHelperThreadState::PRODUCER, lock);
return true;
}
@ -1036,14 +1004,12 @@ bool
js::GCParallelTask::start()
{
AutoLockHelperThreadState helperLock;
return startWithLockHeld();
return startWithLockHeld(helperLock);
}
void
js::GCParallelTask::joinWithLockHeld(AutoLockHelperThreadState& locked)
{
MOZ_ASSERT(HelperThreadState().isLocked());
if (state == NotStarted)
return;
@ -1073,8 +1039,6 @@ js::GCParallelTask::runFromMainThread(JSRuntime* rt)
void
js::GCParallelTask::runFromHelperThread(AutoLockHelperThreadState& locked)
{
MOZ_ASSERT(HelperThreadState().isLocked());
{
AutoUnlockHelperThreadState parallelSection(locked);
uint64_t timeStart = PRMJ_Now();
@ -1083,13 +1047,12 @@ js::GCParallelTask::runFromHelperThread(AutoLockHelperThreadState& locked)
}
state = Finished;
HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER);
HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER, locked);
}
bool
js::GCParallelTask::isRunningWithLockHeld(const AutoLockHelperThreadState& locked) const
{
MOZ_ASSERT(HelperThreadState().isLocked());
return state == Dispatched;
}
@ -1103,17 +1066,16 @@ js::GCParallelTask::isRunning() const
void
HelperThread::handleGCParallelWorkload(AutoLockHelperThreadState& locked)
{
MOZ_ASSERT(HelperThreadState().isLocked());
MOZ_ASSERT(HelperThreadState().canStartGCParallelTask());
MOZ_ASSERT(HelperThreadState().canStartGCParallelTask(locked));
MOZ_ASSERT(idle());
TraceLoggerThread* logger = TraceLoggerForCurrentThread();
AutoTraceLog logCompile(logger, TraceLogger_GC);
currentTask.emplace(HelperThreadState().gcParallelWorklist().popCopy());
currentTask.emplace(HelperThreadState().gcParallelWorklist(locked).popCopy());
gcParallelTask()->runFromHelperThread(locked);
currentTask.reset();
HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER);
HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER, locked);
}
static void
@ -1132,7 +1094,7 @@ GlobalHelperThreadState::removeFinishedParseTask(ParseTaskKind kind, void* token
// Find and remove its entry.
AutoLockHelperThreadState lock;
ParseTaskVector& finished = parseFinishedList();
ParseTaskVector& finished = parseFinishedList(lock);
for (size_t i = 0; i < finished.length(); i++) {
if (finished[i] == token) {
@ -1310,7 +1272,7 @@ HelperThread::destroy()
terminate = true;
/* Notify all helpers, to ensure that this thread wakes up. */
HelperThreadState().notifyAll(GlobalHelperThreadState::PRODUCER);
HelperThreadState().notifyAll(GlobalHelperThreadState::PRODUCER, lock);
}
PR_JoinThread(thread);
@ -1351,11 +1313,10 @@ HelperThread::ThreadMain(void* arg)
void
HelperThread::handleWasmWorkload(AutoLockHelperThreadState& locked)
{
MOZ_ASSERT(HelperThreadState().isLocked());
MOZ_ASSERT(HelperThreadState().canStartWasmCompile());
MOZ_ASSERT(HelperThreadState().canStartWasmCompile(locked));
MOZ_ASSERT(idle());
currentTask.emplace(HelperThreadState().wasmWorklist().popCopy());
currentTask.emplace(HelperThreadState().wasmWorklist(locked).popCopy());
bool success = false;
wasm::IonCompileTask* task = wasmTask();
@ -1366,35 +1327,35 @@ HelperThread::handleWasmWorkload(AutoLockHelperThreadState& locked)
// On success, try to move work to the finished list.
if (success)
success = HelperThreadState().wasmFinishedList().append(task);
success = HelperThreadState().wasmFinishedList(locked).append(task);
// On failure, note the failure for harvesting by the parent.
if (!success)
HelperThreadState().noteWasmFailure();
HelperThreadState().noteWasmFailure(locked);
// Notify the main thread in case it's waiting.
HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER);
HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER, locked);
currentTask.reset();
}
void
HelperThread::handleIonWorkload(AutoLockHelperThreadState& locked)
{
MOZ_ASSERT(HelperThreadState().isLocked());
MOZ_ASSERT(HelperThreadState().canStartIonCompile());
MOZ_ASSERT(HelperThreadState().canStartIonCompile(locked));
MOZ_ASSERT(idle());
// Find the IonBuilder in the worklist with the highest priority, and
// remove it from the worklist.
jit::IonBuilder* builder =
HelperThreadState().highestPriorityPendingIonCompile(/* remove = */ true);
HelperThreadState().highestPriorityPendingIonCompile(locked, /* remove = */ true);
// If there are now too many threads with active IonBuilders, indicate to
// the one with the lowest priority that it should pause. Note that due to
// builder priorities changing since pendingIonCompileHasSufficientPriority
// was called, the builder we are pausing may actually be higher priority
// than the one we are about to start. Oh well.
if (HelperThread* other = HelperThreadState().lowestPriorityUnpausedIonCompileAtThreshold()) {
HelperThread* other = HelperThreadState().lowestPriorityUnpausedIonCompileAtThreshold(locked);
if (other) {
MOZ_ASSERT(other->ionBuilder() && !other->pause);
other->pause = true;
}
@ -1420,7 +1381,7 @@ HelperThread::handleIonWorkload(AutoLockHelperThreadState& locked)
builder->setBackgroundCodegen(jit::CompileBackEnd(builder));
}
FinishOffThreadIonCompile(builder);
FinishOffThreadIonCompile(builder, locked);
currentTask.reset();
pause = false;
@ -1431,7 +1392,7 @@ HelperThread::handleIonWorkload(AutoLockHelperThreadState& locked)
rt->requestInterrupt(JSRuntime::RequestInterruptCanWait);
// Notify the main thread in case it is waiting for the compilation to finish.
HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER);
HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER, locked);
// When finishing Ion compilation jobs, we can start unpausing compilation
// threads that were paused to restrict the number of active compilations.
@ -1440,18 +1401,18 @@ HelperThread::handleIonWorkload(AutoLockHelperThreadState& locked)
// strategy will eventually unpause all paused threads, regardless of how
// many there are, since each thread we unpause will eventually finish and
// end up back here.
if (HelperThread* other = HelperThreadState().highestPriorityPausedIonCompile()) {
if (HelperThread* other = HelperThreadState().highestPriorityPausedIonCompile(locked)) {
MOZ_ASSERT(other->ionBuilder() && other->pause);
// Only unpause the other thread if there isn't a higher priority
// builder which this thread or another can start on.
jit::IonBuilder* builder = HelperThreadState().highestPriorityPendingIonCompile();
jit::IonBuilder* builder = HelperThreadState().highestPriorityPendingIonCompile(locked);
if (!builder || IonBuilderHasHigherPriority(other->ionBuilder(), builder)) {
other->pause = false;
// Notify all paused threads, to make sure the one we just
// unpaused wakes up.
HelperThreadState().notifyAll(GlobalHelperThreadState::PAUSE);
HelperThreadState().notifyAll(GlobalHelperThreadState::PAUSE, locked);
}
}
}
@ -1521,11 +1482,10 @@ ExclusiveContext::addPendingOutOfMemory()
void
HelperThread::handleParseWorkload(AutoLockHelperThreadState& locked)
{
MOZ_ASSERT(HelperThreadState().isLocked());
MOZ_ASSERT(HelperThreadState().canStartParseTask());
MOZ_ASSERT(HelperThreadState().canStartParseTask(locked));
MOZ_ASSERT(idle());
currentTask.emplace(HelperThreadState().parseWorklist().popCopy());
currentTask.emplace(HelperThreadState().parseWorklist(locked).popCopy());
ParseTask* task = parseTask();
task->cx->setHelperThread(this);
@ -1543,24 +1503,23 @@ HelperThread::handleParseWorkload(AutoLockHelperThreadState& locked)
// migrate it into the correct compartment.
{
AutoEnterOOMUnsafeRegion oomUnsafe;
if (!HelperThreadState().parseFinishedList().append(task))
if (!HelperThreadState().parseFinishedList(locked).append(task))
oomUnsafe.crash("handleParseWorkload");
}
currentTask.reset();
// Notify the main thread in case it is waiting for the parse/emit to finish.
HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER);
HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER, locked);
}
void
HelperThread::handleCompressionWorkload(AutoLockHelperThreadState& locked)
{
MOZ_ASSERT(HelperThreadState().isLocked());
MOZ_ASSERT(HelperThreadState().canStartCompressionTask());
MOZ_ASSERT(HelperThreadState().canStartCompressionTask(locked));
MOZ_ASSERT(idle());
currentTask.emplace(HelperThreadState().compressionWorklist().popCopy());
currentTask.emplace(HelperThreadState().compressionWorklist(locked).popCopy());
SourceCompressionTask* task = compressionTask();
task->helperThread = this;
@ -1577,7 +1536,7 @@ HelperThread::handleCompressionWorkload(AutoLockHelperThreadState& locked)
currentTask.reset();
// Notify the main thread in case it is waiting for the compression to finish.
HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER);
HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER, locked);
}
bool
@ -1585,22 +1544,22 @@ js::StartOffThreadCompression(ExclusiveContext* cx, SourceCompressionTask* task)
{
AutoLockHelperThreadState lock;
if (!HelperThreadState().compressionWorklist().append(task)) {
if (!HelperThreadState().compressionWorklist(lock).append(task)) {
if (JSContext* maybecx = cx->maybeJSContext())
ReportOutOfMemory(maybecx);
return false;
}
HelperThreadState().notifyOne(GlobalHelperThreadState::PRODUCER);
HelperThreadState().notifyOne(GlobalHelperThreadState::PRODUCER, lock);
return true;
}
bool
GlobalHelperThreadState::compressionInProgress(SourceCompressionTask* task)
GlobalHelperThreadState::compressionInProgress(SourceCompressionTask* task,
const AutoLockHelperThreadState& lock)
{
MOZ_ASSERT(isLocked());
for (size_t i = 0; i < compressionWorklist().length(); i++) {
if (compressionWorklist()[i] == task)
for (size_t i = 0; i < compressionWorklist(lock).length(); i++) {
if (compressionWorklist(lock)[i] == task)
return true;
}
for (size_t i = 0; i < threadCount; i++) {
@ -1618,7 +1577,7 @@ SourceCompressionTask::complete()
{
AutoLockHelperThreadState lock;
while (HelperThreadState().compressionInProgress(this))
while (HelperThreadState().compressionInProgress(this, lock))
HelperThreadState().wait(lock, GlobalHelperThreadState::CONSUMER);
}
@ -1637,11 +1596,11 @@ SourceCompressionTask::complete()
}
SourceCompressionTask*
GlobalHelperThreadState::compressionTaskForSource(ScriptSource* ss)
GlobalHelperThreadState::compressionTaskForSource(ScriptSource* ss,
const AutoLockHelperThreadState& lock)
{
MOZ_ASSERT(isLocked());
for (size_t i = 0; i < compressionWorklist().length(); i++) {
SourceCompressionTask* task = compressionWorklist()[i];
for (size_t i = 0; i < compressionWorklist(lock).length(); i++) {
SourceCompressionTask* task = compressionWorklist(lock)[i];
if (task->source() == ss)
return task;
}
@ -1656,11 +1615,10 @@ GlobalHelperThreadState::compressionTaskForSource(ScriptSource* ss)
void
HelperThread::handleGCHelperWorkload(AutoLockHelperThreadState& locked)
{
MOZ_ASSERT(HelperThreadState().isLocked());
MOZ_ASSERT(HelperThreadState().canStartGCHelperTask());
MOZ_ASSERT(HelperThreadState().canStartGCHelperTask(locked));
MOZ_ASSERT(idle());
currentTask.emplace(HelperThreadState().gcHelperWorklist().popCopy());
currentTask.emplace(HelperThreadState().gcHelperWorklist(locked).popCopy());
GCHelperState* task = gcHelperTask();
{
@ -1669,7 +1627,7 @@ HelperThread::handleGCHelperWorkload(AutoLockHelperThreadState& locked)
}
currentTask.reset();
HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER);
HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER, locked);
}
void
@ -1702,12 +1660,12 @@ HelperThread::threadLoop()
while (true) {
if (terminate)
return;
if (HelperThreadState().canStartWasmCompile() ||
(ionCompile = HelperThreadState().pendingIonCompileHasSufficientPriority()) ||
HelperThreadState().canStartParseTask() ||
HelperThreadState().canStartCompressionTask() ||
HelperThreadState().canStartGCHelperTask() ||
HelperThreadState().canStartGCParallelTask())
if (HelperThreadState().canStartWasmCompile(lock) ||
(ionCompile = HelperThreadState().pendingIonCompileHasSufficientPriority(lock)) ||
HelperThreadState().canStartParseTask(lock) ||
HelperThreadState().canStartCompressionTask(lock) ||
HelperThreadState().canStartGCHelperTask(lock) ||
HelperThreadState().canStartGCParallelTask(lock))
{
break;
}
@ -1715,22 +1673,22 @@ HelperThread::threadLoop()
}
// Dispatch tasks, prioritizing wasm work.
if (HelperThreadState().canStartWasmCompile()) {
if (HelperThreadState().canStartWasmCompile(lock)) {
js::oom::SetThreadType(js::oom::THREAD_TYPE_ASMJS);
handleWasmWorkload(lock);
} else if (ionCompile) {
js::oom::SetThreadType(js::oom::THREAD_TYPE_ION);
handleIonWorkload(lock);
} else if (HelperThreadState().canStartParseTask()) {
} else if (HelperThreadState().canStartParseTask(lock)) {
js::oom::SetThreadType(js::oom::THREAD_TYPE_PARSE);
handleParseWorkload(lock);
} else if (HelperThreadState().canStartCompressionTask()) {
} else if (HelperThreadState().canStartCompressionTask(lock)) {
js::oom::SetThreadType(js::oom::THREAD_TYPE_COMPRESS);
handleCompressionWorkload(lock);
} else if (HelperThreadState().canStartGCHelperTask()) {
} else if (HelperThreadState().canStartGCHelperTask(lock)) {
js::oom::SetThreadType(js::oom::THREAD_TYPE_GCHELPER);
handleGCHelperWorkload(lock);
} else if (HelperThreadState().canStartGCParallelTask()) {
} else if (HelperThreadState().canStartGCParallelTask(lock)) {
js::oom::SetThreadType(js::oom::THREAD_TYPE_GCPARALLEL);
handleGCParallelWorkload(lock);
} else {

View File

@ -121,10 +121,6 @@ class GlobalHelperThreadState
void lock();
void unlock();
#ifdef DEBUG
bool isLocked();
#endif
enum CondVar {
// For notifying threads waiting for work that they may be able to make progress.
CONSUMER,
@ -139,8 +135,8 @@ class GlobalHelperThreadState
void wait(AutoLockHelperThreadState& locked, CondVar which,
mozilla::TimeDuration timeout = mozilla::TimeDuration::Forever());
void notifyAll(CondVar which);
void notifyOne(CondVar which);
void notifyAll(CondVar which, const AutoLockHelperThreadState&);
void notifyOne(CondVar which, const AutoLockHelperThreadState&);
// Helper method for removing items from the vectors below while iterating over them.
template <typename T>
@ -150,80 +146,69 @@ class GlobalHelperThreadState
vector.popBack();
}
IonBuilderVector& ionWorklist() {
MOZ_ASSERT(isLocked());
IonBuilderVector& ionWorklist(const AutoLockHelperThreadState&) {
return ionWorklist_;
}
IonBuilderVector& ionFinishedList() {
MOZ_ASSERT(isLocked());
IonBuilderVector& ionFinishedList(const AutoLockHelperThreadState&) {
return ionFinishedList_;
}
wasm::IonCompileTaskPtrVector& wasmWorklist() {
MOZ_ASSERT(isLocked());
wasm::IonCompileTaskPtrVector& wasmWorklist(const AutoLockHelperThreadState&) {
return wasmWorklist_;
}
wasm::IonCompileTaskPtrVector& wasmFinishedList() {
MOZ_ASSERT(isLocked());
wasm::IonCompileTaskPtrVector& wasmFinishedList(const AutoLockHelperThreadState&) {
return wasmFinishedList_;
}
ParseTaskVector& parseWorklist() {
MOZ_ASSERT(isLocked());
ParseTaskVector& parseWorklist(const AutoLockHelperThreadState&) {
return parseWorklist_;
}
ParseTaskVector& parseFinishedList() {
MOZ_ASSERT(isLocked());
ParseTaskVector& parseFinishedList(const AutoLockHelperThreadState&) {
return parseFinishedList_;
}
ParseTaskVector& parseWaitingOnGC() {
MOZ_ASSERT(isLocked());
ParseTaskVector& parseWaitingOnGC(const AutoLockHelperThreadState&) {
return parseWaitingOnGC_;
}
SourceCompressionTaskVector& compressionWorklist() {
MOZ_ASSERT(isLocked());
SourceCompressionTaskVector& compressionWorklist(const AutoLockHelperThreadState&) {
return compressionWorklist_;
}
GCHelperStateVector& gcHelperWorklist() {
MOZ_ASSERT(isLocked());
GCHelperStateVector& gcHelperWorklist(const AutoLockHelperThreadState&) {
return gcHelperWorklist_;
}
GCParallelTaskVector& gcParallelWorklist() {
MOZ_ASSERT(isLocked());
GCParallelTaskVector& gcParallelWorklist(const AutoLockHelperThreadState&) {
return gcParallelWorklist_;
}
bool canStartWasmCompile();
bool canStartIonCompile();
bool canStartParseTask();
bool canStartCompressionTask();
bool canStartGCHelperTask();
bool canStartGCParallelTask();
bool canStartWasmCompile(const AutoLockHelperThreadState& lock);
bool canStartIonCompile(const AutoLockHelperThreadState& lock);
bool canStartParseTask(const AutoLockHelperThreadState& lock);
bool canStartCompressionTask(const AutoLockHelperThreadState& lock);
bool canStartGCHelperTask(const AutoLockHelperThreadState& lock);
bool canStartGCParallelTask(const AutoLockHelperThreadState& lock);
// Unlike the methods above, the value returned by this method can change
// over time, even if the helper thread state lock is held throughout.
bool pendingIonCompileHasSufficientPriority();
bool pendingIonCompileHasSufficientPriority(const AutoLockHelperThreadState& lock);
jit::IonBuilder* highestPriorityPendingIonCompile(bool remove = false);
HelperThread* lowestPriorityUnpausedIonCompileAtThreshold();
HelperThread* highestPriorityPausedIonCompile();
jit::IonBuilder* highestPriorityPendingIonCompile(const AutoLockHelperThreadState& lock,
bool remove = false);
HelperThread* lowestPriorityUnpausedIonCompileAtThreshold(
const AutoLockHelperThreadState& lock);
HelperThread* highestPriorityPausedIonCompile(const AutoLockHelperThreadState& lock);
uint32_t harvestFailedWasmJobs() {
MOZ_ASSERT(isLocked());
uint32_t harvestFailedWasmJobs(const AutoLockHelperThreadState&) {
uint32_t n = numWasmFailedJobs;
numWasmFailedJobs = 0;
return n;
}
void noteWasmFailure() {
void noteWasmFailure(const AutoLockHelperThreadState&) {
// Be mindful to signal the main thread after calling this function.
MOZ_ASSERT(isLocked());
numWasmFailedJobs++;
}
bool wasmFailed() {
MOZ_ASSERT(isLocked());
bool wasmFailed(const AutoLockHelperThreadState&) {
return bool(numWasmFailedJobs);
}
@ -244,10 +229,10 @@ class GlobalHelperThreadState
public:
JSScript* finishScriptParseTask(JSContext* cx, void* token);
JSObject* finishModuleParseTask(JSContext* cx, void* token);
bool compressionInProgress(SourceCompressionTask* task);
SourceCompressionTask* compressionTaskForSource(ScriptSource* ss);
bool compressionInProgress(SourceCompressionTask* task, const AutoLockHelperThreadState& lock);
SourceCompressionTask* compressionTaskForSource(ScriptSource* ss, const AutoLockHelperThreadState& lock);
bool hasActiveThreads();
bool hasActiveThreads(const AutoLockHelperThreadState&);
void waitForAllThreads();
template <typename T>
@ -260,9 +245,6 @@ class GlobalHelperThreadState
* used by all condition variables.
*/
js::Mutex helperLock;
#ifdef DEBUG
mozilla::Atomic<PRThread*> lockOwner;
#endif
/* Condvars for threads waiting/notifying each other. */
js::ConditionVariable consumerWakeup;
@ -459,24 +441,12 @@ class MOZ_RAII AutoLockHelperThreadState : public LockGuard<Mutex>
: Base(HelperThreadState().helperLock)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
#ifdef DEBUG
HelperThreadState().lockOwner = PR_GetCurrentThread();
#endif
}
~AutoLockHelperThreadState() {
#ifdef DEBUG
HelperThreadState().lockOwner = nullptr;
#endif
}
};
class MOZ_RAII AutoUnlockHelperThreadState
class MOZ_RAII AutoUnlockHelperThreadState : public UnlockGuard<Mutex>
{
// This is only in a Maybe so that we can update the DEBUG-only lockOwner
// thread in the proper order.
mozilla::Maybe<UnlockGuard<Mutex>> unlocked;
using Base = UnlockGuard<Mutex>;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
@ -484,22 +454,9 @@ class MOZ_RAII AutoUnlockHelperThreadState
explicit AutoUnlockHelperThreadState(AutoLockHelperThreadState& locked
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: Base(locked)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
#ifdef DEBUG
HelperThreadState().lockOwner = nullptr;
#endif
unlocked.emplace(locked);
}
~AutoUnlockHelperThreadState() {
unlocked.reset();
#ifdef DEBUG
HelperThreadState().lockOwner = PR_GetCurrentThread();
#endif
}
};

View File

@ -902,7 +902,6 @@ JSRuntime::assertCanLock(RuntimeLock which)
MOZ_ASSERT(exclusiveAccessOwner != PR_GetCurrentThread());
MOZ_FALLTHROUGH;
case HelperThreadStateLock:
MOZ_ASSERT(!HelperThreadState().isLocked());
MOZ_FALLTHROUGH;
case GCLock:
break;