mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile: fix defer/deferreturn
Make sure we do any just-before-return cleanup on all paths out of a function, including when recovering. Each exit path should include deferreturn (if there are any defers) and then the exit code (e.g. copying heap-escaping return values back to the stack). Introduce a Defer SSA block type which has two outgoing edges - one the fallthrough edge (the defer was queued successfully) and one which immediately returns (the defer had a successful recover() call and normal execution should resume at the return point). Fixes #14725 Change-Id: Iad035c9fd25ef8b7a74dafbd7461cf04833d981f Reviewed-on: https://go-review.googlesource.com/20486 Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
parent
9c8f549abb
commit
ddc6b64444
9 changed files with 124 additions and 58 deletions
|
|
@ -585,7 +585,7 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
// Walk backwards through the block doing liveness analysis.
|
||||
liveSet.clear()
|
||||
d := int32(len(b.Values))
|
||||
if b.Kind == BlockCall {
|
||||
if b.Kind == BlockCall || b.Kind == BlockDefer {
|
||||
d += unlikelyDistance
|
||||
}
|
||||
for _, e := range s.live[b.ID] {
|
||||
|
|
@ -988,7 +988,7 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
continue
|
||||
}
|
||||
for {
|
||||
if p.Kind == BlockCall {
|
||||
if p.Kind == BlockCall || p.Kind == BlockDefer {
|
||||
goto badloop
|
||||
}
|
||||
if p == top {
|
||||
|
|
@ -1607,7 +1607,7 @@ func (s *regAllocState) computeLive() {
|
|||
// to beginning-of-block distance.
|
||||
live.clear()
|
||||
d := int32(len(b.Values))
|
||||
if b.Kind == BlockCall {
|
||||
if b.Kind == BlockCall || b.Kind == BlockDefer {
|
||||
// Because we keep no values in registers across a call,
|
||||
// make every use past a call very far away.
|
||||
d += unlikelyDistance
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue