]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: abstract specials list iteration
authorAustin Clements <austin@google.com>
Mon, 22 Mar 2021 19:00:22 +0000 (15:00 -0400)
committerAustin Clements <austin@google.com>
Mon, 29 Mar 2021 21:50:14 +0000 (21:50 +0000)
The specials processing loop in mspan.sweep is about to get more
complicated and I'm too allergic to list manipulation to open code
more of it there.

Change-Id: I767a0889739da85fb2878fc06a5c55b73bf2ba7d
Reviewed-on: https://go-review.googlesource.com/c/go/+/305551
Trust: Austin Clements <austin@google.com>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Michael Pratt <mpratt@google.com>
src/runtime/mgcsweep.go
src/runtime/mheap.go

index f3d6c6caa479e2fed09fc90b3ba82f33411b1d7a..723217caa93c77a61aba35d756a7c33cfe2b1ab1 100644 (file)
@@ -356,11 +356,10 @@ func (s *mspan) sweep(preserve bool) bool {
        //    If such object is not marked, we need to queue all finalizers at once.
        // Both 1 and 2 are possible at the same time.
        hadSpecials := s.specials != nil
-       specialp := &s.specials
-       special := *specialp
-       for special != nil {
+       siter := newSpecialsIter(s)
+       for siter.valid() {
                // A finalizer can be set for an inner byte of an object, find object beginning.
-               objIndex := uintptr(special.offset) / size
+               objIndex := uintptr(siter.s.offset) / size
                p := s.base() + objIndex*size
                mbits := s.markBitsForIndex(objIndex)
                if !mbits.isMarked() {
@@ -368,7 +367,7 @@ func (s *mspan) sweep(preserve bool) bool {
                        // Pass 1: see if it has at least one finalizer.
                        hasFin := false
                        endOffset := p - s.base() + size
-                       for tmp := special; tmp != nil && uintptr(tmp.offset) < endOffset; tmp = tmp.next {
+                       for tmp := siter.s; tmp != nil && uintptr(tmp.offset) < endOffset; tmp = tmp.next {
                                if tmp.kind == _KindSpecialFinalizer {
                                        // Stop freeing of object if it has a finalizer.
                                        mbits.setMarkedNonAtomic()
@@ -377,27 +376,23 @@ func (s *mspan) sweep(preserve bool) bool {
                                }
                        }
                        // Pass 2: queue all finalizers _or_ handle profile record.
-                       for special != nil && uintptr(special.offset) < endOffset {
+                       for siter.valid() && uintptr(siter.s.offset) < endOffset {
                                // Find the exact byte for which the special was setup
                                // (as opposed to object beginning).
+                               special := siter.s
                                p := s.base() + uintptr(special.offset)
                                if special.kind == _KindSpecialFinalizer || !hasFin {
-                                       // Splice out special record.
-                                       y := special
-                                       special = special.next
-                                       *specialp = special
-                                       freespecial(y, unsafe.Pointer(p), size)
+                                       siter.unlinkAndNext()
+                                       freeSpecial(special, unsafe.Pointer(p), size)
                                } else {
                                        // This is profile record, but the object has finalizers (so kept alive).
                                        // Keep special record.
-                                       specialp = &special.next
-                                       special = *specialp
+                                       siter.next()
                                }
                        }
                } else {
                        // object is still live: keep special record
-                       specialp = &special.next
-                       special = *specialp
+                       siter.next()
                }
        }
        if hadSpecials && s.specials == nil {
index 13ea3377355bfccdfb0067ac463dc5d367d5eaa7..d7f6a88cc93116852598d26110c35139022fe9d3 100644 (file)
@@ -1854,9 +1854,37 @@ func setprofilebucket(p unsafe.Pointer, b *bucket) {
        }
 }
 
-// Do whatever cleanup needs to be done to deallocate s. It has
-// already been unlinked from the mspan specials list.
-func freespecial(s *special, p unsafe.Pointer, size uintptr) {
+// specialsIter helps iterate over specials lists.
+type specialsIter struct {
+       pprev **special
+       s     *special
+}
+
+func newSpecialsIter(span *mspan) specialsIter {
+       return specialsIter{&span.specials, span.specials}
+}
+
+func (i *specialsIter) valid() bool {
+       return i.s != nil
+}
+
+func (i *specialsIter) next() {
+       i.pprev = &i.s.next
+       i.s = *i.pprev
+}
+
+// unlinkAndNext removes the current special from the list and moves
+// the iterator to the next special. It returns the unlinked special.
+func (i *specialsIter) unlinkAndNext() *special {
+       cur := i.s
+       i.s = cur.next
+       *i.pprev = i.s
+       return cur
+}
+
+// freeSpecial performs any cleanup on special s and deallocates it.
+// s must already be unlinked from the specials list.
+func freeSpecial(s *special, p unsafe.Pointer, size uintptr) {
        switch s.kind {
        case _KindSpecialFinalizer:
                sf := (*specialfinalizer)(unsafe.Pointer(s))