From e3e9f0bb2d6cc15b201fe2e0a0ac095d62cf4b8c Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 30 Jul 2021 16:40:17 -0400 Subject: [dev.typeparams] Revert "[dev.typeparams] runtime,cmd/compile,cmd/link: replace jmpdefer with a loop" This reverts CL 227652. I'm reverting CL 337651 and this builds on top of it. Change-Id: I03ce363be44c2a3defff2e43e7b1aad83386820d Reviewed-on: https://go-review.googlesource.com/c/go/+/338709 Trust: Austin Clements Run-TryBot: Austin Clements TryBot-Result: Go Bot Reviewed-by: Cherry Mui --- src/runtime/panic.go | 58 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 25 deletions(-) (limited to 'src/runtime/panic.go') diff --git a/src/runtime/panic.go b/src/runtime/panic.go index 4b8bca6c56..e66fe27be0 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -396,39 +396,47 @@ func freedeferfn() { throw("freedefer with d.fn != nil") } -// deferreturn runs deferred functions for the caller's frame. +// Run a deferred function if there is one. // The compiler inserts a call to this at the end of any // function which calls defer. +// If there is a deferred function, this will call runtime·jmpdefer, +// which will jump to the deferred function such that it appears +// to have been called by the caller of deferreturn at the point +// just before deferreturn was called. The effect is that deferreturn +// is called again and again until there are no more deferred functions. func deferreturn() { gp := getg() - for { - d := gp._defer - if d == nil { - return - } - sp := getcallersp() - if d.sp != sp { - return - } - if d.openDefer { - done := runOpenDeferFrame(gp, d) - if !done { - throw("unfinished open-coded defers in deferreturn") - } - gp._defer = d.link - freedefer(d) - // If this frame uses open defers, then this - // must be the only defer record for the - // frame, so we can just return. - return + d := gp._defer + if d == nil { + return + } + sp := getcallersp() + if d.sp != sp { + return + } + if d.openDefer { + done := runOpenDeferFrame(gp, d) + if !done { + throw("unfinished open-coded defers in deferreturn") } - - fn := d.fn - d.fn = nil gp._defer = d.link freedefer(d) - fn() + return } + + fn := d.fn + d.fn = nil + gp._defer = d.link + freedefer(d) + // 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 jmpdefer manipulates SP (see issue #8153). + _ = **(**funcval)(unsafe.Pointer(&fn)) + // We must not split the stack between computing argp and + // calling jmpdefer because argp is a uintptr stack pointer. + argp := getcallersp() + sys.MinFrameSize + jmpdefer(fn, argp) } // Goexit terminates the goroutine that calls it. No other goroutine is affected. -- cgit v1.3-5-g9baa