blob: 4dc8a6119ad129f373a3a87b3fbdae650cd79e12 [file] [log] [blame]
David du Colombiere9c57d82014-11-21 19:39:01 +01001// Copyright 2010 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
5package runtime
6
7import "unsafe"
8
David du Colombierfb75f852015-02-26 22:41:33 +01009const memDebug = false
10
David du Colombiere9c57d82014-11-21 19:39:01 +010011var bloc uintptr
12var memlock mutex
13
David du Colombierfb75f852015-02-26 22:41:33 +010014type memHdr struct {
15 next *memHdr
16 size uintptr
17}
18
19var memFreelist *memHdr // sorted in ascending order
20
21func memAlloc(n uintptr) unsafe.Pointer {
22 n = memRound(n)
23 var prevp *memHdr
24 for p := memFreelist; p != nil; p = p.next {
25 if p.size >= n {
26 if p.size == n {
27 if prevp != nil {
28 prevp.next = p.next
29 } else {
30 memFreelist = p.next
31 }
32 } else {
33 p.size -= n
34 p = (*memHdr)(add(unsafe.Pointer(p), p.size))
35 }
36 memclr(unsafe.Pointer(p), unsafe.Sizeof(memHdr{}))
37 return unsafe.Pointer(p)
38 }
39 prevp = p
40 }
41 return sbrk(n)
42}
43
44func memFree(ap unsafe.Pointer, n uintptr) {
45 n = memRound(n)
46 memclr(ap, n)
47 bp := (*memHdr)(ap)
48 bp.size = n
49 bpn := uintptr(ap)
50 if memFreelist == nil {
51 bp.next = nil
52 memFreelist = bp
53 return
54 }
55 p := memFreelist
56 if bpn < uintptr(unsafe.Pointer(p)) {
57 memFreelist = bp
58 if bpn+bp.size == uintptr(unsafe.Pointer(p)) {
59 bp.size += p.size
60 bp.next = p.next
61 memclr(unsafe.Pointer(p), unsafe.Sizeof(memHdr{}))
62 } else {
63 bp.next = p
64 }
65 return
66 }
67 for ; p.next != nil; p = p.next {
68 if bpn > uintptr(unsafe.Pointer(p)) && bpn < uintptr(unsafe.Pointer(p.next)) {
69 break
70 }
71 }
72 if bpn+bp.size == uintptr(unsafe.Pointer(p.next)) {
73 bp.size += p.next.size
74 bp.next = p.next.next
75 memclr(unsafe.Pointer(p.next), unsafe.Sizeof(memHdr{}))
76 } else {
77 bp.next = p.next
78 }
79 if uintptr(unsafe.Pointer(p))+p.size == bpn {
80 p.size += bp.size
81 p.next = bp.next
82 memclr(unsafe.Pointer(bp), unsafe.Sizeof(memHdr{}))
83 } else {
84 p.next = bp
85 }
86}
87
88func memCheck() {
89 if memDebug == false {
90 return
91 }
92 for p := memFreelist; p != nil && p.next != nil; p = p.next {
93 if uintptr(unsafe.Pointer(p)) == uintptr(unsafe.Pointer(p.next)) {
94 print("runtime: ", unsafe.Pointer(p), " == ", unsafe.Pointer(p.next), "\n")
95 throw("mem: infinite loop")
96 }
97 if uintptr(unsafe.Pointer(p)) > uintptr(unsafe.Pointer(p.next)) {
98 print("runtime: ", unsafe.Pointer(p), " > ", unsafe.Pointer(p.next), "\n")
99 throw("mem: unordered list")
100 }
101 if uintptr(unsafe.Pointer(p))+p.size > uintptr(unsafe.Pointer(p.next)) {
102 print("runtime: ", unsafe.Pointer(p), "+", p.size, " > ", unsafe.Pointer(p.next), "\n")
103 throw("mem: overlapping blocks")
104 }
105 for b := add(unsafe.Pointer(p), unsafe.Sizeof(memHdr{})); uintptr(b) < uintptr(unsafe.Pointer(p))+p.size; b = add(b, 1) {
106 if *(*byte)(b) != 0 {
107 print("runtime: value at addr ", b, " with offset ", uintptr(b)-uintptr(unsafe.Pointer(p)), " in block ", p, " of size ", p.size, " is not zero\n")
108 throw("mem: uninitialised memory")
109 }
110 }
111 }
112}
113
Dmitry Vyukov3c3848a2015-01-30 14:36:12 +0300114func memRound(p uintptr) uintptr {
115 return (p + _PAGESIZE - 1) &^ (_PAGESIZE - 1)
116}
David du Colombiere9c57d82014-11-21 19:39:01 +0100117
118func initBloc() {
Michael Hudson-Doylea1f57592015-04-07 12:55:02 +1200119 bloc = memRound(firstmoduledata.end)
David du Colombiere9c57d82014-11-21 19:39:01 +0100120}
121
122func sbrk(n uintptr) unsafe.Pointer {
David du Colombiere9c57d82014-11-21 19:39:01 +0100123 // Plan 9 sbrk from /sys/src/libc/9sys/sbrk.c
Dmitry Vyukov3c3848a2015-01-30 14:36:12 +0300124 bl := bloc
125 n = memRound(n)
David du Colombiere9c57d82014-11-21 19:39:01 +0100126 if brk_(unsafe.Pointer(bl+n)) < 0 {
David du Colombiere9c57d82014-11-21 19:39:01 +0100127 return nil
128 }
Dmitry Vyukov3c3848a2015-01-30 14:36:12 +0300129 bloc += n
David du Colombiere9c57d82014-11-21 19:39:01 +0100130 return unsafe.Pointer(bl)
131}
132
133func sysAlloc(n uintptr, stat *uint64) unsafe.Pointer {
David du Colombierfb75f852015-02-26 22:41:33 +0100134 lock(&memlock)
135 p := memAlloc(n)
136 memCheck()
137 unlock(&memlock)
David du Colombiere9c57d82014-11-21 19:39:01 +0100138 if p != nil {
139 xadd64(stat, int64(n))
140 }
141 return p
142}
143
144func sysFree(v unsafe.Pointer, n uintptr, stat *uint64) {
145 xadd64(stat, -int64(n))
146 lock(&memlock)
David du Colombierfb75f852015-02-26 22:41:33 +0100147 memFree(v, n)
148 memCheck()
David du Colombiere9c57d82014-11-21 19:39:01 +0100149 unlock(&memlock)
150}
151
152func sysUnused(v unsafe.Pointer, n uintptr) {
153}
154
155func sysUsed(v unsafe.Pointer, n uintptr) {
156}
157
158func sysMap(v unsafe.Pointer, n uintptr, reserved bool, stat *uint64) {
159 // sysReserve has already allocated all heap memory,
160 // but has not adjusted stats.
161 xadd64(stat, int64(n))
162}
163
164func sysFault(v unsafe.Pointer, n uintptr) {
165}
166
167func sysReserve(v unsafe.Pointer, n uintptr, reserved *bool) unsafe.Pointer {
168 *reserved = true
David du Colombierfb75f852015-02-26 22:41:33 +0100169 lock(&memlock)
170 p := memAlloc(n)
171 memCheck()
172 unlock(&memlock)
173 return p
David du Colombiere9c57d82014-11-21 19:39:01 +0100174}