Source file
src/runtime/export_test.go
1
2
3
4
5
6
7 package runtime
8
9 import (
10 "internal/abi"
11 "internal/goarch"
12 "internal/goos"
13 "internal/runtime/atomic"
14 "internal/runtime/gc"
15 "internal/runtime/sys"
16 "unsafe"
17 )
18
19 var Fadd64 = fadd64
20 var Fsub64 = fsub64
21 var Fmul64 = fmul64
22 var Fdiv64 = fdiv64
23 var F64to32 = f64to32
24 var F32to64 = f32to64
25 var Fcmp64 = fcmp64
26 var Fintto64 = fintto64
27 var F64toint = f64toint
28
29 var Entersyscall = entersyscall
30 var Exitsyscall = exitsyscall
31 var LockedOSThread = lockedOSThread
32 var Xadduintptr = atomic.Xadduintptr
33
34 var ReadRandomFailed = &readRandomFailed
35
36 var Fastlog2 = fastlog2
37
38 var ParseByteCount = parseByteCount
39
40 var Nanotime = nanotime
41 var Cputicks = cputicks
42 var CyclesPerSecond = pprof_cyclesPerSecond
43 var NetpollBreak = netpollBreak
44 var Usleep = usleep
45
46 var PhysPageSize = physPageSize
47 var PhysHugePageSize = physHugePageSize
48
49 var NetpollGenericInit = netpollGenericInit
50
51 var Memmove = memmove
52 var MemclrNoHeapPointers = memclrNoHeapPointers
53
54 var CgoCheckPointer = cgoCheckPointer
55
56 const CrashStackImplemented = crashStackImplemented
57
58 const TracebackInnerFrames = tracebackInnerFrames
59 const TracebackOuterFrames = tracebackOuterFrames
60
61 var LockPartialOrder = lockPartialOrder
62
63 type TimeTimer = timeTimer
64
65 type LockRank lockRank
66
67 func (l LockRank) String() string {
68 return lockRank(l).String()
69 }
70
71 const PreemptMSupported = preemptMSupported
72
73 type LFNode struct {
74 Next uint64
75 Pushcnt uintptr
76 }
77
78 func LFStackPush(head *uint64, node *LFNode) {
79 (*lfstack)(head).push((*lfnode)(unsafe.Pointer(node)))
80 }
81
82 func LFStackPop(head *uint64) *LFNode {
83 return (*LFNode)((*lfstack)(head).pop())
84 }
85 func LFNodeValidate(node *LFNode) {
86 lfnodeValidate((*lfnode)(unsafe.Pointer(node)))
87 }
88
89 func Netpoll(delta int64) {
90 systemstack(func() {
91 netpoll(delta)
92 })
93 }
94
95 func PointerMask(x any) (ret []byte) {
96 systemstack(func() {
97 ret = pointerMask(x)
98 })
99 return
100 }
101
102 func RunSchedLocalQueueTest() {
103 pp := new(p)
104 gs := make([]g, len(pp.runq))
105 Escape(gs)
106 for i := 0; i < len(pp.runq); i++ {
107 if g, _ := runqget(pp); g != nil {
108 throw("runq is not empty initially")
109 }
110 for j := 0; j < i; j++ {
111 runqput(pp, &gs[i], false)
112 }
113 for j := 0; j < i; j++ {
114 if g, _ := runqget(pp); g != &gs[i] {
115 print("bad element at iter ", i, "/", j, "\n")
116 throw("bad element")
117 }
118 }
119 if g, _ := runqget(pp); g != nil {
120 throw("runq is not empty afterwards")
121 }
122 }
123 }
124
125 func RunSchedLocalQueueStealTest() {
126 p1 := new(p)
127 p2 := new(p)
128 gs := make([]g, len(p1.runq))
129 Escape(gs)
130 for i := 0; i < len(p1.runq); i++ {
131 for j := 0; j < i; j++ {
132 gs[j].sig = 0
133 runqput(p1, &gs[j], false)
134 }
135 gp := runqsteal(p2, p1, true)
136 s := 0
137 if gp != nil {
138 s++
139 gp.sig++
140 }
141 for {
142 gp, _ = runqget(p2)
143 if gp == nil {
144 break
145 }
146 s++
147 gp.sig++
148 }
149 for {
150 gp, _ = runqget(p1)
151 if gp == nil {
152 break
153 }
154 gp.sig++
155 }
156 for j := 0; j < i; j++ {
157 if gs[j].sig != 1 {
158 print("bad element ", j, "(", gs[j].sig, ") at iter ", i, "\n")
159 throw("bad element")
160 }
161 }
162 if s != i/2 && s != i/2+1 {
163 print("bad steal ", s, ", want ", i/2, " or ", i/2+1, ", iter ", i, "\n")
164 throw("bad steal")
165 }
166 }
167 }
168
169 func RunSchedLocalQueueEmptyTest(iters int) {
170
171
172
173
174 done := make(chan bool, 1)
175 p := new(p)
176 gs := make([]g, 2)
177 Escape(gs)
178 ready := new(uint32)
179 for i := 0; i < iters; i++ {
180 *ready = 0
181 next0 := (i & 1) == 0
182 next1 := (i & 2) == 0
183 runqput(p, &gs[0], next0)
184 go func() {
185 for atomic.Xadd(ready, 1); atomic.Load(ready) != 2; {
186 }
187 if runqempty(p) {
188 println("next:", next0, next1)
189 throw("queue is empty")
190 }
191 done <- true
192 }()
193 for atomic.Xadd(ready, 1); atomic.Load(ready) != 2; {
194 }
195 runqput(p, &gs[1], next1)
196 runqget(p)
197 <-done
198 runqget(p)
199 }
200 }
201
202 var (
203 StringHash = stringHash
204 BytesHash = bytesHash
205 Int32Hash = int32Hash
206 Int64Hash = int64Hash
207 MemHash = memhash
208 MemHash32 = memhash32
209 MemHash64 = memhash64
210 EfaceHash = efaceHash
211 IfaceHash = ifaceHash
212 )
213
214 var UseAeshash = &useAeshash
215
216 func MemclrBytes(b []byte) {
217 s := (*slice)(unsafe.Pointer(&b))
218 memclrNoHeapPointers(s.array, uintptr(s.len))
219 }
220
221 const HashLoad = hashLoad
222
223
224 func GostringW(w []uint16) (s string) {
225 systemstack(func() {
226 s = gostringw(&w[0])
227 })
228 return
229 }
230
231 var Open = open
232 var Close = closefd
233 var Read = read
234 var Write = write
235
236 func Envs() []string { return envs }
237 func SetEnvs(e []string) { envs = e }
238
239 const PtrSize = goarch.PtrSize
240
241 const ClobberdeadPtr = clobberdeadPtr
242
243 func Clobberfree() bool {
244 return debug.clobberfree != 0
245 }
246
247 var ForceGCPeriod = &forcegcperiod
248
249
250
251
252 func SetTracebackEnv(level string) {
253 setTraceback(level)
254 traceback_env = traceback_cache
255 }
256
257 var ReadUnaligned32 = readUnaligned32
258 var ReadUnaligned64 = readUnaligned64
259
260 func CountPagesInUse() (pagesInUse, counted uintptr) {
261 stw := stopTheWorld(stwForTestCountPagesInUse)
262
263 pagesInUse = mheap_.pagesInUse.Load()
264
265 for _, s := range mheap_.allspans {
266 if s.state.get() == mSpanInUse {
267 counted += s.npages
268 }
269 }
270
271 startTheWorld(stw)
272
273 return
274 }
275
276 func Fastrand() uint32 { return uint32(rand()) }
277 func Fastrand64() uint64 { return rand() }
278 func Fastrandn(n uint32) uint32 { return randn(n) }
279
280 type ProfBuf profBuf
281
282 func NewProfBuf(hdrsize, bufwords, tags int) *ProfBuf {
283 return (*ProfBuf)(newProfBuf(hdrsize, bufwords, tags))
284 }
285
286 func (p *ProfBuf) Write(tag *unsafe.Pointer, now int64, hdr []uint64, stk []uintptr) {
287 (*profBuf)(p).write(tag, now, hdr, stk)
288 }
289
290 const (
291 ProfBufBlocking = profBufBlocking
292 ProfBufNonBlocking = profBufNonBlocking
293 )
294
295 func (p *ProfBuf) Read(mode profBufReadMode) ([]uint64, []unsafe.Pointer, bool) {
296 return (*profBuf)(p).read(mode)
297 }
298
299 func (p *ProfBuf) Close() {
300 (*profBuf)(p).close()
301 }
302
303 type CPUStats = cpuStats
304
305 func ReadCPUStats() CPUStats {
306 return work.cpuStats
307 }
308
309 func ReadMetricsSlow(memStats *MemStats, samplesp unsafe.Pointer, len, cap int) {
310 stw := stopTheWorld(stwForTestReadMetricsSlow)
311
312
313
314 metricsLock()
315 initMetrics()
316
317 systemstack(func() {
318
319
320 getg().racectx = getg().m.curg.racectx
321
322
323
324
325
326
327 readMetricsLocked(samplesp, len, cap)
328
329
330
331
332
333 readmemstats_m(memStats)
334
335
336
337
338 readMetricsLocked(samplesp, len, cap)
339
340
341 getg().racectx = 0
342 })
343 metricsUnlock()
344
345 startTheWorld(stw)
346 }
347
348 var DoubleCheckReadMemStats = &doubleCheckReadMemStats
349
350
351
352 func ReadMemStatsSlow() (base, slow MemStats) {
353 stw := stopTheWorld(stwForTestReadMemStatsSlow)
354
355
356 systemstack(func() {
357
358 getg().m.mallocing++
359
360 readmemstats_m(&base)
361
362
363
364 slow = base
365 slow.Alloc = 0
366 slow.TotalAlloc = 0
367 slow.Mallocs = 0
368 slow.Frees = 0
369 slow.HeapReleased = 0
370 var bySize [gc.NumSizeClasses]struct {
371 Mallocs, Frees uint64
372 }
373
374
375 for _, s := range mheap_.allspans {
376 if s.state.get() != mSpanInUse {
377 continue
378 }
379 if s.isUnusedUserArenaChunk() {
380 continue
381 }
382 if sizeclass := s.spanclass.sizeclass(); sizeclass == 0 {
383 slow.Mallocs++
384 slow.Alloc += uint64(s.elemsize)
385 } else {
386 slow.Mallocs += uint64(s.allocCount)
387 slow.Alloc += uint64(s.allocCount) * uint64(s.elemsize)
388 bySize[sizeclass].Mallocs += uint64(s.allocCount)
389 }
390 }
391
392
393 var m heapStatsDelta
394 memstats.heapStats.unsafeRead(&m)
395
396
397 var smallFree uint64
398 for i := 0; i < gc.NumSizeClasses; i++ {
399 slow.Frees += m.smallFreeCount[i]
400 bySize[i].Frees += m.smallFreeCount[i]
401 bySize[i].Mallocs += m.smallFreeCount[i]
402 smallFree += m.smallFreeCount[i] * uint64(gc.SizeClassToSize[i])
403 }
404 slow.Frees += m.tinyAllocCount + m.largeFreeCount
405 slow.Mallocs += slow.Frees
406
407 slow.TotalAlloc = slow.Alloc + m.largeFree + smallFree
408
409 for i := range slow.BySize {
410 slow.BySize[i].Mallocs = bySize[i].Mallocs
411 slow.BySize[i].Frees = bySize[i].Frees
412 }
413
414 for i := mheap_.pages.start; i < mheap_.pages.end; i++ {
415 chunk := mheap_.pages.tryChunkOf(i)
416 if chunk == nil {
417 continue
418 }
419 pg := chunk.scavenged.popcntRange(0, pallocChunkPages)
420 slow.HeapReleased += uint64(pg) * pageSize
421 }
422 for _, p := range allp {
423
424 pg := sys.OnesCount64(p.pcache.cache & p.pcache.scav)
425 slow.HeapReleased += uint64(pg) * pageSize
426 }
427
428 getg().m.mallocing--
429 })
430
431 startTheWorld(stw)
432 return
433 }
434
435
436
437
438 func ShrinkStackAndVerifyFramePointers() {
439 before := stackPoisonCopy
440 defer func() { stackPoisonCopy = before }()
441 stackPoisonCopy = 1
442
443 gp := getg()
444 systemstack(func() {
445 shrinkstack(gp)
446 })
447
448
449 FPCallers(make([]uintptr, 1024))
450 }
451
452 type StackPoisonCopyRestore int
453
454 func (s StackPoisonCopyRestore) Restore() { stackPoisonCopy = int(s) }
455
456 func StackPoisonCopy() StackPoisonCopyRestore {
457 before := stackPoisonCopy
458 stackPoisonCopy = 1
459 return StackPoisonCopyRestore(before)
460 }
461
462
463
464
465 func BlockOnSystemStack() {
466 systemstack(blockOnSystemStackInternal)
467 }
468
469 func blockOnSystemStackInternal() {
470 print("x\n")
471 lock(&deadlock)
472 lock(&deadlock)
473 }
474
475 type RWMutex struct {
476 rw rwmutex
477 }
478
479 func (rw *RWMutex) Init() {
480 rw.rw.init(lockRankTestR, lockRankTestRInternal, lockRankTestW)
481 }
482
483 func (rw *RWMutex) RLock() {
484 rw.rw.rlock()
485 }
486
487 func (rw *RWMutex) RUnlock() {
488 rw.rw.runlock()
489 }
490
491 func (rw *RWMutex) Lock() {
492 rw.rw.lock()
493 }
494
495 func (rw *RWMutex) Unlock() {
496 rw.rw.unlock()
497 }
498
499 func LockOSCounts() (external, internal uint32) {
500 gp := getg()
501 if gp.m.lockedExt+gp.m.lockedInt == 0 {
502 if gp.lockedm != 0 {
503 panic("lockedm on non-locked goroutine")
504 }
505 } else {
506 if gp.lockedm == 0 {
507 panic("nil lockedm on locked goroutine")
508 }
509 }
510 return gp.m.lockedExt, gp.m.lockedInt
511 }
512
513
514 func TracebackSystemstack(stk []uintptr, i int) int {
515 if i == 0 {
516 pc, sp := sys.GetCallerPC(), sys.GetCallerSP()
517 var u unwinder
518 u.initAt(pc, sp, 0, getg(), unwindJumpStack)
519 return tracebackPCs(&u, 0, stk)
520 }
521 n := 0
522 systemstack(func() {
523 n = TracebackSystemstack(stk, i-1)
524 })
525 return n
526 }
527
528 func KeepNArenaHints(n int) {
529 hint := mheap_.arenaHints
530 for i := 1; i < n; i++ {
531 hint = hint.next
532 if hint == nil {
533 return
534 }
535 }
536 hint.next = nil
537 }
538
539
540
541
542
543
544
545 func MapNextArenaHint() (start, end uintptr, ok bool) {
546 hint := mheap_.arenaHints
547 addr := hint.addr
548 if hint.down {
549 start, end = addr-heapArenaBytes, addr
550 addr -= physPageSize
551 } else {
552 start, end = addr, addr+heapArenaBytes
553 }
554 got := sysReserve(unsafe.Pointer(addr), physPageSize, "")
555 ok = (addr == uintptr(got))
556 if !ok {
557
558
559 sysUnreserve(got, physPageSize)
560 }
561 return
562 }
563
564 func NextArenaHint() (uintptr, bool) {
565 if mheap_.arenaHints == nil {
566 return 0, false
567 }
568 return mheap_.arenaHints.addr, true
569 }
570
571 type G = g
572
573 type Sudog = sudog
574
575 type XRegPerG = xRegPerG
576
577 func Getg() *G {
578 return getg()
579 }
580
581 func Goid() uint64 {
582 return getg().goid
583 }
584
585 func GIsWaitingOnMutex(gp *G) bool {
586 return readgstatus(gp) == _Gwaiting && gp.waitreason.isMutexWait()
587 }
588
589 var CasGStatusAlwaysTrack = &casgstatusAlwaysTrack
590
591
592 func PanicForTesting(b []byte, i int) byte {
593 return unexportedPanicForTesting(b, i)
594 }
595
596
597 func unexportedPanicForTesting(b []byte, i int) byte {
598 return b[i]
599 }
600
601 func G0StackOverflow() {
602 systemstack(func() {
603 g0 := getg()
604 sp := sys.GetCallerSP()
605
606
607
608 g0.stack.lo = sp - 4096 - stackSystem
609 g0.stackguard0 = g0.stack.lo + stackGuard
610 g0.stackguard1 = g0.stackguard0
611
612 stackOverflow(nil)
613 })
614 }
615
616 func stackOverflow(x *byte) {
617 var buf [256]byte
618 stackOverflow(&buf[0])
619 }
620
621 func RunGetgThreadSwitchTest() {
622
623
624
625
626
627
628 ch := make(chan int)
629 go func(ch chan int) {
630 ch <- 5
631 LockOSThread()
632 }(ch)
633
634 g1 := getg()
635
636
637
638
639
640 <-ch
641
642 g2 := getg()
643 if g1 != g2 {
644 panic("g1 != g2")
645 }
646
647
648
649 g3 := getg()
650 if g1 != g3 {
651 panic("g1 != g3")
652 }
653 }
654
655
656 func Freegc(p unsafe.Pointer, size uintptr, noscan bool) {
657 freegc(p, size, noscan)
658 }
659
660
661 func AssistCredit() int64 {
662 assistG := getg()
663 if assistG.m.curg != nil {
664 assistG = assistG.m.curg
665 }
666 return assistG.gcAssistBytes
667 }
668
669
670 func GcBlackenEnable() bool {
671
672
673
674
675
676 return gcBlackenEnabled != 0
677 }
678
679 const SizeSpecializedMallocEnabled = sizeSpecializedMallocEnabled
680
681 const RuntimeFreegcEnabled = runtimeFreegcEnabled
682
683 const (
684 PageSize = pageSize
685 PallocChunkPages = pallocChunkPages
686 PageAlloc64Bit = pageAlloc64Bit
687 PallocSumBytes = pallocSumBytes
688 )
689
690
691 type PallocSum pallocSum
692
693 func PackPallocSum(start, max, end uint) PallocSum { return PallocSum(packPallocSum(start, max, end)) }
694 func (m PallocSum) Start() uint { return pallocSum(m).start() }
695 func (m PallocSum) Max() uint { return pallocSum(m).max() }
696 func (m PallocSum) End() uint { return pallocSum(m).end() }
697
698
699 type PallocBits pallocBits
700
701 func (b *PallocBits) Find(npages uintptr, searchIdx uint) (uint, uint) {
702 return (*pallocBits)(b).find(npages, searchIdx)
703 }
704 func (b *PallocBits) AllocRange(i, n uint) { (*pallocBits)(b).allocRange(i, n) }
705 func (b *PallocBits) Free(i, n uint) { (*pallocBits)(b).free(i, n) }
706 func (b *PallocBits) Summarize() PallocSum { return PallocSum((*pallocBits)(b).summarize()) }
707 func (b *PallocBits) PopcntRange(i, n uint) uint { return (*pageBits)(b).popcntRange(i, n) }
708
709
710
711 func SummarizeSlow(b *PallocBits) PallocSum {
712 var start, most, end uint
713
714 const N = uint(len(b)) * 64
715 for start < N && (*pageBits)(b).get(start) == 0 {
716 start++
717 }
718 for end < N && (*pageBits)(b).get(N-end-1) == 0 {
719 end++
720 }
721 run := uint(0)
722 for i := uint(0); i < N; i++ {
723 if (*pageBits)(b).get(i) == 0 {
724 run++
725 } else {
726 run = 0
727 }
728 most = max(most, run)
729 }
730 return PackPallocSum(start, most, end)
731 }
732
733
734 func FindBitRange64(c uint64, n uint) uint { return findBitRange64(c, n) }
735
736
737
738 func DiffPallocBits(a, b *PallocBits) []BitRange {
739 ba := (*pageBits)(a)
740 bb := (*pageBits)(b)
741
742 var d []BitRange
743 base, size := uint(0), uint(0)
744 for i := uint(0); i < uint(len(ba))*64; i++ {
745 if ba.get(i) != bb.get(i) {
746 if size == 0 {
747 base = i
748 }
749 size++
750 } else {
751 if size != 0 {
752 d = append(d, BitRange{base, size})
753 }
754 size = 0
755 }
756 }
757 if size != 0 {
758 d = append(d, BitRange{base, size})
759 }
760 return d
761 }
762
763
764
765
766 func StringifyPallocBits(b *PallocBits, r BitRange) string {
767 str := ""
768 for j := r.I; j < r.I+r.N; j++ {
769 if (*pageBits)(b).get(j) != 0 {
770 str += "1"
771 } else {
772 str += "0"
773 }
774 }
775 return str
776 }
777
778
779 type PallocData pallocData
780
781 func (d *PallocData) FindScavengeCandidate(searchIdx uint, min, max uintptr) (uint, uint) {
782 return (*pallocData)(d).findScavengeCandidate(searchIdx, min, max)
783 }
784 func (d *PallocData) AllocRange(i, n uint) { (*pallocData)(d).allocRange(i, n) }
785 func (d *PallocData) ScavengedSetRange(i, n uint) {
786 (*pallocData)(d).scavenged.setRange(i, n)
787 }
788 func (d *PallocData) PallocBits() *PallocBits {
789 return (*PallocBits)(&(*pallocData)(d).pallocBits)
790 }
791 func (d *PallocData) Scavenged() *PallocBits {
792 return (*PallocBits)(&(*pallocData)(d).scavenged)
793 }
794
795
796 func FillAligned(x uint64, m uint) uint64 { return fillAligned(x, m) }
797
798
799 type PageCache pageCache
800
801 const PageCachePages = pageCachePages
802
803 func NewPageCache(base uintptr, cache, scav uint64) PageCache {
804 return PageCache(pageCache{base: base, cache: cache, scav: scav})
805 }
806 func (c *PageCache) Empty() bool { return (*pageCache)(c).empty() }
807 func (c *PageCache) Base() uintptr { return (*pageCache)(c).base }
808 func (c *PageCache) Cache() uint64 { return (*pageCache)(c).cache }
809 func (c *PageCache) Scav() uint64 { return (*pageCache)(c).scav }
810 func (c *PageCache) Alloc(npages uintptr) (uintptr, uintptr) {
811 return (*pageCache)(c).alloc(npages)
812 }
813 func (c *PageCache) Flush(s *PageAlloc) {
814 cp := (*pageCache)(c)
815 sp := (*pageAlloc)(s)
816
817 systemstack(func() {
818
819
820 lock(sp.mheapLock)
821 cp.flush(sp)
822 unlock(sp.mheapLock)
823 })
824 }
825
826
827 type ChunkIdx chunkIdx
828
829
830
831 type PageAlloc pageAlloc
832
833 func (p *PageAlloc) Alloc(npages uintptr) (uintptr, uintptr) {
834 pp := (*pageAlloc)(p)
835
836 var addr, scav uintptr
837 systemstack(func() {
838
839
840 lock(pp.mheapLock)
841 addr, scav = pp.alloc(npages)
842 unlock(pp.mheapLock)
843 })
844 return addr, scav
845 }
846 func (p *PageAlloc) AllocToCache() PageCache {
847 pp := (*pageAlloc)(p)
848
849 var c PageCache
850 systemstack(func() {
851
852
853 lock(pp.mheapLock)
854 c = PageCache(pp.allocToCache())
855 unlock(pp.mheapLock)
856 })
857 return c
858 }
859 func (p *PageAlloc) Free(base, npages uintptr) {
860 pp := (*pageAlloc)(p)
861
862 systemstack(func() {
863
864
865 lock(pp.mheapLock)
866 pp.free(base, npages)
867 unlock(pp.mheapLock)
868 })
869 }
870 func (p *PageAlloc) Bounds() (ChunkIdx, ChunkIdx) {
871 return ChunkIdx((*pageAlloc)(p).start), ChunkIdx((*pageAlloc)(p).end)
872 }
873 func (p *PageAlloc) Scavenge(nbytes uintptr) (r uintptr) {
874 pp := (*pageAlloc)(p)
875 systemstack(func() {
876 r = pp.scavenge(nbytes, nil, true)
877 })
878 return
879 }
880 func (p *PageAlloc) InUse() []AddrRange {
881 ranges := make([]AddrRange, 0, len(p.inUse.ranges))
882 for _, r := range p.inUse.ranges {
883 ranges = append(ranges, AddrRange{r})
884 }
885 return ranges
886 }
887
888
889 func (p *PageAlloc) PallocData(i ChunkIdx) *PallocData {
890 ci := chunkIdx(i)
891 return (*PallocData)((*pageAlloc)(p).tryChunkOf(ci))
892 }
893
894
895 type AddrRange struct {
896 addrRange
897 }
898
899
900 func MakeAddrRange(base, limit uintptr) AddrRange {
901 return AddrRange{makeAddrRange(base, limit)}
902 }
903
904
905 func (a AddrRange) Base() uintptr {
906 return a.addrRange.base.addr()
907 }
908
909
910 func (a AddrRange) Limit() uintptr {
911 return a.addrRange.limit.addr()
912 }
913
914
915 func (a AddrRange) Equals(b AddrRange) bool {
916 return a == b
917 }
918
919
920 func (a AddrRange) Size() uintptr {
921 return a.addrRange.size()
922 }
923
924
925
926
927
928 var testSysStat = &memstats.other_sys
929
930
931 type AddrRanges struct {
932 addrRanges
933 mutable bool
934 }
935
936
937
938
939
940
941
942
943
944
945 func NewAddrRanges() AddrRanges {
946 r := addrRanges{}
947 r.init(testSysStat)
948 return AddrRanges{r, true}
949 }
950
951
952
953
954
955
956 func MakeAddrRanges(a ...AddrRange) AddrRanges {
957
958
959
960
961
962 ranges := make([]addrRange, 0, len(a))
963 total := uintptr(0)
964 for _, r := range a {
965 ranges = append(ranges, r.addrRange)
966 total += r.Size()
967 }
968 return AddrRanges{addrRanges{
969 ranges: ranges,
970 totalBytes: total,
971 sysStat: testSysStat,
972 }, false}
973 }
974
975
976
977 func (a *AddrRanges) Ranges() []AddrRange {
978 result := make([]AddrRange, 0, len(a.addrRanges.ranges))
979 for _, r := range a.addrRanges.ranges {
980 result = append(result, AddrRange{r})
981 }
982 return result
983 }
984
985
986
987 func (a *AddrRanges) FindSucc(base uintptr) int {
988 return a.findSucc(base)
989 }
990
991
992
993
994
995 func (a *AddrRanges) Add(r AddrRange) {
996 if !a.mutable {
997 throw("attempt to mutate immutable AddrRanges")
998 }
999 a.add(r.addrRange)
1000 }
1001
1002
1003 func (a *AddrRanges) TotalBytes() uintptr {
1004 return a.addrRanges.totalBytes
1005 }
1006
1007
1008 type BitRange struct {
1009 I, N uint
1010 }
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026 func NewPageAlloc(chunks, scav map[ChunkIdx][]BitRange) *PageAlloc {
1027 p := new(pageAlloc)
1028
1029
1030 p.init(new(mutex), testSysStat, true)
1031 lockInit(p.mheapLock, lockRankMheap)
1032 for i, init := range chunks {
1033 addr := chunkBase(chunkIdx(i))
1034
1035
1036 systemstack(func() {
1037 lock(p.mheapLock)
1038 p.grow(addr, pallocChunkBytes)
1039 unlock(p.mheapLock)
1040 })
1041
1042
1043 ci := chunkIndex(addr)
1044 chunk := p.chunkOf(ci)
1045
1046
1047 chunk.scavenged.clearRange(0, pallocChunkPages)
1048
1049
1050
1051
1052 p.scav.index.alloc(ci, pallocChunkPages)
1053 p.scav.index.free(ci, 0, pallocChunkPages)
1054
1055
1056 if scav != nil {
1057 if scvg, ok := scav[i]; ok {
1058 for _, s := range scvg {
1059
1060
1061 if s.N != 0 {
1062 chunk.scavenged.setRange(s.I, s.N)
1063 }
1064 }
1065 }
1066 }
1067
1068
1069 for _, s := range init {
1070
1071
1072 if s.N != 0 {
1073 chunk.allocRange(s.I, s.N)
1074
1075
1076 p.scav.index.alloc(ci, s.N)
1077 }
1078 }
1079
1080
1081 systemstack(func() {
1082 lock(p.mheapLock)
1083 p.update(addr, pallocChunkPages, false, false)
1084 unlock(p.mheapLock)
1085 })
1086 }
1087
1088 return (*PageAlloc)(p)
1089 }
1090
1091
1092
1093
1094 func FreePageAlloc(pp *PageAlloc) {
1095 p := (*pageAlloc)(pp)
1096
1097
1098 if pageAlloc64Bit != 0 {
1099 for l := 0; l < summaryLevels; l++ {
1100
1101
1102
1103
1104 sysUnreserve(unsafe.Pointer(&p.summary[l][0]), uintptr(cap(p.summary[l]))*pallocSumBytes)
1105 }
1106 } else {
1107 resSize := uintptr(0)
1108 for _, s := range p.summary {
1109 resSize += uintptr(cap(s)) * pallocSumBytes
1110 }
1111
1112 sysUnreserve(unsafe.Pointer(&p.summary[0][0]), alignUp(resSize, physPageSize))
1113 }
1114
1115
1116
1117
1118
1119 gcController.mappedReady.Add(-int64(p.summaryMappedReady))
1120 testSysStat.add(-int64(p.summaryMappedReady))
1121
1122
1123
1124
1125
1126 sysUnreserve(unsafe.Pointer(&p.scav.index.chunks[0]), uintptr(cap(p.scav.index.chunks))*unsafe.Sizeof(atomicScavChunkData{}))
1127
1128
1129 for i := range p.chunks {
1130 if x := p.chunks[i]; x != nil {
1131 p.chunks[i] = nil
1132
1133 sysFree(unsafe.Pointer(x), unsafe.Sizeof(*p.chunks[0]), testSysStat)
1134 }
1135 }
1136 }
1137
1138
1139
1140
1141
1142
1143
1144 var BaseChunkIdx = func() ChunkIdx {
1145 var prefix uintptr
1146 if pageAlloc64Bit != 0 {
1147 prefix = 0xc000
1148 } else {
1149 prefix = 0x100
1150 }
1151 baseAddr := prefix * pallocChunkBytes
1152 if goos.IsAix != 0 {
1153 baseAddr += arenaBaseOffset
1154 }
1155 return ChunkIdx(chunkIndex(baseAddr))
1156 }()
1157
1158
1159
1160 func PageBase(c ChunkIdx, pageIdx uint) uintptr {
1161 return chunkBase(chunkIdx(c)) + uintptr(pageIdx)*pageSize
1162 }
1163
1164 type BitsMismatch struct {
1165 Base uintptr
1166 Got, Want uint64
1167 }
1168
1169 func CheckScavengedBitsCleared(mismatches []BitsMismatch) (n int, ok bool) {
1170 ok = true
1171
1172
1173 systemstack(func() {
1174 getg().m.mallocing++
1175
1176
1177 lock(&mheap_.lock)
1178
1179 chunkLoop:
1180 for i := mheap_.pages.start; i < mheap_.pages.end; i++ {
1181 chunk := mheap_.pages.tryChunkOf(i)
1182 if chunk == nil {
1183 continue
1184 }
1185 cb := chunkBase(i)
1186 for j := 0; j < pallocChunkPages/64; j++ {
1187
1188
1189
1190
1191
1192 want := chunk.scavenged[j] &^ chunk.pallocBits[j]
1193 got := chunk.scavenged[j]
1194 if want != got {
1195 ok = false
1196 if n >= len(mismatches) {
1197 break chunkLoop
1198 }
1199 mismatches[n] = BitsMismatch{
1200 Base: cb + uintptr(j)*64*pageSize,
1201 Got: got,
1202 Want: want,
1203 }
1204 n++
1205 }
1206 }
1207 }
1208 unlock(&mheap_.lock)
1209
1210 getg().m.mallocing--
1211 })
1212
1213 if randomizeHeapBase && len(mismatches) > 0 {
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228 affectedArenas := map[arenaIdx]bool{}
1229 for _, mismatch := range mismatches {
1230 if mismatch.Base > 0 {
1231 affectedArenas[arenaIndex(mismatch.Base)] = true
1232 }
1233 }
1234 if len(affectedArenas) == 1 {
1235 ok = true
1236
1237 for i := range n {
1238 mismatches[i] = BitsMismatch{}
1239 }
1240 }
1241 }
1242
1243 return
1244 }
1245
1246 func PageCachePagesLeaked() (leaked uintptr) {
1247 stw := stopTheWorld(stwForTestPageCachePagesLeaked)
1248
1249
1250 deadp := allp[len(allp):cap(allp)]
1251 for _, p := range deadp {
1252
1253
1254 if p != nil {
1255 leaked += uintptr(sys.OnesCount64(p.pcache.cache))
1256 }
1257 }
1258
1259 startTheWorld(stw)
1260 return
1261 }
1262
1263 var ProcYield = procyield
1264 var OSYield = osyield
1265
1266 type Mutex = mutex
1267
1268 var Lock = lock
1269 var Unlock = unlock
1270
1271 var MutexContended = mutexContended
1272
1273 func SemRootLock(addr *uint32) *mutex {
1274 root := semtable.rootFor(addr)
1275 return &root.lock
1276 }
1277
1278 var Semacquire = semacquire
1279 var Semrelease1 = semrelease1
1280
1281 func SemNwait(addr *uint32) uint32 {
1282 root := semtable.rootFor(addr)
1283 return root.nwait.Load()
1284 }
1285
1286 const SemTableSize = semTabSize
1287
1288
1289 type SemTable struct {
1290 semTable
1291 }
1292
1293
1294 func (t *SemTable) Enqueue(addr *uint32) {
1295 s := acquireSudog()
1296 s.releasetime = 0
1297 s.acquiretime = 0
1298 s.ticket = 0
1299 t.semTable.rootFor(addr).queue(addr, s, false)
1300 }
1301
1302
1303
1304
1305 func (t *SemTable) Dequeue(addr *uint32) bool {
1306 s, _, _ := t.semTable.rootFor(addr).dequeue(addr)
1307 if s != nil {
1308 releaseSudog(s)
1309 return true
1310 }
1311 return false
1312 }
1313
1314
1315 type MSpan mspan
1316
1317
1318 func AllocMSpan() *MSpan {
1319 var s *mspan
1320 systemstack(func() {
1321 lock(&mheap_.lock)
1322 s = (*mspan)(mheap_.spanalloc.alloc())
1323 s.init(0, 0)
1324 unlock(&mheap_.lock)
1325 })
1326 return (*MSpan)(s)
1327 }
1328
1329
1330 func FreeMSpan(s *MSpan) {
1331 systemstack(func() {
1332 lock(&mheap_.lock)
1333 mheap_.spanalloc.free(unsafe.Pointer(s))
1334 unlock(&mheap_.lock)
1335 })
1336 }
1337
1338 func MSpanCountAlloc(ms *MSpan, bits []byte) int {
1339 s := (*mspan)(ms)
1340 s.nelems = uint16(len(bits) * 8)
1341 s.gcmarkBits = (*gcBits)(unsafe.Pointer(&bits[0]))
1342 result := s.countAlloc()
1343 s.gcmarkBits = nil
1344 return result
1345 }
1346
1347 const (
1348 TimeHistSubBucketBits = timeHistSubBucketBits
1349 TimeHistNumSubBuckets = timeHistNumSubBuckets
1350 TimeHistNumBuckets = timeHistNumBuckets
1351 TimeHistMinBucketBits = timeHistMinBucketBits
1352 TimeHistMaxBucketBits = timeHistMaxBucketBits
1353 )
1354
1355 type TimeHistogram timeHistogram
1356
1357
1358
1359
1360
1361 func (th *TimeHistogram) Count(bucket, subBucket int) (uint64, bool) {
1362 t := (*timeHistogram)(th)
1363 if bucket < 0 {
1364 return t.underflow.Load(), false
1365 }
1366 i := bucket*TimeHistNumSubBuckets + subBucket
1367 if i >= len(t.counts) {
1368 return t.overflow.Load(), false
1369 }
1370 return t.counts[i].Load(), true
1371 }
1372
1373 func (th *TimeHistogram) Record(duration int64) {
1374 (*timeHistogram)(th).record(duration)
1375 }
1376
1377 var TimeHistogramMetricsBuckets = timeHistogramMetricsBuckets
1378
1379 func SetIntArgRegs(a int) int {
1380 lock(&finlock)
1381 old := intArgRegs
1382 if a >= 0 {
1383 intArgRegs = a
1384 }
1385 unlock(&finlock)
1386 return old
1387 }
1388
1389 func FinalizerGAsleep() bool {
1390 return fingStatus.Load()&fingWait != 0
1391 }
1392
1393
1394
1395
1396 var GCTestMoveStackOnNextCall = gcTestMoveStackOnNextCall
1397
1398
1399
1400 func GCTestIsReachable(ptrs ...unsafe.Pointer) (mask uint64) {
1401 return gcTestIsReachable(ptrs...)
1402 }
1403
1404
1405
1406
1407
1408
1409
1410 func GCTestPointerClass(p unsafe.Pointer) string {
1411 return gcTestPointerClass(p)
1412 }
1413
1414 const Raceenabled = raceenabled
1415
1416 const (
1417 GCBackgroundUtilization = gcBackgroundUtilization
1418 GCGoalUtilization = gcGoalUtilization
1419 DefaultHeapMinimum = defaultHeapMinimum
1420 MemoryLimitHeapGoalHeadroomPercent = memoryLimitHeapGoalHeadroomPercent
1421 MemoryLimitMinHeapGoalHeadroom = memoryLimitMinHeapGoalHeadroom
1422 )
1423
1424 type GCController struct {
1425 gcControllerState
1426 }
1427
1428 func NewGCController(gcPercent int, memoryLimit int64) *GCController {
1429
1430
1431
1432
1433 g := Escape(new(GCController))
1434 g.gcControllerState.test = true
1435 g.init(int32(gcPercent), memoryLimit)
1436 return g
1437 }
1438
1439 func (c *GCController) StartCycle(stackSize, globalsSize uint64, scannableFrac float64, gomaxprocs int) {
1440 trigger, _ := c.trigger()
1441 if c.heapMarked > trigger {
1442 trigger = c.heapMarked
1443 }
1444 c.maxStackScan.Store(stackSize)
1445 c.globalsScan.Store(globalsSize)
1446 c.heapLive.Store(trigger)
1447 c.heapScan.Add(int64(float64(trigger-c.heapMarked) * scannableFrac))
1448 c.startCycle(0, gomaxprocs, gcTrigger{kind: gcTriggerHeap})
1449 }
1450
1451 func (c *GCController) AssistWorkPerByte() float64 {
1452 return c.assistWorkPerByte.Load()
1453 }
1454
1455 func (c *GCController) HeapGoal() uint64 {
1456 return c.heapGoal()
1457 }
1458
1459 func (c *GCController) HeapLive() uint64 {
1460 return c.heapLive.Load()
1461 }
1462
1463 func (c *GCController) HeapMarked() uint64 {
1464 return c.heapMarked
1465 }
1466
1467 func (c *GCController) Triggered() uint64 {
1468 return c.triggered
1469 }
1470
1471 type GCControllerReviseDelta struct {
1472 HeapLive int64
1473 HeapScan int64
1474 HeapScanWork int64
1475 StackScanWork int64
1476 GlobalsScanWork int64
1477 }
1478
1479 func (c *GCController) Revise(d GCControllerReviseDelta) {
1480 c.heapLive.Add(d.HeapLive)
1481 c.heapScan.Add(d.HeapScan)
1482 c.heapScanWork.Add(d.HeapScanWork)
1483 c.stackScanWork.Add(d.StackScanWork)
1484 c.globalsScanWork.Add(d.GlobalsScanWork)
1485 c.revise()
1486 }
1487
1488 func (c *GCController) EndCycle(bytesMarked uint64, assistTime, elapsed int64, gomaxprocs int) {
1489 c.assistTime.Store(assistTime)
1490 c.endCycle(elapsed, gomaxprocs, false)
1491 c.resetLive(bytesMarked)
1492 c.commit(false)
1493 }
1494
1495 func (c *GCController) AddIdleMarkWorker() bool {
1496 return c.addIdleMarkWorker()
1497 }
1498
1499 func (c *GCController) NeedIdleMarkWorker() bool {
1500 return c.needIdleMarkWorker()
1501 }
1502
1503 func (c *GCController) RemoveIdleMarkWorker() {
1504 c.removeIdleMarkWorker()
1505 }
1506
1507 func (c *GCController) SetMaxIdleMarkWorkers(max int32) {
1508 c.setMaxIdleMarkWorkers(max)
1509 }
1510
1511 var alwaysFalse bool
1512 var escapeSink any
1513
1514 func Escape[T any](x T) T {
1515 if alwaysFalse {
1516 escapeSink = x
1517 }
1518 return x
1519 }
1520
1521
1522 func Acquirem() {
1523 acquirem()
1524 }
1525
1526 func Releasem() {
1527 releasem(getg().m)
1528 }
1529
1530
1531
1532
1533
1534
1535 func GoschedIfBusy() {
1536 goschedIfBusy()
1537 }
1538
1539 type PIController struct {
1540 piController
1541 }
1542
1543 func NewPIController(kp, ti, tt, min, max float64) *PIController {
1544 return &PIController{piController{
1545 kp: kp,
1546 ti: ti,
1547 tt: tt,
1548 min: min,
1549 max: max,
1550 }}
1551 }
1552
1553 func (c *PIController) Next(input, setpoint, period float64) (float64, bool) {
1554 return c.piController.next(input, setpoint, period)
1555 }
1556
1557 const (
1558 CapacityPerProc = capacityPerProc
1559 GCCPULimiterUpdatePeriod = gcCPULimiterUpdatePeriod
1560 )
1561
1562 type GCCPULimiter struct {
1563 limiter gcCPULimiterState
1564 }
1565
1566 func NewGCCPULimiter(now int64, gomaxprocs int32) *GCCPULimiter {
1567
1568
1569
1570
1571 l := Escape(new(GCCPULimiter))
1572 l.limiter.test = true
1573 l.limiter.resetCapacity(now, gomaxprocs)
1574 return l
1575 }
1576
1577 func (l *GCCPULimiter) Fill() uint64 {
1578 return l.limiter.bucket.fill
1579 }
1580
1581 func (l *GCCPULimiter) Capacity() uint64 {
1582 return l.limiter.bucket.capacity
1583 }
1584
1585 func (l *GCCPULimiter) Overflow() uint64 {
1586 return l.limiter.overflow
1587 }
1588
1589 func (l *GCCPULimiter) Limiting() bool {
1590 return l.limiter.limiting()
1591 }
1592
1593 func (l *GCCPULimiter) NeedUpdate(now int64) bool {
1594 return l.limiter.needUpdate(now)
1595 }
1596
1597 func (l *GCCPULimiter) StartGCTransition(enableGC bool, now int64) {
1598 l.limiter.startGCTransition(enableGC, now)
1599 }
1600
1601 func (l *GCCPULimiter) FinishGCTransition(now int64) {
1602 l.limiter.finishGCTransition(now)
1603 }
1604
1605 func (l *GCCPULimiter) Update(now int64) {
1606 l.limiter.update(now)
1607 }
1608
1609 func (l *GCCPULimiter) AddAssistTime(t int64) {
1610 l.limiter.addAssistTime(t)
1611 }
1612
1613 func (l *GCCPULimiter) ResetCapacity(now int64, nprocs int32) {
1614 l.limiter.resetCapacity(now, nprocs)
1615 }
1616
1617 const ScavengePercent = scavengePercent
1618
1619 type Scavenger struct {
1620 Sleep func(int64) int64
1621 Scavenge func(uintptr) (uintptr, int64)
1622 ShouldStop func() bool
1623 GoMaxProcs func() int32
1624
1625 released atomic.Uintptr
1626 scavenger scavengerState
1627 stop chan<- struct{}
1628 done <-chan struct{}
1629 }
1630
1631 func (s *Scavenger) Start() {
1632 if s.Sleep == nil || s.Scavenge == nil || s.ShouldStop == nil || s.GoMaxProcs == nil {
1633 panic("must populate all stubs")
1634 }
1635
1636
1637 s.scavenger.sleepStub = s.Sleep
1638 s.scavenger.scavenge = s.Scavenge
1639 s.scavenger.shouldStop = s.ShouldStop
1640 s.scavenger.gomaxprocs = s.GoMaxProcs
1641
1642
1643 stop := make(chan struct{})
1644 s.stop = stop
1645 done := make(chan struct{})
1646 s.done = done
1647 go func() {
1648
1649 s.scavenger.init()
1650 s.scavenger.park()
1651 for {
1652 select {
1653 case <-stop:
1654 close(done)
1655 return
1656 default:
1657 }
1658 released, workTime := s.scavenger.run()
1659 if released == 0 {
1660 s.scavenger.park()
1661 continue
1662 }
1663 s.released.Add(released)
1664 s.scavenger.sleep(workTime)
1665 }
1666 }()
1667 if !s.BlockUntilParked(1e9 ) {
1668 panic("timed out waiting for scavenger to get ready")
1669 }
1670 }
1671
1672
1673
1674
1675
1676
1677
1678 func (s *Scavenger) BlockUntilParked(timeout int64) bool {
1679
1680
1681
1682
1683
1684 start := nanotime()
1685 for nanotime()-start < timeout {
1686 lock(&s.scavenger.lock)
1687 parked := s.scavenger.parked
1688 unlock(&s.scavenger.lock)
1689 if parked {
1690 return true
1691 }
1692 Gosched()
1693 }
1694 return false
1695 }
1696
1697
1698 func (s *Scavenger) Released() uintptr {
1699 return s.released.Load()
1700 }
1701
1702
1703 func (s *Scavenger) Wake() {
1704 s.scavenger.wake()
1705 }
1706
1707
1708
1709 func (s *Scavenger) Stop() {
1710 lock(&s.scavenger.lock)
1711 parked := s.scavenger.parked
1712 unlock(&s.scavenger.lock)
1713 if !parked {
1714 panic("tried to clean up scavenger that is not parked")
1715 }
1716 close(s.stop)
1717 s.Wake()
1718 <-s.done
1719 }
1720
1721 type ScavengeIndex struct {
1722 i scavengeIndex
1723 }
1724
1725 func NewScavengeIndex(min, max ChunkIdx) *ScavengeIndex {
1726 s := new(ScavengeIndex)
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738 s.i.chunks = make([]atomicScavChunkData, max)
1739 s.i.min.Store(uintptr(min))
1740 s.i.max.Store(uintptr(max))
1741 s.i.minHeapIdx.Store(uintptr(min))
1742 s.i.test = true
1743 return s
1744 }
1745
1746 func (s *ScavengeIndex) Find(force bool) (ChunkIdx, uint) {
1747 ci, off := s.i.find(force)
1748 return ChunkIdx(ci), off
1749 }
1750
1751 func (s *ScavengeIndex) AllocRange(base, limit uintptr) {
1752 sc, ec := chunkIndex(base), chunkIndex(limit-1)
1753 si, ei := chunkPageIndex(base), chunkPageIndex(limit-1)
1754
1755 if sc == ec {
1756
1757 s.i.alloc(sc, ei+1-si)
1758 } else {
1759
1760 s.i.alloc(sc, pallocChunkPages-si)
1761 for c := sc + 1; c < ec; c++ {
1762 s.i.alloc(c, pallocChunkPages)
1763 }
1764 s.i.alloc(ec, ei+1)
1765 }
1766 }
1767
1768 func (s *ScavengeIndex) FreeRange(base, limit uintptr) {
1769 sc, ec := chunkIndex(base), chunkIndex(limit-1)
1770 si, ei := chunkPageIndex(base), chunkPageIndex(limit-1)
1771
1772 if sc == ec {
1773
1774 s.i.free(sc, si, ei+1-si)
1775 } else {
1776
1777 s.i.free(sc, si, pallocChunkPages-si)
1778 for c := sc + 1; c < ec; c++ {
1779 s.i.free(c, 0, pallocChunkPages)
1780 }
1781 s.i.free(ec, 0, ei+1)
1782 }
1783 }
1784
1785 func (s *ScavengeIndex) ResetSearchAddrs() {
1786 for _, a := range []*atomicOffAddr{&s.i.searchAddrBg, &s.i.searchAddrForce} {
1787 addr, marked := a.Load()
1788 if marked {
1789 a.StoreUnmark(addr, addr)
1790 }
1791 a.Clear()
1792 }
1793 s.i.freeHWM = minOffAddr
1794 }
1795
1796 func (s *ScavengeIndex) NextGen() {
1797 s.i.nextGen()
1798 }
1799
1800 func (s *ScavengeIndex) SetEmpty(ci ChunkIdx) {
1801 s.i.setEmpty(chunkIdx(ci))
1802 }
1803
1804 func CheckPackScavChunkData(gen uint32, inUse, lastInUse uint16, flags uint8) bool {
1805 sc0 := scavChunkData{
1806 gen: gen,
1807 inUse: inUse,
1808 lastInUse: lastInUse,
1809 scavChunkFlags: scavChunkFlags(flags),
1810 }
1811 scp := sc0.pack()
1812 sc1 := unpackScavChunkData(scp)
1813 return sc0 == sc1
1814 }
1815
1816 const GTrackingPeriod = gTrackingPeriod
1817
1818 var ZeroBase = unsafe.Pointer(&zerobase)
1819
1820 const UserArenaChunkBytes = userArenaChunkBytes
1821
1822 type UserArena struct {
1823 arena *userArena
1824 }
1825
1826 func NewUserArena() *UserArena {
1827 return &UserArena{newUserArena()}
1828 }
1829
1830 func (a *UserArena) New(out *any) {
1831 i := efaceOf(out)
1832 typ := i._type
1833 if typ.Kind() != abi.Pointer {
1834 panic("new result of non-ptr type")
1835 }
1836 typ = (*ptrtype)(unsafe.Pointer(typ)).Elem
1837 i.data = a.arena.new(typ)
1838 }
1839
1840 func (a *UserArena) Slice(sl any, cap int) {
1841 a.arena.slice(sl, cap)
1842 }
1843
1844 func (a *UserArena) Free() {
1845 a.arena.free()
1846 }
1847
1848 func GlobalWaitingArenaChunks() int {
1849 n := 0
1850 systemstack(func() {
1851 lock(&mheap_.lock)
1852 for s := mheap_.userArena.quarantineList.first; s != nil; s = s.next {
1853 n++
1854 }
1855 unlock(&mheap_.lock)
1856 })
1857 return n
1858 }
1859
1860 func UserArenaClone[T any](s T) T {
1861 return arena_heapify(s).(T)
1862 }
1863
1864 var AlignUp = alignUp
1865
1866 func BlockUntilEmptyFinalizerQueue(timeout int64) bool {
1867 return blockUntilEmptyFinalizerQueue(timeout)
1868 }
1869
1870 func BlockUntilEmptyCleanupQueue(timeout int64) bool {
1871 return gcCleanups.blockUntilEmpty(timeout)
1872 }
1873
1874 func FrameStartLine(f *Frame) int {
1875 return f.startLine
1876 }
1877
1878
1879
1880 func PersistentAlloc(n, align uintptr) unsafe.Pointer {
1881 return persistentalloc(n, align, &memstats.other_sys)
1882 }
1883
1884 const TagAlign = tagAlign
1885
1886
1887
1888 func FPCallers(pcBuf []uintptr) int {
1889 return fpTracebackPCs(unsafe.Pointer(getfp()), pcBuf)
1890 }
1891
1892 const FramePointerEnabled = framepointer_enabled
1893
1894 var (
1895 IsPinned = isPinned
1896 GetPinCounter = pinnerGetPinCounter
1897 )
1898
1899 func SetPinnerLeakPanic(f func()) {
1900 pinnerLeakPanic = f
1901 }
1902 func GetPinnerLeakPanic() func() {
1903 return pinnerLeakPanic
1904 }
1905
1906 var testUintptr uintptr
1907
1908 func MyGenericFunc[T any]() {
1909 systemstack(func() {
1910 testUintptr = 4
1911 })
1912 }
1913
1914 func UnsafePoint(pc uintptr) bool {
1915 fi := findfunc(pc)
1916 v := pcdatavalue(fi, abi.PCDATA_UnsafePoint, pc)
1917 switch v {
1918 case abi.UnsafePointUnsafe:
1919 return true
1920 case abi.UnsafePointSafe:
1921 return false
1922 case abi.UnsafePointRestart1, abi.UnsafePointRestart2, abi.UnsafePointRestartAtEntry:
1923
1924
1925 return false
1926 default:
1927 var buf [20]byte
1928 panic("invalid unsafe point code " + string(itoa(buf[:], uint64(v))))
1929 }
1930 }
1931
1932 type TraceMap struct {
1933 traceMap
1934 }
1935
1936 func (m *TraceMap) PutString(s string) (uint64, bool) {
1937 return m.traceMap.put(unsafe.Pointer(unsafe.StringData(s)), uintptr(len(s)))
1938 }
1939
1940 func (m *TraceMap) Reset() {
1941 m.traceMap.reset()
1942 }
1943
1944 func SetSpinInGCMarkDone(spin bool) {
1945 gcDebugMarkDone.spinAfterRaggedBarrier.Store(spin)
1946 }
1947
1948 func GCMarkDoneRestarted() bool {
1949
1950 mp := acquirem()
1951 if gcphase != _GCoff {
1952 releasem(mp)
1953 return false
1954 }
1955 restarted := gcDebugMarkDone.restartedDueTo27993
1956 releasem(mp)
1957 return restarted
1958 }
1959
1960 func GCMarkDoneResetRestartFlag() {
1961 mp := acquirem()
1962 for gcphase != _GCoff {
1963 releasem(mp)
1964 Gosched()
1965 mp = acquirem()
1966 }
1967 gcDebugMarkDone.restartedDueTo27993 = false
1968 releasem(mp)
1969 }
1970
1971 type BitCursor struct {
1972 b bitCursor
1973 }
1974
1975 func NewBitCursor(buf *byte) BitCursor {
1976 return BitCursor{b: bitCursor{ptr: buf, n: 0}}
1977 }
1978
1979 func (b BitCursor) Write(data *byte, cnt uintptr) {
1980 b.b.write(data, cnt)
1981 }
1982 func (b BitCursor) Offset(cnt uintptr) BitCursor {
1983 return BitCursor{b: b.b.offset(cnt)}
1984 }
1985
1986 const (
1987 BubbleAssocUnbubbled = bubbleAssocUnbubbled
1988 BubbleAssocCurrentBubble = bubbleAssocCurrentBubble
1989 BubbleAssocOtherBubble = bubbleAssocOtherBubble
1990 )
1991
1992 type TraceStackTable traceStackTable
1993
1994 func (t *TraceStackTable) Reset() {
1995 t.tab.reset()
1996 }
1997
1998 func TraceStack(gp *G, tab *TraceStackTable) {
1999 traceStack(0, gp, (*traceStackTable)(tab))
2000 }
2001
2002 var X86HasAVX = &x86HasAVX
2003
2004 var DebugDecorateMappings = &debug.decoratemappings
2005
2006 func SetVMANameSupported() bool { return setVMANameSupported() }
2007
2008 type ListHead struct {
2009 l listHead
2010 }
2011
2012 func (head *ListHead) Init(off uintptr) {
2013 head.l.init(off)
2014 }
2015
2016 type ListNode struct {
2017 l listNode
2018 }
2019
2020 func (head *ListHead) Push(p unsafe.Pointer) {
2021 head.l.push(p)
2022 }
2023
2024 func (head *ListHead) Pop() unsafe.Pointer {
2025 return head.l.pop()
2026 }
2027
2028 func (head *ListHead) Remove(p unsafe.Pointer) {
2029 head.l.remove(p)
2030 }
2031
2032 type ListHeadManual struct {
2033 l listHeadManual
2034 }
2035
2036 func (head *ListHeadManual) Init(off uintptr) {
2037 head.l.init(off)
2038 }
2039
2040 type ListNodeManual struct {
2041 l listNodeManual
2042 }
2043
2044 func (head *ListHeadManual) Push(p unsafe.Pointer) {
2045 head.l.push(p)
2046 }
2047
2048 func (head *ListHeadManual) Pop() unsafe.Pointer {
2049 return head.l.pop()
2050 }
2051
2052 func (head *ListHeadManual) Remove(p unsafe.Pointer) {
2053 head.l.remove(p)
2054 }
2055
2056 func Hexdumper(base uintptr, wordBytes int, mark func(addr uintptr, start func()), data ...[]byte) string {
2057 buf := make([]byte, 0, 2048)
2058 getg().writebuf = buf
2059 h := hexdumper{addr: base, addrBytes: 4, wordBytes: uint8(wordBytes)}
2060 if mark != nil {
2061 h.mark = func(addr uintptr, m hexdumpMarker) {
2062 mark(addr, m.start)
2063 }
2064 }
2065 for _, d := range data {
2066 h.write(d)
2067 }
2068 h.close()
2069 n := len(getg().writebuf)
2070 getg().writebuf = nil
2071 if n == cap(buf) {
2072 panic("Hexdumper buf too small")
2073 }
2074 return string(buf[:n])
2075 }
2076
2077 func HexdumpWords(p, bytes uintptr) string {
2078 buf := make([]byte, 0, 2048)
2079 getg().writebuf = buf
2080 hexdumpWords(p, bytes, nil)
2081 n := len(getg().writebuf)
2082 getg().writebuf = nil
2083 if n == cap(buf) {
2084 panic("HexdumpWords buf too small")
2085 }
2086 return string(buf[:n])
2087 }
2088
2089
2090
2091 func DumpPrintQuoted(s string) string {
2092 gp := getg()
2093 gp.writebuf = make([]byte, 0, 1<<20)
2094 print(quoted(s))
2095 buf := gp.writebuf
2096 gp.writebuf = nil
2097
2098 return string(buf)
2099 }
2100
2101
2102 func DumpPrint[T any](v T) string {
2103 gp := getg()
2104 gp.writebuf = make([]byte, 0, 2048)
2105 print(v)
2106 buf := gp.writebuf
2107 gp.writebuf = nil
2108
2109 return string(buf)
2110 }
2111
2112 var (
2113 Float64Bytes = float64Bytes
2114 Float32Bytes = float32Bytes
2115 Complex128Bytes = complex128Bytes
2116 Complex64Bytes = complex64Bytes
2117 )
2118
View as plain text