aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/panic.go
diff options
context:
space:
mode:
authorAustin Clements <austin@google.com>2021-07-30 16:40:17 -0400
committerAustin Clements <austin@google.com>2021-07-30 21:51:49 +0000
commite3e9f0bb2d6cc15b201fe2e0a0ac095d62cf4b8c (patch)
tree1c5960b23d5810b75637928c33a6bd4c6357e8c1 /src/runtime/panic.go
parent40e561d9337afbae221b34d6d0811761f32412f6 (diff)
downloadgo-e3e9f0bb2d6cc15b201fe2e0a0ac095d62cf4b8c.tar.xz
[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 <austin@google.com> Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cherry Mui <cherryyz@google.com>
Diffstat (limited to 'src/runtime/panic.go')
-rw-r--r--src/runtime/panic.go58
1 files changed, 33 insertions, 25 deletions
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.