libgo: update to go1.9
[official-gcc.git] / libgo / go / runtime / mgclarge.go
blob757e88d1d9da6ff6ca435c5cba15dd3603cf5af8
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 // http://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 keep tree probablistically 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 // http://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) *mspan {
168 if t.spanKey.npages != t.npagesKey {
169 throw("span and treap node npages do not match")
171 result := t.spanKey
173 // Rotate t down to be leaf of tree for removal, respecting priorities.
174 for t.right != nil || t.left != nil {
175 if t.right == nil || t.left != nil && t.left.priority < t.right.priority {
176 root.rotateRight(t)
177 } else {
178 root.rotateLeft(t)
181 // Remove t, now a leaf.
182 if t.parent != nil {
183 if t.parent.left == t {
184 t.parent.left = nil
185 } else {
186 t.parent.right = nil
188 } else {
189 root.treap = nil
191 // Return the found treapNode's span after freeing the treapNode.
192 t.spanKey = nil
193 t.npagesKey = 0
194 mheap_.treapalloc.free(unsafe.Pointer(t))
195 return result
198 // remove searches for, finds, removes from the treap, and returns the smallest
199 // span that can hold npages. If no span has at least npages return nil.
200 // This is slightly more complicated than a simple binary tree search
201 // since if an exact match is not found the next larger node is
202 // returned.
203 // If the last node inspected > npagesKey not holding
204 // a left node (a smaller npages) is the "best fit" node.
205 func (root *mTreap) remove(npages uintptr) *mspan {
206 t := root.treap
207 for t != nil {
208 if t.spanKey == nil {
209 throw("treap node with nil spanKey found")
211 if t.npagesKey < npages {
212 t = t.right
213 } else if t.left != nil && t.left.npagesKey >= npages {
214 t = t.left
215 } else {
216 result := t.spanKey
217 root.removeNode(t)
218 return result
221 return nil
224 // removeSpan searches for, finds, deletes span along with
225 // the associated treap node. If the span is not in the treap
226 // then t will eventually be set to nil and the t.spanKey
227 // will throw.
228 func (root *mTreap) removeSpan(span *mspan) {
229 npages := span.npages
230 t := root.treap
231 for t.spanKey != span {
232 if t.npagesKey < npages {
233 t = t.right
234 } else if t.npagesKey > npages {
235 t = t.left
236 } else if uintptr(unsafe.Pointer(t.spanKey)) < uintptr(unsafe.Pointer(span)) {
237 t = t.right
238 } else if uintptr(unsafe.Pointer(t.spanKey)) > uintptr(unsafe.Pointer(span)) {
239 t = t.left
242 root.removeNode(t)
245 // scavengetreap visits each node in the treap and scavenges the
246 // treapNode's span.
247 func scavengetreap(treap *treapNode, now, limit uint64) uintptr {
248 if treap == nil {
249 return 0
251 return scavengeTreapNode(treap, now, limit) +
252 scavengetreap(treap.left, now, limit) +
253 scavengetreap(treap.right, now, limit)
256 // rotateLeft rotates the tree rooted at node x.
257 // turning (x a (y b c)) into (y (x a b) c).
258 func (root *mTreap) rotateLeft(x *treapNode) {
259 // p -> (x a (y b c))
260 p := x.parent
261 a, y := x.left, x.right
262 b, c := y.left, y.right
264 y.left = x
265 x.parent = y
266 y.right = c
267 if c != nil {
268 c.parent = y
270 x.left = a
271 if a != nil {
272 a.parent = x
274 x.right = b
275 if b != nil {
276 b.parent = x
279 y.parent = p
280 if p == nil {
281 root.treap = y
282 } else if p.left == x {
283 p.left = y
284 } else {
285 if p.right != x {
286 throw("large span treap rotateLeft")
288 p.right = y
292 // rotateRight rotates the tree rooted at node y.
293 // turning (y (x a b) c) into (x a (y b c)).
294 func (root *mTreap) rotateRight(y *treapNode) {
295 // p -> (y (x a b) c)
296 p := y.parent
297 x, c := y.left, y.right
298 a, b := x.left, x.right
300 x.left = a
301 if a != nil {
302 a.parent = x
304 x.right = y
305 y.parent = x
306 y.left = b
307 if b != nil {
308 b.parent = y
310 y.right = c
311 if c != nil {
312 c.parent = y
315 x.parent = p
316 if p == nil {
317 root.treap = x
318 } else if p.left == y {
319 p.left = x
320 } else {
321 if p.right != y {
322 throw("large span treap rotateRight")
324 p.right = x