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
+51
View File
@@ -0,0 +1,51 @@
package main
import (
"runtime"
"syscall/js"
)
//go:wasmimport tester finalizerRan
func finalizerRan()
//go:wasmimport tester backgroundRan
func backgroundRan()
//go:wasmimport tester callNestedExport
func callNestedExport()
var nestedCallback js.Func
//go:wasmexport launchBackground
func launchBackground() {
go func() {
backgroundRan()
}()
}
//go:wasmexport installNestedCallback
func installNestedCallback() {
nestedCallback = js.FuncOf(func(js.Value, []js.Value) any {
callNestedExport()
return nil
})
js.Global().Set("nestedExportCallback", nestedCallback)
}
//go:noinline
func registerFinalizersImpl() {
for i := 0; i < 32; i++ {
p := new([2]int)
runtime.SetFinalizer(p, func(*[2]int) { finalizerRan() })
}
}
//go:wasmexport registerFinalizers
func registerFinalizers() {
registerFinalizersImpl()
go func() {
backgroundRan()
}()
}
func main() {}