Source file
src/runtime/mbitmap.go
Documentation: runtime
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76 package runtime
77
78 import (
79 "runtime/internal/atomic"
80 "runtime/internal/sys"
81 "unsafe"
82 )
83
84 const (
85 bitPointer = 1 << 0
86 bitScan = 1 << 4
87
88 heapBitsShift = 1
89 heapBitmapScale = sys.PtrSize * (8 / 2)
90
91
92 bitScanAll = bitScan | bitScan<<heapBitsShift | bitScan<<(2*heapBitsShift) | bitScan<<(3*heapBitsShift)
93 bitPointerAll = bitPointer | bitPointer<<heapBitsShift | bitPointer<<(2*heapBitsShift) | bitPointer<<(3*heapBitsShift)
94 )
95
96
97
98
99 func addb(p *byte, n uintptr) *byte {
100
101
102
103 return (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + n))
104 }
105
106
107
108
109
110
111 func subtractb(p *byte, n uintptr) *byte {
112
113
114
115 return (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) - n))
116 }
117
118
119
120
121 func add1(p *byte) *byte {
122
123
124
125 return (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + 1))
126 }
127
128
129
130
131
132
133
134
135 func subtract1(p *byte) *byte {
136
137
138
139 return (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) - 1))
140 }
141
142
143
144
145
146
147 func (h *mheap) mapBits(arena_used uintptr) {
148
149
150
151 const bitmapChunk = 8192
152
153 n := (arena_used - mheap_.arena_start) / heapBitmapScale
154 n = round(n, bitmapChunk)
155 n = round(n, physPageSize)
156 if h.bitmap_mapped >= n {
157 return
158 }
159
160 sysMap(unsafe.Pointer(h.bitmap-n), n-h.bitmap_mapped, h.arena_reserved, &memstats.gc_sys)
161 h.bitmap_mapped = n
162 }
163
164
165
166
167
168 type heapBits struct {
169 bitp *uint8
170 shift uint32
171 }
172
173
174
175
176
177
178
179
180
181
182 type markBits struct {
183 bytep *uint8
184 mask uint8
185 index uintptr
186 }
187
188
189 func (s *mspan) allocBitsForIndex(allocBitIndex uintptr) markBits {
190 bytep, mask := s.allocBits.bitp(allocBitIndex)
191 return markBits{bytep, mask, allocBitIndex}
192 }
193
194
195
196
197
198 func (s *mspan) refillAllocCache(whichByte uintptr) {
199 bytes := (*[8]uint8)(unsafe.Pointer(s.allocBits.bytep(whichByte)))
200 aCache := uint64(0)
201 aCache |= uint64(bytes[0])
202 aCache |= uint64(bytes[1]) << (1 * 8)
203 aCache |= uint64(bytes[2]) << (2 * 8)
204 aCache |= uint64(bytes[3]) << (3 * 8)
205 aCache |= uint64(bytes[4]) << (4 * 8)
206 aCache |= uint64(bytes[5]) << (5 * 8)
207 aCache |= uint64(bytes[6]) << (6 * 8)
208 aCache |= uint64(bytes[7]) << (7 * 8)
209 s.allocCache = ^aCache
210 }
211
212
213
214
215
216 func (s *mspan) nextFreeIndex() uintptr {
217 sfreeindex := s.freeindex
218 snelems := s.nelems
219 if sfreeindex == snelems {
220 return sfreeindex
221 }
222 if sfreeindex > snelems {
223 throw("s.freeindex > s.nelems")
224 }
225
226 aCache := s.allocCache
227
228 bitIndex := sys.Ctz64(aCache)
229 for bitIndex == 64 {
230
231 sfreeindex = (sfreeindex + 64) &^ (64 - 1)
232 if sfreeindex >= snelems {
233 s.freeindex = snelems
234 return snelems
235 }
236 whichByte := sfreeindex / 8
237
238 s.refillAllocCache(whichByte)
239 aCache = s.allocCache
240 bitIndex = sys.Ctz64(aCache)
241
242
243 }
244 result := sfreeindex + uintptr(bitIndex)
245 if result >= snelems {
246 s.freeindex = snelems
247 return snelems
248 }
249
250 s.allocCache >>= uint(bitIndex + 1)
251 sfreeindex = result + 1
252
253 if sfreeindex%64 == 0 && sfreeindex != snelems {
254
255
256
257
258
259 whichByte := sfreeindex / 8
260 s.refillAllocCache(whichByte)
261 }
262 s.freeindex = sfreeindex
263 return result
264 }
265
266
267 func (s *mspan) isFree(index uintptr) bool {
268 if index < s.freeindex {
269 return false
270 }
271 bytep, mask := s.allocBits.bitp(index)
272 return *bytep&mask == 0
273 }
274
275 func (s *mspan) objIndex(p uintptr) uintptr {
276 byteOffset := p - s.base()
277 if byteOffset == 0 {
278 return 0
279 }
280 if s.baseMask != 0 {
281
282 return byteOffset >> s.divShift
283 }
284 return uintptr(((uint64(byteOffset) >> s.divShift) * uint64(s.divMul)) >> s.divShift2)
285 }
286
287 func markBitsForAddr(p uintptr) markBits {
288 s := spanOf(p)
289 objIndex := s.objIndex(p)
290 return s.markBitsForIndex(objIndex)
291 }
292
293 func (s *mspan) markBitsForIndex(objIndex uintptr) markBits {
294 bytep, mask := s.gcmarkBits.bitp(objIndex)
295 return markBits{bytep, mask, objIndex}
296 }
297
298 func (s *mspan) markBitsForBase() markBits {
299 return markBits{(*uint8)(s.gcmarkBits), uint8(1), 0}
300 }
301
302
303 func (m markBits) isMarked() bool {
304 return *m.bytep&m.mask != 0
305 }
306
307
308
309
310 func (m markBits) setMarked() {
311
312
313
314 atomic.Or8(m.bytep, m.mask)
315 }
316
317
318 func (m markBits) setMarkedNonAtomic() {
319 *m.bytep |= m.mask
320 }
321
322
323 func (m markBits) clearMarked() {
324
325
326
327 atomic.And8(m.bytep, ^m.mask)
328 }
329
330
331 func markBitsForSpan(base uintptr) (mbits markBits) {
332 if base < mheap_.arena_start || base >= mheap_.arena_used {
333 throw("markBitsForSpan: base out of range")
334 }
335 mbits = markBitsForAddr(base)
336 if mbits.mask != 1 {
337 throw("markBitsForSpan: unaligned start")
338 }
339 return mbits
340 }
341
342
343 func (m *markBits) advance() {
344 if m.mask == 1<<7 {
345 m.bytep = (*uint8)(unsafe.Pointer(uintptr(unsafe.Pointer(m.bytep)) + 1))
346 m.mask = 1
347 } else {
348 m.mask = m.mask << 1
349 }
350 m.index++
351 }
352
353
354
355
356
357
358 func heapBitsForAddr(addr uintptr) heapBits {
359
360 off := (addr - mheap_.arena_start) / sys.PtrSize
361 return heapBits{(*uint8)(unsafe.Pointer(mheap_.bitmap - off/4 - 1)), uint32(off & 3)}
362 }
363
364
365 func heapBitsForSpan(base uintptr) (hbits heapBits) {
366 if base < mheap_.arena_start || base >= mheap_.arena_used {
367 print("runtime: base ", hex(base), " not in range [", hex(mheap_.arena_start), ",", hex(mheap_.arena_used), ")\n")
368 throw("heapBitsForSpan: base out of range")
369 }
370 return heapBitsForAddr(base)
371 }
372
373
374
375
376
377
378
379
380
381
382
383 func heapBitsForObject(p, refBase, refOff uintptr) (base uintptr, hbits heapBits, s *mspan, objIndex uintptr) {
384 arenaStart := mheap_.arena_start
385 if p < arenaStart || p >= mheap_.arena_used {
386 return
387 }
388 off := p - arenaStart
389 idx := off >> _PageShift
390
391
392 s = mheap_.spans[idx]
393 if s == nil || p < s.base() || p >= s.limit || s.state != mSpanInUse {
394 if s == nil || s.state == _MSpanManual {
395
396
397
398 return
399 }
400
401
402
403 if debug.invalidptr != 0 {
404
405
406
407
408
409
410
411
412 printlock()
413 print("runtime: pointer ", hex(p))
414 if s.state != mSpanInUse {
415 print(" to unallocated span")
416 } else {
417 print(" to unused region of span")
418 }
419 print(" idx=", hex(idx), " span.base()=", hex(s.base()), " span.limit=", hex(s.limit), " span.state=", s.state, "\n")
420 if refBase != 0 {
421 print("runtime: found in object at *(", hex(refBase), "+", hex(refOff), ")\n")
422 gcDumpObject("object", refBase, refOff)
423 }
424 getg().m.traceback = 2
425 throw("found bad pointer in Go heap (incorrect use of unsafe or cgo?)")
426 }
427 return
428 }
429
430
431 if s.baseMask != 0 {
432
433 base = s.base()
434 base = base + (p-base)&uintptr(s.baseMask)
435 objIndex = (base - s.base()) >> s.divShift
436
437
438
439 } else {
440 base = s.base()
441 if p-base >= s.elemsize {
442
443 objIndex = uintptr(p-base) >> s.divShift * uintptr(s.divMul) >> s.divShift2
444 base += objIndex * s.elemsize
445 }
446 }
447
448 hbits = heapBitsForAddr(base)
449 return
450 }
451
452
453
454
455
456
457
458 func (h heapBits) next() heapBits {
459 if h.shift < 3*heapBitsShift {
460 return heapBits{h.bitp, h.shift + heapBitsShift}
461 }
462 return heapBits{subtract1(h.bitp), 0}
463 }
464
465
466
467
468
469
470 func (h heapBits) forward(n uintptr) heapBits {
471 n += uintptr(h.shift) / heapBitsShift
472 return heapBits{subtractb(h.bitp, n/4), uint32(n%4) * heapBitsShift}
473 }
474
475
476
477
478
479
480
481 func (h heapBits) bits() uint32 {
482
483
484 return uint32(*h.bitp) >> (h.shift & 31)
485 }
486
487
488
489
490 func (h heapBits) morePointers() bool {
491 return h.bits()&bitScan != 0
492 }
493
494
495
496
497
498 func (h heapBits) isPointer() bool {
499 return h.bits()&bitPointer != 0
500 }
501
502
503
504
505
506 func (h heapBits) isCheckmarked(size uintptr) bool {
507 if size == sys.PtrSize {
508 return (*h.bitp>>h.shift)&bitPointer != 0
509 }
510
511
512
513
514 return (*h.bitp>>(heapBitsShift+h.shift))&bitScan != 0
515 }
516
517
518
519
520
521 func (h heapBits) setCheckmarked(size uintptr) {
522 if size == sys.PtrSize {
523 atomic.Or8(h.bitp, bitPointer<<h.shift)
524 return
525 }
526 atomic.Or8(h.bitp, bitScan<<(heapBitsShift+h.shift))
527 }
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554 func bulkBarrierPreWrite(dst, src, size uintptr) {
555 if (dst|src|size)&(sys.PtrSize-1) != 0 {
556 throw("bulkBarrierPreWrite: unaligned arguments")
557 }
558 if !writeBarrier.needed {
559 return
560 }
561 if !inheap(dst) {
562 gp := getg().m.curg
563 if gp != nil && gp.stack.lo <= dst && dst < gp.stack.hi {
564
565 return
566 }
567
568
569
570 for _, datap := range activeModules() {
571 if datap.data <= dst && dst < datap.edata {
572 bulkBarrierBitmap(dst, src, size, dst-datap.data, datap.gcdatamask.bytedata)
573 return
574 }
575 }
576 for _, datap := range activeModules() {
577 if datap.bss <= dst && dst < datap.ebss {
578 bulkBarrierBitmap(dst, src, size, dst-datap.bss, datap.gcbssmask.bytedata)
579 return
580 }
581 }
582 return
583 }
584
585 buf := &getg().m.p.ptr().wbBuf
586 h := heapBitsForAddr(dst)
587 if src == 0 {
588 for i := uintptr(0); i < size; i += sys.PtrSize {
589 if h.isPointer() {
590 dstx := (*uintptr)(unsafe.Pointer(dst + i))
591 if !buf.putFast(*dstx, 0) {
592 wbBufFlush(nil, 0)
593 }
594 }
595 h = h.next()
596 }
597 } else {
598 for i := uintptr(0); i < size; i += sys.PtrSize {
599 if h.isPointer() {
600 dstx := (*uintptr)(unsafe.Pointer(dst + i))
601 srcx := (*uintptr)(unsafe.Pointer(src + i))
602 if !buf.putFast(*dstx, *srcx) {
603 wbBufFlush(nil, 0)
604 }
605 }
606 h = h.next()
607 }
608 }
609 }
610
611
612
613
614
615
616
617
618
619 func bulkBarrierBitmap(dst, src, size, maskOffset uintptr, bits *uint8) {
620 word := maskOffset / sys.PtrSize
621 bits = addb(bits, word/8)
622 mask := uint8(1) << (word % 8)
623
624 buf := &getg().m.p.ptr().wbBuf
625 for i := uintptr(0); i < size; i += sys.PtrSize {
626 if mask == 0 {
627 bits = addb(bits, 1)
628 if *bits == 0 {
629
630 i += 7 * sys.PtrSize
631 continue
632 }
633 mask = 1
634 }
635 if *bits&mask != 0 {
636 dstx := (*uintptr)(unsafe.Pointer(dst + i))
637 if src == 0 {
638 if !buf.putFast(*dstx, 0) {
639 wbBufFlush(nil, 0)
640 }
641 } else {
642 srcx := (*uintptr)(unsafe.Pointer(src + i))
643 if !buf.putFast(*dstx, *srcx) {
644 wbBufFlush(nil, 0)
645 }
646 }
647 }
648 mask <<= 1
649 }
650 }
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667 func typeBitsBulkBarrier(typ *_type, dst, src, size uintptr) {
668 if typ == nil {
669 throw("runtime: typeBitsBulkBarrier without type")
670 }
671 if typ.size != size {
672 println("runtime: typeBitsBulkBarrier with type ", typ.string(), " of size ", typ.size, " but memory size", size)
673 throw("runtime: invalid typeBitsBulkBarrier")
674 }
675 if typ.kind&kindGCProg != 0 {
676 println("runtime: typeBitsBulkBarrier with type ", typ.string(), " with GC prog")
677 throw("runtime: invalid typeBitsBulkBarrier")
678 }
679 if !writeBarrier.needed {
680 return
681 }
682 ptrmask := typ.gcdata
683 var bits uint32
684 for i := uintptr(0); i < typ.ptrdata; i += sys.PtrSize {
685 if i&(sys.PtrSize*8-1) == 0 {
686 bits = uint32(*ptrmask)
687 ptrmask = addb(ptrmask, 1)
688 } else {
689 bits = bits >> 1
690 }
691 if bits&1 != 0 {
692 dstx := (*uintptr)(unsafe.Pointer(dst + i))
693 srcx := (*uintptr)(unsafe.Pointer(src + i))
694 writebarrierptr_prewrite(dstx, *srcx)
695 }
696 }
697 }
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712 func (h heapBits) initSpan(s *mspan) {
713 size, n, total := s.layout()
714
715
716 s.freeindex = 0
717 s.allocCache = ^uint64(0)
718 s.nelems = n
719 s.allocBits = nil
720 s.gcmarkBits = nil
721 s.gcmarkBits = newMarkBits(s.nelems)
722 s.allocBits = newAllocBits(s.nelems)
723
724
725 if total%heapBitmapScale != 0 {
726 throw("initSpan: unaligned length")
727 }
728 nbyte := total / heapBitmapScale
729 if sys.PtrSize == 8 && size == sys.PtrSize {
730 end := h.bitp
731 bitp := subtractb(end, nbyte-1)
732 for {
733 *bitp = bitPointerAll | bitScanAll
734 if bitp == end {
735 break
736 }
737 bitp = add1(bitp)
738 }
739 return
740 }
741 memclrNoHeapPointers(unsafe.Pointer(subtractb(h.bitp, nbyte-1)), nbyte)
742 }
743
744
745
746 func (h heapBits) initCheckmarkSpan(size, n, total uintptr) {
747
748 if sys.PtrSize == 8 && size == sys.PtrSize {
749
750
751
752
753 bitp := h.bitp
754 for i := uintptr(0); i < n; i += 4 {
755 *bitp &^= bitPointerAll
756 bitp = subtract1(bitp)
757 }
758 return
759 }
760 for i := uintptr(0); i < n; i++ {
761 *h.bitp &^= bitScan << (heapBitsShift + h.shift)
762 h = h.forward(size / sys.PtrSize)
763 }
764 }
765
766
767
768
769
770 func (h heapBits) clearCheckmarkSpan(size, n, total uintptr) {
771
772 if sys.PtrSize == 8 && size == sys.PtrSize {
773
774
775
776
777 bitp := h.bitp
778 for i := uintptr(0); i < n; i += 4 {
779 *bitp |= bitPointerAll
780 bitp = subtract1(bitp)
781 }
782 }
783 }
784
785
786
787
788 var oneBitCount = [256]uint8{
789 0, 1, 1, 2, 1, 2, 2, 3,
790 1, 2, 2, 3, 2, 3, 3, 4,
791 1, 2, 2, 3, 2, 3, 3, 4,
792 2, 3, 3, 4, 3, 4, 4, 5,
793 1, 2, 2, 3, 2, 3, 3, 4,
794 2, 3, 3, 4, 3, 4, 4, 5,
795 2, 3, 3, 4, 3, 4, 4, 5,
796 3, 4, 4, 5, 4, 5, 5, 6,
797 1, 2, 2, 3, 2, 3, 3, 4,
798 2, 3, 3, 4, 3, 4, 4, 5,
799 2, 3, 3, 4, 3, 4, 4, 5,
800 3, 4, 4, 5, 4, 5, 5, 6,
801 2, 3, 3, 4, 3, 4, 4, 5,
802 3, 4, 4, 5, 4, 5, 5, 6,
803 3, 4, 4, 5, 4, 5, 5, 6,
804 4, 5, 5, 6, 5, 6, 6, 7,
805 1, 2, 2, 3, 2, 3, 3, 4,
806 2, 3, 3, 4, 3, 4, 4, 5,
807 2, 3, 3, 4, 3, 4, 4, 5,
808 3, 4, 4, 5, 4, 5, 5, 6,
809 2, 3, 3, 4, 3, 4, 4, 5,
810 3, 4, 4, 5, 4, 5, 5, 6,
811 3, 4, 4, 5, 4, 5, 5, 6,
812 4, 5, 5, 6, 5, 6, 6, 7,
813 2, 3, 3, 4, 3, 4, 4, 5,
814 3, 4, 4, 5, 4, 5, 5, 6,
815 3, 4, 4, 5, 4, 5, 5, 6,
816 4, 5, 5, 6, 5, 6, 6, 7,
817 3, 4, 4, 5, 4, 5, 5, 6,
818 4, 5, 5, 6, 5, 6, 6, 7,
819 4, 5, 5, 6, 5, 6, 6, 7,
820 5, 6, 6, 7, 6, 7, 7, 8}
821
822
823
824
825 func (s *mspan) countAlloc() int {
826 count := 0
827 maxIndex := s.nelems / 8
828 for i := uintptr(0); i < maxIndex; i++ {
829 mrkBits := *s.gcmarkBits.bytep(i)
830 count += int(oneBitCount[mrkBits])
831 }
832 if bitsInLastByte := s.nelems % 8; bitsInLastByte != 0 {
833 mrkBits := *s.gcmarkBits.bytep(maxIndex)
834 mask := uint8((1 << bitsInLastByte) - 1)
835 bits := mrkBits & mask
836 count += int(oneBitCount[bits])
837 }
838 return count
839 }
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864 func heapBitsSetType(x, size, dataSize uintptr, typ *_type) {
865 const doubleCheck = false
866
867
868
869
870
871
872
873
874
875 if sys.PtrSize == 8 && size == sys.PtrSize {
876
877
878
879
880 if doubleCheck {
881 h := heapBitsForAddr(x)
882 if !h.isPointer() {
883 throw("heapBitsSetType: pointer bit missing")
884 }
885 if !h.morePointers() {
886 throw("heapBitsSetType: scan bit missing")
887 }
888 }
889 return
890 }
891
892 h := heapBitsForAddr(x)
893 ptrmask := typ.gcdata
894
895
896
897
898
899
900 if size == 2*sys.PtrSize {
901 if typ.size == sys.PtrSize {
902
903
904
905
906
907
908
909
910 if sys.PtrSize == 4 && dataSize == sys.PtrSize {
911
912
913 *h.bitp &^= (bitPointer | bitScan | ((bitPointer | bitScan) << heapBitsShift)) << h.shift
914 *h.bitp |= (bitPointer | bitScan) << h.shift
915 } else {
916
917 *h.bitp |= (bitPointer | bitScan | bitPointer<<heapBitsShift) << h.shift
918 }
919 return
920 }
921
922
923 if doubleCheck {
924 if typ.size != 2*sys.PtrSize || typ.kind&kindGCProg != 0 {
925 print("runtime: heapBitsSetType size=", size, " but typ.size=", typ.size, " gcprog=", typ.kind&kindGCProg != 0, "\n")
926 throw("heapBitsSetType")
927 }
928 }
929 b := uint32(*ptrmask)
930 hb := (b & 3) | bitScan
931
932
933
934
935 *h.bitp &^= (bitPointer | bitScan | ((bitPointer | bitScan) << heapBitsShift)) << h.shift
936 *h.bitp |= uint8(hb << h.shift)
937 return
938 }
939
940
941
942
943
944
945
946
947 var (
948
949 p *byte
950 b uintptr
951 nb uintptr
952 endp *byte
953 endnb uintptr
954 pbits uintptr
955
956
957 w uintptr
958 nw uintptr
959 hbitp *byte
960 hb uintptr
961 )
962
963 hbitp = h.bitp
964
965
966
967
968
969 if typ.kind&kindGCProg != 0 {
970 heapBitsSetTypeGCProg(h, typ.ptrdata, typ.size, dataSize, size, addb(typ.gcdata, 4))
971 if doubleCheck {
972
973
974
975
976
977
978
979 lock(&debugPtrmask.lock)
980 if debugPtrmask.data == nil {
981 debugPtrmask.data = (*byte)(persistentalloc(1<<20, 1, &memstats.other_sys))
982 }
983 ptrmask = debugPtrmask.data
984 runGCProg(addb(typ.gcdata, 4), nil, ptrmask, 1)
985 goto Phase4
986 }
987 return
988 }
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021 p = ptrmask
1022 if typ.size < dataSize {
1023
1024
1025
1026 const maxBits = sys.PtrSize*8 - 7
1027 if typ.ptrdata/sys.PtrSize <= maxBits {
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038 nb = typ.ptrdata / sys.PtrSize
1039 for i := uintptr(0); i < nb; i += 8 {
1040 b |= uintptr(*p) << i
1041 p = add1(p)
1042 }
1043 nb = typ.size / sys.PtrSize
1044
1045
1046
1047
1048
1049
1050
1051 pbits = b
1052 endnb = nb
1053 if nb+nb <= maxBits {
1054 for endnb <= sys.PtrSize*8 {
1055 pbits |= pbits << endnb
1056 endnb += endnb
1057 }
1058
1059
1060
1061 endnb = uintptr(maxBits/byte(nb)) * nb
1062 pbits &= 1<<endnb - 1
1063 b = pbits
1064 nb = endnb
1065 }
1066
1067
1068
1069 p = nil
1070 endp = nil
1071 } else {
1072
1073 n := (typ.ptrdata/sys.PtrSize+7)/8 - 1
1074 endp = addb(ptrmask, n)
1075 endnb = typ.size/sys.PtrSize - n*8
1076 }
1077 }
1078 if p != nil {
1079 b = uintptr(*p)
1080 p = add1(p)
1081 nb = 8
1082 }
1083
1084 if typ.size == dataSize {
1085
1086 nw = typ.ptrdata / sys.PtrSize
1087 } else {
1088
1089
1090
1091 nw = ((dataSize/typ.size-1)*typ.size + typ.ptrdata) / sys.PtrSize
1092 }
1093 if nw == 0 {
1094
1095 println("runtime: invalid type ", typ.string())
1096 throw("heapBitsSetType: called with non-pointer type")
1097 return
1098 }
1099 if nw < 2 {
1100
1101
1102 nw = 2
1103 }
1104
1105
1106
1107
1108
1109
1110 switch {
1111 default:
1112 throw("heapBitsSetType: unexpected shift")
1113
1114 case h.shift == 0:
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129 hb = b & bitPointerAll
1130 hb |= bitScan | bitScan<<(2*heapBitsShift) | bitScan<<(3*heapBitsShift)
1131 if w += 4; w >= nw {
1132 goto Phase3
1133 }
1134 *hbitp = uint8(hb)
1135 hbitp = subtract1(hbitp)
1136 b >>= 4
1137 nb -= 4
1138
1139 case sys.PtrSize == 8 && h.shift == 2:
1140
1141
1142
1143
1144
1145
1146 hb = (b & (bitPointer | bitPointer<<heapBitsShift)) << (2 * heapBitsShift)
1147
1148
1149 hb |= bitScan << (2 * heapBitsShift)
1150 b >>= 2
1151 nb -= 2
1152
1153
1154 *hbitp &^= uint8((bitPointer | bitScan | (bitPointer << heapBitsShift)) << (2 * heapBitsShift))
1155 *hbitp |= uint8(hb)
1156 hbitp = subtract1(hbitp)
1157 if w += 2; w >= nw {
1158
1159
1160
1161 hb = 0
1162 w += 4
1163 goto Phase3
1164 }
1165 }
1166
1167
1168
1169
1170
1171
1172
1173 nb -= 4
1174 for {
1175
1176
1177
1178
1179
1180 hb = b & bitPointerAll
1181 hb |= bitScanAll
1182 if w += 4; w >= nw {
1183 break
1184 }
1185 *hbitp = uint8(hb)
1186 hbitp = subtract1(hbitp)
1187 b >>= 4
1188
1189
1190 if p != endp {
1191
1192
1193
1194
1195 if nb < 8 {
1196 b |= uintptr(*p) << nb
1197 p = add1(p)
1198 } else {
1199
1200
1201
1202
1203 nb -= 8
1204 }
1205 } else if p == nil {
1206
1207
1208 if nb < 8 {
1209 b |= pbits << nb
1210 nb += endnb
1211 }
1212 nb -= 8
1213 } else {
1214
1215
1216 b |= uintptr(*p) << nb
1217 nb += endnb
1218 if nb < 8 {
1219 b |= uintptr(*ptrmask) << nb
1220 p = add1(ptrmask)
1221 } else {
1222 nb -= 8
1223 p = ptrmask
1224 }
1225 }
1226
1227
1228 hb = b & bitPointerAll
1229 hb |= bitScanAll
1230 if w += 4; w >= nw {
1231 break
1232 }
1233 *hbitp = uint8(hb)
1234 hbitp = subtract1(hbitp)
1235 b >>= 4
1236 }
1237
1238 Phase3:
1239
1240 if w > nw {
1241
1242
1243
1244 mask := uintptr(1)<<(4-(w-nw)) - 1
1245 hb &= mask | mask<<4
1246 }
1247
1248
1249 nw = size / sys.PtrSize
1250
1251
1252
1253 if w <= nw {
1254 *hbitp = uint8(hb)
1255 hbitp = subtract1(hbitp)
1256 hb = 0
1257 for w += 4; w <= nw; w += 4 {
1258 *hbitp = 0
1259 hbitp = subtract1(hbitp)
1260 }
1261 }
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271 if w == nw+2 {
1272 *hbitp = *hbitp&^(bitPointer|bitScan|(bitPointer|bitScan)<<heapBitsShift) | uint8(hb)
1273 }
1274
1275 Phase4:
1276
1277 if doubleCheck {
1278 end := heapBitsForAddr(x + size)
1279 if typ.kind&kindGCProg == 0 && (hbitp != end.bitp || (w == nw+2) != (end.shift == 2)) {
1280 println("ended at wrong bitmap byte for", typ.string(), "x", dataSize/typ.size)
1281 print("typ.size=", typ.size, " typ.ptrdata=", typ.ptrdata, " dataSize=", dataSize, " size=", size, "\n")
1282 print("w=", w, " nw=", nw, " b=", hex(b), " nb=", nb, " hb=", hex(hb), "\n")
1283 h0 := heapBitsForAddr(x)
1284 print("initial bits h0.bitp=", h0.bitp, " h0.shift=", h0.shift, "\n")
1285 print("ended at hbitp=", hbitp, " but next starts at bitp=", end.bitp, " shift=", end.shift, "\n")
1286 throw("bad heapBitsSetType")
1287 }
1288
1289
1290
1291 h := heapBitsForAddr(x)
1292 nptr := typ.ptrdata / sys.PtrSize
1293 ndata := typ.size / sys.PtrSize
1294 count := dataSize / typ.size
1295 totalptr := ((count-1)*typ.size + typ.ptrdata) / sys.PtrSize
1296 for i := uintptr(0); i < size/sys.PtrSize; i++ {
1297 j := i % ndata
1298 var have, want uint8
1299 have = (*h.bitp >> h.shift) & (bitPointer | bitScan)
1300 if i >= totalptr {
1301 want = 0
1302 if typ.kind&kindGCProg != 0 && i < (totalptr+3)/4*4 {
1303 want = bitScan
1304 }
1305 } else {
1306 if j < nptr && (*addb(ptrmask, j/8)>>(j%8))&1 != 0 {
1307 want |= bitPointer
1308 }
1309 if i != 1 {
1310 want |= bitScan
1311 } else {
1312 have &^= bitScan
1313 }
1314 }
1315 if have != want {
1316 println("mismatch writing bits for", typ.string(), "x", dataSize/typ.size)
1317 print("typ.size=", typ.size, " typ.ptrdata=", typ.ptrdata, " dataSize=", dataSize, " size=", size, "\n")
1318 print("kindGCProg=", typ.kind&kindGCProg != 0, "\n")
1319 print("w=", w, " nw=", nw, " b=", hex(b), " nb=", nb, " hb=", hex(hb), "\n")
1320 h0 := heapBitsForAddr(x)
1321 print("initial bits h0.bitp=", h0.bitp, " h0.shift=", h0.shift, "\n")
1322 print("current bits h.bitp=", h.bitp, " h.shift=", h.shift, " *h.bitp=", hex(*h.bitp), "\n")
1323 print("ptrmask=", ptrmask, " p=", p, " endp=", endp, " endnb=", endnb, " pbits=", hex(pbits), " b=", hex(b), " nb=", nb, "\n")
1324 println("at word", i, "offset", i*sys.PtrSize, "have", have, "want", want)
1325 if typ.kind&kindGCProg != 0 {
1326 println("GC program:")
1327 dumpGCProg(addb(typ.gcdata, 4))
1328 }
1329 throw("bad heapBitsSetType")
1330 }
1331 h = h.next()
1332 }
1333 if ptrmask == debugPtrmask.data {
1334 unlock(&debugPtrmask.lock)
1335 }
1336 }
1337 }
1338
1339 var debugPtrmask struct {
1340 lock mutex
1341 data *byte
1342 }
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354 func heapBitsSetTypeGCProg(h heapBits, progSize, elemSize, dataSize, allocSize uintptr, prog *byte) {
1355 if sys.PtrSize == 8 && allocSize%(4*sys.PtrSize) != 0 {
1356
1357 throw("heapBitsSetTypeGCProg: small allocation")
1358 }
1359 var totalBits uintptr
1360 if elemSize == dataSize {
1361 totalBits = runGCProg(prog, nil, h.bitp, 2)
1362 if totalBits*sys.PtrSize != progSize {
1363 println("runtime: heapBitsSetTypeGCProg: total bits", totalBits, "but progSize", progSize)
1364 throw("heapBitsSetTypeGCProg: unexpected bit count")
1365 }
1366 } else {
1367 count := dataSize / elemSize
1368
1369
1370
1371
1372
1373
1374
1375 var trailer [40]byte
1376 i := 0
1377 if n := elemSize/sys.PtrSize - progSize/sys.PtrSize; n > 0 {
1378
1379 trailer[i] = 0x01
1380 i++
1381 trailer[i] = 0
1382 i++
1383 if n > 1 {
1384
1385 trailer[i] = 0x81
1386 i++
1387 n--
1388 for ; n >= 0x80; n >>= 7 {
1389 trailer[i] = byte(n | 0x80)
1390 i++
1391 }
1392 trailer[i] = byte(n)
1393 i++
1394 }
1395 }
1396
1397 trailer[i] = 0x80
1398 i++
1399 n := elemSize / sys.PtrSize
1400 for ; n >= 0x80; n >>= 7 {
1401 trailer[i] = byte(n | 0x80)
1402 i++
1403 }
1404 trailer[i] = byte(n)
1405 i++
1406 n = count - 1
1407 for ; n >= 0x80; n >>= 7 {
1408 trailer[i] = byte(n | 0x80)
1409 i++
1410 }
1411 trailer[i] = byte(n)
1412 i++
1413 trailer[i] = 0
1414 i++
1415
1416 runGCProg(prog, &trailer[0], h.bitp, 2)
1417
1418
1419
1420
1421
1422
1423 totalBits = (elemSize*(count-1) + progSize) / sys.PtrSize
1424 }
1425 endProg := unsafe.Pointer(subtractb(h.bitp, (totalBits+3)/4))
1426 endAlloc := unsafe.Pointer(subtractb(h.bitp, allocSize/heapBitmapScale))
1427 memclrNoHeapPointers(add(endAlloc, 1), uintptr(endProg)-uintptr(endAlloc))
1428 }
1429
1430
1431
1432
1433 func progToPointerMask(prog *byte, size uintptr) bitvector {
1434 n := (size/sys.PtrSize + 7) / 8
1435 x := (*[1 << 30]byte)(persistentalloc(n+1, 1, &memstats.buckhash_sys))[:n+1]
1436 x[len(x)-1] = 0xa1
1437 n = runGCProg(prog, nil, &x[0], 1)
1438 if x[len(x)-1] != 0xa1 {
1439 throw("progToPointerMask: overflow")
1440 }
1441 return bitvector{int32(n), &x[0]}
1442 }
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466 func runGCProg(prog, trailer, dst *byte, size int) uintptr {
1467 dstStart := dst
1468
1469
1470 var bits uintptr
1471 var nbits uintptr
1472
1473 p := prog
1474 Run:
1475 for {
1476
1477
1478 for ; nbits >= 8; nbits -= 8 {
1479 if size == 1 {
1480 *dst = uint8(bits)
1481 dst = add1(dst)
1482 bits >>= 8
1483 } else {
1484 v := bits&bitPointerAll | bitScanAll
1485 *dst = uint8(v)
1486 dst = subtract1(dst)
1487 bits >>= 4
1488 v = bits&bitPointerAll | bitScanAll
1489 *dst = uint8(v)
1490 dst = subtract1(dst)
1491 bits >>= 4
1492 }
1493 }
1494
1495
1496 inst := uintptr(*p)
1497 p = add1(p)
1498 n := inst & 0x7F
1499 if inst&0x80 == 0 {
1500
1501 if n == 0 {
1502
1503 if trailer != nil {
1504
1505 p = trailer
1506 trailer = nil
1507 continue
1508 }
1509
1510 break Run
1511 }
1512
1513 nbyte := n / 8
1514 for i := uintptr(0); i < nbyte; i++ {
1515 bits |= uintptr(*p) << nbits
1516 p = add1(p)
1517 if size == 1 {
1518 *dst = uint8(bits)
1519 dst = add1(dst)
1520 bits >>= 8
1521 } else {
1522 v := bits&0xf | bitScanAll
1523 *dst = uint8(v)
1524 dst = subtract1(dst)
1525 bits >>= 4
1526 v = bits&0xf | bitScanAll
1527 *dst = uint8(v)
1528 dst = subtract1(dst)
1529 bits >>= 4
1530 }
1531 }
1532 if n %= 8; n > 0 {
1533 bits |= uintptr(*p) << nbits
1534 p = add1(p)
1535 nbits += n
1536 }
1537 continue Run
1538 }
1539
1540
1541 if n == 0 {
1542 for off := uint(0); ; off += 7 {
1543 x := uintptr(*p)
1544 p = add1(p)
1545 n |= (x & 0x7F) << off
1546 if x&0x80 == 0 {
1547 break
1548 }
1549 }
1550 }
1551
1552
1553 c := uintptr(0)
1554 for off := uint(0); ; off += 7 {
1555 x := uintptr(*p)
1556 p = add1(p)
1557 c |= (x & 0x7F) << off
1558 if x&0x80 == 0 {
1559 break
1560 }
1561 }
1562 c *= n
1563
1564
1565
1566
1567
1568
1569
1570
1571 src := dst
1572 const maxBits = sys.PtrSize*8 - 7
1573 if n <= maxBits {
1574
1575 pattern := bits
1576 npattern := nbits
1577
1578
1579 if size == 1 {
1580 src = subtract1(src)
1581 for npattern < n {
1582 pattern <<= 8
1583 pattern |= uintptr(*src)
1584 src = subtract1(src)
1585 npattern += 8
1586 }
1587 } else {
1588 src = add1(src)
1589 for npattern < n {
1590 pattern <<= 4
1591 pattern |= uintptr(*src) & 0xf
1592 src = add1(src)
1593 npattern += 4
1594 }
1595 }
1596
1597
1598
1599
1600
1601 if npattern > n {
1602 pattern >>= npattern - n
1603 npattern = n
1604 }
1605
1606
1607 if npattern == 1 {
1608
1609
1610
1611
1612
1613
1614 if pattern == 1 {
1615 pattern = 1<<maxBits - 1
1616 npattern = maxBits
1617 } else {
1618 npattern = c
1619 }
1620 } else {
1621 b := pattern
1622 nb := npattern
1623 if nb+nb <= maxBits {
1624
1625 for nb <= sys.PtrSize*8 {
1626 b |= b << nb
1627 nb += nb
1628 }
1629
1630
1631 nb = maxBits / npattern * npattern
1632 b &= 1<<nb - 1
1633 pattern = b
1634 npattern = nb
1635 }
1636 }
1637
1638
1639
1640
1641 for ; c >= npattern; c -= npattern {
1642 bits |= pattern << nbits
1643 nbits += npattern
1644 if size == 1 {
1645 for nbits >= 8 {
1646 *dst = uint8(bits)
1647 dst = add1(dst)
1648 bits >>= 8
1649 nbits -= 8
1650 }
1651 } else {
1652 for nbits >= 4 {
1653 *dst = uint8(bits&0xf | bitScanAll)
1654 dst = subtract1(dst)
1655 bits >>= 4
1656 nbits -= 4
1657 }
1658 }
1659 }
1660
1661
1662 if c > 0 {
1663 pattern &= 1<<c - 1
1664 bits |= pattern << nbits
1665 nbits += c
1666 }
1667 continue Run
1668 }
1669
1670
1671
1672
1673 off := n - nbits
1674 if size == 1 {
1675
1676 src = subtractb(src, (off+7)/8)
1677 if frag := off & 7; frag != 0 {
1678 bits |= uintptr(*src) >> (8 - frag) << nbits
1679 src = add1(src)
1680 nbits += frag
1681 c -= frag
1682 }
1683
1684
1685 for i := c / 8; i > 0; i-- {
1686 bits |= uintptr(*src) << nbits
1687 src = add1(src)
1688 *dst = uint8(bits)
1689 dst = add1(dst)
1690 bits >>= 8
1691 }
1692
1693 if c %= 8; c > 0 {
1694 bits |= (uintptr(*src) & (1<<c - 1)) << nbits
1695 nbits += c
1696 }
1697 } else {
1698
1699 src = addb(src, (off+3)/4)
1700 if frag := off & 3; frag != 0 {
1701 bits |= (uintptr(*src) & 0xf) >> (4 - frag) << nbits
1702 src = subtract1(src)
1703 nbits += frag
1704 c -= frag
1705 }
1706
1707
1708 for i := c / 4; i > 0; i-- {
1709 bits |= (uintptr(*src) & 0xf) << nbits
1710 src = subtract1(src)
1711 *dst = uint8(bits&0xf | bitScanAll)
1712 dst = subtract1(dst)
1713 bits >>= 4
1714 }
1715
1716 if c %= 4; c > 0 {
1717 bits |= (uintptr(*src) & (1<<c - 1)) << nbits
1718 nbits += c
1719 }
1720 }
1721 }
1722
1723
1724 var totalBits uintptr
1725 if size == 1 {
1726 totalBits = (uintptr(unsafe.Pointer(dst))-uintptr(unsafe.Pointer(dstStart)))*8 + nbits
1727 nbits += -nbits & 7
1728 for ; nbits > 0; nbits -= 8 {
1729 *dst = uint8(bits)
1730 dst = add1(dst)
1731 bits >>= 8
1732 }
1733 } else {
1734 totalBits = (uintptr(unsafe.Pointer(dstStart))-uintptr(unsafe.Pointer(dst)))*4 + nbits
1735 nbits += -nbits & 3
1736 for ; nbits > 0; nbits -= 4 {
1737 v := bits&0xf | bitScanAll
1738 *dst = uint8(v)
1739 dst = subtract1(dst)
1740 bits >>= 4
1741 }
1742 }
1743 return totalBits
1744 }
1745
1746 func dumpGCProg(p *byte) {
1747 nptr := 0
1748 for {
1749 x := *p
1750 p = add1(p)
1751 if x == 0 {
1752 print("\t", nptr, " end\n")
1753 break
1754 }
1755 if x&0x80 == 0 {
1756 print("\t", nptr, " lit ", x, ":")
1757 n := int(x+7) / 8
1758 for i := 0; i < n; i++ {
1759 print(" ", hex(*p))
1760 p = add1(p)
1761 }
1762 print("\n")
1763 nptr += int(x)
1764 } else {
1765 nbit := int(x &^ 0x80)
1766 if nbit == 0 {
1767 for nb := uint(0); ; nb += 7 {
1768 x := *p
1769 p = add1(p)
1770 nbit |= int(x&0x7f) << nb
1771 if x&0x80 == 0 {
1772 break
1773 }
1774 }
1775 }
1776 count := 0
1777 for nb := uint(0); ; nb += 7 {
1778 x := *p
1779 p = add1(p)
1780 count |= int(x&0x7f) << nb
1781 if x&0x80 == 0 {
1782 break
1783 }
1784 }
1785 print("\t", nptr, " repeat ", nbit, " × ", count, "\n")
1786 nptr += nbit * count
1787 }
1788 }
1789 }
1790
1791
1792
1793 func getgcmaskcb(frame *stkframe, ctxt unsafe.Pointer) bool {
1794 target := (*stkframe)(ctxt)
1795 if frame.sp <= target.sp && target.sp < frame.varp {
1796 *target = *frame
1797 return false
1798 }
1799 return true
1800 }
1801
1802
1803
1804
1805 func reflect_gcbits(x interface{}) []byte {
1806 ret := getgcmask(x)
1807 typ := (*ptrtype)(unsafe.Pointer(efaceOf(&x)._type)).elem
1808 nptr := typ.ptrdata / sys.PtrSize
1809 for uintptr(len(ret)) > nptr && ret[len(ret)-1] == 0 {
1810 ret = ret[:len(ret)-1]
1811 }
1812 return ret
1813 }
1814
1815
1816 func getgcmask(ep interface{}) (mask []byte) {
1817 e := *efaceOf(&ep)
1818 p := e.data
1819 t := e._type
1820
1821 for _, datap := range activeModules() {
1822
1823 if datap.data <= uintptr(p) && uintptr(p) < datap.edata {
1824 bitmap := datap.gcdatamask.bytedata
1825 n := (*ptrtype)(unsafe.Pointer(t)).elem.size
1826 mask = make([]byte, n/sys.PtrSize)
1827 for i := uintptr(0); i < n; i += sys.PtrSize {
1828 off := (uintptr(p) + i - datap.data) / sys.PtrSize
1829 mask[i/sys.PtrSize] = (*addb(bitmap, off/8) >> (off % 8)) & 1
1830 }
1831 return
1832 }
1833
1834
1835 if datap.bss <= uintptr(p) && uintptr(p) < datap.ebss {
1836 bitmap := datap.gcbssmask.bytedata
1837 n := (*ptrtype)(unsafe.Pointer(t)).elem.size
1838 mask = make([]byte, n/sys.PtrSize)
1839 for i := uintptr(0); i < n; i += sys.PtrSize {
1840 off := (uintptr(p) + i - datap.bss) / sys.PtrSize
1841 mask[i/sys.PtrSize] = (*addb(bitmap, off/8) >> (off % 8)) & 1
1842 }
1843 return
1844 }
1845 }
1846
1847
1848 var n uintptr
1849 var base uintptr
1850 if mlookup(uintptr(p), &base, &n, nil) != 0 {
1851 mask = make([]byte, n/sys.PtrSize)
1852 for i := uintptr(0); i < n; i += sys.PtrSize {
1853 hbits := heapBitsForAddr(base + i)
1854 if hbits.isPointer() {
1855 mask[i/sys.PtrSize] = 1
1856 }
1857 if i != 1*sys.PtrSize && !hbits.morePointers() {
1858 mask = mask[:i/sys.PtrSize]
1859 break
1860 }
1861 }
1862 return
1863 }
1864
1865
1866 if _g_ := getg(); _g_.m.curg.stack.lo <= uintptr(p) && uintptr(p) < _g_.m.curg.stack.hi {
1867 var frame stkframe
1868 frame.sp = uintptr(p)
1869 _g_ := getg()
1870 gentraceback(_g_.m.curg.sched.pc, _g_.m.curg.sched.sp, 0, _g_.m.curg, 0, nil, 1000, getgcmaskcb, noescape(unsafe.Pointer(&frame)), 0)
1871 if frame.fn.valid() {
1872 f := frame.fn
1873 targetpc := frame.continpc
1874 if targetpc == 0 {
1875 return
1876 }
1877 if targetpc != f.entry {
1878 targetpc--
1879 }
1880 pcdata := pcdatavalue(f, _PCDATA_StackMapIndex, targetpc, nil)
1881 if pcdata == -1 {
1882 return
1883 }
1884 stkmap := (*stackmap)(funcdata(f, _FUNCDATA_LocalsPointerMaps))
1885 if stkmap == nil || stkmap.n <= 0 {
1886 return
1887 }
1888 bv := stackmapdata(stkmap, pcdata)
1889 size := uintptr(bv.n) * sys.PtrSize
1890 n := (*ptrtype)(unsafe.Pointer(t)).elem.size
1891 mask = make([]byte, n/sys.PtrSize)
1892 for i := uintptr(0); i < n; i += sys.PtrSize {
1893 bitmap := bv.bytedata
1894 off := (uintptr(p) + i - frame.varp + size) / sys.PtrSize
1895 mask[i/sys.PtrSize] = (*addb(bitmap, off/8) >> (off % 8)) & 1
1896 }
1897 }
1898 return
1899 }
1900
1901
1902
1903
1904 return
1905 }
1906
View as plain text