1// Copyright 2019 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// Address range data structure. 6// 7// This file contains an implementation of a data structure which 8// manages ordered address ranges. 9 10package runtime 11 12import ( 13 "internal/goarch" 14 "internal/runtime/atomic" 15 "unsafe" 16) 17 18// addrRange represents a region of address space. 19// 20// An addrRange must never span a gap in the address space. 21type addrRange struct { 22 // base and limit together represent the region of address space 23 // [base, limit). That is, base is inclusive, limit is exclusive. 24 // These are address over an offset view of the address space on 25 // platforms with a segmented address space, that is, on platforms 26 // where arenaBaseOffset != 0. 27 base, limit offAddr 28} 29 30// makeAddrRange creates a new address range from two virtual addresses. 31// 32// Throws if the base and limit are not in the same memory segment. 33func makeAddrRange(base, limit uintptr) addrRange { 34 r := addrRange{offAddr{base}, offAddr{limit}} 35 if (base-arenaBaseOffset >= base) != (limit-arenaBaseOffset >= limit) { 36 throw("addr range base and limit are not in the same memory segment") 37 } 38 return r 39} 40 41// size returns the size of the range represented in bytes. 42func (a addrRange) size() uintptr { 43 if !a.base.lessThan(a.limit) { 44 return 0 45 } 46 // Subtraction is safe because limit and base must be in the same 47 // segment of the address space. 48 return a.limit.diff(a.base) 49} 50 51// contains returns whether or not the range contains a given address. 52func (a addrRange) contains(addr uintptr) bool { 53 return a.base.lessEqual(offAddr{addr}) && (offAddr{addr}).lessThan(a.limit) 54} 55 56// subtract takes the addrRange toPrune and cuts out any overlap with 57// from, then returns the new range. subtract assumes that a and b 58// either don't overlap at all, only overlap on one side, or are equal. 59// If b is strictly contained in a, thus forcing a split, it will throw. 60func (a addrRange) subtract(b addrRange) addrRange { 61 if b.base.lessEqual(a.base) && a.limit.lessEqual(b.limit) { 62 return addrRange{} 63 } else if a.base.lessThan(b.base) && b.limit.lessThan(a.limit) { 64 throw("bad prune") 65 } else if b.limit.lessThan(a.limit) && a.base.lessThan(b.limit) { 66 a.base = b.limit 67 } else if a.base.lessThan(b.base) && b.base.lessThan(a.limit) { 68 a.limit = b.base 69 } 70 return a 71} 72 73// takeFromFront takes len bytes from the front of the address range, aligning 74// the base to align first. On success, returns the aligned start of the region 75// taken and true. 76func (a *addrRange) takeFromFront(len uintptr, align uint8) (uintptr, bool) { 77 base := alignUp(a.base.addr(), uintptr(align)) + len 78 if base > a.limit.addr() { 79 return 0, false 80 } 81 a.base = offAddr{base} 82 return base - len, true 83} 84 85// takeFromBack takes len bytes from the end of the address range, aligning 86// the limit to align after subtracting len. On success, returns the aligned 87// start of the region taken and true. 88func (a *addrRange) takeFromBack(len uintptr, align uint8) (uintptr, bool) { 89 limit := alignDown(a.limit.addr()-len, uintptr(align)) 90 if a.base.addr() > limit { 91 return 0, false 92 } 93 a.limit = offAddr{limit} 94 return limit, true 95} 96 97// removeGreaterEqual removes all addresses in a greater than or equal 98// to addr and returns the new range. 99func (a addrRange) removeGreaterEqual(addr uintptr) addrRange { 100 if (offAddr{addr}).lessEqual(a.base) { 101 return addrRange{} 102 } 103 if a.limit.lessEqual(offAddr{addr}) { 104 return a 105 } 106 return makeAddrRange(a.base.addr(), addr) 107} 108 109var ( 110 // minOffAddr is the minimum address in the offset space, and 111 // it corresponds to the virtual address arenaBaseOffset. 112 minOffAddr = offAddr{arenaBaseOffset} 113 114 // maxOffAddr is the maximum address in the offset address 115 // space. It corresponds to the highest virtual address representable 116 // by the page alloc chunk and heap arena maps. 117 maxOffAddr = offAddr{(((1 << heapAddrBits) - 1) + arenaBaseOffset) & uintptrMask} 118) 119 120// offAddr represents an address in a contiguous view 121// of the address space on systems where the address space is 122// segmented. On other systems, it's just a normal address. 123type offAddr struct { 124 // a is just the virtual address, but should never be used 125 // directly. Call addr() to get this value instead. 126 a uintptr 127} 128 129// add adds a uintptr offset to the offAddr. 130func (l offAddr) add(bytes uintptr) offAddr { 131 return offAddr{a: l.a + bytes} 132} 133 134// sub subtracts a uintptr offset from the offAddr. 135func (l offAddr) sub(bytes uintptr) offAddr { 136 return offAddr{a: l.a - bytes} 137} 138 139// diff returns the amount of bytes in between the 140// two offAddrs. 141func (l1 offAddr) diff(l2 offAddr) uintptr { 142 return l1.a - l2.a 143} 144 145// lessThan returns true if l1 is less than l2 in the offset 146// address space. 147func (l1 offAddr) lessThan(l2 offAddr) bool { 148 return (l1.a - arenaBaseOffset) < (l2.a - arenaBaseOffset) 149} 150 151// lessEqual returns true if l1 is less than or equal to l2 in 152// the offset address space. 153func (l1 offAddr) lessEqual(l2 offAddr) bool { 154 return (l1.a - arenaBaseOffset) <= (l2.a - arenaBaseOffset) 155} 156 157// equal returns true if the two offAddr values are equal. 158func (l1 offAddr) equal(l2 offAddr) bool { 159 // No need to compare in the offset space, it 160 // means the same thing. 161 return l1 == l2 162} 163 164// addr returns the virtual address for this offset address. 165func (l offAddr) addr() uintptr { 166 return l.a 167} 168 169// atomicOffAddr is like offAddr, but operations on it are atomic. 170// It also contains operations to be able to store marked addresses 171// to ensure that they're not overridden until they've been seen. 172type atomicOffAddr struct { 173 // a contains the offset address, unlike offAddr. 174 a atomic.Int64 175} 176 177// Clear attempts to store minOffAddr in atomicOffAddr. It may fail 178// if a marked value is placed in the box in the meanwhile. 179func (b *atomicOffAddr) Clear() { 180 for { 181 old := b.a.Load() 182 if old < 0 { 183 return 184 } 185 if b.a.CompareAndSwap(old, int64(minOffAddr.addr()-arenaBaseOffset)) { 186 return 187 } 188 } 189} 190 191// StoreMin stores addr if it's less than the current value in the 192// offset address space if the current value is not marked. 193func (b *atomicOffAddr) StoreMin(addr uintptr) { 194 new := int64(addr - arenaBaseOffset) 195 for { 196 old := b.a.Load() 197 if old < new { 198 return 199 } 200 if b.a.CompareAndSwap(old, new) { 201 return 202 } 203 } 204} 205 206// StoreUnmark attempts to unmark the value in atomicOffAddr and 207// replace it with newAddr. markedAddr must be a marked address 208// returned by Load. This function will not store newAddr if the 209// box no longer contains markedAddr. 210func (b *atomicOffAddr) StoreUnmark(markedAddr, newAddr uintptr) { 211 b.a.CompareAndSwap(-int64(markedAddr-arenaBaseOffset), int64(newAddr-arenaBaseOffset)) 212} 213 214// StoreMarked stores addr but first converted to the offset address 215// space and then negated. 216func (b *atomicOffAddr) StoreMarked(addr uintptr) { 217 b.a.Store(-int64(addr - arenaBaseOffset)) 218} 219 220// Load returns the address in the box as a virtual address. It also 221// returns if the value was marked or not. 222func (b *atomicOffAddr) Load() (uintptr, bool) { 223 v := b.a.Load() 224 wasMarked := false 225 if v < 0 { 226 wasMarked = true 227 v = -v 228 } 229 return uintptr(v) + arenaBaseOffset, wasMarked 230} 231 232// addrRanges is a data structure holding a collection of ranges of 233// address space. 234// 235// The ranges are coalesced eagerly to reduce the 236// number ranges it holds. 237// 238// The slice backing store for this field is persistentalloc'd 239// and thus there is no way to free it. 240// 241// addrRanges is not thread-safe. 242type addrRanges struct { 243 // ranges is a slice of ranges sorted by base. 244 ranges []addrRange 245 246 // totalBytes is the total amount of address space in bytes counted by 247 // this addrRanges. 248 totalBytes uintptr 249 250 // sysStat is the stat to track allocations by this type 251 sysStat *sysMemStat 252} 253 254func (a *addrRanges) init(sysStat *sysMemStat) { 255 ranges := (*notInHeapSlice)(unsafe.Pointer(&a.ranges)) 256 ranges.len = 0 257 ranges.cap = 16 258 ranges.array = (*notInHeap)(persistentalloc(unsafe.Sizeof(addrRange{})*uintptr(ranges.cap), goarch.PtrSize, sysStat)) 259 a.sysStat = sysStat 260 a.totalBytes = 0 261} 262 263// findSucc returns the first index in a such that addr is 264// less than the base of the addrRange at that index. 265func (a *addrRanges) findSucc(addr uintptr) int { 266 base := offAddr{addr} 267 268 // Narrow down the search space via a binary search 269 // for large addrRanges until we have at most iterMax 270 // candidates left. 271 const iterMax = 8 272 bot, top := 0, len(a.ranges) 273 for top-bot > iterMax { 274 i := int(uint(bot+top) >> 1) 275 if a.ranges[i].contains(base.addr()) { 276 // a.ranges[i] contains base, so 277 // its successor is the next index. 278 return i + 1 279 } 280 if base.lessThan(a.ranges[i].base) { 281 // In this case i might actually be 282 // the successor, but we can't be sure 283 // until we check the ones before it. 284 top = i 285 } else { 286 // In this case we know base is 287 // greater than or equal to a.ranges[i].limit-1, 288 // so i is definitely not the successor. 289 // We already checked i, so pick the next 290 // one. 291 bot = i + 1 292 } 293 } 294 // There are top-bot candidates left, so 295 // iterate over them and find the first that 296 // base is strictly less than. 297 for i := bot; i < top; i++ { 298 if base.lessThan(a.ranges[i].base) { 299 return i 300 } 301 } 302 return top 303} 304 305// findAddrGreaterEqual returns the smallest address represented by a 306// that is >= addr. Thus, if the address is represented by a, 307// then it returns addr. The second return value indicates whether 308// such an address exists for addr in a. That is, if addr is larger than 309// any address known to a, the second return value will be false. 310func (a *addrRanges) findAddrGreaterEqual(addr uintptr) (uintptr, bool) { 311 i := a.findSucc(addr) 312 if i == 0 { 313 return a.ranges[0].base.addr(), true 314 } 315 if a.ranges[i-1].contains(addr) { 316 return addr, true 317 } 318 if i < len(a.ranges) { 319 return a.ranges[i].base.addr(), true 320 } 321 return 0, false 322} 323 324// contains returns true if a covers the address addr. 325func (a *addrRanges) contains(addr uintptr) bool { 326 i := a.findSucc(addr) 327 if i == 0 { 328 return false 329 } 330 return a.ranges[i-1].contains(addr) 331} 332 333// add inserts a new address range to a. 334// 335// r must not overlap with any address range in a and r.size() must be > 0. 336func (a *addrRanges) add(r addrRange) { 337 // The copies in this function are potentially expensive, but this data 338 // structure is meant to represent the Go heap. At worst, copying this 339 // would take ~160µs assuming a conservative copying rate of 25 GiB/s (the 340 // copy will almost never trigger a page fault) for a 1 TiB heap with 4 MiB 341 // arenas which is completely discontiguous. ~160µs is still a lot, but in 342 // practice most platforms have 64 MiB arenas (which cuts this by a factor 343 // of 16) and Go heaps are usually mostly contiguous, so the chance that 344 // an addrRanges even grows to that size is extremely low. 345 346 // An empty range has no effect on the set of addresses represented 347 // by a, but passing a zero-sized range is almost always a bug. 348 if r.size() == 0 { 349 print("runtime: range = {", hex(r.base.addr()), ", ", hex(r.limit.addr()), "}\n") 350 throw("attempted to add zero-sized address range") 351 } 352 // Because we assume r is not currently represented in a, 353 // findSucc gives us our insertion index. 354 i := a.findSucc(r.base.addr()) 355 coalescesDown := i > 0 && a.ranges[i-1].limit.equal(r.base) 356 coalescesUp := i < len(a.ranges) && r.limit.equal(a.ranges[i].base) 357 if coalescesUp && coalescesDown { 358 // We have neighbors and they both border us. 359 // Merge a.ranges[i-1], r, and a.ranges[i] together into a.ranges[i-1]. 360 a.ranges[i-1].limit = a.ranges[i].limit 361 362 // Delete a.ranges[i]. 363 copy(a.ranges[i:], a.ranges[i+1:]) 364 a.ranges = a.ranges[:len(a.ranges)-1] 365 } else if coalescesDown { 366 // We have a neighbor at a lower address only and it borders us. 367 // Merge the new space into a.ranges[i-1]. 368 a.ranges[i-1].limit = r.limit 369 } else if coalescesUp { 370 // We have a neighbor at a higher address only and it borders us. 371 // Merge the new space into a.ranges[i]. 372 a.ranges[i].base = r.base 373 } else { 374 // We may or may not have neighbors which don't border us. 375 // Add the new range. 376 if len(a.ranges)+1 > cap(a.ranges) { 377 // Grow the array. Note that this leaks the old array, but since 378 // we're doubling we have at most 2x waste. For a 1 TiB heap and 379 // 4 MiB arenas which are all discontiguous (both very conservative 380 // assumptions), this would waste at most 4 MiB of memory. 381 oldRanges := a.ranges 382 ranges := (*notInHeapSlice)(unsafe.Pointer(&a.ranges)) 383 ranges.len = len(oldRanges) + 1 384 ranges.cap = cap(oldRanges) * 2 385 ranges.array = (*notInHeap)(persistentalloc(unsafe.Sizeof(addrRange{})*uintptr(ranges.cap), goarch.PtrSize, a.sysStat)) 386 387 // Copy in the old array, but make space for the new range. 388 copy(a.ranges[:i], oldRanges[:i]) 389 copy(a.ranges[i+1:], oldRanges[i:]) 390 } else { 391 a.ranges = a.ranges[:len(a.ranges)+1] 392 copy(a.ranges[i+1:], a.ranges[i:]) 393 } 394 a.ranges[i] = r 395 } 396 a.totalBytes += r.size() 397} 398 399// removeLast removes and returns the highest-addressed contiguous range 400// of a, or the last nBytes of that range, whichever is smaller. If a is 401// empty, it returns an empty range. 402func (a *addrRanges) removeLast(nBytes uintptr) addrRange { 403 if len(a.ranges) == 0 { 404 return addrRange{} 405 } 406 r := a.ranges[len(a.ranges)-1] 407 size := r.size() 408 if size > nBytes { 409 newEnd := r.limit.sub(nBytes) 410 a.ranges[len(a.ranges)-1].limit = newEnd 411 a.totalBytes -= nBytes 412 return addrRange{newEnd, r.limit} 413 } 414 a.ranges = a.ranges[:len(a.ranges)-1] 415 a.totalBytes -= size 416 return r 417} 418 419// removeGreaterEqual removes the ranges of a which are above addr, and additionally 420// splits any range containing addr. 421func (a *addrRanges) removeGreaterEqual(addr uintptr) { 422 pivot := a.findSucc(addr) 423 if pivot == 0 { 424 // addr is before all ranges in a. 425 a.totalBytes = 0 426 a.ranges = a.ranges[:0] 427 return 428 } 429 removed := uintptr(0) 430 for _, r := range a.ranges[pivot:] { 431 removed += r.size() 432 } 433 if r := a.ranges[pivot-1]; r.contains(addr) { 434 removed += r.size() 435 r = r.removeGreaterEqual(addr) 436 if r.size() == 0 { 437 pivot-- 438 } else { 439 removed -= r.size() 440 a.ranges[pivot-1] = r 441 } 442 } 443 a.ranges = a.ranges[:pivot] 444 a.totalBytes -= removed 445} 446 447// cloneInto makes a deep clone of a's state into b, re-using 448// b's ranges if able. 449func (a *addrRanges) cloneInto(b *addrRanges) { 450 if len(a.ranges) > cap(b.ranges) { 451 // Grow the array. 452 ranges := (*notInHeapSlice)(unsafe.Pointer(&b.ranges)) 453 ranges.len = 0 454 ranges.cap = cap(a.ranges) 455 ranges.array = (*notInHeap)(persistentalloc(unsafe.Sizeof(addrRange{})*uintptr(ranges.cap), goarch.PtrSize, b.sysStat)) 456 } 457 b.ranges = b.ranges[:len(a.ranges)] 458 b.totalBytes = a.totalBytes 459 copy(b.ranges, a.ranges) 460} 461