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 }