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 "unsafe"
15 )
16
17
18
19
20 type addrRange struct {
21
22
23
24
25
26 base, limit offAddr
27 }
28
29
30
31
32 func makeAddrRange(base, limit uintptr) addrRange {
33 r := addrRange{offAddr{base}, offAddr{limit}}
34 if (base-arenaBaseOffset >= base) != (limit-arenaBaseOffset >= limit) {
35 throw("addr range base and limit are not in the same memory segment")
36 }
37 return r
38 }
39
40
41 func (a addrRange) size() uintptr {
42 if !a.base.lessThan(a.limit) {
43 return 0
44 }
45
46
47 return a.limit.diff(a.base)
48 }
49
50
51 func (a addrRange) contains(addr uintptr) bool {
52 return a.base.lessEqual(offAddr{addr}) && (offAddr{addr}).lessThan(a.limit)
53 }
54
55
56
57
58
59 func (a addrRange) subtract(b addrRange) addrRange {
60 if b.base.lessEqual(a.base) && a.limit.lessEqual(b.limit) {
61 return addrRange{}
62 } else if a.base.lessThan(b.base) && b.limit.lessThan(a.limit) {
63 throw("bad prune")
64 } else if b.limit.lessThan(a.limit) && a.base.lessThan(b.limit) {
65 a.base = b.limit
66 } else if a.base.lessThan(b.base) && b.base.lessThan(a.limit) {
67 a.limit = b.base
68 }
69 return a
70 }
71
72
73
74 func (a addrRange) removeGreaterEqual(addr uintptr) addrRange {
75 if (offAddr{addr}).lessEqual(a.base) {
76 return addrRange{}
77 }
78 if a.limit.lessEqual(offAddr{addr}) {
79 return a
80 }
81 return makeAddrRange(a.base.addr(), addr)
82 }
83
84 var (
85
86
87 minOffAddr = offAddr{arenaBaseOffset}
88
89
90
91
92 maxOffAddr = offAddr{(((1 << heapAddrBits) - 1) + arenaBaseOffset) & uintptrMask}
93 )
94
95
96
97
98 type offAddr struct {
99
100
101 a uintptr
102 }
103
104
105 func (l offAddr) add(bytes uintptr) offAddr {
106 return offAddr{a: l.a + bytes}
107 }
108
109
110 func (l offAddr) sub(bytes uintptr) offAddr {
111 return offAddr{a: l.a - bytes}
112 }
113
114
115
116 func (l1 offAddr) diff(l2 offAddr) uintptr {
117 return l1.a - l2.a
118 }
119
120
121
122 func (l1 offAddr) lessThan(l2 offAddr) bool {
123 return (l1.a - arenaBaseOffset) < (l2.a - arenaBaseOffset)
124 }
125
126
127
128 func (l1 offAddr) lessEqual(l2 offAddr) bool {
129 return (l1.a - arenaBaseOffset) <= (l2.a - arenaBaseOffset)
130 }
131
132
133 func (l1 offAddr) equal(l2 offAddr) bool {
134
135
136 return l1 == l2
137 }
138
139
140 func (l offAddr) addr() uintptr {
141 return l.a
142 }
143
144
145
146
147
148
149
150
151
152
153
154 type addrRanges struct {
155
156 ranges []addrRange
157
158
159
160 totalBytes uintptr
161
162
163 sysStat *sysMemStat
164 }
165
166 func (a *addrRanges) init(sysStat *sysMemStat) {
167 ranges := (*notInHeapSlice)(unsafe.Pointer(&a.ranges))
168 ranges.len = 0
169 ranges.cap = 16
170 ranges.array = (*notInHeap)(persistentalloc(unsafe.Sizeof(addrRange{})*uintptr(ranges.cap), goarch.PtrSize, sysStat))
171 a.sysStat = sysStat
172 a.totalBytes = 0
173 }
174
175
176
177 func (a *addrRanges) findSucc(addr uintptr) int {
178 base := offAddr{addr}
179
180
181
182
183 const iterMax = 8
184 bot, top := 0, len(a.ranges)
185 for top-bot > iterMax {
186 i := ((top - bot) / 2) + bot
187 if a.ranges[i].contains(base.addr()) {
188
189
190 return i + 1
191 }
192 if base.lessThan(a.ranges[i].base) {
193
194
195
196 top = i
197 } else {
198
199
200
201
202
203 bot = i + 1
204 }
205 }
206
207
208
209 for i := bot; i < top; i++ {
210 if base.lessThan(a.ranges[i].base) {
211 return i
212 }
213 }
214 return top
215 }
216
217
218
219
220
221
222 func (a *addrRanges) findAddrGreaterEqual(addr uintptr) (uintptr, bool) {
223 i := a.findSucc(addr)
224 if i == 0 {
225 return a.ranges[0].base.addr(), true
226 }
227 if a.ranges[i-1].contains(addr) {
228 return addr, true
229 }
230 if i < len(a.ranges) {
231 return a.ranges[i].base.addr(), true
232 }
233 return 0, false
234 }
235
236
237 func (a *addrRanges) contains(addr uintptr) bool {
238 i := a.findSucc(addr)
239 if i == 0 {
240 return false
241 }
242 return a.ranges[i-1].contains(addr)
243 }
244
245
246
247
248 func (a *addrRanges) add(r addrRange) {
249
250
251
252
253
254
255
256
257
258
259
260 if r.size() == 0 {
261 print("runtime: range = {", hex(r.base.addr()), ", ", hex(r.limit.addr()), "}\n")
262 throw("attempted to add zero-sized address range")
263 }
264
265
266 i := a.findSucc(r.base.addr())
267 coalescesDown := i > 0 && a.ranges[i-1].limit.equal(r.base)
268 coalescesUp := i < len(a.ranges) && r.limit.equal(a.ranges[i].base)
269 if coalescesUp && coalescesDown {
270
271
272 a.ranges[i-1].limit = a.ranges[i].limit
273
274
275 copy(a.ranges[i:], a.ranges[i+1:])
276 a.ranges = a.ranges[:len(a.ranges)-1]
277 } else if coalescesDown {
278
279
280 a.ranges[i-1].limit = r.limit
281 } else if coalescesUp {
282
283
284 a.ranges[i].base = r.base
285 } else {
286
287
288 if len(a.ranges)+1 > cap(a.ranges) {
289
290
291
292
293 oldRanges := a.ranges
294 ranges := (*notInHeapSlice)(unsafe.Pointer(&a.ranges))
295 ranges.len = len(oldRanges) + 1
296 ranges.cap = cap(oldRanges) * 2
297 ranges.array = (*notInHeap)(persistentalloc(unsafe.Sizeof(addrRange{})*uintptr(ranges.cap), goarch.PtrSize, a.sysStat))
298
299
300 copy(a.ranges[:i], oldRanges[:i])
301 copy(a.ranges[i+1:], oldRanges[i:])
302 } else {
303 a.ranges = a.ranges[:len(a.ranges)+1]
304 copy(a.ranges[i+1:], a.ranges[i:])
305 }
306 a.ranges[i] = r
307 }
308 a.totalBytes += r.size()
309 }
310
311
312
313
314 func (a *addrRanges) removeLast(nBytes uintptr) addrRange {
315 if len(a.ranges) == 0 {
316 return addrRange{}
317 }
318 r := a.ranges[len(a.ranges)-1]
319 size := r.size()
320 if size > nBytes {
321 newEnd := r.limit.sub(nBytes)
322 a.ranges[len(a.ranges)-1].limit = newEnd
323 a.totalBytes -= nBytes
324 return addrRange{newEnd, r.limit}
325 }
326 a.ranges = a.ranges[:len(a.ranges)-1]
327 a.totalBytes -= size
328 return r
329 }
330
331
332
333 func (a *addrRanges) removeGreaterEqual(addr uintptr) {
334 pivot := a.findSucc(addr)
335 if pivot == 0 {
336
337 a.totalBytes = 0
338 a.ranges = a.ranges[:0]
339 return
340 }
341 removed := uintptr(0)
342 for _, r := range a.ranges[pivot:] {
343 removed += r.size()
344 }
345 if r := a.ranges[pivot-1]; r.contains(addr) {
346 removed += r.size()
347 r = r.removeGreaterEqual(addr)
348 if r.size() == 0 {
349 pivot--
350 } else {
351 removed -= r.size()
352 a.ranges[pivot-1] = r
353 }
354 }
355 a.ranges = a.ranges[:pivot]
356 a.totalBytes -= removed
357 }
358
359
360
361 func (a *addrRanges) cloneInto(b *addrRanges) {
362 if len(a.ranges) > cap(b.ranges) {
363
364 ranges := (*notInHeapSlice)(unsafe.Pointer(&b.ranges))
365 ranges.len = 0
366 ranges.cap = cap(a.ranges)
367 ranges.array = (*notInHeap)(persistentalloc(unsafe.Sizeof(addrRange{})*uintptr(ranges.cap), goarch.PtrSize, b.sysStat))
368 }
369 b.ranges = b.ranges[:len(a.ranges)]
370 b.totalBytes = a.totalBytes
371 copy(b.ranges, a.ranges)
372 }
373
View as plain text