|  | // 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 | 
|  | } |