github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/runtime/mcheckmark.go (about) 1 // Copyright 2020 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // GC checkmarks 6 // 7 // In a concurrent garbage collector, one worries about failing to mark 8 // a live object due to mutations without write barriers or bugs in the 9 // collector implementation. As a sanity check, the GC has a 'checkmark' 10 // mode that retraverses the object graph with the world stopped, to make 11 // sure that everything that should be marked is marked. 12 13 package runtime 14 15 import ( 16 "internal/goarch" 17 "runtime/internal/atomic" 18 "runtime/internal/sys" 19 "unsafe" 20 ) 21 22 // A checkmarksMap stores the GC marks in "checkmarks" mode. It is a 23 // per-arena bitmap with a bit for every word in the arena. The mark 24 // is stored on the bit corresponding to the first word of the marked 25 // allocation. 26 type checkmarksMap struct { 27 _ sys.NotInHeap 28 b [heapArenaBytes / goarch.PtrSize / 8]uint8 29 } 30 31 // If useCheckmark is true, marking of an object uses the checkmark 32 // bits instead of the standard mark bits. 33 var useCheckmark = false 34 35 // startCheckmarks prepares for the checkmarks phase. 36 // 37 // The world must be stopped. 38 func startCheckmarks() { 39 assertWorldStopped() 40 41 // Clear all checkmarks. 42 for _, ai := range mheap_.allArenas { 43 arena := mheap_.arenas[ai.l1()][ai.l2()] 44 bitmap := arena.checkmarks 45 46 if bitmap == nil { 47 // Allocate bitmap on first use. 48 bitmap = (*checkmarksMap)(persistentalloc(unsafe.Sizeof(*bitmap), 0, &memstats.gcMiscSys)) 49 if bitmap == nil { 50 throw("out of memory allocating checkmarks bitmap") 51 } 52 arena.checkmarks = bitmap 53 } else { 54 // Otherwise clear the existing bitmap. 55 for i := range bitmap.b { 56 bitmap.b[i] = 0 57 } 58 } 59 } 60 // Enable checkmarking. 61 useCheckmark = true 62 } 63 64 // endCheckmarks ends the checkmarks phase. 65 func endCheckmarks() { 66 if gcMarkWorkAvailable(nil) { 67 throw("GC work not flushed") 68 } 69 useCheckmark = false 70 } 71 72 // setCheckmark throws if marking object is a checkmarks violation, 73 // and otherwise sets obj's checkmark. It returns true if obj was 74 // already checkmarked. 75 func setCheckmark(obj, base, off uintptr, mbits markBits) bool { 76 if !mbits.isMarked() { 77 printlock() 78 print("runtime: checkmarks found unexpected unmarked object obj=", hex(obj), "\n") 79 print("runtime: found obj at *(", hex(base), "+", hex(off), ")\n") 80 81 // Dump the source (base) object 82 gcDumpObject("base", base, off) 83 84 // Dump the object 85 gcDumpObject("obj", obj, ^uintptr(0)) 86 87 getg().m.traceback = 2 88 throw("checkmark found unmarked object") 89 } 90 91 ai := arenaIndex(obj) 92 arena := mheap_.arenas[ai.l1()][ai.l2()] 93 arenaWord := (obj / heapArenaBytes / 8) % uintptr(len(arena.checkmarks.b)) 94 mask := byte(1 << ((obj / heapArenaBytes) % 8)) 95 bytep := &arena.checkmarks.b[arenaWord] 96 97 if atomic.Load8(bytep)&mask != 0 { 98 // Already checkmarked. 99 return true 100 } 101 102 atomic.Or8(bytep, mask) 103 return false 104 }