部分感到困惑。下面是我的测试 golang 代码和它的
plan9
编译。
package main
func main() {
a := func() {
b := func() {
recover()
}
defer b()
}
defer a()
panic(1)
}
main.go:3 0x105a100 493b6610 cmp rsp, qword ptr [r14+0x10]
main.go:3 0x105a104 7651 jbe 0x105a157
=> main.go:3 0x105a106* 4883ec68 sub rsp, 0x68
main.go:3 0x105a10a 48896c2460 mov qword ptr [rsp+0x60], rbp
main.go:3 0x105a10f 488d6c2460 lea rbp, ptr [rsp+0x60]
main.go:4 0x105a114 488d0dc50e0100 lea rcx, ptr [rip+0x10ec5]
main.go:4 0x105a11b 48894c2458 mov qword ptr [rsp+0x58], rcx
main.go:10 0x105a120 48894c2428 mov qword ptr [rsp+0x28], rcx
main.go:10 0x105a125 488d442410 lea rax, ptr [rsp+0x10]
main.go:10 0x105a12a e89136fdff call $runtime.deferprocStack
main.go:10 0x105a12f 85c0 test eax, eax
main.go:10 0x105a131 7515 jnz 0x105a148
main.go:10 0x105a133 eb00 jmp 0x105a135
main.go:11 0x105a135 488d05043f0000 lea rax, ptr [rip+0x3f04]
main.go:11 0x105a13c 488d1d8d3a0100 lea rbx, ptr [rip+0x13a8d]
main.go:11 0x105a143 e83847fdff call $runtime.gopanic
main.go:10 0x105a148 e8533cfdff call $runtime.deferreturn
main.go:10 0x105a14d 488b6c2460 mov rbp, qword ptr [rsp+0x60]
main.go:10 0x105a152 4883c468 add rsp, 0x68
main.go:10 0x105a156 c3 ret
main.go:3 0x105a157 e8c4cfffff call $runtime.morestack_noctxt
.:0 0x105a15c eba2 jmp $main.main
在golang中,
defer
会调用runtime.deferprocStack
,这样当前的g._defer
应该指向最里面的defer。 panic
会打电话给runtime.gopanic
.
在我的测试代码中,调用
runtime.gopanic
时,当前的g._defer.fn
为main.a
。就像这样:
g._defer = &_defer{ fn: `main.a`, link: nil }
所以在panic.go:918中,
main.a()
会被执行,而在main.a
中,另一个fn为_defer
的main.a.b
会被g._defer指向,之前的defer
会赋值给这个一个link
。就像这样:
g._defer = &_defer{ fn: `main.a.b`, link: &_defer{ fn: `main.a`, link: nil } }
Howerer,在 panic.go:923 中,
gp._defer != d
仍然是正确的。我是不是在整个过程中忽略了什么?
我用
dlv
调试我的代码,我的golang版本是1.18.3
我真的很想知道原因,如果你能解释一下,我真的很感激!