1 // 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 5 package runtime 6 7 import "unsafe" 8 9 const memDebug = false 10 11 var bloc uintptr 12 var memlock mutex 13 14 type memHdr struct { 15 next *memHdr 16 size uintptr 17 } 18 19 var memFreelist *memHdr // sorted in ascending order 20 21 func 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 44 func 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 88 func 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 114 func memRound(p uintptr) uintptr { 115 return (p + _PAGESIZE - 1) &^ (_PAGESIZE - 1) 116 } 117 118 func initBloc() { 119 bloc = memRound(firstmoduledata.end) 120 } 121 122 func sbrk(n uintptr) unsafe.Pointer { 123 // Plan 9 sbrk from /sys/src/libc/9sys/sbrk.c 124 bl := bloc 125 n = memRound(n) 126 if brk_(unsafe.Pointer(bl+n)) < 0 { 127 return nil 128 } 129 bloc += n 130 return unsafe.Pointer(bl) 131 } 132 133 func sysAlloc(n uintptr, sysStat *uint64) unsafe.Pointer { 134 lock(&memlock) 135 p := memAlloc(n) 136 memCheck() 137 unlock(&memlock) 138 if p != nil { 139 mSysStatInc(sysStat, n) 140 } 141 return p 142 } 143 144 func sysFree(v unsafe.Pointer, n uintptr, sysStat *uint64) { 145 mSysStatDec(sysStat, n) 146 lock(&memlock) 147 memFree(v, n) 148 memCheck() 149 unlock(&memlock) 150 } 151 152 func sysUnused(v unsafe.Pointer, n uintptr) { 153 } 154 155 func sysUsed(v unsafe.Pointer, n uintptr) { 156 } 157 158 func sysMap(v unsafe.Pointer, n uintptr, reserved bool, sysStat *uint64) { 159 // sysReserve has already allocated all heap memory, 160 // but has not adjusted stats. 161 mSysStatInc(sysStat, n) 162 } 163 164 func sysFault(v unsafe.Pointer, n uintptr) { 165 } 166 167 func sysReserve(v unsafe.Pointer, n uintptr, reserved *bool) unsafe.Pointer { 168 *reserved = true 169 lock(&memlock) 170 p := memAlloc(n) 171 memCheck() 172 unlock(&memlock) 173 return p 174 } 175