Source file
src/runtime/mranges.go
1
2
3
4
5
6
7
8
9
10 package runtime
11
12 import (
13 "internal/goarch"
14 "internal/runtime/atomic"
15 "unsafe"
16 )
17
18
19
20
21 type addrRange struct {
22
23
24
25
26
27 base, limit offAddr
28 }
29
30
31
32
33 func 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
42 func (a addrRange) size() uintptr {
43 if !a.base.lessThan(a.limit) {
44 return 0
45 }
46
47
48 return a.limit.diff(a.base)
49 }
50
51
52 func (a addrRange) contains(addr uintptr) bool {
53 return a.base.lessEqual(offAddr{addr}) && (offAddr{addr}).lessThan(a.limit)
54 }
55
56
57
58
59
60 func (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
74
75
76 func (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
86
87
88 func (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
98
99 func (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
109 var (
110
111
112 minOffAddr = offAddr{arenaBaseOffset}
113
114
115
116
117 maxOffAddr = offAddr{(((1 << heapAddrBits) - 1) + arenaBaseOffset) & uintptrMask}
118 )
119
120
121
122
123 type offAddr struct {
124
125
126 a uintptr
127 }
128
129
130 func (l offAddr) add(bytes uintptr) offAddr {
131 return offAddr{a: l.a + bytes}
132 }
133
134
135 func (l offAddr) sub(bytes uintptr) offAddr {
136 return offAddr{a: l.a - bytes}
137 }
138
139
140
141 func (l1 offAddr) diff(l2 offAddr) uintptr {
142 return l1.a - l2.a
143 }
144
145
146
147 func (l1 offAddr) lessThan(l2 offAddr) bool {
148 return (l1.a - arenaBaseOffset) < (l2.a - arenaBaseOffset)
149 }
150
151
152
153 func (l1 offAddr) lessEqual(l2 offAddr) bool {
154 return (l1.a - arenaBaseOffset) <= (l2.a - arenaBaseOffset)
155 }
156
157
158 func (l1 offAddr) equal(l2 offAddr) bool {
159
160
161 return l1 == l2
162 }
163
164
165 func (l offAddr) addr() uintptr {
166 return l.a
167 }
168
169
170
171
172 type atomicOffAddr struct {
173
174 a atomic.Int64
175 }
176
177
178
179 func (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
192
193 func (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
207
208
209
210 func (b *atomicOffAddr) StoreUnmark(markedAddr, newAddr uintptr) {
211 b.a.CompareAndSwap(-int64(markedAddr-arenaBaseOffset), int64(newAddr-arenaBaseOffset))
212 }
213
214
215
216 func (b *atomicOffAddr) StoreMarked(addr uintptr) {
217 b.a.Store(-int64(addr - arenaBaseOffset))
218 }
219
220
221
222 func (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
233
234
235
236
237
238
239
240
241
242 type addrRanges struct {
243
244 ranges []addrRange
245
246
247
248 totalBytes uintptr
249
250
251 sysStat *sysMemStat
252 }
253
254 func (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
264
265 func (a *addrRanges) findSucc(addr uintptr) int {
266 base := offAddr{addr}
267
268
269
270
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
277
278 return i + 1
279 }
280 if base.lessThan(a.ranges[i].base) {
281
282
283
284 top = i
285 } else {
286
287
288
289
290
291 bot = i + 1
292 }
293 }
294
295
296
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
306
307
308
309
310 func (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
325 func (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
334
335
336 func (a *addrRanges) add(r addrRange) {
337
338
339
340
341
342
343
344
345
346
347
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
353
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
359
360 a.ranges[i-1].limit = a.ranges[i].limit
361
362
363 copy(a.ranges[i:], a.ranges[i+1:])
364 a.ranges = a.ranges[:len(a.ranges)-1]
365 } else if coalescesDown {
366
367
368 a.ranges[i-1].limit = r.limit
369 } else if coalescesUp {
370
371
372 a.ranges[i].base = r.base
373 } else {
374
375
376 if len(a.ranges)+1 > cap(a.ranges) {
377
378
379
380
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
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
400
401
402 func (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
420
421 func (a *addrRanges) removeGreaterEqual(addr uintptr) {
422 pivot := a.findSucc(addr)
423 if pivot == 0 {
424
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
448
449 func (a *addrRanges) cloneInto(b *addrRanges) {
450 if len(a.ranges) > cap(b.ranges) {
451
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
View as plain text