ported from UXP: Issue #3075 - Backport bug 1377238 - Free finished IonBuilders off-thread. (57f841bf)

This commit is contained in:
2026-05-04 00:03:19 +08:00
parent 910ff68854
commit 87ecb69577
5 changed files with 74 additions and 7 deletions
+1
View File
@@ -68,6 +68,7 @@ enum ThreadType {
THREAD_TYPE_GCHELPER, // 6
THREAD_TYPE_GCPARALLEL, // 7
THREAD_TYPE_PROMISE_TASK, // 8
THREAD_TYPE_ION_FREE, // 9
THREAD_TYPE_MAX // Used to check shell function arguments
};
+14 -6
View File
@@ -474,6 +474,17 @@ JitCompartment::ensureIonStubsExist(JSContext* cx)
return true;
}
void
jit::FreeIonBuilder(IonBuilder* builder)
{
// The builder is allocated into its LifoAlloc, so destroying that will
// destroy the builder and all other data accumulated during compilation,
// except any final codegen (which includes an assembler and needs to be
// explicitly destroyed).
js_delete(builder->backgroundCodegen());
js_delete(builder->alloc().lifoAlloc());
}
void
jit::FinishOffThreadBuilder(JSRuntime* runtime, IonBuilder* builder,
const AutoLockHelperThreadState& locked)
@@ -505,12 +516,9 @@ jit::FinishOffThreadBuilder(JSRuntime* runtime, IonBuilder* builder,
builder->script()->setIonScript(runtime, ion);
}
// The builder is allocated into its LifoAlloc, so destroying that will
// destroy the builder and all other data accumulated during compilation,
// except any final codegen (which includes an assembler and needs to be
// explicitly destroyed).
js_delete(builder->backgroundCodegen());
js_delete(builder->alloc().lifoAlloc());
// Free Ion LifoAlloc off-thread. Free on the main thread if this OOMs.
if (!StartOffThreadIonFree(builder, locked))
FreeIonBuilder(builder);
}
static bool
+1
View File
@@ -171,6 +171,7 @@ CodeGenerator* CompileBackEnd(MIRGenerator* mir);
void AttachFinishedCompilations(JSContext* cx);
void FinishOffThreadBuilder(JSRuntime* runtime, IonBuilder* builder,
const AutoLockHelperThreadState& lock);
void FreeIonBuilder(IonBuilder* builder);
void LinkIonScript(JSContext* cx, HandleScript calleescript);
uint8_t* LazyLinkTopActivation(JSContext* cx);
+46
View File
@@ -110,6 +110,18 @@ js::StartOffThreadIonCompile(JSContext* cx, jit::IonBuilder* builder)
return true;
}
bool
js::StartOffThreadIonFree(jit::IonBuilder* builder, const AutoLockHelperThreadState& lock)
{
MOZ_ASSERT(CanUseExtraThreads());
if (!HelperThreadState().ionFreeList(lock).append(builder))
return false;
HelperThreadState().notifyOne(GlobalHelperThreadState::PRODUCER, lock);
return true;
}
/*
* Move an IonBuilder for which compilation has either finished, failed, or
* been cancelled into the global finished compilation list. All off thread
@@ -784,6 +796,14 @@ void
GlobalHelperThreadState::finish()
{
finishThreads();
// Make sure there are no Ion free tasks left. We check this here because,
// unlike the other tasks, we don't explicitly block on this when
// destroying a runtime.
AutoLockHelperThreadState lock;
auto& freeList = ionFreeList(lock);
while (!freeList.empty())
jit::FreeIonBuilder(freeList.popCopy());
}
void
@@ -994,6 +1014,12 @@ GlobalHelperThreadState::canStartIonCompile(const AutoLockHelperThreadState& loc
checkTaskThreadLimit<jit::IonBuilder*>(maxIonCompilationThreads());
}
bool
GlobalHelperThreadState::canStartIonFreeTask(const AutoLockHelperThreadState& lock)
{
return !ionFreeList(lock).empty();
}
jit::IonBuilder*
GlobalHelperThreadState::highestPriorityPendingIonCompile(const AutoLockHelperThreadState& lock,
bool remove /* = false */)
@@ -1610,6 +1636,21 @@ CurrentHelperThread()
return thread;
}
void
HelperThread::handleIonFreeWorkload(AutoLockHelperThreadState& locked)
{
MOZ_ASSERT(idle());
MOZ_ASSERT(HelperThreadState().canStartIonFreeTask(locked));
auto& freeList = HelperThreadState().ionFreeList(locked);
jit::IonBuilder* builder = freeList.popCopy();
{
AutoUnlockHelperThreadState unlock(locked);
FreeIonBuilder(builder);
}
}
void
js::PauseCurrentHelperThread()
{
@@ -1925,6 +1966,8 @@ HelperThread::threadLoop()
task = js::oom::THREAD_TYPE_PARSE;
else if (HelperThreadState().canStartCompressionTask(lock))
task = js::oom::THREAD_TYPE_COMPRESS;
else if (HelperThreadState().canStartIonFreeTask(lock))
task = js::oom::THREAD_TYPE_ION_FREE;
else
task = js::oom::THREAD_TYPE_NONE;
@@ -1957,6 +2000,9 @@ HelperThread::threadLoop()
case js::oom::THREAD_TYPE_COMPRESS:
handleCompressionWorkload(lock);
break;
case js::oom::THREAD_TYPE_ION_FREE:
handleIonFreeWorkload(lock);
break;
default:
MOZ_CRASH("No task to perform");
}
+12 -1
View File
@@ -84,7 +84,7 @@ class GlobalHelperThreadState
// The lists below are all protected by |lock|.
// Ion compilation worklist and finished jobs.
IonBuilderVector ionWorklist_, ionFinishedList_;
IonBuilderVector ionWorklist_, ionFinishedList_, ionFreeList_;
// wasm worklist and finished jobs.
wasm::CompileTaskPtrVector wasmWorklist_, wasmFinishedList_;
@@ -165,6 +165,9 @@ class GlobalHelperThreadState
IonBuilderVector& ionFinishedList(const AutoLockHelperThreadState&) {
return ionFinishedList_;
}
IonBuilderVector& ionFreeList(const AutoLockHelperThreadState&) {
return ionFreeList_;
}
wasm::CompileTaskPtrVector& wasmWorklist(const AutoLockHelperThreadState&) {
return wasmWorklist_;
@@ -202,6 +205,7 @@ class GlobalHelperThreadState
bool canStartWasmCompile(const AutoLockHelperThreadState& lock);
bool canStartPromiseTask(const AutoLockHelperThreadState& lock);
bool canStartIonCompile(const AutoLockHelperThreadState& lock);
bool canStartIonFreeTask(const AutoLockHelperThreadState& lock);
bool canStartParseTask(const AutoLockHelperThreadState& lock);
bool canStartCompressionTask(const AutoLockHelperThreadState& lock);
bool canStartGCHelperTask(const AutoLockHelperThreadState& lock);
@@ -382,6 +386,7 @@ struct HelperThread
void handleWasmWorkload(AutoLockHelperThreadState& locked);
void handlePromiseTaskWorkload(AutoLockHelperThreadState& locked);
void handleIonWorkload(AutoLockHelperThreadState& locked);
void handleIonFreeWorkload(AutoLockHelperThreadState& locked);
void handleParseWorkload(AutoLockHelperThreadState& locked, uintptr_t stackLimit);
void handleCompressionWorkload(AutoLockHelperThreadState& locked);
void handleGCHelperWorkload(AutoLockHelperThreadState& locked);
@@ -439,6 +444,12 @@ StartPromiseTask(JSContext* cx, UniquePtr<PromiseTask> task);
bool
StartOffThreadIonCompile(JSContext* cx, jit::IonBuilder* builder);
/*
* Schedule deletion of Ion compilation data.
*/
bool
StartOffThreadIonFree(jit::IonBuilder* builder, const AutoLockHelperThreadState& lock);
struct AllCompilations {};
struct ZonesInState { JSRuntime* runtime; JS::Zone::GCState state; };