30
30
// indicates scanning can ignore the rest of the allocation.
31
31
//
32
32
// The 2-bit entries are split when written into the byte, so that the top half
33
- // of the byte contains 4 high bits and the bottom half contains 4 low (pointer)
34
- // bits.
35
- // This form allows a copy from the 1-bit to the 4-bit form to keep the
36
- // pointer bits contiguous, instead of having to space them out.
33
+ // of the byte contains 4 high (scan) bits and the bottom half contains 4 low
34
+ // (pointer) bits. This form allows a copy from the 1-bit to the 4-bit form to
35
+ // keep the pointer bits contiguous, instead of having to space them out.
37
36
//
38
37
// The code makes use of the fact that the zero value for a heap
39
38
// bitmap means scalar/dead. This property must be preserved when
@@ -816,6 +815,12 @@ func (s *mspan) countAlloc() int {
816
815
func heapBitsSetType (x , size , dataSize uintptr , typ * _type ) {
817
816
const doubleCheck = false // slow but helpful; enable to test modifications to this code
818
817
818
+ const (
819
+ mask1 = bitPointer | bitScan // 00010001
820
+ mask2 = bitPointer | bitScan | mask1 << heapBitsShift // 00110011
821
+ mask3 = bitPointer | bitScan | mask2 << heapBitsShift // 01110111
822
+ )
823
+
819
824
// dataSize is always size rounded up to the next malloc size class,
820
825
// except in the case of allocating a defer block, in which case
821
826
// size is sizeof(_defer{}) (at least 6 words) and dataSize may be
@@ -844,11 +849,12 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) {
844
849
h := heapBitsForAddr (x )
845
850
ptrmask := typ .gcdata // start of 1-bit pointer mask (or GC program, handled below)
846
851
847
- // Heap bitmap bits for 2-word object are only 4 bits,
848
- // so also shared with objects next to it.
849
- // This is called out as a special case primarily for 32-bit systems,
850
- // so that on 32-bit systems the code below can assume all objects
851
- // are 4-word aligned (because they're all 16-byte aligned).
852
+ // 2-word objects only have 4 bitmap bits and 3-word objects only have 6 bitmap bits.
853
+ // Therefore, these objects share a heap bitmap byte with the objects next to them.
854
+ // These are called out as a special case primarily so the code below can assume all
855
+ // objects are at least 4 words long and that their bitmaps start either at the beginning
856
+ // of a bitmap byte, or half-way in (h.shift of 0 and 2 respectively).
857
+
852
858
if size == 2 * sys .PtrSize {
853
859
if typ .size == sys .PtrSize {
854
860
// We're allocating a block big enough to hold two pointers.
@@ -865,7 +871,7 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) {
865
871
* h .bitp &^= (bitPointer | bitScan | (bitPointer | bitScan )<< heapBitsShift ) << h .shift
866
872
* h .bitp |= (bitPointer | bitScan ) << h .shift
867
873
} else {
868
- // 2-element slice of pointer.
874
+ // 2-element array of pointer.
869
875
* h .bitp |= (bitPointer | bitScan | (bitPointer | bitScan )<< heapBitsShift ) << h .shift
870
876
}
871
877
return
@@ -886,6 +892,70 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) {
886
892
* h .bitp &^= (bitPointer | bitScan | ((bitPointer | bitScan ) << heapBitsShift )) << h .shift
887
893
* h .bitp |= uint8 (hb << h .shift )
888
894
return
895
+ } else if size == 3 * sys .PtrSize {
896
+ b := uint8 (* ptrmask )
897
+ if doubleCheck {
898
+ if b == 0 {
899
+ println ("runtime: invalid type " , typ .string ())
900
+ throw ("heapBitsSetType: called with non-pointer type" )
901
+ }
902
+ if sys .PtrSize != 8 {
903
+ throw ("heapBitsSetType: unexpected 3 pointer wide size class on 32 bit" )
904
+ }
905
+ if typ .kind & kindGCProg != 0 {
906
+ throw ("heapBitsSetType: unexpected GC prog for 3 pointer wide size class" )
907
+ }
908
+ if typ .size == 2 * sys .PtrSize {
909
+ print ("runtime: heapBitsSetType size=" , size , " but typ.size=" , typ .size , "\n " )
910
+ throw ("heapBitsSetType: inconsistent object sizes" )
911
+ }
912
+ }
913
+ if typ .size == sys .PtrSize {
914
+ // The type contains a pointer otherwise heapBitsSetType wouldn't have been called.
915
+ // Since the type is only 1 pointer wide and contains a pointer, its gcdata must be exactly 1.
916
+ if doubleCheck && * typ .gcdata != 1 {
917
+ print ("runtime: heapBitsSetType size=" , size , " typ.size=" , typ .size , "but *typ.gcdata" , * typ .gcdata , "\n " )
918
+ throw ("heapBitsSetType: unexpected gcdata for 1 pointer wide type size in 3 pointer wide size class" )
919
+ }
920
+ // 3 element array of pointers. Unrolling ptrmask 3 times into p yields 00000111.
921
+ b = 7
922
+ }
923
+
924
+ hb := b & 7
925
+ // Set bitScan bits for all pointers.
926
+ hb |= hb << wordsPerBitmapByte
927
+ // First bitScan bit is always set since the type contains pointers.
928
+ hb |= bitScan
929
+ // Second bitScan bit needs to also be set if the third bitScan bit is set.
930
+ hb |= hb & (bitScan << (2 * heapBitsShift )) >> 1
931
+
932
+ // For h.shift > 1 heap bits cross a byte boundary and need to be written part
933
+ // to h.bitp and part to the next h.bitp.
934
+ switch h .shift {
935
+ case 0 :
936
+ * h .bitp &^= mask3 << 0
937
+ * h .bitp |= hb << 0
938
+ case 1 :
939
+ * h .bitp &^= mask3 << 1
940
+ * h .bitp |= hb << 1
941
+ case 2 :
942
+ * h .bitp &^= mask2 << 2
943
+ * h .bitp |= (hb & mask2 ) << 2
944
+ // Two words written to the first byte.
945
+ // Advance two words to get to the next byte.
946
+ h = h .next ().next ()
947
+ * h .bitp &^= mask1
948
+ * h .bitp |= (hb >> 2 ) & mask1
949
+ case 3 :
950
+ * h .bitp &^= mask1 << 3
951
+ * h .bitp |= (hb & mask1 ) << 3
952
+ // One word written to the first byte.
953
+ // Advance one word to get to the next byte.
954
+ h = h .next ()
955
+ * h .bitp &^= mask2
956
+ * h .bitp |= (hb >> 1 ) & mask2
957
+ }
958
+ return
889
959
}
890
960
891
961
// Copy from 1-bit ptrmask into 2-bit bitmap.
@@ -1079,7 +1149,7 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) {
1079
1149
// word must be set to scan since there are pointers
1080
1150
// somewhere in the object.
1081
1151
// In all following words, we set the scan/dead
1082
- // appropriately to indicate that the object contains
1152
+ // appropriately to indicate that the object continues
1083
1153
// to the next 2-bit entry in the bitmap.
1084
1154
//
1085
1155
// We set four bits at a time here, but if the object
@@ -1095,12 +1165,22 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) {
1095
1165
b >>= 4
1096
1166
nb -= 4
1097
1167
1098
- case sys . PtrSize == 8 && h .shift == 2 :
1168
+ case h .shift == 2 :
1099
1169
// Ptrmask and heap bitmap are misaligned.
1170
+ //
1171
+ // On 32 bit architectures only the 6-word object that corresponds
1172
+ // to a 24 bytes size class can start with h.shift of 2 here since
1173
+ // all other non 16 byte aligned size classes have been handled by
1174
+ // special code paths at the beginning of heapBitsSetType on 32 bit.
1175
+ //
1176
+ // Many size classes are only 16 byte aligned. On 64 bit architectures
1177
+ // this results in a heap bitmap position starting with a h.shift of 2.
1178
+ //
1100
1179
// The bits for the first two words are in a byte shared
1101
1180
// with another object, so we must be careful with the bits
1102
1181
// already there.
1103
- // We took care of 1-word and 2-word objects above,
1182
+ //
1183
+ // We took care of 1-word, 2-word, and 3-word objects above,
1104
1184
// so this is at least a 6-word object.
1105
1185
hb = (b & (bitPointer | bitPointer << heapBitsShift )) << (2 * heapBitsShift )
1106
1186
hb |= bitScan << (2 * heapBitsShift )
@@ -1113,7 +1193,7 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) {
1113
1193
* hbitp |= uint8 (hb )
1114
1194
hbitp = add1 (hbitp )
1115
1195
if w += 2 ; w >= nw {
1116
- // We know that there is more data, because we handled 2-word objects above.
1196
+ // We know that there is more data, because we handled 2-word and 3-word objects above.
1117
1197
// This must be at least a 6-word object. If we're out of pointer words,
1118
1198
// mark no scan in next bitmap byte and finish.
1119
1199
hb = 0
@@ -1248,12 +1328,12 @@ Phase4:
1248
1328
// Handle the first byte specially if it's shared. See
1249
1329
// Phase 1 for why this is the only special case we need.
1250
1330
if doubleCheck {
1251
- if ! (h .shift == 0 || ( sys . PtrSize == 8 && h .shift == 2 ) ) {
1331
+ if ! (h .shift == 0 || h .shift == 2 ) {
1252
1332
print ("x=" , x , " size=" , size , " cnw=" , h .shift , "\n " )
1253
1333
throw ("bad start shift" )
1254
1334
}
1255
1335
}
1256
- if sys . PtrSize == 8 && h .shift == 2 {
1336
+ if h .shift == 2 {
1257
1337
* h .bitp = * h .bitp &^((bitPointer | bitScan | (bitPointer | bitScan )<< heapBitsShift )<< (2 * heapBitsShift )) | * src
1258
1338
h = h .next ().next ()
1259
1339
cnw -= 2
0 commit comments