github.com/mattn/go@v0.0.0-20171011075504-07f7db3ea99f/src/runtime/slice.go (about) 1 // Copyright 2009 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 ( 8 "unsafe" 9 ) 10 11 type slice struct { 12 array unsafe.Pointer 13 len int 14 cap int 15 } 16 17 // maxElems is a lookup table containing the maximum capacity for a slice. 18 // The index is the size of the slice element. 19 var maxElems = [...]uintptr{ 20 ^uintptr(0), 21 _MaxMem / 1, _MaxMem / 2, _MaxMem / 3, _MaxMem / 4, 22 _MaxMem / 5, _MaxMem / 6, _MaxMem / 7, _MaxMem / 8, 23 _MaxMem / 9, _MaxMem / 10, _MaxMem / 11, _MaxMem / 12, 24 _MaxMem / 13, _MaxMem / 14, _MaxMem / 15, _MaxMem / 16, 25 _MaxMem / 17, _MaxMem / 18, _MaxMem / 19, _MaxMem / 20, 26 _MaxMem / 21, _MaxMem / 22, _MaxMem / 23, _MaxMem / 24, 27 _MaxMem / 25, _MaxMem / 26, _MaxMem / 27, _MaxMem / 28, 28 _MaxMem / 29, _MaxMem / 30, _MaxMem / 31, _MaxMem / 32, 29 } 30 31 // maxSliceCap returns the maximum capacity for a slice. 32 func maxSliceCap(elemsize uintptr) uintptr { 33 if elemsize < uintptr(len(maxElems)) { 34 return maxElems[elemsize] 35 } 36 return _MaxMem / elemsize 37 } 38 39 func makeslice(et *_type, len, cap int) slice { 40 // NOTE: The len > maxElements check here is not strictly necessary, 41 // but it produces a 'len out of range' error instead of a 'cap out of range' error 42 // when someone does make([]T, bignumber). 'cap out of range' is true too, 43 // but since the cap is only being supplied implicitly, saying len is clearer. 44 // See issue 4085. 45 maxElements := maxSliceCap(et.size) 46 if len < 0 || uintptr(len) > maxElements { 47 panic(errorString("makeslice: len out of range")) 48 } 49 50 if cap < len || uintptr(cap) > maxElements { 51 panic(errorString("makeslice: cap out of range")) 52 } 53 54 p := mallocgc(et.size*uintptr(cap), et, true) 55 return slice{p, len, cap} 56 } 57 58 func makeslice64(et *_type, len64, cap64 int64) slice { 59 len := int(len64) 60 if int64(len) != len64 { 61 panic(errorString("makeslice: len out of range")) 62 } 63 64 cap := int(cap64) 65 if int64(cap) != cap64 { 66 panic(errorString("makeslice: cap out of range")) 67 } 68 69 return makeslice(et, len, cap) 70 } 71 72 // growslice handles slice growth during append. 73 // It is passed the slice element type, the old slice, and the desired new minimum capacity, 74 // and it returns a new slice with at least that capacity, with the old data 75 // copied into it. 76 // The new slice's length is set to the old slice's length, 77 // NOT to the new requested capacity. 78 // This is for codegen convenience. The old slice's length is used immediately 79 // to calculate where to write new values during an append. 80 // TODO: When the old backend is gone, reconsider this decision. 81 // The SSA backend might prefer the new length or to return only ptr/cap and save stack space. 82 func growslice(et *_type, old slice, cap int) slice { 83 if raceenabled { 84 callerpc := getcallerpc() 85 racereadrangepc(old.array, uintptr(old.len*int(et.size)), callerpc, funcPC(growslice)) 86 } 87 if msanenabled { 88 msanread(old.array, uintptr(old.len*int(et.size))) 89 } 90 91 if et.size == 0 { 92 if cap < old.cap { 93 panic(errorString("growslice: cap out of range")) 94 } 95 // append should not create a slice with nil pointer but non-zero len. 96 // We assume that append doesn't need to preserve old.array in this case. 97 return slice{unsafe.Pointer(&zerobase), old.len, cap} 98 } 99 100 newcap := old.cap 101 doublecap := newcap + newcap 102 if cap > doublecap { 103 newcap = cap 104 } else { 105 if old.len < 1024 { 106 newcap = doublecap 107 } else { 108 // Check 0 < newcap to detect overflow 109 // and prevent an infinite loop. 110 for 0 < newcap && newcap < cap { 111 newcap += newcap / 4 112 } 113 // Set newcap to the requested cap when 114 // the newcap calculation overflowed. 115 if newcap <= 0 { 116 newcap = cap 117 } 118 } 119 } 120 121 var lenmem, newlenmem, capmem uintptr 122 const ptrSize = unsafe.Sizeof((*byte)(nil)) 123 switch et.size { 124 case 1: 125 lenmem = uintptr(old.len) 126 newlenmem = uintptr(cap) 127 capmem = roundupsize(uintptr(newcap)) 128 newcap = int(capmem) 129 case ptrSize: 130 lenmem = uintptr(old.len) * ptrSize 131 newlenmem = uintptr(cap) * ptrSize 132 capmem = roundupsize(uintptr(newcap) * ptrSize) 133 newcap = int(capmem / ptrSize) 134 default: 135 lenmem = uintptr(old.len) * et.size 136 newlenmem = uintptr(cap) * et.size 137 capmem = roundupsize(uintptr(newcap) * et.size) 138 newcap = int(capmem / et.size) 139 } 140 141 if cap < old.cap || capmem > _MaxMem { 142 panic(errorString("growslice: cap out of range")) 143 } 144 145 var p unsafe.Pointer 146 if et.kind&kindNoPointers != 0 { 147 p = mallocgc(capmem, nil, false) 148 memmove(p, old.array, lenmem) 149 // The append() that calls growslice is going to overwrite from old.len to cap (which will be the new length). 150 // Only clear the part that will not be overwritten. 151 memclrNoHeapPointers(add(p, newlenmem), capmem-newlenmem) 152 } else { 153 // Note: can't use rawmem (which avoids zeroing of memory), because then GC can scan uninitialized memory. 154 p = mallocgc(capmem, et, true) 155 if !writeBarrier.enabled { 156 memmove(p, old.array, lenmem) 157 } else { 158 for i := uintptr(0); i < lenmem; i += et.size { 159 typedmemmove(et, add(p, i), add(old.array, i)) 160 } 161 } 162 } 163 164 return slice{p, old.len, newcap} 165 } 166 167 func slicecopy(to, fm slice, width uintptr) int { 168 if fm.len == 0 || to.len == 0 { 169 return 0 170 } 171 172 n := fm.len 173 if to.len < n { 174 n = to.len 175 } 176 177 if width == 0 { 178 return n 179 } 180 181 if raceenabled { 182 callerpc := getcallerpc() 183 pc := funcPC(slicecopy) 184 racewriterangepc(to.array, uintptr(n*int(width)), callerpc, pc) 185 racereadrangepc(fm.array, uintptr(n*int(width)), callerpc, pc) 186 } 187 if msanenabled { 188 msanwrite(to.array, uintptr(n*int(width))) 189 msanread(fm.array, uintptr(n*int(width))) 190 } 191 192 size := uintptr(n) * width 193 if size == 1 { // common case worth about 2x to do here 194 // TODO: is this still worth it with new memmove impl? 195 *(*byte)(to.array) = *(*byte)(fm.array) // known to be a byte pointer 196 } else { 197 memmove(to.array, fm.array, size) 198 } 199 return n 200 } 201 202 func slicestringcopy(to []byte, fm string) int { 203 if len(fm) == 0 || len(to) == 0 { 204 return 0 205 } 206 207 n := len(fm) 208 if len(to) < n { 209 n = len(to) 210 } 211 212 if raceenabled { 213 callerpc := getcallerpc() 214 pc := funcPC(slicestringcopy) 215 racewriterangepc(unsafe.Pointer(&to[0]), uintptr(n), callerpc, pc) 216 } 217 if msanenabled { 218 msanwrite(unsafe.Pointer(&to[0]), uintptr(n)) 219 } 220 221 memmove(unsafe.Pointer(&to[0]), stringStructOf(&fm).str, uintptr(n)) 222 return n 223 }