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