1// Copyright 2023 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//go:build plan9 || wasm 6 7package runtime 8 9import "unsafe" 10 11const memDebug = false 12 13var bloc uintptr 14var blocMax uintptr 15var memlock mutex 16 17type memHdr struct { 18 next memHdrPtr 19 size uintptr 20} 21 22var memFreelist memHdrPtr // sorted in ascending order 23 24type memHdrPtr uintptr 25 26func (p memHdrPtr) ptr() *memHdr { return (*memHdr)(unsafe.Pointer(p)) } 27func (p *memHdrPtr) set(x *memHdr) { *p = memHdrPtr(unsafe.Pointer(x)) } 28 29func memAlloc(n uintptr) unsafe.Pointer { 30 n = memRound(n) 31 var prevp *memHdr 32 for p := memFreelist.ptr(); p != nil; p = p.next.ptr() { 33 if p.size >= n { 34 if p.size == n { 35 if prevp != nil { 36 prevp.next = p.next 37 } else { 38 memFreelist = p.next 39 } 40 } else { 41 p.size -= n 42 p = (*memHdr)(add(unsafe.Pointer(p), p.size)) 43 } 44 *p = memHdr{} 45 return unsafe.Pointer(p) 46 } 47 prevp = p 48 } 49 return sbrk(n) 50} 51 52func memFree(ap unsafe.Pointer, n uintptr) { 53 n = memRound(n) 54 memclrNoHeapPointers(ap, n) 55 bp := (*memHdr)(ap) 56 bp.size = n 57 bpn := uintptr(ap) 58 if memFreelist == 0 { 59 bp.next = 0 60 memFreelist.set(bp) 61 return 62 } 63 p := memFreelist.ptr() 64 if bpn < uintptr(unsafe.Pointer(p)) { 65 memFreelist.set(bp) 66 if bpn+bp.size == uintptr(unsafe.Pointer(p)) { 67 bp.size += p.size 68 bp.next = p.next 69 *p = memHdr{} 70 } else { 71 bp.next.set(p) 72 } 73 return 74 } 75 for ; p.next != 0; p = p.next.ptr() { 76 if bpn > uintptr(unsafe.Pointer(p)) && bpn < uintptr(unsafe.Pointer(p.next)) { 77 break 78 } 79 } 80 if bpn+bp.size == uintptr(unsafe.Pointer(p.next)) { 81 bp.size += p.next.ptr().size 82 bp.next = p.next.ptr().next 83 *p.next.ptr() = memHdr{} 84 } else { 85 bp.next = p.next 86 } 87 if uintptr(unsafe.Pointer(p))+p.size == bpn { 88 p.size += bp.size 89 p.next = bp.next 90 *bp = memHdr{} 91 } else { 92 p.next.set(bp) 93 } 94} 95 96func memCheck() { 97 if !memDebug { 98 return 99 } 100 for p := memFreelist.ptr(); p != nil && p.next != 0; p = p.next.ptr() { 101 if uintptr(unsafe.Pointer(p)) == uintptr(unsafe.Pointer(p.next)) { 102 print("runtime: ", unsafe.Pointer(p), " == ", unsafe.Pointer(p.next), "\n") 103 throw("mem: infinite loop") 104 } 105 if uintptr(unsafe.Pointer(p)) > uintptr(unsafe.Pointer(p.next)) { 106 print("runtime: ", unsafe.Pointer(p), " > ", unsafe.Pointer(p.next), "\n") 107 throw("mem: unordered list") 108 } 109 if uintptr(unsafe.Pointer(p))+p.size > uintptr(unsafe.Pointer(p.next)) { 110 print("runtime: ", unsafe.Pointer(p), "+", p.size, " > ", unsafe.Pointer(p.next), "\n") 111 throw("mem: overlapping blocks") 112 } 113 for b := add(unsafe.Pointer(p), unsafe.Sizeof(memHdr{})); uintptr(b) < uintptr(unsafe.Pointer(p))+p.size; b = add(b, 1) { 114 if *(*byte)(b) != 0 { 115 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") 116 throw("mem: uninitialised memory") 117 } 118 } 119 } 120} 121 122func memRound(p uintptr) uintptr { 123 return alignUp(p, physPageSize) 124} 125 126func initBloc() { 127 bloc = memRound(firstmoduledata.end) 128 blocMax = bloc 129} 130 131func sysAllocOS(n uintptr) unsafe.Pointer { 132 lock(&memlock) 133 p := memAlloc(n) 134 memCheck() 135 unlock(&memlock) 136 return p 137} 138 139func sysFreeOS(v unsafe.Pointer, n uintptr) { 140 lock(&memlock) 141 if uintptr(v)+n == bloc { 142 // Address range being freed is at the end of memory, 143 // so record a new lower value for end of memory. 144 // Can't actually shrink address space because segment is shared. 145 memclrNoHeapPointers(v, n) 146 bloc -= n 147 } else { 148 memFree(v, n) 149 memCheck() 150 } 151 unlock(&memlock) 152} 153 154func sysUnusedOS(v unsafe.Pointer, n uintptr) { 155} 156 157func sysUsedOS(v unsafe.Pointer, n uintptr) { 158} 159 160func sysHugePageOS(v unsafe.Pointer, n uintptr) { 161} 162 163func sysNoHugePageOS(v unsafe.Pointer, n uintptr) { 164} 165 166func sysHugePageCollapseOS(v unsafe.Pointer, n uintptr) { 167} 168 169func sysMapOS(v unsafe.Pointer, n uintptr) { 170} 171 172func sysFaultOS(v unsafe.Pointer, n uintptr) { 173} 174 175func sysReserveOS(v unsafe.Pointer, n uintptr) unsafe.Pointer { 176 lock(&memlock) 177 var p unsafe.Pointer 178 if uintptr(v) == bloc { 179 // Address hint is the current end of memory, 180 // so try to extend the address space. 181 p = sbrk(n) 182 } 183 if p == nil && v == nil { 184 p = memAlloc(n) 185 memCheck() 186 } 187 unlock(&memlock) 188 return p 189} 190