const fixedRootFinalizers … const fixedRootFreeGStacks … const fixedRootCount … const rootBlockBytes … const maxObletBytes … const drainCheckThreshold … const pagesPerSpanRoot … // gcMarkRootPrepare queues root scanning jobs (stacks, globals, and // some miscellany) and initializes scanning-related state. // // The world must be stopped. func gcMarkRootPrepare() { … } // gcMarkRootCheck checks that all roots have been scanned. It is // purely for debugging. func gcMarkRootCheck() { … } var oneptrmask … // markroot scans the i'th root. // // Preemption must be disabled (because this uses a gcWork). // // Returns the amount of GC work credit produced by the operation. // If flushBgCredit is true, then that credit is also flushed // to the background credit pool. // // nowritebarrier is only advisory here. // //go:nowritebarrier func markroot(gcw *gcWork, i uint32, flushBgCredit bool) int64 { … } // markrootBlock scans the shard'th shard of the block of memory [b0, // b0+n0), with the given pointer mask. // // Returns the amount of work done. // //go:nowritebarrier func markrootBlock(b0, n0 uintptr, ptrmask0 *uint8, gcw *gcWork, shard int) int64 { … } // markrootFreeGStacks frees stacks of dead Gs. // // This does not free stacks of dead Gs cached on Ps, but having a few // cached stacks around isn't a problem. func markrootFreeGStacks() { … } // markrootSpans marks roots for one shard of markArenas. // //go:nowritebarrier func markrootSpans(gcw *gcWork, shard int) { … } // gcAssistAlloc performs GC work to make gp's assist debt positive. // gp must be the calling user goroutine. // // This must be called with preemption enabled. func gcAssistAlloc(gp *g) { … } // gcAssistAlloc1 is the part of gcAssistAlloc that runs on the system // stack. This is a separate function to make it easier to see that // we're not capturing anything from the user stack, since the user // stack may move while we're in this function. // // gcAssistAlloc1 indicates whether this assist completed the mark // phase by setting gp.param to non-nil. This can't be communicated on // the stack since it may move. // //go:systemstack func gcAssistAlloc1(gp *g, scanWork int64) { … } // gcWakeAllAssists wakes all currently blocked assists. This is used // at the end of a GC cycle. gcBlackenEnabled must be false to prevent // new assists from going to sleep after this point. func gcWakeAllAssists() { … } // gcParkAssist puts the current goroutine on the assist queue and parks. // // gcParkAssist reports whether the assist is now satisfied. If it // returns false, the caller must retry the assist. func gcParkAssist() bool { … } // gcFlushBgCredit flushes scanWork units of background scan work // credit. This first satisfies blocked assists on the // work.assistQueue and then flushes any remaining credit to // gcController.bgScanCredit. // // Write barriers are disallowed because this is used by gcDrain after // it has ensured that all work is drained and this must preserve that // condition. // //go:nowritebarrierrec func gcFlushBgCredit(scanWork int64) { … } // scanstack scans gp's stack, greying all pointers found on the stack. // // Returns the amount of scan work performed, but doesn't update // gcController.stackScanWork or flush any credit. Any background credit produced // by this function should be flushed by its caller. scanstack itself can't // safely flush because it may result in trying to wake up a goroutine that // was just scanned, resulting in a self-deadlock. // // scanstack will also shrink the stack if it is safe to do so. If it // is not, it schedules a stack shrink for the next synchronous safe // point. // // scanstack is marked go:systemstack because it must not be preempted // while using a workbuf. // //go:nowritebarrier //go:systemstack func scanstack(gp *g, gcw *gcWork) int64 { … } // Scan a stack frame: local variables and function arguments/results. // //go:nowritebarrier func scanframeworker(frame *stkframe, state *stackScanState, gcw *gcWork) { … } type gcDrainFlags … const gcDrainUntilPreempt … const gcDrainFlushBgCredit … const gcDrainIdle … const gcDrainFractional … // gcDrainMarkWorkerIdle is a wrapper for gcDrain that exists to better account // mark time in profiles. func gcDrainMarkWorkerIdle(gcw *gcWork) { … } // gcDrainMarkWorkerDedicated is a wrapper for gcDrain that exists to better account // mark time in profiles. func gcDrainMarkWorkerDedicated(gcw *gcWork, untilPreempt bool) { … } // gcDrainMarkWorkerFractional is a wrapper for gcDrain that exists to better account // mark time in profiles. func gcDrainMarkWorkerFractional(gcw *gcWork) { … } // gcDrain scans roots and objects in work buffers, blackening grey // objects until it is unable to get more work. It may return before // GC is done; it's the caller's responsibility to balance work from // other Ps. // // If flags&gcDrainUntilPreempt != 0, gcDrain returns when g.preempt // is set. // // If flags&gcDrainIdle != 0, gcDrain returns when there is other work // to do. // // If flags&gcDrainFractional != 0, gcDrain self-preempts when // pollFractionalWorkerExit() returns true. This implies // gcDrainNoBlock. // // If flags&gcDrainFlushBgCredit != 0, gcDrain flushes scan work // credit to gcController.bgScanCredit every gcCreditSlack units of // scan work. // // gcDrain will always return if there is a pending STW or forEachP. // // Disabling write barriers is necessary to ensure that after we've // confirmed that we've drained gcw, that we don't accidentally end // up flipping that condition by immediately adding work in the form // of a write barrier buffer flush. // // Don't set nowritebarrierrec because it's safe for some callees to // have write barriers enabled. // //go:nowritebarrier func gcDrain(gcw *gcWork, flags gcDrainFlags) { … } // gcDrainN blackens grey objects until it has performed roughly // scanWork units of scan work or the G is preempted. This is // best-effort, so it may perform less work if it fails to get a work // buffer. Otherwise, it will perform at least n units of work, but // may perform more because scanning is always done in whole object // increments. It returns the amount of scan work performed. // // The caller goroutine must be in a preemptible state (e.g., // _Gwaiting) to prevent deadlocks during stack scanning. As a // consequence, this must be called on the system stack. // //go:nowritebarrier //go:systemstack func gcDrainN(gcw *gcWork, scanWork int64) int64 { … } // scanblock scans b as scanobject would, but using an explicit // pointer bitmap instead of the heap bitmap. // // This is used to scan non-heap roots, so it does not update // gcw.bytesMarked or gcw.heapScanWork. // // If stk != nil, possible stack pointers are also reported to stk.putPtr. // //go:nowritebarrier func scanblock(b0, n0 uintptr, ptrmask *uint8, gcw *gcWork, stk *stackScanState) { … } // scanobject scans the object starting at b, adding pointers to gcw. // b must point to the beginning of a heap object or an oblet. // scanobject consults the GC bitmap for the pointer mask and the // spans for the size of the object. // //go:nowritebarrier func scanobject(b uintptr, gcw *gcWork) { … } // scanConservative scans block [b, b+n) conservatively, treating any // pointer-like value in the block as a pointer. // // If ptrmask != nil, only words that are marked in ptrmask are // considered as potential pointers. // // If state != nil, it's assumed that [b, b+n) is a block in the stack // and may contain pointers to stack objects. func scanConservative(b, n uintptr, ptrmask *uint8, gcw *gcWork, state *stackScanState) { … } // Shade the object if it isn't already. // The object is not nil and known to be in the heap. // Preemption must be disabled. // //go:nowritebarrier func shade(b uintptr) { … } // obj is the start of an object with mark mbits. // If it isn't already marked, mark it and enqueue into gcw. // base and off are for debugging only and could be removed. // // See also wbBufFlush1, which partially duplicates this logic. // //go:nowritebarrierrec func greyobject(obj, base, off uintptr, span *mspan, gcw *gcWork, objIndex uintptr) { … } // gcDumpObject dumps the contents of obj for debugging and marks the // field at byte offset off in obj. func gcDumpObject(label string, obj, off uintptr) { … } // gcmarknewobject marks a newly allocated object black. obj must // not contain any non-nil pointers. // // This is nosplit so it can manipulate a gcWork without preemption. // //go:nowritebarrier //go:nosplit func gcmarknewobject(span *mspan, obj uintptr) { … } // gcMarkTinyAllocs greys all active tiny alloc blocks. // // The world must be stopped. func gcMarkTinyAllocs() { … }