mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 06:11:37 +00:00
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:
parent
7862c33d73
commit
9f15a50ddf
@ -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;
|
||||
|
@ -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*
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user