libgo: update to Go 1.11
[official-gcc.git] / libgo / go / runtime / mgclarge.go
blobe7fa831937aca0e7235397b3f3ea29878bf99b53
1 // Copyright 2009 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.
5 // Page heap.
6 //
7 // See malloc.go for the general overview.
8 //
9 // Large spans are the subject of this file. Spans consisting of less than
10 // _MaxMHeapLists are held in lists of like sized spans. Larger spans
11 // are held in a treap. See https://en.wikipedia.org/wiki/Treap or
12 // https://faculty.washington.edu/aragon/pubs/rst89.pdf for an overview.
13 // sema.go also holds an implementation of a treap.
15 // Each treapNode holds a single span. The treap is sorted by page size
16 // and for spans of the same size a secondary sort based on start address
17 // is done.
18 // Spans are returned based on a best fit algorithm and for spans of the same
19 // size the one at the lowest address is selected.
21 // The primary routines are
22 // insert: adds a span to the treap
23 // remove: removes the span from that treap that best fits the required size
24 // removeSpan: which removes a specific span from the treap
26 // _mheap.lock must be held when manipulating this data structure.
28 package runtime
30 import (
31 "unsafe"
34 //go:notinheap
35 type mTreap struct {
36 treap *treapNode
39 //go:notinheap
40 type treapNode struct {
41 right *treapNode // all treapNodes > this treap node
42 left *treapNode // all treapNodes < this treap node
43 parent *treapNode // direct parent of this node, nil if root
44 npagesKey uintptr // number of pages in spanKey, used as primary sort key
45 spanKey *mspan // span of size npagesKey, used as secondary sort key
46 priority uint32 // random number used by treap algorithm to keep tree probabilistically balanced
49 func (t *treapNode) init() {
50 t.right = nil
51 t.left = nil
52 t.parent = nil
53 t.spanKey = nil
54 t.npagesKey = 0
55 t.priority = 0
58 // isSpanInTreap is handy for debugging. One should hold the heap lock, usually
59 // mheap_.lock().
60 func (t *treapNode) isSpanInTreap(s *mspan) bool {
61 if t == nil {
62 return false
64 return t.spanKey == s || t.left.isSpanInTreap(s) || t.right.isSpanInTreap(s)
67 // walkTreap is handy for debugging.
68 // Starting at some treapnode t, for example the root, do a depth first preorder walk of
69 // the tree executing fn at each treap node. One should hold the heap lock, usually
70 // mheap_.lock().
71 func (t *treapNode) walkTreap(fn func(tn *treapNode)) {
72 if t == nil {
73 return
75 fn(t)
76 t.left.walkTreap(fn)
77 t.right.walkTreap(fn)
80 // checkTreapNode when used in conjunction with walkTreap can usually detect a
81 // poorly formed treap.
82 func checkTreapNode(t *treapNode) {
83 // lessThan is used to order the treap.
84 // npagesKey and npages are the primary keys.
85 // spanKey and span are the secondary keys.
86 // span == nil (0) will always be lessThan all
87 // spans of the same size.
88 lessThan := func(npages uintptr, s *mspan) bool {
89 if t.npagesKey != npages {
90 return t.npagesKey < npages
92 // t.npagesKey == npages
93 return uintptr(unsafe.Pointer(t.spanKey)) < uintptr(unsafe.Pointer(s))
96 if t == nil {
97 return
99 if t.spanKey.npages != t.npagesKey || t.spanKey.next != nil {
100 println("runtime: checkTreapNode treapNode t=", t, " t.npagesKey=", t.npagesKey,
101 "t.spanKey.npages=", t.spanKey.npages)
102 throw("why does span.npages and treap.ngagesKey do not match?")
104 if t.left != nil && lessThan(t.left.npagesKey, t.left.spanKey) {
105 throw("t.lessThan(t.left.npagesKey, t.left.spanKey) is not false")
107 if t.right != nil && !lessThan(t.right.npagesKey, t.right.spanKey) {
108 throw("!t.lessThan(t.left.npagesKey, t.left.spanKey) is not false")
112 // insert adds span to the large span treap.
113 func (root *mTreap) insert(span *mspan) {
114 npages := span.npages
115 var last *treapNode
116 pt := &root.treap
117 for t := *pt; t != nil; t = *pt {
118 last = t
119 if t.npagesKey < npages {
120 pt = &t.right
121 } else if t.npagesKey > npages {
122 pt = &t.left
123 } else if uintptr(unsafe.Pointer(t.spanKey)) < uintptr(unsafe.Pointer(span)) {
124 // t.npagesKey == npages, so sort on span addresses.
125 pt = &t.right
126 } else if uintptr(unsafe.Pointer(t.spanKey)) > uintptr(unsafe.Pointer(span)) {
127 pt = &t.left
128 } else {
129 throw("inserting span already in treap")
133 // Add t as new leaf in tree of span size and unique addrs.
134 // The balanced tree is a treap using priority as the random heap priority.
135 // That is, it is a binary tree ordered according to the npagesKey,
136 // but then among the space of possible binary trees respecting those
137 // npagesKeys, it is kept balanced on average by maintaining a heap ordering
138 // on the priority: s.priority <= both s.right.priority and s.right.priority.
139 // https://en.wikipedia.org/wiki/Treap
140 // https://faculty.washington.edu/aragon/pubs/rst89.pdf
142 t := (*treapNode)(mheap_.treapalloc.alloc())
143 t.init()
144 t.npagesKey = span.npages
145 t.priority = fastrand()
146 t.spanKey = span
147 t.parent = last
148 *pt = t // t now at a leaf.
149 // Rotate up into tree according to priority.
150 for t.parent != nil && t.parent.priority > t.priority {
151 if t != nil && t.spanKey.npages != t.npagesKey {
152 println("runtime: insert t=", t, "t.npagesKey=", t.npagesKey)
153 println("runtime: t.spanKey=", t.spanKey, "t.spanKey.npages=", t.spanKey.npages)
154 throw("span and treap sizes do not match?")
156 if t.parent.left == t {
157 root.rotateRight(t.parent)
158 } else {
159 if t.parent.right != t {
160 throw("treap insert finds a broken treap")
162 root.rotateLeft(t.parent)
167 func (root *mTreap) removeNode(t *treapNode) {
168 if t.spanKey.npages != t.npagesKey {
169 throw("span and treap node npages do not match")
172 // Rotate t down to be leaf of tree for removal, respecting priorities.
173 for t.right != nil || t.left != nil {
174 if t.right == nil || t.left != nil && t.left.priority < t.right.priority {
175 root.rotateRight(t)
176 } else {
177 root.rotateLeft(t)
180 // Remove t, now a leaf.
181 if t.parent != nil {
182 if t.parent.left == t {
183 t.parent.left = nil
184 } else {
185 t.parent.right = nil
187 } else {
188 root.treap = nil
190 // Return the found treapNode's span after freeing the treapNode.
191 t.spanKey = nil
192 t.npagesKey = 0
193 mheap_.treapalloc.free(unsafe.Pointer(t))
196 // remove searches for, finds, removes from the treap, and returns the smallest
197 // span that can hold npages. If no span has at least npages return nil.
198 // This is slightly more complicated than a simple binary tree search
199 // since if an exact match is not found the next larger node is
200 // returned.
201 // If the last node inspected > npagesKey not holding
202 // a left node (a smaller npages) is the "best fit" node.
203 func (root *mTreap) remove(npages uintptr) *mspan {
204 t := root.treap
205 for t != nil {
206 if t.spanKey == nil {
207 throw("treap node with nil spanKey found")
209 if t.npagesKey < npages {
210 t = t.right
211 } else if t.left != nil && t.left.npagesKey >= npages {
212 t = t.left
213 } else {
214 result := t.spanKey
215 root.removeNode(t)
216 return result
219 return nil
222 // removeSpan searches for, finds, deletes span along with
223 // the associated treap node. If the span is not in the treap
224 // then t will eventually be set to nil and the t.spanKey
225 // will throw.
226 func (root *mTreap) removeSpan(span *mspan) {
227 npages := span.npages
228 t := root.treap
229 for t.spanKey != span {
230 if t.npagesKey < npages {
231 t = t.right
232 } else if t.npagesKey > npages {
233 t = t.left
234 } else if uintptr(unsafe.Pointer(t.spanKey)) < uintptr(unsafe.Pointer(span)) {
235 t = t.right
236 } else if uintptr(unsafe.Pointer(t.spanKey)) > uintptr(unsafe.Pointer(span)) {
237 t = t.left
240 root.removeNode(t)
243 // scavengetreap visits each node in the treap and scavenges the
244 // treapNode's span.
245 func scavengetreap(treap *treapNode, now, limit uint64) uintptr {
246 if treap == nil {
247 return 0
249 return scavengeTreapNode(treap, now, limit) +
250 scavengetreap(treap.left, now, limit) +
251 scavengetreap(treap.right, now, limit)
254 // rotateLeft rotates the tree rooted at node x.
255 // turning (x a (y b c)) into (y (x a b) c).
256 func (root *mTreap) rotateLeft(x *treapNode) {
257 // p -> (x a (y b c))
258 p := x.parent
259 a, y := x.left, x.right
260 b, c := y.left, y.right
262 y.left = x
263 x.parent = y
264 y.right = c
265 if c != nil {
266 c.parent = y
268 x.left = a
269 if a != nil {
270 a.parent = x
272 x.right = b
273 if b != nil {
274 b.parent = x
277 y.parent = p
278 if p == nil {
279 root.treap = y
280 } else if p.left == x {
281 p.left = y
282 } else {
283 if p.right != x {
284 throw("large span treap rotateLeft")
286 p.right = y
290 // rotateRight rotates the tree rooted at node y.
291 // turning (y (x a b) c) into (x a (y b c)).
292 func (root *mTreap) rotateRight(y *treapNode) {
293 // p -> (y (x a b) c)
294 p := y.parent
295 x, c := y.left, y.right
296 a, b := x.left, x.right
298 x.left = a
299 if a != nil {
300 a.parent = x
302 x.right = y
303 y.parent = x
304 y.left = b
305 if b != nil {
306 b.parent = y
308 y.right = c
309 if c != nil {
310 c.parent = y
313 x.parent = p
314 if p == nil {
315 root.treap = x
316 } else if p.left == y {
317 p.left = x
318 } else {
319 if p.right != y {
320 throw("large span treap rotateRight")
322 p.right = x