From ea94e5d3c57fadea088cdc5002e014b3c7ef4bc1 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 23 Jul 2021 15:03:00 -0400 Subject: [dev.typeparams] runtime: use func() for deferred functions Prior to regabi, a deferred function could have any signature, so the runtime always manipulated them as funcvals. Now, a deferred function is always func(). Hence, this CL makes the runtime's manipulation of deferred functions more type-safe by using func() directly instead of *funcval. Change-Id: Ib55f38ed49107f74149725c65044e4690761971d Reviewed-on: https://go-review.googlesource.com/c/go/+/337650 Trust: Austin Clements Run-TryBot: Austin Clements TryBot-Result: Go Bot Reviewed-by: Cherry Mui --- src/runtime/asm_amd64.s | 2 +- src/runtime/asm_riscv64.s | 2 +- src/runtime/heapdump.go | 5 +++-- src/runtime/panic.go | 28 +++++++++------------------- src/runtime/runtime2.go | 8 ++++---- src/runtime/stubs.go | 2 +- 6 files changed, 19 insertions(+), 28 deletions(-) diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s index 50ffa30ac5..0f719b2664 100644 --- a/src/runtime/asm_amd64.s +++ b/src/runtime/asm_amd64.s @@ -662,7 +662,7 @@ TEXT ·publicationBarrier(SB),NOSPLIT,$0-0 // compile barrier. RET -// func jmpdefer(fv *funcval, argp uintptr) +// func jmpdefer(fv func(), argp uintptr) // argp is a caller SP. // called from deferreturn. // 1. pop the caller diff --git a/src/runtime/asm_riscv64.s b/src/runtime/asm_riscv64.s index 69ab88f1d2..9957ae201b 100644 --- a/src/runtime/asm_riscv64.s +++ b/src/runtime/asm_riscv64.s @@ -248,7 +248,7 @@ TEXT gogo<>(SB), NOSPLIT|NOFRAME, $0 MOV gobuf_pc(T0), T0 JALR ZERO, T0 -// func jmpdefer(fv *funcval, argp uintptr) +// func jmpdefer(fv func(), argp uintptr) // called from deferreturn // 1. grab stored return address from the caller's frame // 2. sub 8 bytes to get back to JAL deferreturn diff --git a/src/runtime/heapdump.go b/src/runtime/heapdump.go index 18e4666fa4..8fb30d95b9 100644 --- a/src/runtime/heapdump.go +++ b/src/runtime/heapdump.go @@ -381,12 +381,13 @@ func dumpgoroutine(gp *g) { dumpint(uint64(uintptr(unsafe.Pointer(gp)))) dumpint(uint64(d.sp)) dumpint(uint64(d.pc)) - dumpint(uint64(uintptr(unsafe.Pointer(d.fn)))) + fn := *(**funcval)(unsafe.Pointer(&d.fn)) + dumpint(uint64(uintptr(unsafe.Pointer(fn)))) if d.fn == nil { // d.fn can be nil for open-coded defers dumpint(uint64(0)) } else { - dumpint(uint64(uintptr(unsafe.Pointer(d.fn.fn)))) + dumpint(uint64(uintptr(unsafe.Pointer(fn.fn)))) } dumpint(uint64(uintptr(unsafe.Pointer(d.link)))) } diff --git a/src/runtime/panic.go b/src/runtime/panic.go index 85d39b9250..35f3b44a4d 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -227,7 +227,7 @@ func panicmemAddr(addr uintptr) { // Create a new deferred function fn, which has no arguments and results. // The compiler turns a defer statement into a call to this. -func deferproc(fn *funcval) { // TODO: Make deferproc just take a func(). +func deferproc(fn func()) { gp := getg() if gp.m.curg != gp { // go code on the system stack can't defer @@ -303,16 +303,6 @@ func deferprocStack(d *_defer) { // been set and must not be clobbered. } -// deferFunc returns d's deferred function. This is temporary while we -// support both modes of GOEXPERIMENT=regabidefer. Once we commit to -// that experiment, we should change the type of d.fn. -//go:nosplit -func deferFunc(d *_defer) func() { - var fn func() - *(**funcval)(unsafe.Pointer(&fn)) = d.fn - return fn -} - // Each P holds a pool for defers. // Allocate a Defer, usually using per-P pool. @@ -470,9 +460,8 @@ func deferreturn() { // If the defer function pointer is nil, force the seg fault to happen // here rather than in jmpdefer. gentraceback() throws an error if it is // called with a callback on an LR architecture and jmpdefer is on the - // stack, because the stack trace can be incorrect in that case - see - // issue #8153). - _ = fn.fn + // stack, because jmpdefer manipulates SP (see issue #8153). + _ = **(**funcval)(unsafe.Pointer(&fn)) jmpdefer(fn, argp) } @@ -536,7 +525,7 @@ func Goexit() { } else { // Save the pc/sp in deferCallSave(), so we can "recover" back to this // loop if necessary. - deferCallSave(&p, deferFunc(d)) + deferCallSave(&p, d.fn) } if p.aborted { // We had a recursive panic in the defer d we started, and @@ -728,12 +717,14 @@ func runOpenDeferFrame(gp *g, d *_defer) bool { if deferBits&(1<