github.com/jonasi/go@v0.0.0-20150930005915-e78e654c1de0/src/runtime/mgcmark.go (about)

     1  // Copyright 2009 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  // Garbage collector: marking and scanning
     6  
     7  package runtime
     8  
     9  import "unsafe"
    10  
    11  // Scan all of the stacks, greying (or graying if in America) the referents
    12  // but not blackening them since the mark write barrier isn't installed.
    13  //go:nowritebarrier
    14  func gcscan_m() {
    15  	_g_ := getg()
    16  
    17  	// Grab the g that called us and potentially allow rescheduling.
    18  	// This allows it to be scanned like other goroutines.
    19  	mastergp := _g_.m.curg
    20  	casgstatus(mastergp, _Grunning, _Gwaiting)
    21  	mastergp.waitreason = "garbage collection scan"
    22  
    23  	// Span sweeping has been done by finishsweep_m.
    24  	// Long term we will want to make this goroutine runnable
    25  	// by placing it onto a scanenqueue state and then calling
    26  	// runtimeĀ·restartg(mastergp) to make it Grunnable.
    27  	// At the bottom we will want to return this p back to the scheduler.
    28  
    29  	// Prepare flag indicating that the scan has not been completed.
    30  	local_allglen := gcResetGState()
    31  
    32  	work.ndone = 0
    33  	useOneP := uint32(1) // For now do not do this in parallel.
    34  	//	ackgcphase is not needed since we are not scanning running goroutines.
    35  	parforsetup(work.markfor, useOneP, uint32(_RootCount+local_allglen), false, markroot)
    36  	parfordo(work.markfor)
    37  
    38  	lock(&allglock)
    39  	// Check that gc work is done.
    40  	for i := 0; i < local_allglen; i++ {
    41  		gp := allgs[i]
    42  		if !gp.gcscandone {
    43  			throw("scan missed a g")
    44  		}
    45  	}
    46  	unlock(&allglock)
    47  
    48  	casgstatus(mastergp, _Gwaiting, _Grunning)
    49  	// Let the g that called us continue to run.
    50  }
    51  
    52  // ptrmask for an allocation containing a single pointer.
    53  var oneptrmask = [...]uint8{1}
    54  
    55  //go:nowritebarrier
    56  func markroot(desc *parfor, i uint32) {
    57  	// TODO: Consider using getg().m.p.ptr().gcw.
    58  	var gcw gcWork
    59  
    60  	// Note: if you add a case here, please also update heapdump.go:dumproots.
    61  	switch i {
    62  	case _RootData:
    63  		for datap := &firstmoduledata; datap != nil; datap = datap.next {
    64  			scanblock(datap.data, datap.edata-datap.data, datap.gcdatamask.bytedata, &gcw)
    65  		}
    66  
    67  	case _RootBss:
    68  		for datap := &firstmoduledata; datap != nil; datap = datap.next {
    69  			scanblock(datap.bss, datap.ebss-datap.bss, datap.gcbssmask.bytedata, &gcw)
    70  		}
    71  
    72  	case _RootFinalizers:
    73  		for fb := allfin; fb != nil; fb = fb.alllink {
    74  			scanblock(uintptr(unsafe.Pointer(&fb.fin[0])), uintptr(fb.cnt)*unsafe.Sizeof(fb.fin[0]), &finptrmask[0], &gcw)
    75  		}
    76  
    77  	case _RootFlushCaches:
    78  		if gcphase != _GCscan { // Do not flush mcaches during GCscan phase.
    79  			flushallmcaches()
    80  		}
    81  
    82  	default:
    83  		if _RootSpans0 <= i && i < _RootSpans0+_RootSpansShards {
    84  			// mark MSpan.specials
    85  			markrootSpans(&gcw, int(i)-_RootSpans0)
    86  			break
    87  		}
    88  
    89  		// the rest is scanning goroutine stacks
    90  		if uintptr(i-_RootCount) >= allglen {
    91  			throw("markroot: bad index")
    92  		}
    93  		gp := allgs[i-_RootCount]
    94  
    95  		// remember when we've first observed the G blocked
    96  		// needed only to output in traceback
    97  		status := readgstatus(gp) // We are not in a scan state
    98  		if (status == _Gwaiting || status == _Gsyscall) && gp.waitsince == 0 {
    99  			gp.waitsince = work.tstart
   100  		}
   101  
   102  		// Shrink a stack if not much of it is being used but not in the scan phase.
   103  		if gcphase == _GCmarktermination {
   104  			// Shrink during STW GCmarktermination phase thus avoiding
   105  			// complications introduced by shrinking during
   106  			// non-STW phases.
   107  			shrinkstack(gp)
   108  		}
   109  
   110  		scang(gp)
   111  	}
   112  
   113  	gcw.dispose()
   114  }
   115  
   116  // markrootSpans marks roots for one shard (out of _RootSpansShards)
   117  // of work.spans.
   118  //
   119  //go:nowritebarrier
   120  func markrootSpans(gcw *gcWork, shard int) {
   121  	sg := mheap_.sweepgen
   122  	startSpan := shard * len(work.spans) / _RootSpansShards
   123  	endSpan := (shard + 1) * len(work.spans) / _RootSpansShards
   124  	for _, s := range work.spans[startSpan:endSpan] {
   125  		if s.state != mSpanInUse {
   126  			continue
   127  		}
   128  		if !useCheckmark && s.sweepgen != sg {
   129  			// sweepgen was updated (+2) during non-checkmark GC pass
   130  			print("sweep ", s.sweepgen, " ", sg, "\n")
   131  			throw("gc: unswept span")
   132  		}
   133  		for sp := s.specials; sp != nil; sp = sp.next {
   134  			if sp.kind != _KindSpecialFinalizer {
   135  				continue
   136  			}
   137  			// don't mark finalized object, but scan it so we
   138  			// retain everything it points to.
   139  			spf := (*specialfinalizer)(unsafe.Pointer(sp))
   140  			// A finalizer can be set for an inner byte of an object, find object beginning.
   141  			p := uintptr(s.start<<_PageShift) + uintptr(spf.special.offset)/s.elemsize*s.elemsize
   142  			if gcphase != _GCscan {
   143  				scanobject(p, gcw) // scanned during mark termination
   144  			}
   145  			scanblock(uintptr(unsafe.Pointer(&spf.fn)), ptrSize, &oneptrmask[0], gcw)
   146  		}
   147  	}
   148  }
   149  
   150  // gcAssistAlloc records and allocation of size bytes and, if
   151  // allowAssist is true, may assist GC scanning in proportion to the
   152  // allocations performed by this mutator since the last assist.
   153  //
   154  // It should only be called if gcAssistAlloc != 0.
   155  //
   156  // This must be called with preemption disabled.
   157  //go:nowritebarrier
   158  func gcAssistAlloc(size uintptr, allowAssist bool) {
   159  	// Find the G responsible for this assist.
   160  	gp := getg()
   161  	if gp.m.curg != nil {
   162  		gp = gp.m.curg
   163  	}
   164  
   165  	// Record allocation.
   166  	gp.gcalloc += size
   167  
   168  	if !allowAssist {
   169  		return
   170  	}
   171  
   172  	// Don't assist in non-preemptible contexts. These are
   173  	// generally fragile and won't allow the assist to block.
   174  	if getg() == gp.m.g0 {
   175  		return
   176  	}
   177  	if mp := getg().m; mp.locks > 0 || mp.preemptoff != "" {
   178  		return
   179  	}
   180  
   181  	// Compute the amount of assist scan work we need to do.
   182  	scanWork := int64(gcController.assistRatio*float64(gp.gcalloc)) - gp.gcscanwork
   183  	// scanWork can be negative if the last assist scanned a large
   184  	// object and we're still ahead of our assist goal.
   185  	if scanWork <= 0 {
   186  		return
   187  	}
   188  
   189  retry:
   190  	// Steal as much credit as we can from the background GC's
   191  	// scan credit. This is racy and may drop the background
   192  	// credit below 0 if two mutators steal at the same time. This
   193  	// will just cause steals to fail until credit is accumulated
   194  	// again, so in the long run it doesn't really matter, but we
   195  	// do have to handle the negative credit case.
   196  	bgScanCredit := atomicloadint64(&gcController.bgScanCredit)
   197  	stolen := int64(0)
   198  	if bgScanCredit > 0 {
   199  		if bgScanCredit < scanWork {
   200  			stolen = bgScanCredit
   201  		} else {
   202  			stolen = scanWork
   203  		}
   204  		xaddint64(&gcController.bgScanCredit, -stolen)
   205  
   206  		scanWork -= stolen
   207  		gp.gcscanwork += stolen
   208  
   209  		if scanWork == 0 {
   210  			return
   211  		}
   212  	}
   213  
   214  	// Perform assist work
   215  	completed := false
   216  	systemstack(func() {
   217  		if atomicload(&gcBlackenEnabled) == 0 {
   218  			// The gcBlackenEnabled check in malloc races with the
   219  			// store that clears it but an atomic check in every malloc
   220  			// would be a performance hit.
   221  			// Instead we recheck it here on the non-preemptable system
   222  			// stack to determine if we should preform an assist.
   223  
   224  			// GC is done, so ignore any remaining debt.
   225  			scanWork = 0
   226  			return
   227  		}
   228  		// Track time spent in this assist. Since we're on the
   229  		// system stack, this is non-preemptible, so we can
   230  		// just measure start and end time.
   231  		startTime := nanotime()
   232  
   233  		decnwait := xadd(&work.nwait, -1)
   234  		if decnwait == work.nproc {
   235  			println("runtime: work.nwait =", decnwait, "work.nproc=", work.nproc)
   236  			throw("nwait > work.nprocs")
   237  		}
   238  
   239  		// drain own cached work first in the hopes that it
   240  		// will be more cache friendly.
   241  		gcw := &getg().m.p.ptr().gcw
   242  		startScanWork := gcw.scanWork
   243  		gcDrainN(gcw, scanWork)
   244  		// Record that we did this much scan work.
   245  		workDone := gcw.scanWork - startScanWork
   246  		gp.gcscanwork += workDone
   247  		scanWork -= workDone
   248  		// If we are near the end of the mark phase
   249  		// dispose of the gcw.
   250  		if gcBlackenPromptly {
   251  			gcw.dispose()
   252  		}
   253  		// If this is the last worker and we ran out of work,
   254  		// signal a completion point.
   255  		incnwait := xadd(&work.nwait, +1)
   256  		if incnwait > work.nproc {
   257  			println("runtime: work.nwait=", incnwait,
   258  				"work.nproc=", work.nproc,
   259  				"gcBlackenPromptly=", gcBlackenPromptly)
   260  			throw("work.nwait > work.nproc")
   261  		}
   262  
   263  		if incnwait == work.nproc && work.full == 0 && work.partial == 0 {
   264  			// This has reached a background completion
   265  			// point.
   266  			if gcBlackenPromptly {
   267  				if work.bgMark1.done == 0 {
   268  					throw("completing mark 2, but bgMark1.done == 0")
   269  				}
   270  				work.bgMark2.complete()
   271  			} else {
   272  				work.bgMark1.complete()
   273  			}
   274  			completed = true
   275  		}
   276  		duration := nanotime() - startTime
   277  		_p_ := gp.m.p.ptr()
   278  		_p_.gcAssistTime += duration
   279  		if _p_.gcAssistTime > gcAssistTimeSlack {
   280  			xaddint64(&gcController.assistTime, _p_.gcAssistTime)
   281  			_p_.gcAssistTime = 0
   282  		}
   283  	})
   284  
   285  	if completed {
   286  		// We called complete() above, so we should yield to
   287  		// the now-runnable GC coordinator.
   288  		Gosched()
   289  
   290  		// It's likely that this assist wasn't able to pay off
   291  		// its debt, but it's also likely that the Gosched let
   292  		// the GC finish this cycle and there's no point in
   293  		// waiting. If the GC finished, skip the delay below.
   294  		if atomicload(&gcBlackenEnabled) == 0 {
   295  			scanWork = 0
   296  		}
   297  	}
   298  
   299  	if scanWork > 0 {
   300  		// We were unable steal enough credit or perform
   301  		// enough work to pay off the assist debt. We need to
   302  		// do one of these before letting the mutator allocate
   303  		// more, so go around again after performing an
   304  		// interruptible sleep for 100 us (the same as the
   305  		// getfull barrier) to let other mutators run.
   306  		timeSleep(100 * 1000)
   307  		goto retry
   308  	}
   309  }
   310  
   311  //go:nowritebarrier
   312  func scanstack(gp *g) {
   313  	if gp.gcscanvalid {
   314  		if gcphase == _GCmarktermination {
   315  			gcRemoveStackBarriers(gp)
   316  		}
   317  		return
   318  	}
   319  
   320  	if readgstatus(gp)&_Gscan == 0 {
   321  		print("runtime:scanstack: gp=", gp, ", goid=", gp.goid, ", gp->atomicstatus=", hex(readgstatus(gp)), "\n")
   322  		throw("scanstack - bad status")
   323  	}
   324  
   325  	switch readgstatus(gp) &^ _Gscan {
   326  	default:
   327  		print("runtime: gp=", gp, ", goid=", gp.goid, ", gp->atomicstatus=", readgstatus(gp), "\n")
   328  		throw("mark - bad status")
   329  	case _Gdead:
   330  		return
   331  	case _Grunning:
   332  		print("runtime: gp=", gp, ", goid=", gp.goid, ", gp->atomicstatus=", readgstatus(gp), "\n")
   333  		throw("scanstack: goroutine not stopped")
   334  	case _Grunnable, _Gsyscall, _Gwaiting:
   335  		// ok
   336  	}
   337  
   338  	if gp == getg() {
   339  		throw("can't scan our own stack")
   340  	}
   341  	mp := gp.m
   342  	if mp != nil && mp.helpgc != 0 {
   343  		throw("can't scan gchelper stack")
   344  	}
   345  
   346  	var sp, barrierOffset, nextBarrier uintptr
   347  	if gp.syscallsp != 0 {
   348  		sp = gp.syscallsp
   349  	} else {
   350  		sp = gp.sched.sp
   351  	}
   352  	switch gcphase {
   353  	case _GCscan:
   354  		// Install stack barriers during stack scan.
   355  		barrierOffset = uintptr(firstStackBarrierOffset)
   356  		nextBarrier = sp + barrierOffset
   357  
   358  		if debug.gcstackbarrieroff > 0 {
   359  			nextBarrier = ^uintptr(0)
   360  		}
   361  
   362  		if gp.stkbarPos != 0 || len(gp.stkbar) != 0 {
   363  			// If this happens, it's probably because we
   364  			// scanned a stack twice in the same phase.
   365  			print("stkbarPos=", gp.stkbarPos, " len(stkbar)=", len(gp.stkbar), " goid=", gp.goid, " gcphase=", gcphase, "\n")
   366  			throw("g already has stack barriers")
   367  		}
   368  
   369  	case _GCmarktermination:
   370  		if int(gp.stkbarPos) == len(gp.stkbar) {
   371  			// gp hit all of the stack barriers (or there
   372  			// were none). Re-scan the whole stack.
   373  			nextBarrier = ^uintptr(0)
   374  		} else {
   375  			// Only re-scan up to the lowest un-hit
   376  			// barrier. Any frames above this have not
   377  			// executed since the _GCscan scan of gp and
   378  			// any writes through up-pointers to above
   379  			// this barrier had write barriers.
   380  			nextBarrier = gp.stkbar[gp.stkbarPos].savedLRPtr
   381  			if debugStackBarrier {
   382  				print("rescan below ", hex(nextBarrier), " in [", hex(sp), ",", hex(gp.stack.hi), ") goid=", gp.goid, "\n")
   383  			}
   384  		}
   385  
   386  		gcRemoveStackBarriers(gp)
   387  
   388  	default:
   389  		throw("scanstack in wrong phase")
   390  	}
   391  
   392  	gcw := &getg().m.p.ptr().gcw
   393  	n := 0
   394  	scanframe := func(frame *stkframe, unused unsafe.Pointer) bool {
   395  		scanframeworker(frame, unused, gcw)
   396  
   397  		if frame.fp > nextBarrier {
   398  			// We skip installing a barrier on bottom-most
   399  			// frame because on LR machines this LR is not
   400  			// on the stack.
   401  			if gcphase == _GCscan && n != 0 {
   402  				if gcInstallStackBarrier(gp, frame) {
   403  					barrierOffset *= 2
   404  					nextBarrier = sp + barrierOffset
   405  				}
   406  			} else if gcphase == _GCmarktermination {
   407  				// We just scanned a frame containing
   408  				// a return to a stack barrier. Since
   409  				// this frame never returned, we can
   410  				// stop scanning.
   411  				return false
   412  			}
   413  		}
   414  		n++
   415  
   416  		return true
   417  	}
   418  	gentraceback(^uintptr(0), ^uintptr(0), 0, gp, 0, nil, 0x7fffffff, scanframe, nil, 0)
   419  	tracebackdefers(gp, scanframe, nil)
   420  	if gcphase == _GCmarktermination {
   421  		gcw.dispose()
   422  	}
   423  	gp.gcscanvalid = true
   424  }
   425  
   426  // Scan a stack frame: local variables and function arguments/results.
   427  //go:nowritebarrier
   428  func scanframeworker(frame *stkframe, unused unsafe.Pointer, gcw *gcWork) {
   429  
   430  	f := frame.fn
   431  	targetpc := frame.continpc
   432  	if targetpc == 0 {
   433  		// Frame is dead.
   434  		return
   435  	}
   436  	if _DebugGC > 1 {
   437  		print("scanframe ", funcname(f), "\n")
   438  	}
   439  	if targetpc != f.entry {
   440  		targetpc--
   441  	}
   442  	pcdata := pcdatavalue(f, _PCDATA_StackMapIndex, targetpc)
   443  	if pcdata == -1 {
   444  		// We do not have a valid pcdata value but there might be a
   445  		// stackmap for this function.  It is likely that we are looking
   446  		// at the function prologue, assume so and hope for the best.
   447  		pcdata = 0
   448  	}
   449  
   450  	// Scan local variables if stack frame has been allocated.
   451  	size := frame.varp - frame.sp
   452  	var minsize uintptr
   453  	switch thechar {
   454  	case '6', '8':
   455  		minsize = 0
   456  	case '7':
   457  		minsize = spAlign
   458  	default:
   459  		minsize = ptrSize
   460  	}
   461  	if size > minsize {
   462  		stkmap := (*stackmap)(funcdata(f, _FUNCDATA_LocalsPointerMaps))
   463  		if stkmap == nil || stkmap.n <= 0 {
   464  			print("runtime: frame ", funcname(f), " untyped locals ", hex(frame.varp-size), "+", hex(size), "\n")
   465  			throw("missing stackmap")
   466  		}
   467  
   468  		// Locals bitmap information, scan just the pointers in locals.
   469  		if pcdata < 0 || pcdata >= stkmap.n {
   470  			// don't know where we are
   471  			print("runtime: pcdata is ", pcdata, " and ", stkmap.n, " locals stack map entries for ", funcname(f), " (targetpc=", targetpc, ")\n")
   472  			throw("scanframe: bad symbol table")
   473  		}
   474  		bv := stackmapdata(stkmap, pcdata)
   475  		size = uintptr(bv.n) * ptrSize
   476  		scanblock(frame.varp-size, size, bv.bytedata, gcw)
   477  	}
   478  
   479  	// Scan arguments.
   480  	if frame.arglen > 0 {
   481  		var bv bitvector
   482  		if frame.argmap != nil {
   483  			bv = *frame.argmap
   484  		} else {
   485  			stkmap := (*stackmap)(funcdata(f, _FUNCDATA_ArgsPointerMaps))
   486  			if stkmap == nil || stkmap.n <= 0 {
   487  				print("runtime: frame ", funcname(f), " untyped args ", hex(frame.argp), "+", hex(frame.arglen), "\n")
   488  				throw("missing stackmap")
   489  			}
   490  			if pcdata < 0 || pcdata >= stkmap.n {
   491  				// don't know where we are
   492  				print("runtime: pcdata is ", pcdata, " and ", stkmap.n, " args stack map entries for ", funcname(f), " (targetpc=", targetpc, ")\n")
   493  				throw("scanframe: bad symbol table")
   494  			}
   495  			bv = stackmapdata(stkmap, pcdata)
   496  		}
   497  		scanblock(frame.argp, uintptr(bv.n)*ptrSize, bv.bytedata, gcw)
   498  	}
   499  }
   500  
   501  // TODO(austin): Can we consolidate the gcDrain* functions?
   502  
   503  // gcDrain scans objects in work buffers, blackening grey
   504  // objects until all work buffers have been drained.
   505  // If flushScanCredit != -1, gcDrain flushes accumulated scan work
   506  // credit to gcController.bgScanCredit whenever gcw's local scan work
   507  // credit exceeds flushScanCredit.
   508  //go:nowritebarrier
   509  func gcDrain(gcw *gcWork, flushScanCredit int64) {
   510  	if !writeBarrierEnabled {
   511  		throw("gcDrain phase incorrect")
   512  	}
   513  
   514  	var lastScanFlush, nextScanFlush int64
   515  	if flushScanCredit != -1 {
   516  		lastScanFlush = gcw.scanWork
   517  		nextScanFlush = lastScanFlush + flushScanCredit
   518  	} else {
   519  		nextScanFlush = int64(^uint64(0) >> 1)
   520  	}
   521  
   522  	for {
   523  		// If another proc wants a pointer, give it some.
   524  		if work.nwait > 0 && work.full == 0 {
   525  			gcw.balance()
   526  		}
   527  
   528  		b := gcw.get()
   529  		if b == 0 {
   530  			// work barrier reached
   531  			break
   532  		}
   533  		// If the current wbuf is filled by the scan a new wbuf might be
   534  		// returned that could possibly hold only a single object. This
   535  		// could result in each iteration draining only a single object
   536  		// out of the wbuf passed in + a single object placed
   537  		// into an empty wbuf in scanobject so there could be
   538  		// a performance hit as we keep fetching fresh wbufs.
   539  		scanobject(b, gcw)
   540  
   541  		// Flush background scan work credit to the global
   542  		// account if we've accumulated enough locally so
   543  		// mutator assists can draw on it.
   544  		if gcw.scanWork >= nextScanFlush {
   545  			credit := gcw.scanWork - lastScanFlush
   546  			xaddint64(&gcController.bgScanCredit, credit)
   547  			lastScanFlush = gcw.scanWork
   548  			nextScanFlush = lastScanFlush + flushScanCredit
   549  		}
   550  	}
   551  	if flushScanCredit != -1 {
   552  		credit := gcw.scanWork - lastScanFlush
   553  		xaddint64(&gcController.bgScanCredit, credit)
   554  	}
   555  }
   556  
   557  // gcDrainUntilPreempt blackens grey objects until g.preempt is set.
   558  // This is best-effort, so it will return as soon as it is unable to
   559  // get work, even though there may be more work in the system.
   560  //go:nowritebarrier
   561  func gcDrainUntilPreempt(gcw *gcWork, flushScanCredit int64) {
   562  	if !writeBarrierEnabled {
   563  		println("gcphase =", gcphase)
   564  		throw("gcDrainUntilPreempt phase incorrect")
   565  	}
   566  
   567  	var lastScanFlush, nextScanFlush int64
   568  	if flushScanCredit != -1 {
   569  		lastScanFlush = gcw.scanWork
   570  		nextScanFlush = lastScanFlush + flushScanCredit
   571  	} else {
   572  		nextScanFlush = int64(^uint64(0) >> 1)
   573  	}
   574  
   575  	gp := getg()
   576  	for !gp.preempt {
   577  		// If the work queue is empty, balance. During
   578  		// concurrent mark we don't really know if anyone else
   579  		// can make use of this work, but even if we're the
   580  		// only worker, the total cost of this per cycle is
   581  		// only O(_WorkbufSize) pointer copies.
   582  		if work.full == 0 && work.partial == 0 {
   583  			gcw.balance()
   584  		}
   585  
   586  		b := gcw.tryGet()
   587  		if b == 0 {
   588  			// No more work
   589  			break
   590  		}
   591  		scanobject(b, gcw)
   592  
   593  		// Flush background scan work credit to the global
   594  		// account if we've accumulated enough locally so
   595  		// mutator assists can draw on it.
   596  		if gcw.scanWork >= nextScanFlush {
   597  			credit := gcw.scanWork - lastScanFlush
   598  			xaddint64(&gcController.bgScanCredit, credit)
   599  			lastScanFlush = gcw.scanWork
   600  			nextScanFlush = lastScanFlush + flushScanCredit
   601  		}
   602  	}
   603  	if flushScanCredit != -1 {
   604  		credit := gcw.scanWork - lastScanFlush
   605  		xaddint64(&gcController.bgScanCredit, credit)
   606  	}
   607  }
   608  
   609  // gcDrainN blackens grey objects until it has performed roughly
   610  // scanWork units of scan work. This is best-effort, so it may perform
   611  // less work if it fails to get a work buffer. Otherwise, it will
   612  // perform at least n units of work, but may perform more because
   613  // scanning is always done in whole object increments.
   614  //go:nowritebarrier
   615  func gcDrainN(gcw *gcWork, scanWork int64) {
   616  	if !writeBarrierEnabled {
   617  		throw("gcDrainN phase incorrect")
   618  	}
   619  	targetScanWork := gcw.scanWork + scanWork
   620  	for gcw.scanWork < targetScanWork {
   621  		// This might be a good place to add prefetch code...
   622  		// if(wbuf.nobj > 4) {
   623  		//         PREFETCH(wbuf->obj[wbuf.nobj - 3];
   624  		//  }
   625  		b := gcw.tryGet()
   626  		if b == 0 {
   627  			return
   628  		}
   629  		scanobject(b, gcw)
   630  	}
   631  }
   632  
   633  // scanblock scans b as scanobject would, but using an explicit
   634  // pointer bitmap instead of the heap bitmap.
   635  //
   636  // This is used to scan non-heap roots, so it does not update
   637  // gcw.bytesMarked or gcw.scanWork.
   638  //
   639  //go:nowritebarrier
   640  func scanblock(b0, n0 uintptr, ptrmask *uint8, gcw *gcWork) {
   641  	// Use local copies of original parameters, so that a stack trace
   642  	// due to one of the throws below shows the original block
   643  	// base and extent.
   644  	b := b0
   645  	n := n0
   646  
   647  	arena_start := mheap_.arena_start
   648  	arena_used := mheap_.arena_used
   649  
   650  	for i := uintptr(0); i < n; {
   651  		// Find bits for the next word.
   652  		bits := uint32(*addb(ptrmask, i/(ptrSize*8)))
   653  		if bits == 0 {
   654  			i += ptrSize * 8
   655  			continue
   656  		}
   657  		for j := 0; j < 8 && i < n; j++ {
   658  			if bits&1 != 0 {
   659  				// Same work as in scanobject; see comments there.
   660  				obj := *(*uintptr)(unsafe.Pointer(b + i))
   661  				if obj != 0 && arena_start <= obj && obj < arena_used {
   662  					if obj, hbits, span := heapBitsForObject(obj, b, i); obj != 0 {
   663  						greyobject(obj, b, i, hbits, span, gcw)
   664  					}
   665  				}
   666  			}
   667  			bits >>= 1
   668  			i += ptrSize
   669  		}
   670  	}
   671  }
   672  
   673  // scanobject scans the object starting at b, adding pointers to gcw.
   674  // b must point to the beginning of a heap object; scanobject consults
   675  // the GC bitmap for the pointer mask and the spans for the size of the
   676  // object (it ignores n).
   677  //go:nowritebarrier
   678  func scanobject(b uintptr, gcw *gcWork) {
   679  	// Note that arena_used may change concurrently during
   680  	// scanobject and hence scanobject may encounter a pointer to
   681  	// a newly allocated heap object that is *not* in
   682  	// [start,used). It will not mark this object; however, we
   683  	// know that it was just installed by a mutator, which means
   684  	// that mutator will execute a write barrier and take care of
   685  	// marking it. This is even more pronounced on relaxed memory
   686  	// architectures since we access arena_used without barriers
   687  	// or synchronization, but the same logic applies.
   688  	arena_start := mheap_.arena_start
   689  	arena_used := mheap_.arena_used
   690  
   691  	// Find bits of the beginning of the object.
   692  	// b must point to the beginning of a heap object, so
   693  	// we can get its bits and span directly.
   694  	hbits := heapBitsForAddr(b)
   695  	s := spanOfUnchecked(b)
   696  	n := s.elemsize
   697  	if n == 0 {
   698  		throw("scanobject n == 0")
   699  	}
   700  
   701  	var i uintptr
   702  	for i = 0; i < n; i += ptrSize {
   703  		// Find bits for this word.
   704  		if i != 0 {
   705  			// Avoid needless hbits.next() on last iteration.
   706  			hbits = hbits.next()
   707  		}
   708  		// During checkmarking, 1-word objects store the checkmark
   709  		// in the type bit for the one word. The only one-word objects
   710  		// are pointers, or else they'd be merged with other non-pointer
   711  		// data into larger allocations.
   712  		bits := hbits.bits()
   713  		if i >= 2*ptrSize && bits&bitMarked == 0 {
   714  			break // no more pointers in this object
   715  		}
   716  		if bits&bitPointer == 0 {
   717  			continue // not a pointer
   718  		}
   719  
   720  		// Work here is duplicated in scanblock and above.
   721  		// If you make changes here, make changes there too.
   722  		obj := *(*uintptr)(unsafe.Pointer(b + i))
   723  
   724  		// At this point we have extracted the next potential pointer.
   725  		// Check if it points into heap and not back at the current object.
   726  		if obj != 0 && arena_start <= obj && obj < arena_used && obj-b >= n {
   727  			// Mark the object.
   728  			if obj, hbits, span := heapBitsForObject(obj, b, i); obj != 0 {
   729  				greyobject(obj, b, i, hbits, span, gcw)
   730  			}
   731  		}
   732  	}
   733  	gcw.bytesMarked += uint64(n)
   734  	gcw.scanWork += int64(i)
   735  }
   736  
   737  // Shade the object if it isn't already.
   738  // The object is not nil and known to be in the heap.
   739  // Preemption must be disabled.
   740  //go:nowritebarrier
   741  func shade(b uintptr) {
   742  	if obj, hbits, span := heapBitsForObject(b, 0, 0); obj != 0 {
   743  		gcw := &getg().m.p.ptr().gcw
   744  		greyobject(obj, 0, 0, hbits, span, gcw)
   745  		if gcphase == _GCmarktermination || gcBlackenPromptly {
   746  			// Ps aren't allowed to cache work during mark
   747  			// termination.
   748  			gcw.dispose()
   749  		}
   750  	}
   751  }
   752  
   753  // obj is the start of an object with mark mbits.
   754  // If it isn't already marked, mark it and enqueue into gcw.
   755  // base and off are for debugging only and could be removed.
   756  //go:nowritebarrier
   757  func greyobject(obj, base, off uintptr, hbits heapBits, span *mspan, gcw *gcWork) {
   758  	// obj should be start of allocation, and so must be at least pointer-aligned.
   759  	if obj&(ptrSize-1) != 0 {
   760  		throw("greyobject: obj not pointer-aligned")
   761  	}
   762  
   763  	if useCheckmark {
   764  		if !hbits.isMarked() {
   765  			printlock()
   766  			print("runtime:greyobject: checkmarks finds unexpected unmarked object obj=", hex(obj), "\n")
   767  			print("runtime: found obj at *(", hex(base), "+", hex(off), ")\n")
   768  
   769  			// Dump the source (base) object
   770  			gcDumpObject("base", base, off)
   771  
   772  			// Dump the object
   773  			gcDumpObject("obj", obj, ^uintptr(0))
   774  
   775  			throw("checkmark found unmarked object")
   776  		}
   777  		if hbits.isCheckmarked(span.elemsize) {
   778  			return
   779  		}
   780  		hbits.setCheckmarked(span.elemsize)
   781  		if !hbits.isCheckmarked(span.elemsize) {
   782  			throw("setCheckmarked and isCheckmarked disagree")
   783  		}
   784  	} else {
   785  		// If marked we have nothing to do.
   786  		if hbits.isMarked() {
   787  			return
   788  		}
   789  		hbits.setMarked()
   790  
   791  		// If this is a noscan object, fast-track it to black
   792  		// instead of greying it.
   793  		if !hbits.hasPointers(span.elemsize) {
   794  			gcw.bytesMarked += uint64(span.elemsize)
   795  			return
   796  		}
   797  	}
   798  
   799  	// Queue the obj for scanning. The PREFETCH(obj) logic has been removed but
   800  	// seems like a nice optimization that can be added back in.
   801  	// There needs to be time between the PREFETCH and the use.
   802  	// Previously we put the obj in an 8 element buffer that is drained at a rate
   803  	// to give the PREFETCH time to do its work.
   804  	// Use of PREFETCHNTA might be more appropriate than PREFETCH
   805  
   806  	gcw.put(obj)
   807  }
   808  
   809  // gcDumpObject dumps the contents of obj for debugging and marks the
   810  // field at byte offset off in obj.
   811  func gcDumpObject(label string, obj, off uintptr) {
   812  	if obj < mheap_.arena_start || obj >= mheap_.arena_used {
   813  		print(label, "=", hex(obj), " is not in the Go heap\n")
   814  		return
   815  	}
   816  	k := obj >> _PageShift
   817  	x := k
   818  	x -= mheap_.arena_start >> _PageShift
   819  	s := h_spans[x]
   820  	print(label, "=", hex(obj), " k=", hex(k))
   821  	if s == nil {
   822  		print(" s=nil\n")
   823  		return
   824  	}
   825  	print(" s.start*_PageSize=", hex(s.start*_PageSize), " s.limit=", hex(s.limit), " s.sizeclass=", s.sizeclass, " s.elemsize=", s.elemsize, "\n")
   826  	skipped := false
   827  	for i := uintptr(0); i < s.elemsize; i += ptrSize {
   828  		// For big objects, just print the beginning (because
   829  		// that usually hints at the object's type) and the
   830  		// fields around off.
   831  		if !(i < 128*ptrSize || off-16*ptrSize < i && i < off+16*ptrSize) {
   832  			skipped = true
   833  			continue
   834  		}
   835  		if skipped {
   836  			print(" ...\n")
   837  			skipped = false
   838  		}
   839  		print(" *(", label, "+", i, ") = ", hex(*(*uintptr)(unsafe.Pointer(obj + uintptr(i)))))
   840  		if i == off {
   841  			print(" <==")
   842  		}
   843  		print("\n")
   844  	}
   845  	if skipped {
   846  		print(" ...\n")
   847  	}
   848  }
   849  
   850  // If gcBlackenPromptly is true we are in the second mark phase phase so we allocate black.
   851  //go:nowritebarrier
   852  func gcmarknewobject_m(obj, size uintptr) {
   853  	if useCheckmark && !gcBlackenPromptly { // The world should be stopped so this should not happen.
   854  		throw("gcmarknewobject called while doing checkmark")
   855  	}
   856  	heapBitsForAddr(obj).setMarked()
   857  	xadd64(&work.bytesMarked, int64(size))
   858  }
   859  
   860  // Checkmarking
   861  
   862  // To help debug the concurrent GC we remark with the world
   863  // stopped ensuring that any object encountered has their normal
   864  // mark bit set. To do this we use an orthogonal bit
   865  // pattern to indicate the object is marked. The following pattern
   866  // uses the upper two bits in the object's boundary nibble.
   867  // 01: scalar  not marked
   868  // 10: pointer not marked
   869  // 11: pointer     marked
   870  // 00: scalar      marked
   871  // Xoring with 01 will flip the pattern from marked to unmarked and vica versa.
   872  // The higher bit is 1 for pointers and 0 for scalars, whether the object
   873  // is marked or not.
   874  // The first nibble no longer holds the typeDead pattern indicating that the
   875  // there are no more pointers in the object. This information is held
   876  // in the second nibble.
   877  
   878  // If useCheckmark is true, marking of an object uses the
   879  // checkmark bits (encoding above) instead of the standard
   880  // mark bits.
   881  var useCheckmark = false
   882  
   883  //go:nowritebarrier
   884  func initCheckmarks() {
   885  	useCheckmark = true
   886  	for _, s := range work.spans {
   887  		if s.state == _MSpanInUse {
   888  			heapBitsForSpan(s.base()).initCheckmarkSpan(s.layout())
   889  		}
   890  	}
   891  }
   892  
   893  func clearCheckmarks() {
   894  	useCheckmark = false
   895  	for _, s := range work.spans {
   896  		if s.state == _MSpanInUse {
   897  			heapBitsForSpan(s.base()).clearCheckmarkSpan(s.layout())
   898  		}
   899  	}
   900  }