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