@@ -81,15 +81,14 @@ const (
81
81
// there should this change.
82
82
pallocChunksL2Bits = heapAddrBits - logPallocChunkBytes - pallocChunksL1Bits
83
83
pallocChunksL1Shift = pallocChunksL2Bits
84
-
85
- // Maximum searchAddr value, which indicates that the heap has no free space.
86
- //
87
- // We subtract arenaBaseOffset because we want this to represent the maximum
88
- // value in the shifted address space, but searchAddr is stored as a regular
89
- // memory address. See arenaBaseOffset for details.
90
- maxSearchAddr = ^ uintptr (0 ) - arenaBaseOffset
91
84
)
92
85
86
+ // Maximum searchAddr value, which indicates that the heap has no free space.
87
+ //
88
+ // We alias maxOffAddr just to make it clear that this is the maximum address
89
+ // for the page allocator's search space. See maxOffAddr for details.
90
+ var maxSearchAddr = maxOffAddr
91
+
93
92
// Global chunk index.
94
93
//
95
94
// Represents an index into the leaf level of the radix tree.
@@ -134,6 +133,18 @@ func (i chunkIdx) l2() uint {
134
133
}
135
134
}
136
135
136
+ // offAddrToLevelIndex converts an address in the offset address space
137
+ // to the index into summary[level] containing addr.
138
+ func offAddrToLevelIndex (level int , addr offAddr ) int {
139
+ return int ((addr .a + arenaBaseOffset ) >> levelShift [level ])
140
+ }
141
+
142
+ // levelIndexToOffAddr converts an index into summary[level] into
143
+ // the corresponding address in the offset address space.
144
+ func levelIndexToOffAddr (level , idx int ) offAddr {
145
+ return offAddr {(uintptr (idx ) << levelShift [level ]) - arenaBaseOffset }
146
+ }
147
+
137
148
// addrsToSummaryRange converts base and limit pointers into a range
138
149
// of entries for the given summary level.
139
150
//
@@ -232,7 +243,7 @@ type pageAlloc struct {
232
243
// Note that adding in arenaBaseOffset transforms addresses
233
244
// to a new address space with a linear view of the full address
234
245
// space on architectures with segmented address spaces.
235
- searchAddr uintptr
246
+ searchAddr offAddr
236
247
237
248
// start and end represent the chunk indices
238
249
// which pageAlloc knows about. It assumes
@@ -271,13 +282,13 @@ type pageAlloc struct {
271
282
// released is the amount of memory released this generation.
272
283
released uintptr
273
284
274
- // scavLWM is the lowest address that the scavenger reached this
285
+ // scavLWM is the lowest (offset) address that the scavenger reached this
275
286
// scavenge generation.
276
- scavLWM uintptr
287
+ scavLWM offAddr
277
288
278
- // freeHWM is the highest address of a page that was freed to
289
+ // freeHWM is the highest (offset) address of a page that was freed to
279
290
// the page allocator this scavenge generation.
280
- freeHWM uintptr
291
+ freeHWM offAddr
281
292
}
282
293
283
294
// mheap_.lock. This level of indirection makes it possible
@@ -319,29 +330,6 @@ func (s *pageAlloc) init(mheapLock *mutex, sysStat *uint64) {
319
330
s .scav .scavLWM = maxSearchAddr
320
331
}
321
332
322
- // compareSearchAddrTo compares an address against s.searchAddr in a linearized
323
- // view of the address space on systems with discontinuous process address spaces.
324
- // This linearized view is the same one generated by chunkIndex and arenaIndex,
325
- // done by adding arenaBaseOffset.
326
- //
327
- // On systems without a discontinuous address space, it's just a normal comparison.
328
- //
329
- // Returns < 0 if addr is less than s.searchAddr in the linearized address space.
330
- // Returns > 0 if addr is greater than s.searchAddr in the linearized address space.
331
- // Returns 0 if addr and s.searchAddr are equal.
332
- func (s * pageAlloc ) compareSearchAddrTo (addr uintptr ) int {
333
- // Compare with arenaBaseOffset added because it gives us a linear, contiguous view
334
- // of the heap on architectures with signed address spaces.
335
- lAddr := addr + arenaBaseOffset
336
- lSearchAddr := s .searchAddr + arenaBaseOffset
337
- if lAddr < lSearchAddr {
338
- return - 1
339
- } else if lAddr > lSearchAddr {
340
- return 1
341
- }
342
- return 0
343
- }
344
-
345
333
// chunkOf returns the chunk at the given chunk index.
346
334
func (s * pageAlloc ) chunkOf (ci chunkIdx ) * pallocData {
347
335
return & s .chunks [ci .l1 ()][ci .l2 ()]
@@ -378,10 +366,10 @@ func (s *pageAlloc) grow(base, size uintptr) {
378
366
s .inUse .add (makeAddrRange (base , limit ))
379
367
380
368
// A grow operation is a lot like a free operation, so if our
381
- // chunk ends up below the (linearized) s.searchAddr, update
382
- // s.searchAddr to the new address, just like in free.
383
- if s . compareSearchAddrTo ( base ) < 0 {
384
- s .searchAddr = base
369
+ // chunk ends up below s.searchAddr, update s.searchAddr to the
370
+ // new address, just like in free.
371
+ if b := ( offAddr { base }); b . lessThan ( s . searchAddr ) {
372
+ s .searchAddr = b
385
373
}
386
374
387
375
// Add entries into chunks, which is sparse, if needed. Then,
@@ -545,7 +533,7 @@ func (s *pageAlloc) allocRange(base, npages uintptr) uintptr {
545
533
// searchAddr returned is invalid and must be ignored.
546
534
//
547
535
// s.mheapLock must be held.
548
- func (s * pageAlloc ) find (npages uintptr ) (uintptr , uintptr ) {
536
+ func (s * pageAlloc ) find (npages uintptr ) (uintptr , offAddr ) {
549
537
// Search algorithm.
550
538
//
551
539
// This algorithm walks each level l of the radix tree from the root level
@@ -585,13 +573,13 @@ func (s *pageAlloc) find(npages uintptr) (uintptr, uintptr) {
585
573
// firstFree is updated by calling foundFree each time free space in the
586
574
// heap is discovered.
587
575
//
588
- // At the end of the search, base-arenaBaseOffset is the best new
576
+ // At the end of the search, base.addr() is the best new
589
577
// searchAddr we could deduce in this search.
590
578
firstFree := struct {
591
- base , bound uintptr
579
+ base , bound offAddr
592
580
}{
593
- base : 0 ,
594
- bound : ( 1 << heapAddrBits - 1 ) ,
581
+ base : minOffAddr ,
582
+ bound : maxOffAddr ,
595
583
}
596
584
// foundFree takes the given address range [addr, addr+size) and
597
585
// updates firstFree if it is a narrower range. The input range must
@@ -602,17 +590,17 @@ func (s *pageAlloc) find(npages uintptr) (uintptr, uintptr) {
602
590
// pages on the root level and narrow that down if we descend into
603
591
// that summary. But as soon as we need to iterate beyond that summary
604
592
// in a level to find a large enough range, we'll stop narrowing.
605
- foundFree := func (addr , size uintptr ) {
606
- if firstFree .base <= addr && addr + size - 1 <= firstFree .bound {
593
+ foundFree := func (addr offAddr , size uintptr ) {
594
+ if firstFree .base . lessEqual ( addr ) && addr . add ( size - 1 ). lessEqual ( firstFree .bound ) {
607
595
// This range fits within the current firstFree window, so narrow
608
596
// down the firstFree window to the base and bound of this range.
609
597
firstFree .base = addr
610
- firstFree .bound = addr + size - 1
611
- } else if ! (addr + size - 1 < firstFree .base || addr > firstFree .bound ) {
598
+ firstFree .bound = addr . add ( size - 1 )
599
+ } else if ! (addr . add ( size - 1 ). lessThan ( firstFree .base ) || firstFree .bound . lessThan ( addr ) ) {
612
600
// This range only partially overlaps with the firstFree range,
613
601
// so throw.
614
- print ("runtime: addr = " , hex (addr ), ", size = " , size , "\n " )
615
- print ("runtime: base = " , hex (firstFree .base ) , ", bound = " , hex (firstFree .bound ), "\n " )
602
+ print ("runtime: addr = " , hex (addr . addr () ), ", size = " , size , "\n " )
603
+ print ("runtime: base = " , hex (firstFree .base . addr ()) , ", bound = " , hex (firstFree .bound . addr () ), "\n " )
616
604
throw ("range partially overlaps" )
617
605
}
618
606
}
@@ -642,7 +630,7 @@ nextLevel:
642
630
// searchAddr on the previous level or we're on the root leve, in which
643
631
// case the searchAddr should be the same as i after levelShift.
644
632
j0 := 0
645
- if searchIdx := int (( s .searchAddr + arenaBaseOffset ) >> levelShift [ l ] ); searchIdx &^(entriesPerBlock - 1 ) == i {
633
+ if searchIdx := offAddrToLevelIndex ( l , s .searchAddr ); searchIdx &^(entriesPerBlock - 1 ) == i {
646
634
j0 = searchIdx & (entriesPerBlock - 1 )
647
635
}
648
636
@@ -668,7 +656,7 @@ nextLevel:
668
656
669
657
// We've encountered a non-zero summary which means
670
658
// free memory, so update firstFree.
671
- foundFree (uintptr (( i + j ) << levelShift [ l ] ), (uintptr (1 )<< logMaxPages )* pageSize )
659
+ foundFree (levelIndexToOffAddr ( l , i + j ), (uintptr (1 )<< logMaxPages )* pageSize )
672
660
673
661
s := sum .start ()
674
662
if size + s >= uint (npages ) {
@@ -706,8 +694,8 @@ nextLevel:
706
694
if size >= uint (npages ) {
707
695
// We found a sufficiently large run of free pages straddling
708
696
// some boundary, so compute the address and return it.
709
- addr := uintptr ( i << levelShift [ l ]) - arenaBaseOffset + uintptr (base )* pageSize
710
- return addr , firstFree .base - arenaBaseOffset
697
+ addr := levelIndexToOffAddr ( l , i ). add ( uintptr (base ) * pageSize ). addr ()
698
+ return addr , firstFree .base
711
699
}
712
700
if l == 0 {
713
701
// We're at level zero, so that means we've exhausted our search.
@@ -719,7 +707,7 @@ nextLevel:
719
707
// lied to us. In either case, dump some useful state and throw.
720
708
print ("runtime: summary[" , l - 1 , "][" , lastSumIdx , "] = " , lastSum .start (), ", " , lastSum .max (), ", " , lastSum .end (), "\n " )
721
709
print ("runtime: level = " , l , ", npages = " , npages , ", j0 = " , j0 , "\n " )
722
- print ("runtime: s.searchAddr = " , hex (s .searchAddr ), ", i = " , i , "\n " )
710
+ print ("runtime: s.searchAddr = " , hex (s .searchAddr . addr () ), ", i = " , i , "\n " )
723
711
print ("runtime: levelShift[level] = " , levelShift [l ], ", levelBits[level] = " , levelBits [l ], "\n " )
724
712
for j := 0 ; j < len (entries ); j ++ {
725
713
sum := entries [j ]
@@ -752,8 +740,8 @@ nextLevel:
752
740
// Since we actually searched the chunk, we may have
753
741
// found an even narrower free window.
754
742
searchAddr := chunkBase (ci ) + uintptr (searchIdx )* pageSize
755
- foundFree (searchAddr + arenaBaseOffset , chunkBase (ci + 1 )- searchAddr )
756
- return addr , firstFree .base - arenaBaseOffset
743
+ foundFree (offAddr { searchAddr } , chunkBase (ci + 1 )- searchAddr )
744
+ return addr , firstFree .base
757
745
}
758
746
759
747
// alloc allocates npages worth of memory from the page heap, returning the base
@@ -767,25 +755,25 @@ nextLevel:
767
755
func (s * pageAlloc ) alloc (npages uintptr ) (addr uintptr , scav uintptr ) {
768
756
// If the searchAddr refers to a region which has a higher address than
769
757
// any known chunk, then we know we're out of memory.
770
- if chunkIndex (s .searchAddr ) >= s .end {
758
+ if chunkIndex (s .searchAddr . addr () ) >= s .end {
771
759
return 0 , 0
772
760
}
773
761
774
762
// If npages has a chance of fitting in the chunk where the searchAddr is,
775
763
// search it directly.
776
- searchAddr := uintptr ( 0 )
777
- if pallocChunkPages - chunkPageIndex (s .searchAddr ) >= uint (npages ) {
764
+ searchAddr := minOffAddr
765
+ if pallocChunkPages - chunkPageIndex (s .searchAddr . addr () ) >= uint (npages ) {
778
766
// npages is guaranteed to be no greater than pallocChunkPages here.
779
- i := chunkIndex (s .searchAddr )
767
+ i := chunkIndex (s .searchAddr . addr () )
780
768
if max := s .summary [len (s .summary )- 1 ][i ].max (); max >= uint (npages ) {
781
- j , searchIdx := s .chunkOf (i ).find (npages , chunkPageIndex (s .searchAddr ))
769
+ j , searchIdx := s .chunkOf (i ).find (npages , chunkPageIndex (s .searchAddr . addr () ))
782
770
if j == ^ uint (0 ) {
783
771
print ("runtime: max = " , max , ", npages = " , npages , "\n " )
784
- print ("runtime: searchIdx = " , chunkPageIndex (s .searchAddr ) , ", s.searchAddr = " , hex (s .searchAddr ), "\n " )
772
+ print ("runtime: searchIdx = " , chunkPageIndex (s .searchAddr . addr ()) , ", s.searchAddr = " , hex (s .searchAddr . addr () ), "\n " )
785
773
throw ("bad summary data" )
786
774
}
787
775
addr = chunkBase (i ) + uintptr (j )* pageSize
788
- searchAddr = chunkBase (i ) + uintptr (searchIdx )* pageSize
776
+ searchAddr = offAddr { chunkBase (i ) + uintptr (searchIdx )* pageSize }
789
777
goto Found
790
778
}
791
779
}
@@ -807,10 +795,10 @@ Found:
807
795
// Go ahead and actually mark the bits now that we have an address.
808
796
scav = s .allocRange (addr , npages )
809
797
810
- // If we found a higher (linearized) searchAddr, we know that all the
811
- // heap memory before that searchAddr in a linear address space is
798
+ // If we found a higher searchAddr, we know that all the
799
+ // heap memory before that searchAddr in an offset address space is
812
800
// allocated, so bump s.searchAddr up to the new one.
813
- if s .compareSearchAddrTo (searchAddr ) > 0 {
801
+ if s .searchAddr . lessThan (searchAddr ) {
814
802
s .searchAddr = searchAddr
815
803
}
816
804
return addr , scav
@@ -820,14 +808,14 @@ Found:
820
808
//
821
809
// s.mheapLock must be held.
822
810
func (s * pageAlloc ) free (base , npages uintptr ) {
823
- // If we're freeing pages below the (linearized) s.searchAddr, update searchAddr.
824
- if s . compareSearchAddrTo ( base ) < 0 {
825
- s .searchAddr = base
811
+ // If we're freeing pages below the s.searchAddr, update searchAddr.
812
+ if b := ( offAddr { base }); b . lessThan ( s . searchAddr ) {
813
+ s .searchAddr = b
826
814
}
827
815
// Update the free high watermark for the scavenger.
828
816
limit := base + npages * pageSize - 1
829
- if s .scav .freeHWM < limit {
830
- s .scav .freeHWM = limit
817
+ if offLimit := ( offAddr { limit }); s .scav .freeHWM . lessThan ( offLimit ) {
818
+ s .scav .freeHWM = offLimit
831
819
}
832
820
if npages == 1 {
833
821
// Fast path: we're clearing a single bit, and we know exactly
0 commit comments