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.
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.
17 "runtime/internal/atomic"
18 "runtime/internal/sys"
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
26 type checkmarksMap struct {
28 b [heapArenaBytes / goarch.PtrSize / 8]uint8
31 // If useCheckmark is true, marking of an object uses the checkmark
32 // bits instead of the standard mark bits.
33 var useCheckmark = false
35 // startCheckmarks prepares for the checkmarks phase.
37 // The world must be stopped.
38 func startCheckmarks() {
41 // Clear all checkmarks.
42 for _, ai := range mheap_.allArenas {
43 arena := mheap_.arenas[ai.l1()][ai.l2()]
44 bitmap := arena.checkmarks
47 // Allocate bitmap on first use.
48 bitmap = (*checkmarksMap)(persistentalloc(unsafe.Sizeof(*bitmap), 0, &memstats.gcMiscSys))
50 throw("out of memory allocating checkmarks bitmap")
52 arena.checkmarks = bitmap
54 // Otherwise clear the existing bitmap.
55 for i := range bitmap.b {
60 // Enable checkmarking.
64 // endCheckmarks ends the checkmarks phase.
65 func endCheckmarks() {
66 if gcMarkWorkAvailable(nil) {
67 throw("GC work not flushed")
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() {
78 print("runtime: checkmarks found unexpected unmarked object obj=", hex(obj), "\n")
79 print("runtime: found obj at *(", hex(base), "+", hex(off), ")\n")
81 // Dump the source (base) object
82 gcDumpObject("base", base, off)
85 gcDumpObject("obj", obj, ^uintptr(0))
87 getg().m.traceback = 2
88 throw("checkmark found unmarked object")
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]
97 if atomic.Load8(bytep)&mask != 0 {
98 // Already checkmarked.
102 atomic.Or8(bytep, mask)