runtime: precisely scan Wasm globals

This commit is contained in:
Jake Bailey
2026-08-07 10:32:00 -07:00
committed by Ron Evans
parent a7360d5ad3
commit 829fe514cc
11 changed files with 345 additions and 5 deletions
-1
View File
@@ -48,7 +48,6 @@ func alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer
func free(ptr unsafe.Pointer)
// markRoots is called with the start and end addresses to scan for references.
// It is currently only called with the top and bottom of the stack.
func markRoots(start, end uintptr)
// GC is called to explicitly run garbage collection.
+22
View File
@@ -0,0 +1,22 @@
//go:build (gc.conservative || gc.precise) && tinygo.wasm
package runtime
import "unsafe"
func markGlobals() {
for i := uintptr(0); i < gcGlobalRootCount(); i++ {
addr := gcGlobalRoot(i)
size := gcGlobalRootSize(i)
for offset := uintptr(0); offset < size; offset += unsafe.Sizeof(uintptr(0)) {
slot := unsafe.Add(addr, offset)
markRoot(uintptr(slot), *(*uintptr)(slot))
}
}
}
// These functions are generated by the compiler from the pointer layouts of
// mutable globals. Each range contains only pointer slots.
func gcGlobalRootCount() uintptr
func gcGlobalRoot(index uintptr) unsafe.Pointer
func gcGlobalRootSize(index uintptr) uintptr
+18
View File
@@ -0,0 +1,18 @@
//go:build gc.custom && tinygo.wasm
package runtime
import "unsafe"
func markGlobals() {
for i := uintptr(0); i < gcGlobalRootCount(); i++ {
start := uintptr(gcGlobalRoot(i))
markRoots(start, start+gcGlobalRootSize(i))
}
}
// These functions are generated by the compiler from the pointer layouts of
// mutable globals. Each range contains only pointer slots.
func gcGlobalRootCount() uintptr
func gcGlobalRoot(index uintptr) unsafe.Pointer
func gcGlobalRootSize(index uintptr) uintptr
+40
View File
@@ -0,0 +1,40 @@
//go:build gc.boehm && tinygo.wasm
package runtime
import "unsafe"
func markGlobals() {
rangeCount := gcGlobalRootCount()
if rangeCount == 0 {
return
}
var rootCount uintptr
for i := uintptr(0); i < rangeCount; i++ {
rootCount += gcGlobalRootSize(i) / unsafe.Sizeof(uintptr(0))
}
// markRoots only accepts a range, so copy all global pointers into
// contiguous scratch space for marking.
roots := unsafe.Slice((*uintptr)(gcGlobalRootValues()), rootCount)
var rootIndex uintptr
for i := uintptr(0); i < rangeCount; i++ {
addr := gcGlobalRoot(i)
size := gcGlobalRootSize(i)
for offset := uintptr(0); offset < size; offset += unsafe.Sizeof(uintptr(0)) {
roots[rootIndex] = *(*uintptr)(unsafe.Add(addr, offset))
rootIndex++
}
}
start := uintptr(unsafe.Pointer(&roots[0]))
markRoots(start, start+rootCount*unsafe.Sizeof(roots[0]))
}
// These functions are generated by the compiler from the pointer layouts of
// mutable globals. Each range contains only pointer slots.
func gcGlobalRootCount() uintptr
func gcGlobalRoot(index uintptr) unsafe.Pointer
func gcGlobalRootSize(index uintptr) uintptr
func gcGlobalRootValues() unsafe.Pointer
+1 -1
View File
@@ -10,7 +10,7 @@ import (
func gcMarkReachable() {
markStack()
findGlobals(markRoots)
markGlobals()
}
//go:extern runtime.stackChainStart