// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package runtime
import "unsafe"
const memDebug = false
var bloc uintptr
var memlock mutex
type memHdr struct {
next *memHdr
size uintptr
}
var memFreelist *memHdr // sorted in ascending order
func memAlloc(n uintptr) unsafe.Pointer {
n = memRound(n)
var prevp *memHdr
for p := memFreelist; p != nil; p = p.next {
if p.size >= n {
if p.size == n {
if prevp != nil {
prevp.next = p.next
} else {
memFreelist = p.next
}
} else {
p.size -= n
p = (*memHdr)(add(unsafe.Pointer(p), p.size))
}
memclr(unsafe.Pointer(p), unsafe.Sizeof(memHdr{}))
return unsafe.Pointer(p)
}
prevp = p
}
return sbrk(n)
}
func memFree(ap unsafe.Pointer, n uintptr) {
n = memRound(n)
memclr(ap, n)
bp := (*memHdr)(ap)
bp.size = n
bpn := uintptr(ap)
if memFreelist == nil {
bp.next = nil
memFreelist = bp
return
}
p := memFreelist
if bpn < uintptr(unsafe.Pointer(p)) {
memFreelist = bp
if bpn+bp.size == uintptr(unsafe.Pointer(p)) {
bp.size += p.size
bp.next = p.next
memclr(unsafe.Pointer(p), unsafe.Sizeof(memHdr{}))
} else {
bp.next = p
}
return
}
for ; p.next != nil; p = p.next {
if bpn > uintptr(unsafe.Pointer(p)) && bpn < uintptr(unsafe.Pointer(p.next)) {
break
}
}
if bpn+bp.size == uintptr(unsafe.Pointer(p.next)) {
bp.size += p.next.size
bp.next = p.next.next
memclr(unsafe.Pointer(p.next), unsafe.Sizeof(memHdr{}))
} else {
bp.next = p.next
}
if uintptr(unsafe.Pointer(p))+p.size == bpn {
p.size += bp.size
p.next = bp.next
memclr(unsafe.Pointer(bp), unsafe.Sizeof(memHdr{}))
} else {
p.next = bp
}
}
func memCheck() {
if memDebug == false {
return
}
for p := memFreelist; p != nil && p.next != nil; p = p.next {
if uintptr(unsafe.Pointer(p)) == uintptr(unsafe.Pointer(p.next)) {
print("runtime: ", unsafe.Pointer(p), " == ", unsafe.Pointer(p.next), "\n")
throw("mem: infinite loop")
}
if uintptr(unsafe.Pointer(p)) > uintptr(unsafe.Pointer(p.next)) {
print("runtime: ", unsafe.Pointer(p), " > ", unsafe.Pointer(p.next), "\n")
throw("mem: unordered list")
}
if uintptr(unsafe.Pointer(p))+p.size > uintptr(unsafe.Pointer(p.next)) {
print("runtime: ", unsafe.Pointer(p), "+", p.size, " > ", unsafe.Pointer(p.next), "\n")
throw("mem: overlapping blocks")
}
for b := add(unsafe.Pointer(p), unsafe.Sizeof(memHdr{})); uintptr(b) < uintptr(unsafe.Pointer(p))+p.size; b = add(b, 1) {
if *(*byte)(b) != 0 {
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")
throw("mem: uninitialised memory")
}
}
}
}
func memRound(p uintptr) uintptr {
return (p + _PAGESIZE - 1) &^ (_PAGESIZE - 1)
}
func initBloc() {
bloc = memRound(firstmoduledata.end)
}
func sbrk(n uintptr) unsafe.Pointer {
// Plan 9 sbrk from /sys/src/libc/9sys/sbrk.c
bl := bloc
n = memRound(n)
if brk_(unsafe.Pointer(bl+n)) < 0 {
return nil
}
bloc += n
return unsafe.Pointer(bl)
}
func sysAlloc(n uintptr, sysStat *uint64) unsafe.Pointer {
lock(&memlock)
p := memAlloc(n)
memCheck()
unlock(&memlock)
if p != nil {
mSysStatInc(sysStat, n)
}
return p
}
func sysFree(v unsafe.Pointer, n uintptr, sysStat *uint64) {
mSysStatDec(sysStat, n)
lock(&memlock)
memFree(v, n)
memCheck()
unlock(&memlock)
}
func sysUnused(v unsafe.Pointer, n uintptr) {
}
func sysUsed(v unsafe.Pointer, n uintptr) {
}
func sysMap(v unsafe.Pointer, n uintptr, reserved bool, sysStat *uint64) {
// sysReserve has already allocated all heap memory,
// but has not adjusted stats.
mSysStatInc(sysStat, n)
}
func sysFault(v unsafe.Pointer, n uintptr) {
}
func sysReserve(v unsafe.Pointer, n uintptr, reserved *bool) unsafe.Pointer {
*reserved = true
lock(&memlock)
p := memAlloc(n)
memCheck()
unlock(&memlock)
return p
}