aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/panic.go
diff options
context:
space:
mode:
authorAustin Clements <austin@google.com>2023-02-13 16:20:54 -0500
committerAustin Clements <austin@google.com>2023-03-10 17:59:32 +0000
commit2d99109cfcaef22b6872dc2e07e4582586c032a2 (patch)
tree958a2c7da4df9d94953e7c2f09aaff9e4c788129 /src/runtime/panic.go
parentda384766a053d851d912f04afaa1113b627a0822 (diff)
downloadgo-2d99109cfcaef22b6872dc2e07e4582586c032a2.tar.xz
runtime: replace all callback uses of gentraceback with unwinder
This is a really nice simplification for all of these call sites. It also achieves a nice performance improvement for stack copying: goos: linux goarch: amd64 pkg: runtime cpu: Intel(R) Xeon(R) CPU E5-2690 v3 @ 2.60GHz │ before │ after │ │ sec/op │ sec/op vs base │ StackCopyPtr-48 89.25m ± 1% 79.78m ± 1% -10.62% (p=0.000 n=20) StackCopy-48 83.48m ± 2% 71.88m ± 1% -13.90% (p=0.000 n=20) StackCopyNoCache-48 2.504m ± 2% 2.195m ± 1% -12.32% (p=0.000 n=20) StackCopyWithStkobj-48 21.66m ± 1% 21.02m ± 2% -2.95% (p=0.000 n=20) geomean 25.21m 22.68m -10.04% Updates #54466. Change-Id: I31715b7b6efd65726940041d3052bb1c0a1186f3 Reviewed-on: https://go-review.googlesource.com/c/go/+/468297 Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Michael Pratt <mpratt@google.com>
Diffstat (limited to 'src/runtime/panic.go')
-rw-r--r--src/runtime/panic.go133
1 files changed, 67 insertions, 66 deletions
diff --git a/src/runtime/panic.go b/src/runtime/panic.go
index e7059af15f..ccc4643711 100644
--- a/src/runtime/panic.go
+++ b/src/runtime/panic.go
@@ -642,77 +642,78 @@ func addOneOpenDeferFrame(gp *g, pc uintptr, sp unsafe.Pointer) {
sp = unsafe.Pointer(prevDefer.sp)
}
systemstack(func() {
- gentraceback(pc, uintptr(sp), 0, gp, 0, nil, 0x7fffffff,
- func(frame *stkframe, unused unsafe.Pointer) bool {
- if prevDefer != nil && prevDefer.sp == frame.sp {
- // Skip the frame for the previous defer that
- // we just finished (and was used to set
- // where we restarted the stack scan)
- return true
- }
- f := frame.fn
- fd := funcdata(f, _FUNCDATA_OpenCodedDeferInfo)
- if fd == nil {
- return true
+ var u unwinder
+ frames:
+ for u.initAt(pc, uintptr(sp), 0, gp, 0); u.valid(); u.next() {
+ frame := &u.frame
+ if prevDefer != nil && prevDefer.sp == frame.sp {
+ // Skip the frame for the previous defer that
+ // we just finished (and was used to set
+ // where we restarted the stack scan)
+ continue
+ }
+ f := frame.fn
+ fd := funcdata(f, _FUNCDATA_OpenCodedDeferInfo)
+ if fd == nil {
+ continue
+ }
+ // Insert the open defer record in the
+ // chain, in order sorted by sp.
+ d := gp._defer
+ var prev *_defer
+ for d != nil {
+ dsp := d.sp
+ if frame.sp < dsp {
+ break
}
- // Insert the open defer record in the
- // chain, in order sorted by sp.
- d := gp._defer
- var prev *_defer
- for d != nil {
- dsp := d.sp
- if frame.sp < dsp {
- break
+ if frame.sp == dsp {
+ if !d.openDefer {
+ throw("duplicated defer entry")
}
- if frame.sp == dsp {
- if !d.openDefer {
- throw("duplicated defer entry")
- }
- // Don't add any record past an
- // in-progress defer entry. We don't
- // need it, and more importantly, we
- // want to keep the invariant that
- // there is no open defer entry
- // passed an in-progress entry (see
- // header comment).
- if d.started {
- return false
- }
- return true
+ // Don't add any record past an
+ // in-progress defer entry. We don't
+ // need it, and more importantly, we
+ // want to keep the invariant that
+ // there is no open defer entry
+ // passed an in-progress entry (see
+ // header comment).
+ if d.started {
+ break frames
}
- prev = d
- d = d.link
- }
- if frame.fn.deferreturn == 0 {
- throw("missing deferreturn")
+ continue frames
}
+ prev = d
+ d = d.link
+ }
+ if frame.fn.deferreturn == 0 {
+ throw("missing deferreturn")
+ }
- d1 := newdefer()
- d1.openDefer = true
- d1._panic = nil
- // These are the pc/sp to set after we've
- // run a defer in this frame that did a
- // recover. We return to a special
- // deferreturn that runs any remaining
- // defers and then returns from the
- // function.
- d1.pc = frame.fn.entry() + uintptr(frame.fn.deferreturn)
- d1.varp = frame.varp
- d1.fd = fd
- // Save the SP/PC associated with current frame,
- // so we can continue stack trace later if needed.
- d1.framepc = frame.pc
- d1.sp = frame.sp
- d1.link = d
- if prev == nil {
- gp._defer = d1
- } else {
- prev.link = d1
- }
- // Stop stack scanning after adding one open defer record
- return false
- },
- nil, 0)
+ d1 := newdefer()
+ d1.openDefer = true
+ d1._panic = nil
+ // These are the pc/sp to set after we've
+ // run a defer in this frame that did a
+ // recover. We return to a special
+ // deferreturn that runs any remaining
+ // defers and then returns from the
+ // function.
+ d1.pc = frame.fn.entry() + uintptr(frame.fn.deferreturn)
+ d1.varp = frame.varp
+ d1.fd = fd
+ // Save the SP/PC associated with current frame,
+ // so we can continue stack trace later if needed.
+ d1.framepc = frame.pc
+ d1.sp = frame.sp
+ d1.link = d
+ if prev == nil {
+ gp._defer = d1
+ } else {
+ prev.link = d1
+ }
+ // Stop stack scanning after adding one open defer record
+ break
+ }
})
}