mirror of
https://github.com/golang/go
synced 2024-11-23 17:20:02 -07:00
runtime: make maxOffAddr reflect the actual address space upper bound
Currently maxOffAddr is defined in terms of the whole 64-bit address space, assuming that it's all supported, by using ^uintptr(0) as the maximal address in the offset space. In reality, the maximal address in the offset space is (1<<heapAddrBits)-1 because we don't have more than that actually available to us on a given platform. On most platforms this is fine, because arenaBaseOffset is just connecting two segments of address space, but on AIX we use it as an actual offset for the starting address of the available address space, which is limited. This means using ^uintptr(0) as the maximal address in the offset address space causes wrap-around, especially when we just want to represent a range approximately like [addr, infinity), which today we do by using maxOffAddr. To fix this, we define maxOffAddr more appropriately, in terms of (1<<heapAddrBits)-1. This change also redefines arenaBaseOffset to not be the negation of the virtual address corresponding to address zero in the virtual address space, but instead directly as the virtual address corresponding to zero. This matches the existing documentation more closely and makes the logic around arenaBaseOffset decidedly simpler, especially when trying to reason about its use on AIX. Fixes #38966. Change-Id: I1336e5036a39de846f64cc2d253e8536dee57611 Reviewed-on: https://go-review.googlesource.com/c/go/+/233497 Run-TryBot: Michael Knyszek <mknyszek@google.com> Reviewed-by: Austin Clements <austin@google.com> Reviewed-by: Michael Pratt <mpratt@google.com>
This commit is contained in:
parent
364a05e2fe
commit
796786cd0c
@ -876,13 +876,9 @@ func FreePageAlloc(pp *PageAlloc) {
|
||||
// 64 bit and 32 bit platforms, allowing the tests to share code
|
||||
// between the two.
|
||||
//
|
||||
// On AIX, the arenaBaseOffset is 0x0a00000000000000. However, this
|
||||
// constant can't be used here because it is negative and will cause
|
||||
// a constant overflow.
|
||||
//
|
||||
// This should not be higher than 0x100*pallocChunkBytes to support
|
||||
// mips and mipsle, which only have 31-bit address spaces.
|
||||
var BaseChunkIdx = ChunkIdx(chunkIndex(((0xc000*pageAlloc64Bit + 0x100*pageAlloc32Bit) * pallocChunkBytes) + 0x0a00000000000000*sys.GoosAix))
|
||||
var BaseChunkIdx = ChunkIdx(chunkIndex(((0xc000*pageAlloc64Bit + 0x100*pageAlloc32Bit) * pallocChunkBytes) + arenaBaseOffset*sys.GoosAix))
|
||||
|
||||
// PageBase returns an address given a chunk index and a page index
|
||||
// relative to that chunk.
|
||||
|
@ -302,7 +302,7 @@ const (
|
||||
//
|
||||
// On other platforms, the user address space is contiguous
|
||||
// and starts at 0, so no offset is necessary.
|
||||
arenaBaseOffset = sys.GoarchAmd64*(1<<47) + (^0x0a00000000000000+1)&uintptrMask*sys.GoosAix
|
||||
arenaBaseOffset = 0xffff800000000000*sys.GoarchAmd64 + 0x0a00000000000000*sys.GoosAix
|
||||
|
||||
// Max number of threads to run garbage collection.
|
||||
// 2, 3, and 4 are all plausible maximums depending
|
||||
|
@ -576,13 +576,13 @@ func (sc spanClass) noscan() bool {
|
||||
//
|
||||
//go:nosplit
|
||||
func arenaIndex(p uintptr) arenaIdx {
|
||||
return arenaIdx((p + arenaBaseOffset) / heapArenaBytes)
|
||||
return arenaIdx((p - arenaBaseOffset) / heapArenaBytes)
|
||||
}
|
||||
|
||||
// arenaBase returns the low address of the region covered by heap
|
||||
// arena i.
|
||||
func arenaBase(i arenaIdx) uintptr {
|
||||
return uintptr(i)*heapArenaBytes - arenaBaseOffset
|
||||
return uintptr(i)*heapArenaBytes + arenaBaseOffset
|
||||
}
|
||||
|
||||
type arenaIdx uint
|
||||
|
@ -99,12 +99,12 @@ type chunkIdx uint
|
||||
// chunkIndex returns the global index of the palloc chunk containing the
|
||||
// pointer p.
|
||||
func chunkIndex(p uintptr) chunkIdx {
|
||||
return chunkIdx((p + arenaBaseOffset) / pallocChunkBytes)
|
||||
return chunkIdx((p - arenaBaseOffset) / pallocChunkBytes)
|
||||
}
|
||||
|
||||
// chunkIndex returns the base address of the palloc chunk at index ci.
|
||||
func chunkBase(ci chunkIdx) uintptr {
|
||||
return uintptr(ci)*pallocChunkBytes - arenaBaseOffset
|
||||
return uintptr(ci)*pallocChunkBytes + arenaBaseOffset
|
||||
}
|
||||
|
||||
// chunkPageIndex computes the index of the page that contains p,
|
||||
@ -136,13 +136,13 @@ func (i chunkIdx) l2() uint {
|
||||
// offAddrToLevelIndex converts an address in the offset address space
|
||||
// to the index into summary[level] containing addr.
|
||||
func offAddrToLevelIndex(level int, addr offAddr) int {
|
||||
return int((addr.a + arenaBaseOffset) >> levelShift[level])
|
||||
return int((addr.a - arenaBaseOffset) >> levelShift[level])
|
||||
}
|
||||
|
||||
// levelIndexToOffAddr converts an index into summary[level] into
|
||||
// the corresponding address in the offset address space.
|
||||
func levelIndexToOffAddr(level, idx int) offAddr {
|
||||
return offAddr{(uintptr(idx) << levelShift[level]) - arenaBaseOffset}
|
||||
return offAddr{(uintptr(idx) << levelShift[level]) + arenaBaseOffset}
|
||||
}
|
||||
|
||||
// addrsToSummaryRange converts base and limit pointers into a range
|
||||
@ -159,8 +159,8 @@ func addrsToSummaryRange(level int, base, limit uintptr) (lo int, hi int) {
|
||||
// of a summary's max page count boundary for this level
|
||||
// (1 << levelLogPages[level]). So, make limit an inclusive upper bound
|
||||
// then shift, then add 1, so we get an exclusive upper bound at the end.
|
||||
lo = int((base + arenaBaseOffset) >> levelShift[level])
|
||||
hi = int(((limit-1)+arenaBaseOffset)>>levelShift[level]) + 1
|
||||
lo = int((base - arenaBaseOffset) >> levelShift[level])
|
||||
hi = int(((limit-1)-arenaBaseOffset)>>levelShift[level]) + 1
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ type addrRange struct {
|
||||
// Throws if the base and limit are not in the same memory segment.
|
||||
func makeAddrRange(base, limit uintptr) addrRange {
|
||||
r := addrRange{offAddr{base}, offAddr{limit}}
|
||||
if (base+arenaBaseOffset >= arenaBaseOffset) != (limit+arenaBaseOffset >= arenaBaseOffset) {
|
||||
if (base-arenaBaseOffset >= base) != (limit-arenaBaseOffset >= limit) {
|
||||
throw("addr range base and limit are not in the same memory segment")
|
||||
}
|
||||
return r
|
||||
@ -71,33 +71,21 @@ func (a addrRange) subtract(b addrRange) addrRange {
|
||||
|
||||
var (
|
||||
// minOffAddr is the minimum address in the offset space, and
|
||||
// it corresponds to the virtual address -arenaBaseOffset.
|
||||
//
|
||||
// We don't initialize this with offAddrFromRaw because allocation
|
||||
// may happen during bootstrapping, and we rely on this value
|
||||
// being initialized.
|
||||
//
|
||||
// As a result, creating this value in Go is tricky because of
|
||||
// overflow not being allowed in constants. In order to get
|
||||
// the value we want, we take arenaBaseOffset and do a manual
|
||||
// two's complement negation, then mask that into what can fit
|
||||
// into a uintptr.
|
||||
minOffAddr = offAddr{((^arenaBaseOffset) + 1) & uintptrMask}
|
||||
// it corresponds to the virtual address arenaBaseOffset.
|
||||
minOffAddr = offAddr{arenaBaseOffset}
|
||||
|
||||
// maxOffAddr is the maximum address in the offset address
|
||||
// space, and it corresponds to the virtual address
|
||||
// ^uintptr(0) - arenaBaseOffset.
|
||||
//
|
||||
// We don't initialize this with offAddrFromRaw because allocation
|
||||
// may happen during bootstrapping, and we rely on this value
|
||||
// being initialized.
|
||||
maxOffAddr = offAddr{^uintptr(0) - arenaBaseOffset}
|
||||
// space. It corresponds to the highest virtual address representable
|
||||
// by the page alloc chunk and heap arena maps.
|
||||
maxOffAddr = offAddr{(((1 << heapAddrBits) - 1) + arenaBaseOffset) & uintptrMask}
|
||||
)
|
||||
|
||||
// offAddr represents an address in a contiguous view
|
||||
// of the address space on systems where the address space is
|
||||
// segmented. On other systems, it's just a normal address.
|
||||
type offAddr struct {
|
||||
// a is just the virtual address, but should never be used
|
||||
// directly. Call addr() to get this value instead.
|
||||
a uintptr
|
||||
}
|
||||
|
||||
@ -120,13 +108,13 @@ func (l1 offAddr) diff(l2 offAddr) uintptr {
|
||||
// lessThan returns true if l1 is less than l2 in the offset
|
||||
// address space.
|
||||
func (l1 offAddr) lessThan(l2 offAddr) bool {
|
||||
return (l1.a + arenaBaseOffset) < (l2.a + arenaBaseOffset)
|
||||
return (l1.a - arenaBaseOffset) < (l2.a - arenaBaseOffset)
|
||||
}
|
||||
|
||||
// lessEqual returns true if l1 is less than or equal to l2 in
|
||||
// the offset address space.
|
||||
func (l1 offAddr) lessEqual(l2 offAddr) bool {
|
||||
return (l1.a + arenaBaseOffset) <= (l2.a + arenaBaseOffset)
|
||||
return (l1.a - arenaBaseOffset) <= (l2.a - arenaBaseOffset)
|
||||
}
|
||||
|
||||
// equal returns true if the two offAddr values are equal.
|
||||
|
Loading…
Reference in New Issue
Block a user