libgo: export NetBSD-specific types in mksysinfo.sh
[gcc.git] / libgo / go / 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 "runtime/internal/atomic"
11 "runtime/internal/sys"
12 "unsafe"
13 )
14
15 //var Fadd64 = fadd64
16 //var Fsub64 = fsub64
17 //var Fmul64 = fmul64
18 //var Fdiv64 = fdiv64
19 //var F64to32 = f64to32
20 //var F32to64 = f32to64
21 //var Fcmp64 = fcmp64
22 //var Fintto64 = fintto64
23 //var F64toint = f64toint
24
25 var Entersyscall = entersyscall
26 var Exitsyscall = exitsyscall
27 var LockedOSThread = lockedOSThread
28 var Xadduintptr = atomic.Xadduintptr
29
30 var FuncPC = funcPC
31
32 var Fastlog2 = fastlog2
33
34 var Atoi = atoi
35 var Atoi32 = atoi32
36
37 var Nanotime = nanotime
38 var NetpollBreak = netpollBreak
39 var Usleep = usleep
40
41 var PhysPageSize = physPageSize
42 var PhysHugePageSize = physHugePageSize
43
44 var NetpollGenericInit = netpollGenericInit
45
46 var ParseRelease = parseRelease
47
48 var Memmove = memmove
49 var MemclrNoHeapPointers = memclrNoHeapPointers
50
51 const PreemptMSupported = preemptMSupported
52
53 type LFNode struct {
54 Next uint64
55 Pushcnt uintptr
56 }
57
58 func LFStackPush(head *uint64, node *LFNode) {
59 (*lfstack)(head).push((*lfnode)(unsafe.Pointer(node)))
60 }
61
62 func LFStackPop(head *uint64) *LFNode {
63 return (*LFNode)(unsafe.Pointer((*lfstack)(head).pop()))
64 }
65
66 func Netpoll(delta int64) {
67 systemstack(func() {
68 netpoll(delta)
69 })
70 }
71
72 func GCMask(x interface{}) (ret []byte) {
73 return nil
74 }
75
76 func RunSchedLocalQueueTest() {
77 _p_ := new(p)
78 gs := make([]g, len(_p_.runq))
79 for i := 0; i < len(_p_.runq); i++ {
80 if g, _ := runqget(_p_); g != nil {
81 throw("runq is not empty initially")
82 }
83 for j := 0; j < i; j++ {
84 runqput(_p_, &gs[i], false)
85 }
86 for j := 0; j < i; j++ {
87 if g, _ := runqget(_p_); g != &gs[i] {
88 print("bad element at iter ", i, "/", j, "\n")
89 throw("bad element")
90 }
91 }
92 if g, _ := runqget(_p_); g != nil {
93 throw("runq is not empty afterwards")
94 }
95 }
96 }
97
98 func RunSchedLocalQueueStealTest() {
99 p1 := new(p)
100 p2 := new(p)
101 gs := make([]g, len(p1.runq))
102 for i := 0; i < len(p1.runq); i++ {
103 for j := 0; j < i; j++ {
104 gs[j].sig = 0
105 runqput(p1, &gs[j], false)
106 }
107 gp := runqsteal(p2, p1, true)
108 s := 0
109 if gp != nil {
110 s++
111 gp.sig++
112 }
113 for {
114 gp, _ = runqget(p2)
115 if gp == nil {
116 break
117 }
118 s++
119 gp.sig++
120 }
121 for {
122 gp, _ = runqget(p1)
123 if gp == nil {
124 break
125 }
126 gp.sig++
127 }
128 for j := 0; j < i; j++ {
129 if gs[j].sig != 1 {
130 print("bad element ", j, "(", gs[j].sig, ") at iter ", i, "\n")
131 throw("bad element")
132 }
133 }
134 if s != i/2 && s != i/2+1 {
135 print("bad steal ", s, ", want ", i/2, " or ", i/2+1, ", iter ", i, "\n")
136 throw("bad steal")
137 }
138 }
139 }
140
141 func RunSchedLocalQueueEmptyTest(iters int) {
142 // Test that runq is not spuriously reported as empty.
143 // Runq emptiness affects scheduling decisions and spurious emptiness
144 // can lead to underutilization (both runnable Gs and idle Ps coexist
145 // for arbitrary long time).
146 done := make(chan bool, 1)
147 _p_ := new(p)
148 gs := make([]g, 2)
149 ready := new(uint32)
150 for i := 0; i < iters; i++ {
151 *ready = 0
152 next0 := (i & 1) == 0
153 next1 := (i & 2) == 0
154 runqput(_p_, &gs[0], next0)
155 go func(done chan bool, p *p, ready *uint32, next0, next1 bool) {
156 for atomic.Xadd(ready, 1); atomic.Load(ready) != 2; {
157 }
158 if runqempty(p) {
159 println("next:", next0, next1)
160 throw("queue is empty")
161 }
162 done <- true
163 }(done, _p_, ready, next0, next1)
164 for atomic.Xadd(ready, 1); atomic.Load(ready) != 2; {
165 }
166 runqput(_p_, &gs[1], next1)
167 runqget(_p_)
168 <-done
169 runqget(_p_)
170 }
171 }
172
173 var (
174 StringHash = stringHash
175 BytesHash = bytesHash
176 Int32Hash = int32Hash
177 Int64Hash = int64Hash
178 MemHash = memhash
179 MemHash32 = memhash32
180 MemHash64 = memhash64
181 EfaceHash = efaceHash
182 IfaceHash = ifaceHash
183 )
184
185 var UseAeshash = &useAeshash
186
187 func MemclrBytes(b []byte) {
188 s := (*slice)(unsafe.Pointer(&b))
189 memclrNoHeapPointers(s.array, uintptr(s.len))
190 }
191
192 var HashLoad = &hashLoad
193
194 // entry point for testing
195 //func GostringW(w []uint16) (s string) {
196 // s = gostringw(&w[0])
197 // return
198 //}
199
200 type Uintreg sys.Uintreg
201
202 var Open = open
203 var Close = closefd
204 var Read = read
205 var Write = write
206
207 func Envs() []string { return envs }
208 func SetEnvs(e []string) { envs = e }
209
210 //var BigEndian = sys.BigEndian
211
212 // For benchmarking.
213
214 func BenchSetType(n int, x interface{}) {
215 e := *efaceOf(&x)
216 t := e._type
217 var size uintptr
218 var p unsafe.Pointer
219 switch t.kind & kindMask {
220 case kindPtr:
221 t = (*ptrtype)(unsafe.Pointer(t)).elem
222 size = t.size
223 p = e.data
224 case kindSlice:
225 slice := *(*struct {
226 ptr unsafe.Pointer
227 len, cap uintptr
228 })(e.data)
229 t = (*slicetype)(unsafe.Pointer(t)).elem
230 size = t.size * slice.len
231 p = slice.ptr
232 }
233 allocSize := roundupsize(size)
234 systemstack(func() {
235 for i := 0; i < n; i++ {
236 heapBitsSetType(uintptr(p), allocSize, size, t)
237 }
238 })
239 }
240
241 const PtrSize = sys.PtrSize
242
243 var ForceGCPeriod = &forcegcperiod
244
245 // SetTracebackEnv is like runtime/debug.SetTraceback, but it raises
246 // the "environment" traceback level, so later calls to
247 // debug.SetTraceback (e.g., from testing timeouts) can't lower it.
248 func SetTracebackEnv(level string) {
249 setTraceback(level)
250 traceback_env = traceback_cache
251 }
252
253 var ReadUnaligned32 = readUnaligned32
254 var ReadUnaligned64 = readUnaligned64
255
256 func CountPagesInUse() (pagesInUse, counted uintptr) {
257 stopTheWorld("CountPagesInUse")
258
259 pagesInUse = uintptr(mheap_.pagesInUse)
260
261 for _, s := range mheap_.allspans {
262 if s.state.get() == mSpanInUse {
263 counted += s.npages
264 }
265 }
266
267 startTheWorld()
268
269 return
270 }
271
272 func Fastrand() uint32 { return fastrand() }
273 func Fastrandn(n uint32) uint32 { return fastrandn(n) }
274
275 type ProfBuf profBuf
276
277 func NewProfBuf(hdrsize, bufwords, tags int) *ProfBuf {
278 return (*ProfBuf)(newProfBuf(hdrsize, bufwords, tags))
279 }
280
281 func (p *ProfBuf) Write(tag *unsafe.Pointer, now int64, hdr []uint64, stk []uintptr) {
282 (*profBuf)(p).write(tag, now, hdr, stk)
283 }
284
285 const (
286 ProfBufBlocking = profBufBlocking
287 ProfBufNonBlocking = profBufNonBlocking
288 )
289
290 func (p *ProfBuf) Read(mode profBufReadMode) ([]uint64, []unsafe.Pointer, bool) {
291 return (*profBuf)(p).read(profBufReadMode(mode))
292 }
293
294 func (p *ProfBuf) Close() {
295 (*profBuf)(p).close()
296 }
297
298 // ReadMemStatsSlow returns both the runtime-computed MemStats and
299 // MemStats accumulated by scanning the heap.
300 func ReadMemStatsSlow() (base, slow MemStats) {
301 stopTheWorld("ReadMemStatsSlow")
302
303 // Run on the system stack to avoid stack growth allocation.
304 systemstack(func() {
305 // Make sure stats don't change.
306 getg().m.mallocing++
307
308 readmemstats_m(&base)
309
310 // Initialize slow from base and zero the fields we're
311 // recomputing.
312 slow = base
313 slow.Alloc = 0
314 slow.TotalAlloc = 0
315 slow.Mallocs = 0
316 slow.Frees = 0
317 slow.HeapReleased = 0
318 var bySize [_NumSizeClasses]struct {
319 Mallocs, Frees uint64
320 }
321
322 // Add up current allocations in spans.
323 for _, s := range mheap_.allspans {
324 if s.state.get() != mSpanInUse {
325 continue
326 }
327 if sizeclass := s.spanclass.sizeclass(); sizeclass == 0 {
328 slow.Mallocs++
329 slow.Alloc += uint64(s.elemsize)
330 } else {
331 slow.Mallocs += uint64(s.allocCount)
332 slow.Alloc += uint64(s.allocCount) * uint64(s.elemsize)
333 bySize[sizeclass].Mallocs += uint64(s.allocCount)
334 }
335 }
336
337 // Add in frees. readmemstats_m flushed the cached stats, so
338 // these are up-to-date.
339 var smallFree uint64
340 slow.Frees = mheap_.nlargefree
341 for i := range mheap_.nsmallfree {
342 slow.Frees += mheap_.nsmallfree[i]
343 bySize[i].Frees = mheap_.nsmallfree[i]
344 bySize[i].Mallocs += mheap_.nsmallfree[i]
345 smallFree += mheap_.nsmallfree[i] * uint64(class_to_size[i])
346 }
347 slow.Frees += memstats.tinyallocs
348 slow.Mallocs += slow.Frees
349
350 slow.TotalAlloc = slow.Alloc + mheap_.largefree + smallFree
351
352 for i := range slow.BySize {
353 slow.BySize[i].Mallocs = bySize[i].Mallocs
354 slow.BySize[i].Frees = bySize[i].Frees
355 }
356
357 for i := mheap_.pages.start; i < mheap_.pages.end; i++ {
358 pg := mheap_.pages.chunkOf(i).scavenged.popcntRange(0, pallocChunkPages)
359 slow.HeapReleased += uint64(pg) * pageSize
360 }
361 for _, p := range allp {
362 pg := sys.OnesCount64(p.pcache.scav)
363 slow.HeapReleased += uint64(pg) * pageSize
364 }
365
366 // Unused space in the current arena also counts as released space.
367 slow.HeapReleased += uint64(mheap_.curArena.end - mheap_.curArena.base)
368
369 getg().m.mallocing--
370 })
371
372 startTheWorld()
373 return
374 }
375
376 // BlockOnSystemStack switches to the system stack, prints "x\n" to
377 // stderr, and blocks in a stack containing
378 // "runtime.blockOnSystemStackInternal".
379 func BlockOnSystemStack() {
380 systemstack(blockOnSystemStackInternal)
381 }
382
383 func blockOnSystemStackInternal() {
384 print("x\n")
385 lock(&deadlock)
386 lock(&deadlock)
387 }
388
389 type RWMutex struct {
390 rw rwmutex
391 }
392
393 func (rw *RWMutex) RLock() {
394 rw.rw.rlock()
395 }
396
397 func (rw *RWMutex) RUnlock() {
398 rw.rw.runlock()
399 }
400
401 func (rw *RWMutex) Lock() {
402 rw.rw.lock()
403 }
404
405 func (rw *RWMutex) Unlock() {
406 rw.rw.unlock()
407 }
408
409 const RuntimeHmapSize = unsafe.Sizeof(hmap{})
410
411 func MapBucketsCount(m map[int]int) int {
412 h := *(**hmap)(unsafe.Pointer(&m))
413 return 1 << h.B
414 }
415
416 func MapBucketsPointerIsNil(m map[int]int) bool {
417 h := *(**hmap)(unsafe.Pointer(&m))
418 return h.buckets == nil
419 }
420
421 func LockOSCounts() (external, internal uint32) {
422 g := getg()
423 if g.m.lockedExt+g.m.lockedInt == 0 {
424 if g.lockedm != 0 {
425 panic("lockedm on non-locked goroutine")
426 }
427 } else {
428 if g.lockedm == 0 {
429 panic("nil lockedm on locked goroutine")
430 }
431 }
432 return g.m.lockedExt, g.m.lockedInt
433 }
434
435 //go:noinline
436 func TracebackSystemstack(stk []uintptr, i int) int {
437 if i == 0 {
438 return callersRaw(stk)
439 }
440 n := 0
441 systemstack(func() {
442 n = TracebackSystemstack(stk, i-1)
443 })
444 return n
445 }
446
447 func KeepNArenaHints(n int) {
448 hint := mheap_.arenaHints
449 for i := 1; i < n; i++ {
450 hint = hint.next
451 if hint == nil {
452 return
453 }
454 }
455 hint.next = nil
456 }
457
458 // MapNextArenaHint reserves a page at the next arena growth hint,
459 // preventing the arena from growing there, and returns the range of
460 // addresses that are no longer viable.
461 func MapNextArenaHint() (start, end uintptr) {
462 hint := mheap_.arenaHints
463 addr := hint.addr
464 if hint.down {
465 start, end = addr-heapArenaBytes, addr
466 addr -= physPageSize
467 } else {
468 start, end = addr, addr+heapArenaBytes
469 }
470 sysReserve(unsafe.Pointer(addr), physPageSize)
471 return
472 }
473
474 func GetNextArenaHint() uintptr {
475 return mheap_.arenaHints.addr
476 }
477
478 type G = g
479
480 type Sudog = sudog
481
482 func Getg() *G {
483 return getg()
484 }
485
486 //go:noinline
487 func PanicForTesting(b []byte, i int) byte {
488 return unexportedPanicForTesting(b, i)
489 }
490
491 //go:noinline
492 func unexportedPanicForTesting(b []byte, i int) byte {
493 return b[i]
494 }
495
496 func G0StackOverflow() {
497 systemstack(func() {
498 stackOverflow(nil)
499 })
500 }
501
502 func stackOverflow(x *byte) {
503 var buf [256]byte
504 stackOverflow(&buf[0])
505 }
506
507 func MapTombstoneCheck(m map[int]int) {
508 // Make sure emptyOne and emptyRest are distributed correctly.
509 // We should have a series of filled and emptyOne cells, followed by
510 // a series of emptyRest cells.
511 h := *(**hmap)(unsafe.Pointer(&m))
512 i := interface{}(m)
513 t := *(**maptype)(unsafe.Pointer(&i))
514
515 for x := 0; x < 1<<h.B; x++ {
516 b0 := (*bmap)(add(h.buckets, uintptr(x)*uintptr(t.bucketsize)))
517 n := 0
518 for b := b0; b != nil; b = b.overflow(t) {
519 for i := 0; i < bucketCnt; i++ {
520 if b.tophash[i] != emptyRest {
521 n++
522 }
523 }
524 }
525 k := 0
526 for b := b0; b != nil; b = b.overflow(t) {
527 for i := 0; i < bucketCnt; i++ {
528 if k < n && b.tophash[i] == emptyRest {
529 panic("early emptyRest")
530 }
531 if k >= n && b.tophash[i] != emptyRest {
532 panic("late non-emptyRest")
533 }
534 if k == n-1 && b.tophash[i] == emptyOne {
535 panic("last non-emptyRest entry is emptyOne")
536 }
537 k++
538 }
539 }
540 }
541 }
542
543 func RunGetgThreadSwitchTest() {
544 // Test that getg works correctly with thread switch.
545 // With gccgo, if we generate getg inlined, the backend
546 // may cache the address of the TLS variable, which
547 // will become invalid after a thread switch. This test
548 // checks that the bad caching doesn't happen.
549
550 ch := make(chan int)
551 go func(ch chan int) {
552 ch <- 5
553 LockOSThread()
554 }(ch)
555
556 g1 := getg()
557
558 // Block on a receive. This is likely to get us a thread
559 // switch. If we yield to the sender goroutine, it will
560 // lock the thread, forcing us to resume on a different
561 // thread.
562 <-ch
563
564 g2 := getg()
565 if g1 != g2 {
566 panic("g1 != g2")
567 }
568
569 // Also test getg after some control flow, as the
570 // backend is sensitive to control flow.
571 g3 := getg()
572 if g1 != g3 {
573 panic("g1 != g3")
574 }
575 }
576
577 const (
578 PageSize = pageSize
579 PallocChunkPages = pallocChunkPages
580 PageAlloc64Bit = pageAlloc64Bit
581 PallocSumBytes = pallocSumBytes
582 )
583
584 // Expose pallocSum for testing.
585 type PallocSum pallocSum
586
587 func PackPallocSum(start, max, end uint) PallocSum { return PallocSum(packPallocSum(start, max, end)) }
588 func (m PallocSum) Start() uint { return pallocSum(m).start() }
589 func (m PallocSum) Max() uint { return pallocSum(m).max() }
590 func (m PallocSum) End() uint { return pallocSum(m).end() }
591
592 // Expose pallocBits for testing.
593 type PallocBits pallocBits
594
595 func (b *PallocBits) Find(npages uintptr, searchIdx uint) (uint, uint) {
596 return (*pallocBits)(b).find(npages, searchIdx)
597 }
598 func (b *PallocBits) AllocRange(i, n uint) { (*pallocBits)(b).allocRange(i, n) }
599 func (b *PallocBits) Free(i, n uint) { (*pallocBits)(b).free(i, n) }
600 func (b *PallocBits) Summarize() PallocSum { return PallocSum((*pallocBits)(b).summarize()) }
601 func (b *PallocBits) PopcntRange(i, n uint) uint { return (*pageBits)(b).popcntRange(i, n) }
602
603 // SummarizeSlow is a slow but more obviously correct implementation
604 // of (*pallocBits).summarize. Used for testing.
605 func SummarizeSlow(b *PallocBits) PallocSum {
606 var start, max, end uint
607
608 const N = uint(len(b)) * 64
609 for start < N && (*pageBits)(b).get(start) == 0 {
610 start++
611 }
612 for end < N && (*pageBits)(b).get(N-end-1) == 0 {
613 end++
614 }
615 run := uint(0)
616 for i := uint(0); i < N; i++ {
617 if (*pageBits)(b).get(i) == 0 {
618 run++
619 } else {
620 run = 0
621 }
622 if run > max {
623 max = run
624 }
625 }
626 return PackPallocSum(start, max, end)
627 }
628
629 // Expose non-trivial helpers for testing.
630 func FindBitRange64(c uint64, n uint) uint { return findBitRange64(c, n) }
631
632 // Given two PallocBits, returns a set of bit ranges where
633 // they differ.
634 func DiffPallocBits(a, b *PallocBits) []BitRange {
635 ba := (*pageBits)(a)
636 bb := (*pageBits)(b)
637
638 var d []BitRange
639 base, size := uint(0), uint(0)
640 for i := uint(0); i < uint(len(ba))*64; i++ {
641 if ba.get(i) != bb.get(i) {
642 if size == 0 {
643 base = i
644 }
645 size++
646 } else {
647 if size != 0 {
648 d = append(d, BitRange{base, size})
649 }
650 size = 0
651 }
652 }
653 if size != 0 {
654 d = append(d, BitRange{base, size})
655 }
656 return d
657 }
658
659 // StringifyPallocBits gets the bits in the bit range r from b,
660 // and returns a string containing the bits as ASCII 0 and 1
661 // characters.
662 func StringifyPallocBits(b *PallocBits, r BitRange) string {
663 str := ""
664 for j := r.I; j < r.I+r.N; j++ {
665 if (*pageBits)(b).get(j) != 0 {
666 str += "1"
667 } else {
668 str += "0"
669 }
670 }
671 return str
672 }
673
674 // Expose pallocData for testing.
675 type PallocData pallocData
676
677 func (d *PallocData) FindScavengeCandidate(searchIdx uint, min, max uintptr) (uint, uint) {
678 return (*pallocData)(d).findScavengeCandidate(searchIdx, min, max)
679 }
680 func (d *PallocData) AllocRange(i, n uint) { (*pallocData)(d).allocRange(i, n) }
681 func (d *PallocData) ScavengedSetRange(i, n uint) {
682 (*pallocData)(d).scavenged.setRange(i, n)
683 }
684 func (d *PallocData) PallocBits() *PallocBits {
685 return (*PallocBits)(&(*pallocData)(d).pallocBits)
686 }
687 func (d *PallocData) Scavenged() *PallocBits {
688 return (*PallocBits)(&(*pallocData)(d).scavenged)
689 }
690
691 // Expose fillAligned for testing.
692 func FillAligned(x uint64, m uint) uint64 { return fillAligned(x, m) }
693
694 // Expose pageCache for testing.
695 type PageCache pageCache
696
697 const PageCachePages = pageCachePages
698
699 func NewPageCache(base uintptr, cache, scav uint64) PageCache {
700 return PageCache(pageCache{base: base, cache: cache, scav: scav})
701 }
702 func (c *PageCache) Empty() bool { return (*pageCache)(c).empty() }
703 func (c *PageCache) Base() uintptr { return (*pageCache)(c).base }
704 func (c *PageCache) Cache() uint64 { return (*pageCache)(c).cache }
705 func (c *PageCache) Scav() uint64 { return (*pageCache)(c).scav }
706 func (c *PageCache) Alloc(npages uintptr) (uintptr, uintptr) {
707 return (*pageCache)(c).alloc(npages)
708 }
709 func (c *PageCache) Flush(s *PageAlloc) {
710 (*pageCache)(c).flush((*pageAlloc)(s))
711 }
712
713 // Expose chunk index type.
714 type ChunkIdx chunkIdx
715
716 // Expose pageAlloc for testing. Note that because pageAlloc is
717 // not in the heap, so is PageAlloc.
718 type PageAlloc pageAlloc
719
720 func (p *PageAlloc) Alloc(npages uintptr) (uintptr, uintptr) {
721 return (*pageAlloc)(p).alloc(npages)
722 }
723 func (p *PageAlloc) AllocToCache() PageCache {
724 return PageCache((*pageAlloc)(p).allocToCache())
725 }
726 func (p *PageAlloc) Free(base, npages uintptr) {
727 (*pageAlloc)(p).free(base, npages)
728 }
729 func (p *PageAlloc) Bounds() (ChunkIdx, ChunkIdx) {
730 return ChunkIdx((*pageAlloc)(p).start), ChunkIdx((*pageAlloc)(p).end)
731 }
732 func (p *PageAlloc) Scavenge(nbytes uintptr, mayUnlock bool) (r uintptr) {
733 pp := (*pageAlloc)(p)
734 systemstack(func() {
735 lock(pp.mheapLock)
736 r = pp.scavenge(nbytes, mayUnlock)
737 unlock(pp.mheapLock)
738 })
739 return
740 }
741 func (p *PageAlloc) InUse() []AddrRange {
742 ranges := make([]AddrRange, 0, len(p.inUse.ranges))
743 for _, r := range p.inUse.ranges {
744 ranges = append(ranges, AddrRange{
745 Base: r.base.addr(),
746 Limit: r.limit.addr(),
747 })
748 }
749 return ranges
750 }
751
752 // Returns nil if the PallocData's L2 is missing.
753 func (p *PageAlloc) PallocData(i ChunkIdx) *PallocData {
754 ci := chunkIdx(i)
755 l2 := (*pageAlloc)(p).chunks[ci.l1()]
756 if l2 == nil {
757 return nil
758 }
759 return (*PallocData)(&l2[ci.l2()])
760 }
761
762 // AddrRange represents a range over addresses.
763 // Specifically, it represents the range [Base, Limit).
764 type AddrRange struct {
765 Base, Limit uintptr
766 }
767
768 // BitRange represents a range over a bitmap.
769 type BitRange struct {
770 I, N uint // bit index and length in bits
771 }
772
773 // NewPageAlloc creates a new page allocator for testing and
774 // initializes it with the scav and chunks maps. Each key in these maps
775 // represents a chunk index and each value is a series of bit ranges to
776 // set within each bitmap's chunk.
777 //
778 // The initialization of the pageAlloc preserves the invariant that if a
779 // scavenged bit is set the alloc bit is necessarily unset, so some
780 // of the bits described by scav may be cleared in the final bitmap if
781 // ranges in chunks overlap with them.
782 //
783 // scav is optional, and if nil, the scavenged bitmap will be cleared
784 // (as opposed to all 1s, which it usually is). Furthermore, every
785 // chunk index in scav must appear in chunks; ones that do not are
786 // ignored.
787 func NewPageAlloc(chunks, scav map[ChunkIdx][]BitRange) *PageAlloc {
788 p := new(pageAlloc)
789
790 // We've got an entry, so initialize the pageAlloc.
791 p.init(new(mutex), nil)
792 lockInit(p.mheapLock, lockRankMheap)
793 p.test = true
794
795 for i, init := range chunks {
796 addr := chunkBase(chunkIdx(i))
797
798 // Mark the chunk's existence in the pageAlloc.
799 p.grow(addr, pallocChunkBytes)
800
801 // Initialize the bitmap and update pageAlloc metadata.
802 chunk := p.chunkOf(chunkIndex(addr))
803
804 // Clear all the scavenged bits which grow set.
805 chunk.scavenged.clearRange(0, pallocChunkPages)
806
807 // Apply scavenge state if applicable.
808 if scav != nil {
809 if scvg, ok := scav[i]; ok {
810 for _, s := range scvg {
811 // Ignore the case of s.N == 0. setRange doesn't handle
812 // it and it's a no-op anyway.
813 if s.N != 0 {
814 chunk.scavenged.setRange(s.I, s.N)
815 }
816 }
817 }
818 }
819
820 // Apply alloc state.
821 for _, s := range init {
822 // Ignore the case of s.N == 0. allocRange doesn't handle
823 // it and it's a no-op anyway.
824 if s.N != 0 {
825 chunk.allocRange(s.I, s.N)
826 }
827 }
828
829 // Update heap metadata for the allocRange calls above.
830 p.update(addr, pallocChunkPages, false, false)
831 }
832 systemstack(func() {
833 lock(p.mheapLock)
834 p.scavengeStartGen()
835 unlock(p.mheapLock)
836 })
837 return (*PageAlloc)(p)
838 }
839
840 // FreePageAlloc releases hard OS resources owned by the pageAlloc. Once this
841 // is called the pageAlloc may no longer be used. The object itself will be
842 // collected by the garbage collector once it is no longer live.
843 func FreePageAlloc(pp *PageAlloc) {
844 p := (*pageAlloc)(pp)
845
846 // Free all the mapped space for the summary levels.
847 if pageAlloc64Bit != 0 {
848 for l := 0; l < summaryLevels; l++ {
849 sysFree(unsafe.Pointer(&p.summary[l][0]), uintptr(cap(p.summary[l]))*pallocSumBytes, nil)
850 }
851 } else {
852 resSize := uintptr(0)
853 for _, s := range p.summary {
854 resSize += uintptr(cap(s)) * pallocSumBytes
855 }
856 sysFree(unsafe.Pointer(&p.summary[0][0]), alignUp(resSize, physPageSize), nil)
857 }
858
859 // Free the mapped space for chunks.
860 for i := range p.chunks {
861 if x := p.chunks[i]; x != nil {
862 p.chunks[i] = nil
863 // This memory comes from sysAlloc and will always be page-aligned.
864 sysFree(unsafe.Pointer(x), unsafe.Sizeof(*p.chunks[0]), nil)
865 }
866 }
867 }
868
869 // BaseChunkIdx is a convenient chunkIdx value which works on both
870 // 64 bit and 32 bit platforms, allowing the tests to share code
871 // between the two.
872 //
873 // This should not be higher than 0x100*pallocChunkBytes to support
874 // mips and mipsle, which only have 31-bit address spaces.
875 var BaseChunkIdx = ChunkIdx(chunkIndex(((0xc000*pageAlloc64Bit + 0x100*pageAlloc32Bit) * pallocChunkBytes) + arenaBaseOffset*sys.GoosAix*sys.GoarchPpc64))
876
877 // PageBase returns an address given a chunk index and a page index
878 // relative to that chunk.
879 func PageBase(c ChunkIdx, pageIdx uint) uintptr {
880 return chunkBase(chunkIdx(c)) + uintptr(pageIdx)*pageSize
881 }
882
883 type BitsMismatch struct {
884 Base uintptr
885 Got, Want uint64
886 }
887
888 func CheckScavengedBitsCleared(mismatches []BitsMismatch) (n int, ok bool) {
889 ok = true
890
891 // Run on the system stack to avoid stack growth allocation.
892 systemstack(func() {
893 getg().m.mallocing++
894
895 // Lock so that we can safely access the bitmap.
896 lock(&mheap_.lock)
897 chunkLoop:
898 for i := mheap_.pages.start; i < mheap_.pages.end; i++ {
899 chunk := mheap_.pages.chunkOf(i)
900 for j := 0; j < pallocChunkPages/64; j++ {
901 // Run over each 64-bit bitmap section and ensure
902 // scavenged is being cleared properly on allocation.
903 // If a used bit and scavenged bit are both set, that's
904 // an error, and could indicate a larger problem, or
905 // an accounting problem.
906 want := chunk.scavenged[j] &^ chunk.pallocBits[j]
907 got := chunk.scavenged[j]
908 if want != got {
909 ok = false
910 if n >= len(mismatches) {
911 break chunkLoop
912 }
913 mismatches[n] = BitsMismatch{
914 Base: chunkBase(i) + uintptr(j)*64*pageSize,
915 Got: got,
916 Want: want,
917 }
918 n++
919 }
920 }
921 }
922 unlock(&mheap_.lock)
923
924 getg().m.mallocing--
925 })
926 return
927 }
928
929 func PageCachePagesLeaked() (leaked uintptr) {
930 stopTheWorld("PageCachePagesLeaked")
931
932 // Walk over destroyed Ps and look for unflushed caches.
933 deadp := allp[len(allp):cap(allp)]
934 for _, p := range deadp {
935 // Since we're going past len(allp) we may see nil Ps.
936 // Just ignore them.
937 if p != nil {
938 leaked += uintptr(sys.OnesCount64(p.pcache.cache))
939 }
940 }
941
942 startTheWorld()
943 return
944 }
945
946 var Semacquire = semacquire
947 var Semrelease1 = semrelease1
948
949 func SemNwait(addr *uint32) uint32 {
950 root := semroot(addr)
951 return atomic.Load(&root.nwait)
952 }
953
954 // MapHashCheck computes the hash of the key k for the map m, twice.
955 // Method 1 uses the built-in hasher for the map.
956 // Method 2 uses the typehash function (the one used by reflect).
957 // Returns the two hash values, which should always be equal.
958 func MapHashCheck(m interface{}, k interface{}) (uintptr, uintptr) {
959 // Unpack m.
960 mt := (*maptype)(unsafe.Pointer(efaceOf(&m)._type))
961 mh := (*hmap)(efaceOf(&m).data)
962
963 // Unpack k.
964 kt := efaceOf(&k)._type
965 var p unsafe.Pointer
966 if isDirectIface(kt) {
967 q := efaceOf(&k).data
968 p = unsafe.Pointer(&q)
969 } else {
970 p = efaceOf(&k).data
971 }
972
973 // Compute the hash functions.
974 x := mt.hasher(noescape(p), uintptr(mh.hash0))
975 y := typehash(kt, noescape(p), uintptr(mh.hash0))
976 return x, y
977 }
978
979 func MSpanCountAlloc(bits []byte) int {
980 s := mspan{
981 nelems: uintptr(len(bits) * 8),
982 gcmarkBits: (*gcBits)(unsafe.Pointer(&bits[0])),
983 }
984 return s.countAlloc()
985 }
986
987 var Pusestackmaps = &usestackmaps