]> Cypherpunks.ru repositories - gostls13.git/blob - src/runtime/export_test.go
d5a3258a06ca31df0eca57e813b6fe6843860c20
[gostls13.git] / src / runtime / export_test.go
1 // Copyright 2010 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 // Export guts for testing.
6
7 package runtime
8
9 import (
10         "internal/goarch"
11         "internal/goos"
12         "runtime/internal/atomic"
13         "runtime/internal/sys"
14         "unsafe"
15 )
16
17 var Fadd64 = fadd64
18 var Fsub64 = fsub64
19 var Fmul64 = fmul64
20 var Fdiv64 = fdiv64
21 var F64to32 = f64to32
22 var F32to64 = f32to64
23 var Fcmp64 = fcmp64
24 var Fintto64 = fintto64
25 var F64toint = f64toint
26
27 var Entersyscall = entersyscall
28 var Exitsyscall = exitsyscall
29 var LockedOSThread = lockedOSThread
30 var Xadduintptr = atomic.Xadduintptr
31
32 var Fastlog2 = fastlog2
33
34 var Atoi = atoi
35 var Atoi32 = atoi32
36 var ParseByteCount = parseByteCount
37
38 var Nanotime = nanotime
39 var NetpollBreak = netpollBreak
40 var Usleep = usleep
41
42 var PhysPageSize = physPageSize
43 var PhysHugePageSize = physHugePageSize
44
45 var NetpollGenericInit = netpollGenericInit
46
47 var Memmove = memmove
48 var MemclrNoHeapPointers = memclrNoHeapPointers
49
50 const TracebackInnerFrames = tracebackInnerFrames
51 const TracebackOuterFrames = tracebackOuterFrames
52
53 var LockPartialOrder = lockPartialOrder
54
55 type LockRank lockRank
56
57 func (l LockRank) String() string {
58         return lockRank(l).String()
59 }
60
61 const PreemptMSupported = preemptMSupported
62
63 type LFNode struct {
64         Next    uint64
65         Pushcnt uintptr
66 }
67
68 func LFStackPush(head *uint64, node *LFNode) {
69         (*lfstack)(head).push((*lfnode)(unsafe.Pointer(node)))
70 }
71
72 func LFStackPop(head *uint64) *LFNode {
73         return (*LFNode)(unsafe.Pointer((*lfstack)(head).pop()))
74 }
75 func LFNodeValidate(node *LFNode) {
76         lfnodeValidate((*lfnode)(unsafe.Pointer(node)))
77 }
78
79 func Netpoll(delta int64) {
80         systemstack(func() {
81                 netpoll(delta)
82         })
83 }
84
85 func GCMask(x any) (ret []byte) {
86         systemstack(func() {
87                 ret = getgcmask(x)
88         })
89         return
90 }
91
92 func RunSchedLocalQueueTest() {
93         pp := new(p)
94         gs := make([]g, len(pp.runq))
95         Escape(gs) // Ensure gs doesn't move, since we use guintptrs
96         for i := 0; i < len(pp.runq); i++ {
97                 if g, _ := runqget(pp); g != nil {
98                         throw("runq is not empty initially")
99                 }
100                 for j := 0; j < i; j++ {
101                         runqput(pp, &gs[i], false)
102                 }
103                 for j := 0; j < i; j++ {
104                         if g, _ := runqget(pp); g != &gs[i] {
105                                 print("bad element at iter ", i, "/", j, "\n")
106                                 throw("bad element")
107                         }
108                 }
109                 if g, _ := runqget(pp); g != nil {
110                         throw("runq is not empty afterwards")
111                 }
112         }
113 }
114
115 func RunSchedLocalQueueStealTest() {
116         p1 := new(p)
117         p2 := new(p)
118         gs := make([]g, len(p1.runq))
119         Escape(gs) // Ensure gs doesn't move, since we use guintptrs
120         for i := 0; i < len(p1.runq); i++ {
121                 for j := 0; j < i; j++ {
122                         gs[j].sig = 0
123                         runqput(p1, &gs[j], false)
124                 }
125                 gp := runqsteal(p2, p1, true)
126                 s := 0
127                 if gp != nil {
128                         s++
129                         gp.sig++
130                 }
131                 for {
132                         gp, _ = runqget(p2)
133                         if gp == nil {
134                                 break
135                         }
136                         s++
137                         gp.sig++
138                 }
139                 for {
140                         gp, _ = runqget(p1)
141                         if gp == nil {
142                                 break
143                         }
144                         gp.sig++
145                 }
146                 for j := 0; j < i; j++ {
147                         if gs[j].sig != 1 {
148                                 print("bad element ", j, "(", gs[j].sig, ") at iter ", i, "\n")
149                                 throw("bad element")
150                         }
151                 }
152                 if s != i/2 && s != i/2+1 {
153                         print("bad steal ", s, ", want ", i/2, " or ", i/2+1, ", iter ", i, "\n")
154                         throw("bad steal")
155                 }
156         }
157 }
158
159 func RunSchedLocalQueueEmptyTest(iters int) {
160         // Test that runq is not spuriously reported as empty.
161         // Runq emptiness affects scheduling decisions and spurious emptiness
162         // can lead to underutilization (both runnable Gs and idle Ps coexist
163         // for arbitrary long time).
164         done := make(chan bool, 1)
165         p := new(p)
166         gs := make([]g, 2)
167         Escape(gs) // Ensure gs doesn't move, since we use guintptrs
168         ready := new(uint32)
169         for i := 0; i < iters; i++ {
170                 *ready = 0
171                 next0 := (i & 1) == 0
172                 next1 := (i & 2) == 0
173                 runqput(p, &gs[0], next0)
174                 go func() {
175                         for atomic.Xadd(ready, 1); atomic.Load(ready) != 2; {
176                         }
177                         if runqempty(p) {
178                                 println("next:", next0, next1)
179                                 throw("queue is empty")
180                         }
181                         done <- true
182                 }()
183                 for atomic.Xadd(ready, 1); atomic.Load(ready) != 2; {
184                 }
185                 runqput(p, &gs[1], next1)
186                 runqget(p)
187                 <-done
188                 runqget(p)
189         }
190 }
191
192 var (
193         StringHash = stringHash
194         BytesHash  = bytesHash
195         Int32Hash  = int32Hash
196         Int64Hash  = int64Hash
197         MemHash    = memhash
198         MemHash32  = memhash32
199         MemHash64  = memhash64
200         EfaceHash  = efaceHash
201         IfaceHash  = ifaceHash
202 )
203
204 var UseAeshash = &useAeshash
205
206 func MemclrBytes(b []byte) {
207         s := (*slice)(unsafe.Pointer(&b))
208         memclrNoHeapPointers(s.array, uintptr(s.len))
209 }
210
211 const HashLoad = hashLoad
212
213 // entry point for testing
214 func GostringW(w []uint16) (s string) {
215         systemstack(func() {
216                 s = gostringw(&w[0])
217         })
218         return
219 }
220
221 var Open = open
222 var Close = closefd
223 var Read = read
224 var Write = write
225
226 func Envs() []string     { return envs }
227 func SetEnvs(e []string) { envs = e }
228
229 // For benchmarking.
230
231 func BenchSetType(n int, x any) {
232         // Escape x to ensure it is allocated on the heap, as we are
233         // working on the heap bits here.
234         Escape(x)
235         e := *efaceOf(&x)
236         t := e._type
237         var size uintptr
238         var p unsafe.Pointer
239         switch t.Kind_ & kindMask {
240         case kindPtr:
241                 t = (*ptrtype)(unsafe.Pointer(t)).Elem
242                 size = t.Size_
243                 p = e.data
244         case kindSlice:
245                 slice := *(*struct {
246                         ptr      unsafe.Pointer
247                         len, cap uintptr
248                 })(e.data)
249                 t = (*slicetype)(unsafe.Pointer(t)).Elem
250                 size = t.Size_ * slice.len
251                 p = slice.ptr
252         }
253         allocSize := roundupsize(size)
254         systemstack(func() {
255                 for i := 0; i < n; i++ {
256                         heapBitsSetType(uintptr(p), allocSize, size, t)
257                 }
258         })
259 }
260
261 const PtrSize = goarch.PtrSize
262
263 var ForceGCPeriod = &forcegcperiod
264
265 // SetTracebackEnv is like runtime/debug.SetTraceback, but it raises
266 // the "environment" traceback level, so later calls to
267 // debug.SetTraceback (e.g., from testing timeouts) can't lower it.
268 func SetTracebackEnv(level string) {
269         setTraceback(level)
270         traceback_env = traceback_cache
271 }
272
273 var ReadUnaligned32 = readUnaligned32
274 var ReadUnaligned64 = readUnaligned64
275
276 func CountPagesInUse() (pagesInUse, counted uintptr) {
277         stopTheWorld("CountPagesInUse")
278
279         pagesInUse = uintptr(mheap_.pagesInUse.Load())
280
281         for _, s := range mheap_.allspans {
282                 if s.state.get() == mSpanInUse {
283                         counted += s.npages
284                 }
285         }
286
287         startTheWorld()
288
289         return
290 }
291
292 func Fastrand() uint32          { return fastrand() }
293 func Fastrand64() uint64        { return fastrand64() }
294 func Fastrandn(n uint32) uint32 { return fastrandn(n) }
295
296 type ProfBuf profBuf
297
298 func NewProfBuf(hdrsize, bufwords, tags int) *ProfBuf {
299         return (*ProfBuf)(newProfBuf(hdrsize, bufwords, tags))
300 }
301
302 func (p *ProfBuf) Write(tag *unsafe.Pointer, now int64, hdr []uint64, stk []uintptr) {
303         (*profBuf)(p).write(tag, now, hdr, stk)
304 }
305
306 const (
307         ProfBufBlocking    = profBufBlocking
308         ProfBufNonBlocking = profBufNonBlocking
309 )
310
311 func (p *ProfBuf) Read(mode profBufReadMode) ([]uint64, []unsafe.Pointer, bool) {
312         return (*profBuf)(p).read(profBufReadMode(mode))
313 }
314
315 func (p *ProfBuf) Close() {
316         (*profBuf)(p).close()
317 }
318
319 func ReadMetricsSlow(memStats *MemStats, samplesp unsafe.Pointer, len, cap int) {
320         stopTheWorld("ReadMetricsSlow")
321
322         // Initialize the metrics beforehand because this could
323         // allocate and skew the stats.
324         metricsLock()
325         initMetrics()
326         metricsUnlock()
327
328         systemstack(func() {
329                 // Read memstats first. It's going to flush
330                 // the mcaches which readMetrics does not do, so
331                 // going the other way around may result in
332                 // inconsistent statistics.
333                 readmemstats_m(memStats)
334         })
335
336         // Read metrics off the system stack.
337         //
338         // The only part of readMetrics that could allocate
339         // and skew the stats is initMetrics.
340         readMetrics(samplesp, len, cap)
341
342         startTheWorld()
343 }
344
345 // ReadMemStatsSlow returns both the runtime-computed MemStats and
346 // MemStats accumulated by scanning the heap.
347 func ReadMemStatsSlow() (base, slow MemStats) {
348         stopTheWorld("ReadMemStatsSlow")
349
350         // Run on the system stack to avoid stack growth allocation.
351         systemstack(func() {
352                 // Make sure stats don't change.
353                 getg().m.mallocing++
354
355                 readmemstats_m(&base)
356
357                 // Initialize slow from base and zero the fields we're
358                 // recomputing.
359                 slow = base
360                 slow.Alloc = 0
361                 slow.TotalAlloc = 0
362                 slow.Mallocs = 0
363                 slow.Frees = 0
364                 slow.HeapReleased = 0
365                 var bySize [_NumSizeClasses]struct {
366                         Mallocs, Frees uint64
367                 }
368
369                 // Add up current allocations in spans.
370                 for _, s := range mheap_.allspans {
371                         if s.state.get() != mSpanInUse {
372                                 continue
373                         }
374                         if s.isUnusedUserArenaChunk() {
375                                 continue
376                         }
377                         if sizeclass := s.spanclass.sizeclass(); sizeclass == 0 {
378                                 slow.Mallocs++
379                                 slow.Alloc += uint64(s.elemsize)
380                         } else {
381                                 slow.Mallocs += uint64(s.allocCount)
382                                 slow.Alloc += uint64(s.allocCount) * uint64(s.elemsize)
383                                 bySize[sizeclass].Mallocs += uint64(s.allocCount)
384                         }
385                 }
386
387                 // Add in frees by just reading the stats for those directly.
388                 var m heapStatsDelta
389                 memstats.heapStats.unsafeRead(&m)
390
391                 // Collect per-sizeclass free stats.
392                 var smallFree uint64
393                 for i := 0; i < _NumSizeClasses; i++ {
394                         slow.Frees += uint64(m.smallFreeCount[i])
395                         bySize[i].Frees += uint64(m.smallFreeCount[i])
396                         bySize[i].Mallocs += uint64(m.smallFreeCount[i])
397                         smallFree += uint64(m.smallFreeCount[i]) * uint64(class_to_size[i])
398                 }
399                 slow.Frees += uint64(m.tinyAllocCount) + uint64(m.largeFreeCount)
400                 slow.Mallocs += slow.Frees
401
402                 slow.TotalAlloc = slow.Alloc + uint64(m.largeFree) + smallFree
403
404                 for i := range slow.BySize {
405                         slow.BySize[i].Mallocs = bySize[i].Mallocs
406                         slow.BySize[i].Frees = bySize[i].Frees
407                 }
408
409                 for i := mheap_.pages.start; i < mheap_.pages.end; i++ {
410                         chunk := mheap_.pages.tryChunkOf(i)
411                         if chunk == nil {
412                                 continue
413                         }
414                         pg := chunk.scavenged.popcntRange(0, pallocChunkPages)
415                         slow.HeapReleased += uint64(pg) * pageSize
416                 }
417                 for _, p := range allp {
418                         pg := sys.OnesCount64(p.pcache.scav)
419                         slow.HeapReleased += uint64(pg) * pageSize
420                 }
421
422                 getg().m.mallocing--
423         })
424
425         startTheWorld()
426         return
427 }
428
429 // ShrinkStackAndVerifyFramePointers attempts to shrink the stack of the current goroutine
430 // and verifies that unwinding the new stack doesn't crash, even if the old
431 // stack has been freed or reused (simulated via poisoning).
432 func ShrinkStackAndVerifyFramePointers() {
433         before := stackPoisonCopy
434         defer func() { stackPoisonCopy = before }()
435         stackPoisonCopy = 1
436
437         gp := getg()
438         systemstack(func() {
439                 shrinkstack(gp)
440         })
441         // If our new stack contains frame pointers into the old stack, this will
442         // crash because the old stack has been poisoned.
443         FPCallers(make([]uintptr, 1024))
444 }
445
446 // BlockOnSystemStack switches to the system stack, prints "x\n" to
447 // stderr, and blocks in a stack containing
448 // "runtime.blockOnSystemStackInternal".
449 func BlockOnSystemStack() {
450         systemstack(blockOnSystemStackInternal)
451 }
452
453 func blockOnSystemStackInternal() {
454         print("x\n")
455         lock(&deadlock)
456         lock(&deadlock)
457 }
458
459 type RWMutex struct {
460         rw rwmutex
461 }
462
463 func (rw *RWMutex) RLock() {
464         rw.rw.rlock()
465 }
466
467 func (rw *RWMutex) RUnlock() {
468         rw.rw.runlock()
469 }
470
471 func (rw *RWMutex) Lock() {
472         rw.rw.lock()
473 }
474
475 func (rw *RWMutex) Unlock() {
476         rw.rw.unlock()
477 }
478
479 const RuntimeHmapSize = unsafe.Sizeof(hmap{})
480
481 func MapBucketsCount(m map[int]int) int {
482         h := *(**hmap)(unsafe.Pointer(&m))
483         return 1 << h.B
484 }
485
486 func MapBucketsPointerIsNil(m map[int]int) bool {
487         h := *(**hmap)(unsafe.Pointer(&m))
488         return h.buckets == nil
489 }
490
491 func LockOSCounts() (external, internal uint32) {
492         gp := getg()
493         if gp.m.lockedExt+gp.m.lockedInt == 0 {
494                 if gp.lockedm != 0 {
495                         panic("lockedm on non-locked goroutine")
496                 }
497         } else {
498                 if gp.lockedm == 0 {
499                         panic("nil lockedm on locked goroutine")
500                 }
501         }
502         return gp.m.lockedExt, gp.m.lockedInt
503 }
504
505 //go:noinline
506 func TracebackSystemstack(stk []uintptr, i int) int {
507         if i == 0 {
508                 pc, sp := getcallerpc(), getcallersp()
509                 var u unwinder
510                 u.initAt(pc, sp, 0, getg(), unwindJumpStack) // Don't ignore errors, for testing
511                 return tracebackPCs(&u, 0, stk)
512         }
513         n := 0
514         systemstack(func() {
515                 n = TracebackSystemstack(stk, i-1)
516         })
517         return n
518 }
519
520 func KeepNArenaHints(n int) {
521         hint := mheap_.arenaHints
522         for i := 1; i < n; i++ {
523                 hint = hint.next
524                 if hint == nil {
525                         return
526                 }
527         }
528         hint.next = nil
529 }
530
531 // MapNextArenaHint reserves a page at the next arena growth hint,
532 // preventing the arena from growing there, and returns the range of
533 // addresses that are no longer viable.
534 //
535 // This may fail to reserve memory. If it fails, it still returns the
536 // address range it attempted to reserve.
537 func MapNextArenaHint() (start, end uintptr, ok bool) {
538         hint := mheap_.arenaHints
539         addr := hint.addr
540         if hint.down {
541                 start, end = addr-heapArenaBytes, addr
542                 addr -= physPageSize
543         } else {
544                 start, end = addr, addr+heapArenaBytes
545         }
546         got := sysReserve(unsafe.Pointer(addr), physPageSize)
547         ok = (addr == uintptr(got))
548         if !ok {
549                 // We were unable to get the requested reservation.
550                 // Release what we did get and fail.
551                 sysFreeOS(got, physPageSize)
552         }
553         return
554 }
555
556 func GetNextArenaHint() uintptr {
557         return mheap_.arenaHints.addr
558 }
559
560 type G = g
561
562 type Sudog = sudog
563
564 func Getg() *G {
565         return getg()
566 }
567
568 func Goid() uint64 {
569         return getg().goid
570 }
571
572 func GIsWaitingOnMutex(gp *G) bool {
573         return readgstatus(gp) == _Gwaiting && gp.waitreason.isMutexWait()
574 }
575
576 var CasGStatusAlwaysTrack = &casgstatusAlwaysTrack
577
578 //go:noinline
579 func PanicForTesting(b []byte, i int) byte {
580         return unexportedPanicForTesting(b, i)
581 }
582
583 //go:noinline
584 func unexportedPanicForTesting(b []byte, i int) byte {
585         return b[i]
586 }
587
588 func G0StackOverflow() {
589         systemstack(func() {
590                 stackOverflow(nil)
591         })
592 }
593
594 func stackOverflow(x *byte) {
595         var buf [256]byte
596         stackOverflow(&buf[0])
597 }
598
599 func MapTombstoneCheck(m map[int]int) {
600         // Make sure emptyOne and emptyRest are distributed correctly.
601         // We should have a series of filled and emptyOne cells, followed by
602         // a series of emptyRest cells.
603         h := *(**hmap)(unsafe.Pointer(&m))
604         i := any(m)
605         t := *(**maptype)(unsafe.Pointer(&i))
606
607         for x := 0; x < 1<<h.B; x++ {
608                 b0 := (*bmap)(add(h.buckets, uintptr(x)*uintptr(t.BucketSize)))
609                 n := 0
610                 for b := b0; b != nil; b = b.overflow(t) {
611                         for i := 0; i < bucketCnt; i++ {
612                                 if b.tophash[i] != emptyRest {
613                                         n++
614                                 }
615                         }
616                 }
617                 k := 0
618                 for b := b0; b != nil; b = b.overflow(t) {
619                         for i := 0; i < bucketCnt; i++ {
620                                 if k < n && b.tophash[i] == emptyRest {
621                                         panic("early emptyRest")
622                                 }
623                                 if k >= n && b.tophash[i] != emptyRest {
624                                         panic("late non-emptyRest")
625                                 }
626                                 if k == n-1 && b.tophash[i] == emptyOne {
627                                         panic("last non-emptyRest entry is emptyOne")
628                                 }
629                                 k++
630                         }
631                 }
632         }
633 }
634
635 func RunGetgThreadSwitchTest() {
636         // Test that getg works correctly with thread switch.
637         // With gccgo, if we generate getg inlined, the backend
638         // may cache the address of the TLS variable, which
639         // will become invalid after a thread switch. This test
640         // checks that the bad caching doesn't happen.
641
642         ch := make(chan int)
643         go func(ch chan int) {
644                 ch <- 5
645                 LockOSThread()
646         }(ch)
647
648         g1 := getg()
649
650         // Block on a receive. This is likely to get us a thread
651         // switch. If we yield to the sender goroutine, it will
652         // lock the thread, forcing us to resume on a different
653         // thread.
654         <-ch
655
656         g2 := getg()
657         if g1 != g2 {
658                 panic("g1 != g2")
659         }
660
661         // Also test getg after some control flow, as the
662         // backend is sensitive to control flow.
663         g3 := getg()
664         if g1 != g3 {
665                 panic("g1 != g3")
666         }
667 }
668
669 const (
670         PageSize         = pageSize
671         PallocChunkPages = pallocChunkPages
672         PageAlloc64Bit   = pageAlloc64Bit
673         PallocSumBytes   = pallocSumBytes
674 )
675
676 // Expose pallocSum for testing.
677 type PallocSum pallocSum
678
679 func PackPallocSum(start, max, end uint) PallocSum { return PallocSum(packPallocSum(start, max, end)) }
680 func (m PallocSum) Start() uint                    { return pallocSum(m).start() }
681 func (m PallocSum) Max() uint                      { return pallocSum(m).max() }
682 func (m PallocSum) End() uint                      { return pallocSum(m).end() }
683
684 // Expose pallocBits for testing.
685 type PallocBits pallocBits
686
687 func (b *PallocBits) Find(npages uintptr, searchIdx uint) (uint, uint) {
688         return (*pallocBits)(b).find(npages, searchIdx)
689 }
690 func (b *PallocBits) AllocRange(i, n uint)       { (*pallocBits)(b).allocRange(i, n) }
691 func (b *PallocBits) Free(i, n uint)             { (*pallocBits)(b).free(i, n) }
692 func (b *PallocBits) Summarize() PallocSum       { return PallocSum((*pallocBits)(b).summarize()) }
693 func (b *PallocBits) PopcntRange(i, n uint) uint { return (*pageBits)(b).popcntRange(i, n) }
694
695 // SummarizeSlow is a slow but more obviously correct implementation
696 // of (*pallocBits).summarize. Used for testing.
697 func SummarizeSlow(b *PallocBits) PallocSum {
698         var start, max, end uint
699
700         const N = uint(len(b)) * 64
701         for start < N && (*pageBits)(b).get(start) == 0 {
702                 start++
703         }
704         for end < N && (*pageBits)(b).get(N-end-1) == 0 {
705                 end++
706         }
707         run := uint(0)
708         for i := uint(0); i < N; i++ {
709                 if (*pageBits)(b).get(i) == 0 {
710                         run++
711                 } else {
712                         run = 0
713                 }
714                 if run > max {
715                         max = run
716                 }
717         }
718         return PackPallocSum(start, max, end)
719 }
720
721 // Expose non-trivial helpers for testing.
722 func FindBitRange64(c uint64, n uint) uint { return findBitRange64(c, n) }
723
724 // Given two PallocBits, returns a set of bit ranges where
725 // they differ.
726 func DiffPallocBits(a, b *PallocBits) []BitRange {
727         ba := (*pageBits)(a)
728         bb := (*pageBits)(b)
729
730         var d []BitRange
731         base, size := uint(0), uint(0)
732         for i := uint(0); i < uint(len(ba))*64; i++ {
733                 if ba.get(i) != bb.get(i) {
734                         if size == 0 {
735                                 base = i
736                         }
737                         size++
738                 } else {
739                         if size != 0 {
740                                 d = append(d, BitRange{base, size})
741                         }
742                         size = 0
743                 }
744         }
745         if size != 0 {
746                 d = append(d, BitRange{base, size})
747         }
748         return d
749 }
750
751 // StringifyPallocBits gets the bits in the bit range r from b,
752 // and returns a string containing the bits as ASCII 0 and 1
753 // characters.
754 func StringifyPallocBits(b *PallocBits, r BitRange) string {
755         str := ""
756         for j := r.I; j < r.I+r.N; j++ {
757                 if (*pageBits)(b).get(j) != 0 {
758                         str += "1"
759                 } else {
760                         str += "0"
761                 }
762         }
763         return str
764 }
765
766 // Expose pallocData for testing.
767 type PallocData pallocData
768
769 func (d *PallocData) FindScavengeCandidate(searchIdx uint, min, max uintptr) (uint, uint) {
770         return (*pallocData)(d).findScavengeCandidate(searchIdx, min, max)
771 }
772 func (d *PallocData) AllocRange(i, n uint) { (*pallocData)(d).allocRange(i, n) }
773 func (d *PallocData) ScavengedSetRange(i, n uint) {
774         (*pallocData)(d).scavenged.setRange(i, n)
775 }
776 func (d *PallocData) PallocBits() *PallocBits {
777         return (*PallocBits)(&(*pallocData)(d).pallocBits)
778 }
779 func (d *PallocData) Scavenged() *PallocBits {
780         return (*PallocBits)(&(*pallocData)(d).scavenged)
781 }
782
783 // Expose fillAligned for testing.
784 func FillAligned(x uint64, m uint) uint64 { return fillAligned(x, m) }
785
786 // Expose pageCache for testing.
787 type PageCache pageCache
788
789 const PageCachePages = pageCachePages
790
791 func NewPageCache(base uintptr, cache, scav uint64) PageCache {
792         return PageCache(pageCache{base: base, cache: cache, scav: scav})
793 }
794 func (c *PageCache) Empty() bool   { return (*pageCache)(c).empty() }
795 func (c *PageCache) Base() uintptr { return (*pageCache)(c).base }
796 func (c *PageCache) Cache() uint64 { return (*pageCache)(c).cache }
797 func (c *PageCache) Scav() uint64  { return (*pageCache)(c).scav }
798 func (c *PageCache) Alloc(npages uintptr) (uintptr, uintptr) {
799         return (*pageCache)(c).alloc(npages)
800 }
801 func (c *PageCache) Flush(s *PageAlloc) {
802         cp := (*pageCache)(c)
803         sp := (*pageAlloc)(s)
804
805         systemstack(func() {
806                 // None of the tests need any higher-level locking, so we just
807                 // take the lock internally.
808                 lock(sp.mheapLock)
809                 cp.flush(sp)
810                 unlock(sp.mheapLock)
811         })
812 }
813
814 // Expose chunk index type.
815 type ChunkIdx chunkIdx
816
817 // Expose pageAlloc for testing. Note that because pageAlloc is
818 // not in the heap, so is PageAlloc.
819 type PageAlloc pageAlloc
820
821 func (p *PageAlloc) Alloc(npages uintptr) (uintptr, uintptr) {
822         pp := (*pageAlloc)(p)
823
824         var addr, scav uintptr
825         systemstack(func() {
826                 // None of the tests need any higher-level locking, so we just
827                 // take the lock internally.
828                 lock(pp.mheapLock)
829                 addr, scav = pp.alloc(npages)
830                 unlock(pp.mheapLock)
831         })
832         return addr, scav
833 }
834 func (p *PageAlloc) AllocToCache() PageCache {
835         pp := (*pageAlloc)(p)
836
837         var c PageCache
838         systemstack(func() {
839                 // None of the tests need any higher-level locking, so we just
840                 // take the lock internally.
841                 lock(pp.mheapLock)
842                 c = PageCache(pp.allocToCache())
843                 unlock(pp.mheapLock)
844         })
845         return c
846 }
847 func (p *PageAlloc) Free(base, npages uintptr) {
848         pp := (*pageAlloc)(p)
849
850         systemstack(func() {
851                 // None of the tests need any higher-level locking, so we just
852                 // take the lock internally.
853                 lock(pp.mheapLock)
854                 pp.free(base, npages)
855                 unlock(pp.mheapLock)
856         })
857 }
858 func (p *PageAlloc) Bounds() (ChunkIdx, ChunkIdx) {
859         return ChunkIdx((*pageAlloc)(p).start), ChunkIdx((*pageAlloc)(p).end)
860 }
861 func (p *PageAlloc) Scavenge(nbytes uintptr) (r uintptr) {
862         pp := (*pageAlloc)(p)
863         systemstack(func() {
864                 r = pp.scavenge(nbytes, nil, true)
865         })
866         return
867 }
868 func (p *PageAlloc) InUse() []AddrRange {
869         ranges := make([]AddrRange, 0, len(p.inUse.ranges))
870         for _, r := range p.inUse.ranges {
871                 ranges = append(ranges, AddrRange{r})
872         }
873         return ranges
874 }
875
876 // Returns nil if the PallocData's L2 is missing.
877 func (p *PageAlloc) PallocData(i ChunkIdx) *PallocData {
878         ci := chunkIdx(i)
879         return (*PallocData)((*pageAlloc)(p).tryChunkOf(ci))
880 }
881
882 // AddrRange is a wrapper around addrRange for testing.
883 type AddrRange struct {
884         addrRange
885 }
886
887 // MakeAddrRange creates a new address range.
888 func MakeAddrRange(base, limit uintptr) AddrRange {
889         return AddrRange{makeAddrRange(base, limit)}
890 }
891
892 // Base returns the virtual base address of the address range.
893 func (a AddrRange) Base() uintptr {
894         return a.addrRange.base.addr()
895 }
896
897 // Base returns the virtual address of the limit of the address range.
898 func (a AddrRange) Limit() uintptr {
899         return a.addrRange.limit.addr()
900 }
901
902 // Equals returns true if the two address ranges are exactly equal.
903 func (a AddrRange) Equals(b AddrRange) bool {
904         return a == b
905 }
906
907 // Size returns the size in bytes of the address range.
908 func (a AddrRange) Size() uintptr {
909         return a.addrRange.size()
910 }
911
912 // testSysStat is the sysStat passed to test versions of various
913 // runtime structures. We do actually have to keep track of this
914 // because otherwise memstats.mappedReady won't actually line up
915 // with other stats in the runtime during tests.
916 var testSysStat = &memstats.other_sys
917
918 // AddrRanges is a wrapper around addrRanges for testing.
919 type AddrRanges struct {
920         addrRanges
921         mutable bool
922 }
923
924 // NewAddrRanges creates a new empty addrRanges.
925 //
926 // Note that this initializes addrRanges just like in the
927 // runtime, so its memory is persistentalloc'd. Call this
928 // function sparingly since the memory it allocates is
929 // leaked.
930 //
931 // This AddrRanges is mutable, so we can test methods like
932 // Add.
933 func NewAddrRanges() AddrRanges {
934         r := addrRanges{}
935         r.init(testSysStat)
936         return AddrRanges{r, true}
937 }
938
939 // MakeAddrRanges creates a new addrRanges populated with
940 // the ranges in a.
941 //
942 // The returned AddrRanges is immutable, so methods like
943 // Add will fail.
944 func MakeAddrRanges(a ...AddrRange) AddrRanges {
945         // Methods that manipulate the backing store of addrRanges.ranges should
946         // not be used on the result from this function (e.g. add) since they may
947         // trigger reallocation. That would normally be fine, except the new
948         // backing store won't come from the heap, but from persistentalloc, so
949         // we'll leak some memory implicitly.
950         ranges := make([]addrRange, 0, len(a))
951         total := uintptr(0)
952         for _, r := range a {
953                 ranges = append(ranges, r.addrRange)
954                 total += r.Size()
955         }
956         return AddrRanges{addrRanges{
957                 ranges:     ranges,
958                 totalBytes: total,
959                 sysStat:    testSysStat,
960         }, false}
961 }
962
963 // Ranges returns a copy of the ranges described by the
964 // addrRanges.
965 func (a *AddrRanges) Ranges() []AddrRange {
966         result := make([]AddrRange, 0, len(a.addrRanges.ranges))
967         for _, r := range a.addrRanges.ranges {
968                 result = append(result, AddrRange{r})
969         }
970         return result
971 }
972
973 // FindSucc returns the successor to base. See addrRanges.findSucc
974 // for more details.
975 func (a *AddrRanges) FindSucc(base uintptr) int {
976         return a.findSucc(base)
977 }
978
979 // Add adds a new AddrRange to the AddrRanges.
980 //
981 // The AddrRange must be mutable (i.e. created by NewAddrRanges),
982 // otherwise this method will throw.
983 func (a *AddrRanges) Add(r AddrRange) {
984         if !a.mutable {
985                 throw("attempt to mutate immutable AddrRanges")
986         }
987         a.add(r.addrRange)
988 }
989
990 // TotalBytes returns the totalBytes field of the addrRanges.
991 func (a *AddrRanges) TotalBytes() uintptr {
992         return a.addrRanges.totalBytes
993 }
994
995 // BitRange represents a range over a bitmap.
996 type BitRange struct {
997         I, N uint // bit index and length in bits
998 }
999
1000 // NewPageAlloc creates a new page allocator for testing and
1001 // initializes it with the scav and chunks maps. Each key in these maps
1002 // represents a chunk index and each value is a series of bit ranges to
1003 // set within each bitmap's chunk.
1004 //
1005 // The initialization of the pageAlloc preserves the invariant that if a
1006 // scavenged bit is set the alloc bit is necessarily unset, so some
1007 // of the bits described by scav may be cleared in the final bitmap if
1008 // ranges in chunks overlap with them.
1009 //
1010 // scav is optional, and if nil, the scavenged bitmap will be cleared
1011 // (as opposed to all 1s, which it usually is). Furthermore, every
1012 // chunk index in scav must appear in chunks; ones that do not are
1013 // ignored.
1014 func NewPageAlloc(chunks, scav map[ChunkIdx][]BitRange) *PageAlloc {
1015         p := new(pageAlloc)
1016
1017         // We've got an entry, so initialize the pageAlloc.
1018         p.init(new(mutex), testSysStat, true)
1019         lockInit(p.mheapLock, lockRankMheap)
1020         for i, init := range chunks {
1021                 addr := chunkBase(chunkIdx(i))
1022
1023                 // Mark the chunk's existence in the pageAlloc.
1024                 systemstack(func() {
1025                         lock(p.mheapLock)
1026                         p.grow(addr, pallocChunkBytes)
1027                         unlock(p.mheapLock)
1028                 })
1029
1030                 // Initialize the bitmap and update pageAlloc metadata.
1031                 ci := chunkIndex(addr)
1032                 chunk := p.chunkOf(ci)
1033
1034                 // Clear all the scavenged bits which grow set.
1035                 chunk.scavenged.clearRange(0, pallocChunkPages)
1036
1037                 // Simulate the allocation and subsequent free of all pages in
1038                 // the chunk for the scavenge index. This sets the state equivalent
1039                 // with all pages within the index being free.
1040                 p.scav.index.alloc(ci, pallocChunkPages)
1041                 p.scav.index.free(ci, 0, pallocChunkPages)
1042
1043                 // Apply scavenge state if applicable.
1044                 if scav != nil {
1045                         if scvg, ok := scav[i]; ok {
1046                                 for _, s := range scvg {
1047                                         // Ignore the case of s.N == 0. setRange doesn't handle
1048                                         // it and it's a no-op anyway.
1049                                         if s.N != 0 {
1050                                                 chunk.scavenged.setRange(s.I, s.N)
1051                                         }
1052                                 }
1053                         }
1054                 }
1055
1056                 // Apply alloc state.
1057                 for _, s := range init {
1058                         // Ignore the case of s.N == 0. allocRange doesn't handle
1059                         // it and it's a no-op anyway.
1060                         if s.N != 0 {
1061                                 chunk.allocRange(s.I, s.N)
1062
1063                                 // Make sure the scavenge index is updated.
1064                                 p.scav.index.alloc(ci, s.N)
1065                         }
1066                 }
1067
1068                 // Update heap metadata for the allocRange calls above.
1069                 systemstack(func() {
1070                         lock(p.mheapLock)
1071                         p.update(addr, pallocChunkPages, false, false)
1072                         unlock(p.mheapLock)
1073                 })
1074         }
1075
1076         return (*PageAlloc)(p)
1077 }
1078
1079 // FreePageAlloc releases hard OS resources owned by the pageAlloc. Once this
1080 // is called the pageAlloc may no longer be used. The object itself will be
1081 // collected by the garbage collector once it is no longer live.
1082 func FreePageAlloc(pp *PageAlloc) {
1083         p := (*pageAlloc)(pp)
1084
1085         // Free all the mapped space for the summary levels.
1086         if pageAlloc64Bit != 0 {
1087                 for l := 0; l < summaryLevels; l++ {
1088                         sysFreeOS(unsafe.Pointer(&p.summary[l][0]), uintptr(cap(p.summary[l]))*pallocSumBytes)
1089                 }
1090         } else {
1091                 resSize := uintptr(0)
1092                 for _, s := range p.summary {
1093                         resSize += uintptr(cap(s)) * pallocSumBytes
1094                 }
1095                 sysFreeOS(unsafe.Pointer(&p.summary[0][0]), alignUp(resSize, physPageSize))
1096         }
1097
1098         // Free extra data structures.
1099         sysFreeOS(unsafe.Pointer(&p.scav.index.chunks[0]), uintptr(cap(p.scav.index.chunks))*unsafe.Sizeof(atomicScavChunkData{}))
1100
1101         // Subtract back out whatever we mapped for the summaries.
1102         // sysUsed adds to p.sysStat and memstats.mappedReady no matter what
1103         // (and in anger should actually be accounted for), and there's no other
1104         // way to figure out how much we actually mapped.
1105         gcController.mappedReady.Add(-int64(p.summaryMappedReady))
1106         testSysStat.add(-int64(p.summaryMappedReady))
1107
1108         // Free the mapped space for chunks.
1109         for i := range p.chunks {
1110                 if x := p.chunks[i]; x != nil {
1111                         p.chunks[i] = nil
1112                         // This memory comes from sysAlloc and will always be page-aligned.
1113                         sysFree(unsafe.Pointer(x), unsafe.Sizeof(*p.chunks[0]), testSysStat)
1114                 }
1115         }
1116 }
1117
1118 // BaseChunkIdx is a convenient chunkIdx value which works on both
1119 // 64 bit and 32 bit platforms, allowing the tests to share code
1120 // between the two.
1121 //
1122 // This should not be higher than 0x100*pallocChunkBytes to support
1123 // mips and mipsle, which only have 31-bit address spaces.
1124 var BaseChunkIdx = func() ChunkIdx {
1125         var prefix uintptr
1126         if pageAlloc64Bit != 0 {
1127                 prefix = 0xc000
1128         } else {
1129                 prefix = 0x100
1130         }
1131         baseAddr := prefix * pallocChunkBytes
1132         if goos.IsAix != 0 {
1133                 baseAddr += arenaBaseOffset
1134         }
1135         return ChunkIdx(chunkIndex(baseAddr))
1136 }()
1137
1138 // PageBase returns an address given a chunk index and a page index
1139 // relative to that chunk.
1140 func PageBase(c ChunkIdx, pageIdx uint) uintptr {
1141         return chunkBase(chunkIdx(c)) + uintptr(pageIdx)*pageSize
1142 }
1143
1144 type BitsMismatch struct {
1145         Base      uintptr
1146         Got, Want uint64
1147 }
1148
1149 func CheckScavengedBitsCleared(mismatches []BitsMismatch) (n int, ok bool) {
1150         ok = true
1151
1152         // Run on the system stack to avoid stack growth allocation.
1153         systemstack(func() {
1154                 getg().m.mallocing++
1155
1156                 // Lock so that we can safely access the bitmap.
1157                 lock(&mheap_.lock)
1158         chunkLoop:
1159                 for i := mheap_.pages.start; i < mheap_.pages.end; i++ {
1160                         chunk := mheap_.pages.tryChunkOf(i)
1161                         if chunk == nil {
1162                                 continue
1163                         }
1164                         for j := 0; j < pallocChunkPages/64; j++ {
1165                                 // Run over each 64-bit bitmap section and ensure
1166                                 // scavenged is being cleared properly on allocation.
1167                                 // If a used bit and scavenged bit are both set, that's
1168                                 // an error, and could indicate a larger problem, or
1169                                 // an accounting problem.
1170                                 want := chunk.scavenged[j] &^ chunk.pallocBits[j]
1171                                 got := chunk.scavenged[j]
1172                                 if want != got {
1173                                         ok = false
1174                                         if n >= len(mismatches) {
1175                                                 break chunkLoop
1176                                         }
1177                                         mismatches[n] = BitsMismatch{
1178                                                 Base: chunkBase(i) + uintptr(j)*64*pageSize,
1179                                                 Got:  got,
1180                                                 Want: want,
1181                                         }
1182                                         n++
1183                                 }
1184                         }
1185                 }
1186                 unlock(&mheap_.lock)
1187
1188                 getg().m.mallocing--
1189         })
1190         return
1191 }
1192
1193 func PageCachePagesLeaked() (leaked uintptr) {
1194         stopTheWorld("PageCachePagesLeaked")
1195
1196         // Walk over destroyed Ps and look for unflushed caches.
1197         deadp := allp[len(allp):cap(allp)]
1198         for _, p := range deadp {
1199                 // Since we're going past len(allp) we may see nil Ps.
1200                 // Just ignore them.
1201                 if p != nil {
1202                         leaked += uintptr(sys.OnesCount64(p.pcache.cache))
1203                 }
1204         }
1205
1206         startTheWorld()
1207         return
1208 }
1209
1210 var Semacquire = semacquire
1211 var Semrelease1 = semrelease1
1212
1213 func SemNwait(addr *uint32) uint32 {
1214         root := semtable.rootFor(addr)
1215         return root.nwait.Load()
1216 }
1217
1218 const SemTableSize = semTabSize
1219
1220 // SemTable is a wrapper around semTable exported for testing.
1221 type SemTable struct {
1222         semTable
1223 }
1224
1225 // Enqueue simulates enqueuing a waiter for a semaphore (or lock) at addr.
1226 func (t *SemTable) Enqueue(addr *uint32) {
1227         s := acquireSudog()
1228         s.releasetime = 0
1229         s.acquiretime = 0
1230         s.ticket = 0
1231         t.semTable.rootFor(addr).queue(addr, s, false)
1232 }
1233
1234 // Dequeue simulates dequeuing a waiter for a semaphore (or lock) at addr.
1235 //
1236 // Returns true if there actually was a waiter to be dequeued.
1237 func (t *SemTable) Dequeue(addr *uint32) bool {
1238         s, _ := t.semTable.rootFor(addr).dequeue(addr)
1239         if s != nil {
1240                 releaseSudog(s)
1241                 return true
1242         }
1243         return false
1244 }
1245
1246 // mspan wrapper for testing.
1247 type MSpan mspan
1248
1249 // Allocate an mspan for testing.
1250 func AllocMSpan() *MSpan {
1251         var s *mspan
1252         systemstack(func() {
1253                 lock(&mheap_.lock)
1254                 s = (*mspan)(mheap_.spanalloc.alloc())
1255                 unlock(&mheap_.lock)
1256         })
1257         return (*MSpan)(s)
1258 }
1259
1260 // Free an allocated mspan.
1261 func FreeMSpan(s *MSpan) {
1262         systemstack(func() {
1263                 lock(&mheap_.lock)
1264                 mheap_.spanalloc.free(unsafe.Pointer(s))
1265                 unlock(&mheap_.lock)
1266         })
1267 }
1268
1269 func MSpanCountAlloc(ms *MSpan, bits []byte) int {
1270         s := (*mspan)(ms)
1271         s.nelems = uintptr(len(bits) * 8)
1272         s.gcmarkBits = (*gcBits)(unsafe.Pointer(&bits[0]))
1273         result := s.countAlloc()
1274         s.gcmarkBits = nil
1275         return result
1276 }
1277
1278 const (
1279         TimeHistSubBucketBits = timeHistSubBucketBits
1280         TimeHistNumSubBuckets = timeHistNumSubBuckets
1281         TimeHistNumBuckets    = timeHistNumBuckets
1282         TimeHistMinBucketBits = timeHistMinBucketBits
1283         TimeHistMaxBucketBits = timeHistMaxBucketBits
1284 )
1285
1286 type TimeHistogram timeHistogram
1287
1288 // Counts returns the counts for the given bucket, subBucket indices.
1289 // Returns true if the bucket was valid, otherwise returns the counts
1290 // for the overflow bucket if bucket > 0 or the underflow bucket if
1291 // bucket < 0, and false.
1292 func (th *TimeHistogram) Count(bucket, subBucket int) (uint64, bool) {
1293         t := (*timeHistogram)(th)
1294         if bucket < 0 {
1295                 return t.underflow.Load(), false
1296         }
1297         i := bucket*TimeHistNumSubBuckets + subBucket
1298         if i >= len(t.counts) {
1299                 return t.overflow.Load(), false
1300         }
1301         return t.counts[i].Load(), true
1302 }
1303
1304 func (th *TimeHistogram) Record(duration int64) {
1305         (*timeHistogram)(th).record(duration)
1306 }
1307
1308 var TimeHistogramMetricsBuckets = timeHistogramMetricsBuckets
1309
1310 func SetIntArgRegs(a int) int {
1311         lock(&finlock)
1312         old := intArgRegs
1313         if a >= 0 {
1314                 intArgRegs = a
1315         }
1316         unlock(&finlock)
1317         return old
1318 }
1319
1320 func FinalizerGAsleep() bool {
1321         return fingStatus.Load()&fingWait != 0
1322 }
1323
1324 // For GCTestMoveStackOnNextCall, it's important not to introduce an
1325 // extra layer of call, since then there's a return before the "real"
1326 // next call.
1327 var GCTestMoveStackOnNextCall = gcTestMoveStackOnNextCall
1328
1329 // For GCTestIsReachable, it's important that we do this as a call so
1330 // escape analysis can see through it.
1331 func GCTestIsReachable(ptrs ...unsafe.Pointer) (mask uint64) {
1332         return gcTestIsReachable(ptrs...)
1333 }
1334
1335 // For GCTestPointerClass, it's important that we do this as a call so
1336 // escape analysis can see through it.
1337 //
1338 // This is nosplit because gcTestPointerClass is.
1339 //
1340 //go:nosplit
1341 func GCTestPointerClass(p unsafe.Pointer) string {
1342         return gcTestPointerClass(p)
1343 }
1344
1345 const Raceenabled = raceenabled
1346
1347 const (
1348         GCBackgroundUtilization            = gcBackgroundUtilization
1349         GCGoalUtilization                  = gcGoalUtilization
1350         DefaultHeapMinimum                 = defaultHeapMinimum
1351         MemoryLimitHeapGoalHeadroomPercent = memoryLimitHeapGoalHeadroomPercent
1352         MemoryLimitMinHeapGoalHeadroom     = memoryLimitMinHeapGoalHeadroom
1353 )
1354
1355 type GCController struct {
1356         gcControllerState
1357 }
1358
1359 func NewGCController(gcPercent int, memoryLimit int64) *GCController {
1360         // Force the controller to escape. We're going to
1361         // do 64-bit atomics on it, and if it gets stack-allocated
1362         // on a 32-bit architecture, it may get allocated unaligned
1363         // space.
1364         g := Escape(new(GCController))
1365         g.gcControllerState.test = true // Mark it as a test copy.
1366         g.init(int32(gcPercent), memoryLimit)
1367         return g
1368 }
1369
1370 func (c *GCController) StartCycle(stackSize, globalsSize uint64, scannableFrac float64, gomaxprocs int) {
1371         trigger, _ := c.trigger()
1372         if c.heapMarked > trigger {
1373                 trigger = c.heapMarked
1374         }
1375         c.maxStackScan.Store(stackSize)
1376         c.globalsScan.Store(globalsSize)
1377         c.heapLive.Store(trigger)
1378         c.heapScan.Add(int64(float64(trigger-c.heapMarked) * scannableFrac))
1379         c.startCycle(0, gomaxprocs, gcTrigger{kind: gcTriggerHeap})
1380 }
1381
1382 func (c *GCController) AssistWorkPerByte() float64 {
1383         return c.assistWorkPerByte.Load()
1384 }
1385
1386 func (c *GCController) HeapGoal() uint64 {
1387         return c.heapGoal()
1388 }
1389
1390 func (c *GCController) HeapLive() uint64 {
1391         return c.heapLive.Load()
1392 }
1393
1394 func (c *GCController) HeapMarked() uint64 {
1395         return c.heapMarked
1396 }
1397
1398 func (c *GCController) Triggered() uint64 {
1399         return c.triggered
1400 }
1401
1402 type GCControllerReviseDelta struct {
1403         HeapLive        int64
1404         HeapScan        int64
1405         HeapScanWork    int64
1406         StackScanWork   int64
1407         GlobalsScanWork int64
1408 }
1409
1410 func (c *GCController) Revise(d GCControllerReviseDelta) {
1411         c.heapLive.Add(d.HeapLive)
1412         c.heapScan.Add(d.HeapScan)
1413         c.heapScanWork.Add(d.HeapScanWork)
1414         c.stackScanWork.Add(d.StackScanWork)
1415         c.globalsScanWork.Add(d.GlobalsScanWork)
1416         c.revise()
1417 }
1418
1419 func (c *GCController) EndCycle(bytesMarked uint64, assistTime, elapsed int64, gomaxprocs int) {
1420         c.assistTime.Store(assistTime)
1421         c.endCycle(elapsed, gomaxprocs, false)
1422         c.resetLive(bytesMarked)
1423         c.commit(false)
1424 }
1425
1426 func (c *GCController) AddIdleMarkWorker() bool {
1427         return c.addIdleMarkWorker()
1428 }
1429
1430 func (c *GCController) NeedIdleMarkWorker() bool {
1431         return c.needIdleMarkWorker()
1432 }
1433
1434 func (c *GCController) RemoveIdleMarkWorker() {
1435         c.removeIdleMarkWorker()
1436 }
1437
1438 func (c *GCController) SetMaxIdleMarkWorkers(max int32) {
1439         c.setMaxIdleMarkWorkers(max)
1440 }
1441
1442 var alwaysFalse bool
1443 var escapeSink any
1444
1445 func Escape[T any](x T) T {
1446         if alwaysFalse {
1447                 escapeSink = x
1448         }
1449         return x
1450 }
1451
1452 // Acquirem blocks preemption.
1453 func Acquirem() {
1454         acquirem()
1455 }
1456
1457 func Releasem() {
1458         releasem(getg().m)
1459 }
1460
1461 var Timediv = timediv
1462
1463 type PIController struct {
1464         piController
1465 }
1466
1467 func NewPIController(kp, ti, tt, min, max float64) *PIController {
1468         return &PIController{piController{
1469                 kp:  kp,
1470                 ti:  ti,
1471                 tt:  tt,
1472                 min: min,
1473                 max: max,
1474         }}
1475 }
1476
1477 func (c *PIController) Next(input, setpoint, period float64) (float64, bool) {
1478         return c.piController.next(input, setpoint, period)
1479 }
1480
1481 const (
1482         CapacityPerProc          = capacityPerProc
1483         GCCPULimiterUpdatePeriod = gcCPULimiterUpdatePeriod
1484 )
1485
1486 type GCCPULimiter struct {
1487         limiter gcCPULimiterState
1488 }
1489
1490 func NewGCCPULimiter(now int64, gomaxprocs int32) *GCCPULimiter {
1491         // Force the controller to escape. We're going to
1492         // do 64-bit atomics on it, and if it gets stack-allocated
1493         // on a 32-bit architecture, it may get allocated unaligned
1494         // space.
1495         l := Escape(new(GCCPULimiter))
1496         l.limiter.test = true
1497         l.limiter.resetCapacity(now, gomaxprocs)
1498         return l
1499 }
1500
1501 func (l *GCCPULimiter) Fill() uint64 {
1502         return l.limiter.bucket.fill
1503 }
1504
1505 func (l *GCCPULimiter) Capacity() uint64 {
1506         return l.limiter.bucket.capacity
1507 }
1508
1509 func (l *GCCPULimiter) Overflow() uint64 {
1510         return l.limiter.overflow
1511 }
1512
1513 func (l *GCCPULimiter) Limiting() bool {
1514         return l.limiter.limiting()
1515 }
1516
1517 func (l *GCCPULimiter) NeedUpdate(now int64) bool {
1518         return l.limiter.needUpdate(now)
1519 }
1520
1521 func (l *GCCPULimiter) StartGCTransition(enableGC bool, now int64) {
1522         l.limiter.startGCTransition(enableGC, now)
1523 }
1524
1525 func (l *GCCPULimiter) FinishGCTransition(now int64) {
1526         l.limiter.finishGCTransition(now)
1527 }
1528
1529 func (l *GCCPULimiter) Update(now int64) {
1530         l.limiter.update(now)
1531 }
1532
1533 func (l *GCCPULimiter) AddAssistTime(t int64) {
1534         l.limiter.addAssistTime(t)
1535 }
1536
1537 func (l *GCCPULimiter) ResetCapacity(now int64, nprocs int32) {
1538         l.limiter.resetCapacity(now, nprocs)
1539 }
1540
1541 const ScavengePercent = scavengePercent
1542
1543 type Scavenger struct {
1544         Sleep      func(int64) int64
1545         Scavenge   func(uintptr) (uintptr, int64)
1546         ShouldStop func() bool
1547         GoMaxProcs func() int32
1548
1549         released  atomic.Uintptr
1550         scavenger scavengerState
1551         stop      chan<- struct{}
1552         done      <-chan struct{}
1553 }
1554
1555 func (s *Scavenger) Start() {
1556         if s.Sleep == nil || s.Scavenge == nil || s.ShouldStop == nil || s.GoMaxProcs == nil {
1557                 panic("must populate all stubs")
1558         }
1559
1560         // Install hooks.
1561         s.scavenger.sleepStub = s.Sleep
1562         s.scavenger.scavenge = s.Scavenge
1563         s.scavenger.shouldStop = s.ShouldStop
1564         s.scavenger.gomaxprocs = s.GoMaxProcs
1565
1566         // Start up scavenger goroutine, and wait for it to be ready.
1567         stop := make(chan struct{})
1568         s.stop = stop
1569         done := make(chan struct{})
1570         s.done = done
1571         go func() {
1572                 // This should match bgscavenge, loosely.
1573                 s.scavenger.init()
1574                 s.scavenger.park()
1575                 for {
1576                         select {
1577                         case <-stop:
1578                                 close(done)
1579                                 return
1580                         default:
1581                         }
1582                         released, workTime := s.scavenger.run()
1583                         if released == 0 {
1584                                 s.scavenger.park()
1585                                 continue
1586                         }
1587                         s.released.Add(released)
1588                         s.scavenger.sleep(workTime)
1589                 }
1590         }()
1591         if !s.BlockUntilParked(1e9 /* 1 second */) {
1592                 panic("timed out waiting for scavenger to get ready")
1593         }
1594 }
1595
1596 // BlockUntilParked blocks until the scavenger parks, or until
1597 // timeout is exceeded. Returns true if the scavenger parked.
1598 //
1599 // Note that in testing, parked means something slightly different.
1600 // In anger, the scavenger parks to sleep, too, but in testing,
1601 // it only parks when it actually has no work to do.
1602 func (s *Scavenger) BlockUntilParked(timeout int64) bool {
1603         // Just spin, waiting for it to park.
1604         //
1605         // The actual parking process is racy with respect to
1606         // wakeups, which is fine, but for testing we need something
1607         // a bit more robust.
1608         start := nanotime()
1609         for nanotime()-start < timeout {
1610                 lock(&s.scavenger.lock)
1611                 parked := s.scavenger.parked
1612                 unlock(&s.scavenger.lock)
1613                 if parked {
1614                         return true
1615                 }
1616                 Gosched()
1617         }
1618         return false
1619 }
1620
1621 // Released returns how many bytes the scavenger released.
1622 func (s *Scavenger) Released() uintptr {
1623         return s.released.Load()
1624 }
1625
1626 // Wake wakes up a parked scavenger to keep running.
1627 func (s *Scavenger) Wake() {
1628         s.scavenger.wake()
1629 }
1630
1631 // Stop cleans up the scavenger's resources. The scavenger
1632 // must be parked for this to work.
1633 func (s *Scavenger) Stop() {
1634         lock(&s.scavenger.lock)
1635         parked := s.scavenger.parked
1636         unlock(&s.scavenger.lock)
1637         if !parked {
1638                 panic("tried to clean up scavenger that is not parked")
1639         }
1640         close(s.stop)
1641         s.Wake()
1642         <-s.done
1643 }
1644
1645 type ScavengeIndex struct {
1646         i scavengeIndex
1647 }
1648
1649 func NewScavengeIndex(min, max ChunkIdx) *ScavengeIndex {
1650         s := new(ScavengeIndex)
1651         // This is a bit lazy but we easily guarantee we'll be able
1652         // to reference all the relevant chunks. The worst-case
1653         // memory usage here is 512 MiB, but tests generally use
1654         // small offsets from BaseChunkIdx, which results in ~100s
1655         // of KiB in memory use.
1656         //
1657         // This may still be worth making better, at least by sharing
1658         // this fairly large array across calls with a sync.Pool or
1659         // something. Currently, when the tests are run serially,
1660         // it takes around 0.5s. Not all that much, but if we have
1661         // a lot of tests like this it could add up.
1662         s.i.chunks = make([]atomicScavChunkData, max)
1663         s.i.min.Store(uintptr(min))
1664         s.i.max.Store(uintptr(max))
1665         s.i.minHeapIdx.Store(uintptr(min))
1666         s.i.test = true
1667         return s
1668 }
1669
1670 func (s *ScavengeIndex) Find(force bool) (ChunkIdx, uint) {
1671         ci, off := s.i.find(force)
1672         return ChunkIdx(ci), off
1673 }
1674
1675 func (s *ScavengeIndex) AllocRange(base, limit uintptr) {
1676         sc, ec := chunkIndex(base), chunkIndex(limit-1)
1677         si, ei := chunkPageIndex(base), chunkPageIndex(limit-1)
1678
1679         if sc == ec {
1680                 // The range doesn't cross any chunk boundaries.
1681                 s.i.alloc(sc, ei+1-si)
1682         } else {
1683                 // The range crosses at least one chunk boundary.
1684                 s.i.alloc(sc, pallocChunkPages-si)
1685                 for c := sc + 1; c < ec; c++ {
1686                         s.i.alloc(c, pallocChunkPages)
1687                 }
1688                 s.i.alloc(ec, ei+1)
1689         }
1690 }
1691
1692 func (s *ScavengeIndex) FreeRange(base, limit uintptr) {
1693         sc, ec := chunkIndex(base), chunkIndex(limit-1)
1694         si, ei := chunkPageIndex(base), chunkPageIndex(limit-1)
1695
1696         if sc == ec {
1697                 // The range doesn't cross any chunk boundaries.
1698                 s.i.free(sc, si, ei+1-si)
1699         } else {
1700                 // The range crosses at least one chunk boundary.
1701                 s.i.free(sc, si, pallocChunkPages-si)
1702                 for c := sc + 1; c < ec; c++ {
1703                         s.i.free(c, 0, pallocChunkPages)
1704                 }
1705                 s.i.free(ec, 0, ei+1)
1706         }
1707 }
1708
1709 func (s *ScavengeIndex) ResetSearchAddrs() {
1710         for _, a := range []*atomicOffAddr{&s.i.searchAddrBg, &s.i.searchAddrForce} {
1711                 addr, marked := a.Load()
1712                 if marked {
1713                         a.StoreUnmark(addr, addr)
1714                 }
1715                 a.Clear()
1716         }
1717         s.i.freeHWM = minOffAddr
1718 }
1719
1720 func (s *ScavengeIndex) NextGen() {
1721         s.i.nextGen()
1722 }
1723
1724 func (s *ScavengeIndex) SetEmpty(ci ChunkIdx) {
1725         s.i.setEmpty(chunkIdx(ci))
1726 }
1727
1728 func (s *ScavengeIndex) SetNoHugePage(ci ChunkIdx) bool {
1729         return s.i.setNoHugePage(chunkIdx(ci))
1730 }
1731
1732 func CheckPackScavChunkData(gen uint32, inUse, lastInUse uint16, flags uint8) bool {
1733         sc0 := scavChunkData{
1734                 gen:            gen,
1735                 inUse:          inUse,
1736                 lastInUse:      lastInUse,
1737                 scavChunkFlags: scavChunkFlags(flags),
1738         }
1739         scp := sc0.pack()
1740         sc1 := unpackScavChunkData(scp)
1741         return sc0 == sc1
1742 }
1743
1744 const GTrackingPeriod = gTrackingPeriod
1745
1746 var ZeroBase = unsafe.Pointer(&zerobase)
1747
1748 const UserArenaChunkBytes = userArenaChunkBytes
1749
1750 type UserArena struct {
1751         arena *userArena
1752 }
1753
1754 func NewUserArena() *UserArena {
1755         return &UserArena{newUserArena()}
1756 }
1757
1758 func (a *UserArena) New(out *any) {
1759         i := efaceOf(out)
1760         typ := i._type
1761         if typ.Kind_&kindMask != kindPtr {
1762                 panic("new result of non-ptr type")
1763         }
1764         typ = (*ptrtype)(unsafe.Pointer(typ)).Elem
1765         i.data = a.arena.new(typ)
1766 }
1767
1768 func (a *UserArena) Slice(sl any, cap int) {
1769         a.arena.slice(sl, cap)
1770 }
1771
1772 func (a *UserArena) Free() {
1773         a.arena.free()
1774 }
1775
1776 func GlobalWaitingArenaChunks() int {
1777         n := 0
1778         systemstack(func() {
1779                 lock(&mheap_.lock)
1780                 for s := mheap_.userArena.quarantineList.first; s != nil; s = s.next {
1781                         n++
1782                 }
1783                 unlock(&mheap_.lock)
1784         })
1785         return n
1786 }
1787
1788 func UserArenaClone[T any](s T) T {
1789         return arena_heapify(s).(T)
1790 }
1791
1792 var AlignUp = alignUp
1793
1794 // BlockUntilEmptyFinalizerQueue blocks until either the finalizer
1795 // queue is emptied (and the finalizers have executed) or the timeout
1796 // is reached. Returns true if the finalizer queue was emptied.
1797 func BlockUntilEmptyFinalizerQueue(timeout int64) bool {
1798         start := nanotime()
1799         for nanotime()-start < timeout {
1800                 lock(&finlock)
1801                 // We know the queue has been drained when both finq is nil
1802                 // and the finalizer g has stopped executing.
1803                 empty := finq == nil
1804                 empty = empty && readgstatus(fing) == _Gwaiting && fing.waitreason == waitReasonFinalizerWait
1805                 unlock(&finlock)
1806                 if empty {
1807                         return true
1808                 }
1809                 Gosched()
1810         }
1811         return false
1812 }
1813
1814 func FrameStartLine(f *Frame) int {
1815         return f.startLine
1816 }
1817
1818 // PersistentAlloc allocates some memory that lives outside the Go heap.
1819 // This memory will never be freed; use sparingly.
1820 func PersistentAlloc(n uintptr) unsafe.Pointer {
1821         return persistentalloc(n, 0, &memstats.other_sys)
1822 }
1823
1824 // FPCallers works like Callers and uses frame pointer unwinding to populate
1825 // pcBuf with the return addresses of the physical frames on the stack.
1826 func FPCallers(pcBuf []uintptr) int {
1827         return fpTracebackPCs(unsafe.Pointer(getcallerfp()), pcBuf)
1828 }