runtime: run syscall/js finalizers on wasm without a manual GC (#5545)

* runtime: run syscall/js finalizers on wasm without a manual GC

* runtime: address review feedback on finalizer idle GC

* runtime: clear a finished task's args pointer so its arguments are collectable

* runtime: skip the finalizer scan with a per-block registration bit

* runtime: guard the finalizer registration bitmap with gcLock

* testdata: cover finalizer invariants on every scheduler

* main_test: limit the finalizer scheduler variants to linux and darwin

* testdata: wait for the finalizer queue to drain before asserting

* testdata: make the finalizer counters atomic and wait for a known drain count

* runtime: add finalizer bookkeeping asserts under runtime_asserts

* runtime: address finalizer GC review feedback

* testdata: strengthen blocked stack finalizer test

* runtime: fix finalizer cleanup edge cases

* runtime: decouple wasm export scheduling from finalizers

* runtime: avoid redundant wakeups for re-entrant wasm exports

* runtime: simplify finalizer comments
This commit is contained in:
Felipe Gené
2026-08-26 15:03:44 -03:00
committed by GitHub
parent 8d6240a5e6
commit 31fff2c9a3
22 changed files with 1048 additions and 56 deletions
+5 -6
View File
@@ -309,10 +309,10 @@ func (c *compilerContext) createGoroutineStartWrapper(fnType llvm.Type, fn llvm.
}
defer b.Dispose()
var deadlock llvm.Value
var deadlockType llvm.Type
var exitGoroutine llvm.Value
var exitGoroutineType llvm.Type
if c.Scheduler == "asyncify" {
deadlockType, deadlock = c.getFunction(c.program.ImportedPackage("runtime").Members["deadlock"].(*ssa.Function))
exitGoroutineType, exitGoroutine = c.getFunction(c.program.ImportedPackage("runtime").Members["exitGoroutine"].(*ssa.Function))
}
if !fn.IsAFunction().IsNil() {
@@ -377,7 +377,7 @@ func (c *compilerContext) createGoroutineStartWrapper(fnType llvm.Type, fn llvm.
b.CreateCall(fnType, fn, params, "")
if c.Scheduler == "asyncify" {
b.CreateCall(deadlockType, deadlock, []llvm.Value{
b.CreateCall(exitGoroutineType, exitGoroutine, []llvm.Value{
llvm.Undef(c.dataPtrType),
}, "")
}
@@ -528,14 +528,13 @@ func (c *compilerContext) createGoroutineStartWrapper(fnType llvm.Type, fn llvm.
b.CreateCall(fnType, fnPtr, params, "")
if c.Scheduler == "asyncify" {
b.CreateCall(deadlockType, deadlock, []llvm.Value{
b.CreateCall(exitGoroutineType, exitGoroutine, []llvm.Value{
llvm.Undef(c.dataPtrType),
}, "")
}
}
if c.Scheduler == "asyncify" {
// The goroutine was terminated via deadlock.
b.CreateUnreachable()
} else {
// Finish the function. Every basic block must end in a terminator, and