wasm: use precise GC for WebAssembly (including WASI)

With a few small modifications, all the problems with `-gc=precise` in
WebAssembly seem to have been fixed.

I didn't do any performance measurements, but this is supposed to
improve GC performance.
This commit is contained in:
Ayke van Laethem
2024-10-22 15:53:57 +02:00
committed by Ron Evans
parent 24c11d4ba5
commit 0f95b4102d
6 changed files with 25 additions and 14 deletions
+3
View File
@@ -30,3 +30,6 @@ type Task struct {
// the given function and falls back to the default stack size. It is replaced
// with a load from a special section just before codegen.
func getGoroutineStackSize(fn uintptr) uintptr
//go:linkname runtime_alloc runtime.alloc
func runtime_alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer
+19 -11
View File
@@ -35,11 +35,16 @@ type state struct {
type stackState struct {
// asyncify is the stack pointer of the asyncify stack.
// This starts from the bottom and grows upwards.
asyncifysp uintptr
asyncifysp unsafe.Pointer
// asyncify is stack pointer of the C stack.
// This starts from the top and grows downwards.
csp uintptr
csp unsafe.Pointer
// Pointer to the first (lowest address) of the stack. It must never be
// overwritten. It can be checked from time to time to see whether a stack
// overflow happened in the past.
canaryPtr *uintptr
}
// start creates and starts a new goroutine with the given function and arguments.
@@ -63,12 +68,18 @@ func (s *state) initialize(fn uintptr, args unsafe.Pointer, stackSize uintptr) {
s.args = args
// Create a stack.
stack := make([]uintptr, stackSize/unsafe.Sizeof(uintptr(0)))
stack := runtime_alloc(stackSize, nil)
// Set up the stack canary, a random number that should be checked when
// switching from the task back to the scheduler. The stack canary pointer
// points to the first word of the stack. If it has changed between now and
// the next stack switch, there was a stack overflow.
s.canaryPtr = (*uintptr)(stack)
*s.canaryPtr = stackCanary
// Calculate stack base addresses.
s.asyncifysp = uintptr(unsafe.Pointer(&stack[0]))
s.csp = uintptr(unsafe.Pointer(&stack[0])) + uintptr(len(stack))*unsafe.Sizeof(uintptr(0))
stack[0] = stackCanary
s.asyncifysp = unsafe.Add(stack, unsafe.Sizeof(uintptr(0)))
s.csp = unsafe.Add(stack, stackSize)
}
//go:linkname runqueuePushBack runtime.runqueuePushBack
@@ -85,14 +96,11 @@ func Current() *Task {
// Pause suspends the current task and returns to the scheduler.
// This function may only be called when running on a goroutine stack, not when running on the system stack.
func Pause() {
// This is mildly unsafe but this is also the only place we can do this.
if *(*uintptr)(unsafe.Pointer(currentTask.state.asyncifysp)) != stackCanary {
if *currentTask.state.canaryPtr != stackCanary {
runtimePanic("stack overflow")
}
currentTask.state.unwind()
*(*uintptr)(unsafe.Pointer(currentTask.state.asyncifysp)) = stackCanary
}
//export tinygo_unwind
@@ -113,7 +121,7 @@ func (t *Task) Resume() {
}
currentTask = prevTask
t.gcData.swap()
if t.state.asyncifysp > t.state.csp {
if uintptr(t.state.asyncifysp) > uintptr(t.state.csp) {
runtimePanic("stack overflow")
}
}
-3
View File
@@ -104,9 +104,6 @@ var startTask [0]uint8
//go:linkname runqueuePushBack runtime.runqueuePushBack
func runqueuePushBack(*Task)
//go:linkname runtime_alloc runtime.alloc
func runtime_alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer
// start creates and starts a new goroutine with the given function and arguments.
// The new goroutine is scheduled to run later.
func start(fn uintptr, args unsafe.Pointer, stackSize uintptr) {
+1
View File
@@ -8,6 +8,7 @@
"linker": "wasm-ld",
"libc": "wasi-libc",
"rtlib": "compiler-rt",
"gc": "precise",
"scheduler": "asyncify",
"default-stack-size": 65536,
"cflags": [
+1
View File
@@ -9,6 +9,7 @@
"linker": "wasm-ld",
"libc": "wasmbuiltins",
"rtlib": "compiler-rt",
"gc": "precise",
"scheduler": "asyncify",
"default-stack-size": 65536,
"cflags": [
+1
View File
@@ -8,6 +8,7 @@
"linker": "wasm-ld",
"libc": "wasi-libc",
"rtlib": "compiler-rt",
"gc": "precise",
"scheduler": "asyncify",
"default-stack-size": 65536,
"cflags": [