]> Cypherpunks repositories - gostls13.git/commitdiff
Revert "runtime: remove the pc field of _defer struct"
authorKeith Randall <khr@golang.org>
Thu, 6 Nov 2025 02:05:42 +0000 (18:05 -0800)
committerDavid Chase <drchase@google.com>
Thu, 6 Nov 2025 13:00:27 +0000 (05:00 -0800)
This reverts commit 361d51a6b58bccaab0559e06737c918018a7a5fa.

Reason for revert: Breaks some tests inside Google (on arm64?)

Change-Id: Iaea45fdcf9b4f9d36553687ca7f479750fe559da
Reviewed-on: https://go-review.googlesource.com/c/go/+/718066
Auto-Submit: Keith Randall <khr@golang.org>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: Youlin Feng <fengyoulin@live.com>
Reviewed-by: Keith Randall <khr@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: David Chase <drchase@google.com>
src/cmd/compile/internal/ssagen/ssa.go
src/runtime/heapdump.go
src/runtime/panic.go
src/runtime/runtime2.go

index db2ffb5752f1ce842554154038d34bd95a028941..ae7d57566f7e0defe86b3de2591e0dc739f00ed5 100644 (file)
@@ -7797,7 +7797,7 @@ func callTargetLSym(callee *ir.Name) *obj.LSym {
 }
 
 // deferStructFnField is the field index of _defer.fn.
-const deferStructFnField = 3
+const deferStructFnField = 4
 
 var deferType *types.Type
 
@@ -7817,6 +7817,7 @@ func deferstruct() *types.Type {
                makefield("heap", types.Types[types.TBOOL]),
                makefield("rangefunc", types.Types[types.TBOOL]),
                makefield("sp", types.Types[types.TUINTPTR]),
+               makefield("pc", types.Types[types.TUINTPTR]),
                // Note: the types here don't really matter. Defer structures
                // are always scanned explicitly during stack copying and GC,
                // so we make them uintptr type even though they are real pointers.
index 3a8c374fc0f497b276169c32c6faa86c256440ef..3671c65ab731513141dfc521b7f145620016ed27 100644 (file)
@@ -382,6 +382,7 @@ func dumpgoroutine(gp *g) {
                dumpint(uint64(uintptr(unsafe.Pointer(d))))
                dumpint(uint64(uintptr(unsafe.Pointer(gp))))
                dumpint(uint64(d.sp))
+               dumpint(uint64(d.pc))
                fn := *(**funcval)(unsafe.Pointer(&d.fn))
                dumpint(uint64(uintptr(unsafe.Pointer(fn))))
                if d.fn == nil {
index ded85feffa12cbe6f2b191bf0c957c38cc0aa82a..325bf74aa822b93adf71cf7d95ab83e38c12e74d 100644 (file)
@@ -354,6 +354,7 @@ func deferproc(fn func()) {
        d.link = gp._defer
        gp._defer = d
        d.fn = fn
+       d.pc = sys.GetCallerPC()
        // We must not be preempted between calling GetCallerSP and
        // storing it to d.sp because GetCallerSP's result is a
        // uintptr stack pointer.
@@ -457,6 +458,7 @@ func deferrangefunc() any {
        d := newdefer()
        d.link = gp._defer
        gp._defer = d
+       d.pc = sys.GetCallerPC()
        // We must not be preempted between calling GetCallerSP and
        // storing it to d.sp because GetCallerSP's result is a
        // uintptr stack pointer.
@@ -516,6 +518,7 @@ func deferconvert(d0 *_defer) {
        }
        for d1 := d; ; d1 = d1.link {
                d1.sp = d0.sp
+               d1.pc = d0.pc
                if d1.link == nil {
                        d1.link = tail
                        break
@@ -544,6 +547,7 @@ func deferprocStack(d *_defer) {
        d.heap = false
        d.rangefunc = false
        d.sp = sys.GetCallerSP()
+       d.pc = sys.GetCallerPC()
        // The lines below implement:
        //   d.link = gp._defer
        //   d.head = nil
@@ -971,6 +975,8 @@ func (p *_panic) nextDefer() (func(), bool) {
 
                        fn := d.fn
 
+                       p.retpc = d.pc
+
                        // Unlink and free.
                        popDefer(gp)
 
@@ -1010,12 +1016,6 @@ func (p *_panic) nextFrame() (ok bool) {
                        // it's non-zero.
 
                        if u.frame.sp == limit {
-                               f := u.frame.fn
-                               if f.deferreturn == 0 {
-                                       throw("no deferreturn")
-                               }
-                               p.retpc = f.entry() + uintptr(f.deferreturn)
-
                                break // found a frame with linked defers
                        }
 
@@ -1271,6 +1271,15 @@ func recovery(gp *g) {
        pc, sp, fp := p.retpc, uintptr(p.sp), uintptr(p.fp)
        p0, saveOpenDeferState := p, p.deferBitsPtr != nil && *p.deferBitsPtr != 0
 
+       // The linker records the f-relative address of a call to deferreturn in f's funcInfo.
+       // Assuming a "normal" call to recover() inside one of f's deferred functions
+       // invoked for a panic, that is the desired PC for exiting f.
+       f := findfunc(pc)
+       if f.deferreturn == 0 {
+               throw("no deferreturn")
+       }
+       gotoPc := f.entry() + uintptr(f.deferreturn)
+
        // Unwind the panic stack.
        for ; p != nil && uintptr(p.startSP) < sp; p = p.link {
                // Don't allow jumping past a pending Goexit.
@@ -1293,7 +1302,7 @@ func recovery(gp *g) {
                // With how subtle defer handling is, this might not actually be
                // worthwhile though.
                if p.goexit {
-                       pc, sp = p.startPC, uintptr(p.startSP)
+                       gotoPc, sp = p.startPC, uintptr(p.startSP)
                        saveOpenDeferState = false // goexit is unwinding the stack anyway
                        break
                }
@@ -1356,7 +1365,7 @@ func recovery(gp *g) {
 
        // branch directly to the deferreturn
        gp.sched.sp = sp
-       gp.sched.pc = pc
+       gp.sched.pc = gotoPc
        gp.sched.lr = 0
        // Restore the bp on platforms that support frame pointers.
        // N.B. It's fine to not set anything for platforms that don't
index 1deeb1244caead852ca86529d97b3b6fab428ac7..6d1f9b13a28563b7ae57820963dd8aea19c8b0b0 100644 (file)
@@ -1090,6 +1090,7 @@ type _defer struct {
        heap      bool
        rangefunc bool    // true for rangefunc list
        sp        uintptr // sp at time of defer
+       pc        uintptr // pc at time of defer
        fn        func()  // can be nil for open-coded defers
        link      *_defer // next defer on G; can point to either heap or stack!