@@ -177,12 +177,9 @@ func buildssa(fn *Node) *ssa.Func {
177
177
178
178
// fallthrough to exit
179
179
if s .curBlock != nil {
180
- s .stmts (s .exitCode )
181
- m := s .mem ()
182
- b := s .endBlock ()
183
- b .Line = fn .Func .Endlineno
184
- b .Kind = ssa .BlockRet
185
- b .Control = m
180
+ s .pushLine (fn .Func .Endlineno )
181
+ s .exit ()
182
+ s .popLine ()
186
183
}
187
184
188
185
// Check that we used all labels
@@ -904,6 +901,10 @@ func (s *state) stmt(n *Node) {
904
901
// It returns a BlockRet block that ends the control flow. Its control value
905
902
// will be set to the final memory state.
906
903
func (s * state ) exit () * ssa.Block {
904
+ if hasdefer {
905
+ s .rtcall (Deferreturn , true , nil )
906
+ }
907
+
907
908
// Run exit code. Typically, this code copies heap-allocated PPARAMOUT
908
909
// variables back to the stack.
909
910
s .stmts (s .exitCode )
@@ -2402,6 +2403,15 @@ func (s *state) call(n *Node, k callKind) *ssa.Value {
2402
2403
b .Kind = ssa .BlockCall
2403
2404
b .Control = call
2404
2405
b .AddEdgeTo (bNext )
2406
+ if k == callDefer {
2407
+ // Add recover edge to exit code.
2408
+ b .Kind = ssa .BlockDefer
2409
+ r := s .f .NewBlock (ssa .BlockPlain )
2410
+ s .startBlock (r )
2411
+ s .exit ()
2412
+ b .AddEdgeTo (r )
2413
+ b .Likely = ssa .BranchLikely
2414
+ }
2405
2415
2406
2416
// Start exit block, find address of result.
2407
2417
s .startBlock (bNext )
@@ -3622,12 +3632,6 @@ type genState struct {
3622
3632
3623
3633
// bstart remembers where each block starts (indexed by block ID)
3624
3634
bstart []* obj.Prog
3625
-
3626
- // deferBranches remembers all the defer branches we've seen.
3627
- deferBranches []* obj.Prog
3628
-
3629
- // deferTarget remembers the (last) deferreturn call site.
3630
- deferTarget * obj.Prog
3631
3635
}
3632
3636
3633
3637
// genssa appends entries to ptxt for each instruction in f.
@@ -3690,15 +3694,6 @@ func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) {
3690
3694
for _ , br := range s .branches {
3691
3695
br .p .To .Val = s .bstart [br .b .ID ]
3692
3696
}
3693
- if s .deferBranches != nil && s .deferTarget == nil {
3694
- // This can happen when the function has a defer but
3695
- // no return (because it has an infinite loop).
3696
- s .deferReturn ()
3697
- Prog (obj .ARET )
3698
- }
3699
- for _ , p := range s .deferBranches {
3700
- p .To .Val = s .deferTarget
3701
- }
3702
3697
3703
3698
if logProgs {
3704
3699
for p := ptxt ; p != nil ; p = p .Link {
@@ -4529,6 +4524,17 @@ func (s *genState) genValue(v *ssa.Value) {
4529
4524
q .To .Reg = r
4530
4525
}
4531
4526
case ssa .OpAMD64CALLstatic :
4527
+ if v .Aux .(* Sym ) == Deferreturn .Sym {
4528
+ // Deferred calls will appear to be returning to
4529
+ // the CALL deferreturn(SB) that we are about to emit.
4530
+ // However, the stack trace code will show the line
4531
+ // of the instruction byte before the return PC.
4532
+ // To avoid that being an unrelated instruction,
4533
+ // insert an actual hardware NOP that will have the right line number.
4534
+ // This is different from obj.ANOP, which is a virtual no-op
4535
+ // that doesn't make it into the instruction stream.
4536
+ Thearch .Ginsnop ()
4537
+ }
4532
4538
p := Prog (obj .ACALL )
4533
4539
p .To .Type = obj .TYPE_MEM
4534
4540
p .To .Name = obj .NAME_EXTERN
@@ -4551,17 +4557,6 @@ func (s *genState) genValue(v *ssa.Value) {
4551
4557
if Maxarg < v .AuxInt {
4552
4558
Maxarg = v .AuxInt
4553
4559
}
4554
- // defer returns in rax:
4555
- // 0 if we should continue executing
4556
- // 1 if we should jump to deferreturn call
4557
- p = Prog (x86 .ATESTL )
4558
- p .From .Type = obj .TYPE_REG
4559
- p .From .Reg = x86 .REG_AX
4560
- p .To .Type = obj .TYPE_REG
4561
- p .To .Reg = x86 .REG_AX
4562
- p = Prog (x86 .AJNE )
4563
- p .To .Type = obj .TYPE_BRANCH
4564
- s .deferBranches = append (s .deferBranches , p )
4565
4560
case ssa .OpAMD64CALLgo :
4566
4561
p := Prog (obj .ACALL )
4567
4562
p .To .Type = obj .TYPE_MEM
@@ -4835,12 +4830,26 @@ func (s *genState) genBlock(b, next *ssa.Block) {
4835
4830
p .To .Type = obj .TYPE_BRANCH
4836
4831
s .branches = append (s .branches , branch {p , b .Succs [0 ]})
4837
4832
}
4833
+ case ssa .BlockDefer :
4834
+ // defer returns in rax:
4835
+ // 0 if we should continue executing
4836
+ // 1 if we should jump to deferreturn call
4837
+ p := Prog (x86 .ATESTL )
4838
+ p .From .Type = obj .TYPE_REG
4839
+ p .From .Reg = x86 .REG_AX
4840
+ p .To .Type = obj .TYPE_REG
4841
+ p .To .Reg = x86 .REG_AX
4842
+ p = Prog (x86 .AJNE )
4843
+ p .To .Type = obj .TYPE_BRANCH
4844
+ s .branches = append (s .branches , branch {p , b .Succs [1 ]})
4845
+ if b .Succs [0 ] != next {
4846
+ p := Prog (obj .AJMP )
4847
+ p .To .Type = obj .TYPE_BRANCH
4848
+ s .branches = append (s .branches , branch {p , b .Succs [0 ]})
4849
+ }
4838
4850
case ssa .BlockExit :
4839
4851
Prog (obj .AUNDEF ) // tell plive.go that we never reach here
4840
4852
case ssa .BlockRet :
4841
- if hasdefer {
4842
- s .deferReturn ()
4843
- }
4844
4853
Prog (obj .ARET )
4845
4854
case ssa .BlockRetJmp :
4846
4855
p := Prog (obj .AJMP )
@@ -4899,23 +4908,6 @@ func (s *genState) genBlock(b, next *ssa.Block) {
4899
4908
}
4900
4909
}
4901
4910
4902
- func (s * genState ) deferReturn () {
4903
- // Deferred calls will appear to be returning to
4904
- // the CALL deferreturn(SB) that we are about to emit.
4905
- // However, the stack trace code will show the line
4906
- // of the instruction byte before the return PC.
4907
- // To avoid that being an unrelated instruction,
4908
- // insert an actual hardware NOP that will have the right line number.
4909
- // This is different from obj.ANOP, which is a virtual no-op
4910
- // that doesn't make it into the instruction stream.
4911
- s .deferTarget = Pc
4912
- Thearch .Ginsnop ()
4913
- p := Prog (obj .ACALL )
4914
- p .To .Type = obj .TYPE_MEM
4915
- p .To .Name = obj .NAME_EXTERN
4916
- p .To .Sym = Linksym (Deferreturn .Sym )
4917
- }
4918
-
4919
4911
// addAux adds the offset in the aux fields (AuxInt and Aux) of v to a.
4920
4912
func addAux (a * obj.Addr , v * ssa.Value ) {
4921
4913
addAux2 (a , v , v .AuxInt )
0 commit comments