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 sbrk(n uintptr) unsafe.Pointer {
- lock(&memlock)
// Plan 9 sbrk from /sys/src/libc/9sys/sbrk.c
bl := bloc
n = memRound(n)
if brk_(unsafe.Pointer(bl+n)) < 0 {
- unlock(&memlock)
return nil
}
bloc += n
- unlock(&memlock)
return unsafe.Pointer(bl)
}
func sysAlloc(n uintptr, stat *uint64) unsafe.Pointer {
- p := sbrk(n)
+ lock(&memlock)
+ p := memAlloc(n)
+ memCheck()
+ unlock(&memlock)
if p != nil {
xadd64(stat, int64(n))
}
func sysFree(v unsafe.Pointer, n uintptr, stat *uint64) {
xadd64(stat, -int64(n))
lock(&memlock)
- // from tiny/mem.c
- // Push pointer back if this is a free
- // of the most recent sysAlloc.
- n = memRound(n)
- if bloc == uintptr(v)+n {
- bloc -= n
- memclr(unsafe.Pointer(bloc), n)
- }
+ memFree(v, n)
+ memCheck()
unlock(&memlock)
}
func sysReserve(v unsafe.Pointer, n uintptr, reserved *bool) unsafe.Pointer {
*reserved = true
- return sbrk(n)
+ lock(&memlock)
+ p := memAlloc(n)
+ memCheck()
+ unlock(&memlock)
+ return p
}