mirror of
https://github.com/golang/go
synced 2024-11-26 11:08:38 -07:00
[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 <austin@google.com> Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cherry Mui <cherryyz@google.com>
This commit is contained in:
parent
4480e3b11a
commit
ea94e5d3c5
@ -662,7 +662,7 @@ TEXT ·publicationBarrier(SB),NOSPLIT,$0-0
|
|||||||
// compile barrier.
|
// compile barrier.
|
||||||
RET
|
RET
|
||||||
|
|
||||||
// func jmpdefer(fv *funcval, argp uintptr)
|
// func jmpdefer(fv func(), argp uintptr)
|
||||||
// argp is a caller SP.
|
// argp is a caller SP.
|
||||||
// called from deferreturn.
|
// called from deferreturn.
|
||||||
// 1. pop the caller
|
// 1. pop the caller
|
||||||
|
@ -248,7 +248,7 @@ TEXT gogo<>(SB), NOSPLIT|NOFRAME, $0
|
|||||||
MOV gobuf_pc(T0), T0
|
MOV gobuf_pc(T0), T0
|
||||||
JALR ZERO, T0
|
JALR ZERO, T0
|
||||||
|
|
||||||
// func jmpdefer(fv *funcval, argp uintptr)
|
// func jmpdefer(fv func(), argp uintptr)
|
||||||
// called from deferreturn
|
// called from deferreturn
|
||||||
// 1. grab stored return address from the caller's frame
|
// 1. grab stored return address from the caller's frame
|
||||||
// 2. sub 8 bytes to get back to JAL deferreturn
|
// 2. sub 8 bytes to get back to JAL deferreturn
|
||||||
|
@ -381,12 +381,13 @@ func dumpgoroutine(gp *g) {
|
|||||||
dumpint(uint64(uintptr(unsafe.Pointer(gp))))
|
dumpint(uint64(uintptr(unsafe.Pointer(gp))))
|
||||||
dumpint(uint64(d.sp))
|
dumpint(uint64(d.sp))
|
||||||
dumpint(uint64(d.pc))
|
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 {
|
if d.fn == nil {
|
||||||
// d.fn can be nil for open-coded defers
|
// d.fn can be nil for open-coded defers
|
||||||
dumpint(uint64(0))
|
dumpint(uint64(0))
|
||||||
} else {
|
} else {
|
||||||
dumpint(uint64(uintptr(unsafe.Pointer(d.fn.fn))))
|
dumpint(uint64(uintptr(unsafe.Pointer(fn.fn))))
|
||||||
}
|
}
|
||||||
dumpint(uint64(uintptr(unsafe.Pointer(d.link))))
|
dumpint(uint64(uintptr(unsafe.Pointer(d.link))))
|
||||||
}
|
}
|
||||||
|
@ -227,7 +227,7 @@ func panicmemAddr(addr uintptr) {
|
|||||||
|
|
||||||
// Create a new deferred function fn, which has no arguments and results.
|
// Create a new deferred function fn, which has no arguments and results.
|
||||||
// The compiler turns a defer statement into a call to this.
|
// 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()
|
gp := getg()
|
||||||
if gp.m.curg != gp {
|
if gp.m.curg != gp {
|
||||||
// go code on the system stack can't defer
|
// go code on the system stack can't defer
|
||||||
@ -303,16 +303,6 @@ func deferprocStack(d *_defer) {
|
|||||||
// been set and must not be clobbered.
|
// 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.
|
// Each P holds a pool for defers.
|
||||||
|
|
||||||
// Allocate a Defer, usually using per-P pool.
|
// 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
|
// 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
|
// 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
|
// 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
|
// stack, because jmpdefer manipulates SP (see issue #8153).
|
||||||
// issue #8153).
|
_ = **(**funcval)(unsafe.Pointer(&fn))
|
||||||
_ = fn.fn
|
|
||||||
jmpdefer(fn, argp)
|
jmpdefer(fn, argp)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -536,7 +525,7 @@ func Goexit() {
|
|||||||
} else {
|
} else {
|
||||||
// Save the pc/sp in deferCallSave(), so we can "recover" back to this
|
// Save the pc/sp in deferCallSave(), so we can "recover" back to this
|
||||||
// loop if necessary.
|
// loop if necessary.
|
||||||
deferCallSave(&p, deferFunc(d))
|
deferCallSave(&p, d.fn)
|
||||||
}
|
}
|
||||||
if p.aborted {
|
if p.aborted {
|
||||||
// We had a recursive panic in the defer d we started, and
|
// 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<<i) == 0 {
|
if deferBits&(1<<i) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
closure := *(**funcval)(unsafe.Pointer(d.varp - uintptr(closureOffset)))
|
closure := *(*func())(unsafe.Pointer(d.varp - uintptr(closureOffset)))
|
||||||
d.fn = closure
|
d.fn = closure
|
||||||
deferBits = deferBits &^ (1 << i)
|
deferBits = deferBits &^ (1 << i)
|
||||||
*(*uint8)(unsafe.Pointer(d.varp - uintptr(deferBitsOffset))) = deferBits
|
*(*uint8)(unsafe.Pointer(d.varp - uintptr(deferBitsOffset))) = deferBits
|
||||||
p := d._panic
|
p := d._panic
|
||||||
deferCallSave(p, deferFunc(d))
|
// Call the defer. Note that this can change d.varp if
|
||||||
|
// the stack moves.
|
||||||
|
deferCallSave(p, d.fn)
|
||||||
if p != nil && p.aborted {
|
if p != nil && p.aborted {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -854,8 +845,7 @@ func gopanic(e interface{}) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
p.argp = unsafe.Pointer(getargp())
|
p.argp = unsafe.Pointer(getargp())
|
||||||
fn := deferFunc(d)
|
d.fn()
|
||||||
fn()
|
|
||||||
}
|
}
|
||||||
p.argp = nil
|
p.argp = nil
|
||||||
|
|
||||||
|
@ -953,10 +953,10 @@ type _defer struct {
|
|||||||
// defers. We have only one defer record for the entire frame (which may
|
// defers. We have only one defer record for the entire frame (which may
|
||||||
// currently have 0, 1, or more defers active).
|
// currently have 0, 1, or more defers active).
|
||||||
openDefer bool
|
openDefer bool
|
||||||
sp uintptr // sp at time of defer
|
sp uintptr // sp at time of defer
|
||||||
pc uintptr // pc at time of defer
|
pc uintptr // pc at time of defer
|
||||||
fn *funcval // can be nil for open-coded defers
|
fn func() // can be nil for open-coded defers
|
||||||
_panic *_panic // panic that is running defer
|
_panic *_panic // panic that is running defer
|
||||||
link *_defer
|
link *_defer
|
||||||
|
|
||||||
// If openDefer is true, the fields below record values about the stack
|
// If openDefer is true, the fields below record values about the stack
|
||||||
|
@ -177,7 +177,7 @@ func cgocallback(fn, frame, ctxt uintptr)
|
|||||||
func gogo(buf *gobuf)
|
func gogo(buf *gobuf)
|
||||||
|
|
||||||
//go:noescape
|
//go:noescape
|
||||||
func jmpdefer(fv *funcval, argp uintptr)
|
func jmpdefer(fv func(), argp uintptr)
|
||||||
func asminit()
|
func asminit()
|
||||||
func setg(gg *g)
|
func setg(gg *g)
|
||||||
func breakpoint()
|
func breakpoint()
|
||||||
|
Loading…
Reference in New Issue
Block a user