@@ -140,24 +140,14 @@ type Liveness struct {
140140 regMaps []liveRegMask
141141
142142 cache progeffectscache
143-
144- // These are only populated if open-coded defers are being used.
145- // List of vars/stack slots storing defer args
146- openDeferVars []openDeferVarInfo
147- // Map from defer arg OpVarDef to the block where the OpVarDef occurs.
148- openDeferVardefToBlockMap map [* Node ]* ssa.Block
149- // Map of blocks that cannot reach a return or exit (panic)
150- nonReturnBlocks map [* ssa.Block ]bool
151- }
152-
153- type openDeferVarInfo struct {
154- n * Node // Var/stack slot storing a defer arg
155- varsIndex int // Index of variable in lv.vars
156143}
157144
158145// LivenessMap maps from *ssa.Value to LivenessIndex.
159146type LivenessMap struct {
160147 vals map [ssa.ID ]LivenessIndex
148+ // The set of live, pointer-containing variables at the deferreturn
149+ // call (only set when open-coded defers are used).
150+ deferreturn LivenessIndex
161151}
162152
163153func (m * LivenessMap ) reset () {
@@ -168,6 +158,7 @@ func (m *LivenessMap) reset() {
168158 delete (m .vals , k )
169159 }
170160 }
161+ m .deferreturn = LivenessInvalid
171162}
172163
173164func (m * LivenessMap ) set (v * ssa.Value , i LivenessIndex ) {
@@ -542,7 +533,7 @@ func newliveness(fn *Node, f *ssa.Func, vars []*Node, idx map[*Node]int32, stkpt
542533 if cap (lc .be ) >= f .NumBlocks () {
543534 lv .be = lc .be [:f .NumBlocks ()]
544535 }
545- lv .livenessMap = LivenessMap {lc .livenessMap .vals }
536+ lv .livenessMap = LivenessMap {vals : lc .livenessMap .vals , deferreturn : LivenessInvalid }
546537 lc .livenessMap .vals = nil
547538 }
548539 if lv .be == nil {
@@ -893,58 +884,12 @@ func (lv *Liveness) hasStackMap(v *ssa.Value) bool {
893884func (lv * Liveness ) prologue () {
894885 lv .initcache ()
895886
896- if lv .fn .Func .HasDefer () && ! lv .fn .Func .OpenCodedDeferDisallowed () {
897- lv .openDeferVardefToBlockMap = make (map [* Node ]* ssa.Block )
898- for i , n := range lv .vars {
899- if n .Name .OpenDeferSlot () {
900- lv .openDeferVars = append (lv .openDeferVars , openDeferVarInfo {n : n , varsIndex : i })
901- }
902- }
903-
904- // Find any blocks that cannot reach a return or a BlockExit
905- // (panic) -- these must be because of an infinite loop.
906- reachesRet := make (map [ssa.ID ]bool )
907- blockList := make ([]* ssa.Block , 0 , 256 )
908-
909- for _ , b := range lv .f .Blocks {
910- if b .Kind == ssa .BlockRet || b .Kind == ssa .BlockRetJmp || b .Kind == ssa .BlockExit {
911- blockList = append (blockList , b )
912- }
913- }
914-
915- for len (blockList ) > 0 {
916- b := blockList [0 ]
917- blockList = blockList [1 :]
918- if reachesRet [b .ID ] {
919- continue
920- }
921- reachesRet [b .ID ] = true
922- for _ , e := range b .Preds {
923- blockList = append (blockList , e .Block ())
924- }
925- }
926-
927- lv .nonReturnBlocks = make (map [* ssa.Block ]bool )
928- for _ , b := range lv .f .Blocks {
929- if ! reachesRet [b .ID ] {
930- lv .nonReturnBlocks [b ] = true
931- //fmt.Println("No reach ret", lv.f.Name, b.ID, b.Kind)
932- }
933- }
934- }
935-
936887 for _ , b := range lv .f .Blocks {
937888 be := lv .blockEffects (b )
938889
939890 // Walk the block instructions backward and update the block
940891 // effects with the each prog effects.
941892 for j := len (b .Values ) - 1 ; j >= 0 ; j -- {
942- if b .Values [j ].Op == ssa .OpVarDef {
943- n := b .Values [j ].Aux .(* Node )
944- if n .Name .OpenDeferSlot () {
945- lv .openDeferVardefToBlockMap [n ] = b
946- }
947- }
948893 pos , e := lv .valueEffects (b .Values [j ])
949894 regUevar , regKill := lv .regEffects (b .Values [j ])
950895 if e & varkill != 0 {
@@ -961,20 +906,6 @@ func (lv *Liveness) prologue() {
961906 }
962907}
963908
964- // markDeferVarsLive marks each variable storing an open-coded defer arg as
965- // specially live in block b if the variable definition dominates block b.
966- func (lv * Liveness ) markDeferVarsLive (b * ssa.Block , newliveout * varRegVec ) {
967- // Only force computation of dominators if we have a block where we need
968- // to specially mark defer args live.
969- sdom := lv .f .Sdom ()
970- for _ , info := range lv .openDeferVars {
971- defB := lv .openDeferVardefToBlockMap [info .n ]
972- if sdom .IsAncestorEq (defB , b ) {
973- newliveout .vars .Set (int32 (info .varsIndex ))
974- }
975- }
976- }
977-
978909// Solve the liveness dataflow equations.
979910func (lv * Liveness ) solve () {
980911 // These temporary bitvectors exist to avoid successive allocations and
@@ -1018,23 +949,6 @@ func (lv *Liveness) solve() {
1018949 }
1019950 }
1020951
1021- if lv .fn .Func .HasDefer () && ! lv .fn .Func .OpenCodedDeferDisallowed () &&
1022- (b .Kind == ssa .BlockExit || lv .nonReturnBlocks [b ]) {
1023- // Open-coded defer args slots must be live
1024- // everywhere in a function, since a panic can
1025- // occur (almost) anywhere. Force all appropriate
1026- // defer arg slots to be live in BlockExit (panic)
1027- // blocks and in blocks that do not reach a return
1028- // (because of infinite loop).
1029- //
1030- // We are assuming that the defer exit code at
1031- // BlockReturn/BlockReturnJmp accesses all of the
1032- // defer args (with pointers), and so keeps them
1033- // live. This analysis may have to be adjusted if
1034- // that changes (because of optimizations).
1035- lv .markDeferVarsLive (b , & newliveout )
1036- }
1037-
1038952 if ! be .liveout .Eq (newliveout ) {
1039953 change = true
1040954 be .liveout .Copy (newliveout )
@@ -1087,6 +1001,17 @@ func (lv *Liveness) epilogue() {
10871001 n .Name .SetNeedzero (true )
10881002 livedefer .Set (int32 (i ))
10891003 }
1004+ if n .Name .OpenDeferSlot () {
1005+ // Open-coded defer args slots must be live
1006+ // everywhere in a function, since a panic can
1007+ // occur (almost) anywhere. Because it is live
1008+ // everywhere, it must be zeroed on entry.
1009+ livedefer .Set (int32 (i ))
1010+ // It was already marked as Needzero when created.
1011+ if ! n .Name .Needzero () {
1012+ Fatalf ("all pointer-containing defer arg slots should have Needzero set" )
1013+ }
1014+ }
10901015 }
10911016 }
10921017
@@ -1188,6 +1113,17 @@ func (lv *Liveness) epilogue() {
11881113 lv .compact (b )
11891114 }
11901115
1116+ // If we have an open-coded deferreturn call, make a liveness map for it.
1117+ if lv .fn .Func .OpenCodedDeferDisallowed () {
1118+ lv .livenessMap .deferreturn = LivenessInvalid
1119+ } else {
1120+ lv .livenessMap .deferreturn = LivenessIndex {
1121+ stackMapIndex : lv .stackMapSet .add (livedefer ),
1122+ regMapIndex : 0 , // entry regMap, containing no live registers
1123+ isUnsafePoint : false ,
1124+ }
1125+ }
1126+
11911127 // Done compacting. Throw out the stack map set.
11921128 lv .stackMaps = lv .stackMapSet .extractUniqe ()
11931129 lv .stackMapSet = bvecSet {}
0 commit comments