Home | History | Annotate | Download | only in runtime
      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 memHdrPtr
     16 	size uintptr
     17 }
     18 
     19 var memFreelist memHdrPtr // sorted in ascending order
     20 
     21 type memHdrPtr uintptr
     22 
     23 func (p memHdrPtr) ptr() *memHdr   { return (*memHdr)(unsafe.Pointer(p)) }
     24 func (p *memHdrPtr) set(x *memHdr) { *p = memHdrPtr(unsafe.Pointer(x)) }
     25 
     26 func memAlloc(n uintptr) unsafe.Pointer {
     27 	n = memRound(n)
     28 	var prevp *memHdr
     29 	for p := memFreelist.ptr(); p != nil; p = p.next.ptr() {
     30 		if p.size >= n {
     31 			if p.size == n {
     32 				if prevp != nil {
     33 					prevp.next = p.next
     34 				} else {
     35 					memFreelist = p.next
     36 				}
     37 			} else {
     38 				p.size -= n
     39 				p = (*memHdr)(add(unsafe.Pointer(p), p.size))
     40 			}
     41 			*p = memHdr{}
     42 			return unsafe.Pointer(p)
     43 		}
     44 		prevp = p
     45 	}
     46 	return sbrk(n)
     47 }
     48 
     49 func memFree(ap unsafe.Pointer, n uintptr) {
     50 	n = memRound(n)
     51 	memclrNoHeapPointers(ap, n)
     52 	bp := (*memHdr)(ap)
     53 	bp.size = n
     54 	bpn := uintptr(ap)
     55 	if memFreelist == 0 {
     56 		bp.next = 0
     57 		memFreelist.set(bp)
     58 		return
     59 	}
     60 	p := memFreelist.ptr()
     61 	if bpn < uintptr(unsafe.Pointer(p)) {
     62 		memFreelist.set(bp)
     63 		if bpn+bp.size == uintptr(unsafe.Pointer(p)) {
     64 			bp.size += p.size
     65 			bp.next = p.next
     66 			*p = memHdr{}
     67 		} else {
     68 			bp.next.set(p)
     69 		}
     70 		return
     71 	}
     72 	for ; p.next != 0; p = p.next.ptr() {
     73 		if bpn > uintptr(unsafe.Pointer(p)) && bpn < uintptr(unsafe.Pointer(p.next)) {
     74 			break
     75 		}
     76 	}
     77 	if bpn+bp.size == uintptr(unsafe.Pointer(p.next)) {
     78 		bp.size += p.next.ptr().size
     79 		bp.next = p.next.ptr().next
     80 		*p.next.ptr() = memHdr{}
     81 	} else {
     82 		bp.next = p.next
     83 	}
     84 	if uintptr(unsafe.Pointer(p))+p.size == bpn {
     85 		p.size += bp.size
     86 		p.next = bp.next
     87 		*bp = memHdr{}
     88 	} else {
     89 		p.next.set(bp)
     90 	}
     91 }
     92 
     93 func memCheck() {
     94 	if memDebug == false {
     95 		return
     96 	}
     97 	for p := memFreelist.ptr(); p != nil && p.next != 0; p = p.next.ptr() {
     98 		if uintptr(unsafe.Pointer(p)) == uintptr(unsafe.Pointer(p.next)) {
     99 			print("runtime: ", unsafe.Pointer(p), " == ", unsafe.Pointer(p.next), "\n")
    100 			throw("mem: infinite loop")
    101 		}
    102 		if uintptr(unsafe.Pointer(p)) > uintptr(unsafe.Pointer(p.next)) {
    103 			print("runtime: ", unsafe.Pointer(p), " > ", unsafe.Pointer(p.next), "\n")
    104 			throw("mem: unordered list")
    105 		}
    106 		if uintptr(unsafe.Pointer(p))+p.size > uintptr(unsafe.Pointer(p.next)) {
    107 			print("runtime: ", unsafe.Pointer(p), "+", p.size, " > ", unsafe.Pointer(p.next), "\n")
    108 			throw("mem: overlapping blocks")
    109 		}
    110 		for b := add(unsafe.Pointer(p), unsafe.Sizeof(memHdr{})); uintptr(b) < uintptr(unsafe.Pointer(p))+p.size; b = add(b, 1) {
    111 			if *(*byte)(b) != 0 {
    112 				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")
    113 				throw("mem: uninitialised memory")
    114 			}
    115 		}
    116 	}
    117 }
    118 
    119 func memRound(p uintptr) uintptr {
    120 	return (p + _PAGESIZE - 1) &^ (_PAGESIZE - 1)
    121 }
    122 
    123 func initBloc() {
    124 	bloc = memRound(firstmoduledata.end)
    125 }
    126 
    127 func sbrk(n uintptr) unsafe.Pointer {
    128 	// Plan 9 sbrk from /sys/src/libc/9sys/sbrk.c
    129 	bl := bloc
    130 	n = memRound(n)
    131 	if brk_(unsafe.Pointer(bl+n)) < 0 {
    132 		return nil
    133 	}
    134 	bloc += n
    135 	return unsafe.Pointer(bl)
    136 }
    137 
    138 func sysAlloc(n uintptr, sysStat *uint64) unsafe.Pointer {
    139 	lock(&memlock)
    140 	p := memAlloc(n)
    141 	memCheck()
    142 	unlock(&memlock)
    143 	if p != nil {
    144 		mSysStatInc(sysStat, n)
    145 	}
    146 	return p
    147 }
    148 
    149 func sysFree(v unsafe.Pointer, n uintptr, sysStat *uint64) {
    150 	mSysStatDec(sysStat, n)
    151 	lock(&memlock)
    152 	memFree(v, n)
    153 	memCheck()
    154 	unlock(&memlock)
    155 }
    156 
    157 func sysUnused(v unsafe.Pointer, n uintptr) {
    158 }
    159 
    160 func sysUsed(v unsafe.Pointer, n uintptr) {
    161 }
    162 
    163 func sysMap(v unsafe.Pointer, n uintptr, reserved bool, sysStat *uint64) {
    164 	// sysReserve has already allocated all heap memory,
    165 	// but has not adjusted stats.
    166 	mSysStatInc(sysStat, n)
    167 }
    168 
    169 func sysFault(v unsafe.Pointer, n uintptr) {
    170 }
    171 
    172 func sysReserve(v unsafe.Pointer, n uintptr, reserved *bool) unsafe.Pointer {
    173 	*reserved = true
    174 	lock(&memlock)
    175 	p := memAlloc(n)
    176 	memCheck()
    177 	unlock(&memlock)
    178 	return p
    179 }
    180