github.com/4ad/go@v0.0.0-20161219182952-69a12818b605/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 // TODO: take uintptrs instead of int64s? 40 func makeslice(et *_type, len64, cap64 int64) slice { 41 // NOTE: The len > maxElements check here is not strictly necessary, 42 // but it produces a 'len out of range' error instead of a 'cap out of range' error 43 // when someone does make([]T, bignumber). 'cap out of range' is true too, 44 // but since the cap is only being supplied implicitly, saying len is clearer. 45 // See issue 4085. 46 maxElements := maxSliceCap(et.size) 47 len := int(len64) 48 if len64 < 0 || int64(len) != len64 || uintptr(len) > maxElements { 49 panic(errorString("makeslice: len out of range")) 50 } 51 52 cap := int(cap64) 53 if cap < len || int64(cap) != cap64 || uintptr(cap) > maxElements { 54 panic(errorString("makeslice: cap out of range")) 55 } 56 57 p := mallocgc(et.size*uintptr(cap), et, true) 58 return slice{p, len, cap} 59 } 60 61 // growslice handles slice growth during append. 62 // It is passed the slice element type, the old slice, and the desired new minimum capacity, 63 // and it returns a new slice with at least that capacity, with the old data 64 // copied into it. 65 // The new slice's length is set to the old slice's length, 66 // NOT to the new requested capacity. 67 // This is for codegen convenience. The old slice's length is used immediately 68 // to calculate where to write new values during an append. 69 // TODO: When the old backend is gone, reconsider this decision. 70 // The SSA backend might prefer the new length or to return only ptr/cap and save stack space. 71 func growslice(et *_type, old slice, cap int) slice { 72 if raceenabled { 73 callerpc := getcallerpc(unsafe.Pointer(&et)) 74 racereadrangepc(old.array, uintptr(old.len*int(et.size)), callerpc, funcPC(growslice)) 75 } 76 if msanenabled { 77 msanread(old.array, uintptr(old.len*int(et.size))) 78 } 79 80 if et.size == 0 { 81 if cap < old.cap { 82 panic(errorString("growslice: cap out of range")) 83 } 84 // append should not create a slice with nil pointer but non-zero len. 85 // We assume that append doesn't need to preserve old.array in this case. 86 return slice{unsafe.Pointer(&zerobase), old.len, cap} 87 } 88 89 newcap := old.cap 90 doublecap := newcap + newcap 91 if cap > doublecap { 92 newcap = cap 93 } else { 94 if old.len < 1024 { 95 newcap = doublecap 96 } else { 97 for newcap < cap { 98 newcap += newcap / 4 99 } 100 } 101 } 102 103 var lenmem, capmem uintptr 104 const ptrSize = unsafe.Sizeof((*byte)(nil)) 105 switch et.size { 106 case 1: 107 lenmem = uintptr(old.len) 108 capmem = roundupsize(uintptr(newcap)) 109 newcap = int(capmem) 110 case ptrSize: 111 lenmem = uintptr(old.len) * ptrSize 112 capmem = roundupsize(uintptr(newcap) * ptrSize) 113 newcap = int(capmem / ptrSize) 114 default: 115 lenmem = uintptr(old.len) * et.size 116 capmem = roundupsize(uintptr(newcap) * et.size) 117 newcap = int(capmem / et.size) 118 } 119 120 if cap < old.cap || uintptr(newcap) > maxSliceCap(et.size) { 121 panic(errorString("growslice: cap out of range")) 122 } 123 124 var p unsafe.Pointer 125 if et.kind&kindNoPointers != 0 { 126 p = mallocgc(capmem, nil, false) 127 memmove(p, old.array, lenmem) 128 memclr(add(p, lenmem), capmem-lenmem) 129 } else { 130 // Note: can't use rawmem (which avoids zeroing of memory), because then GC can scan uninitialized memory. 131 p = mallocgc(capmem, et, true) 132 if !writeBarrier.enabled { 133 if lenmem > 0 { 134 memmove(p, old.array, lenmem) 135 } 136 } else { 137 for i := uintptr(0); i < lenmem; i += et.size { 138 typedmemmove(et, add(p, i), add(old.array, i)) 139 } 140 } 141 } 142 143 return slice{p, old.len, newcap} 144 } 145 146 func slicecopy(to, fm slice, width uintptr) int { 147 if fm.len == 0 || to.len == 0 { 148 return 0 149 } 150 151 n := fm.len 152 if to.len < n { 153 n = to.len 154 } 155 156 if width == 0 { 157 return n 158 } 159 160 if raceenabled { 161 callerpc := getcallerpc(unsafe.Pointer(&to)) 162 pc := funcPC(slicecopy) 163 racewriterangepc(to.array, uintptr(n*int(width)), callerpc, pc) 164 racereadrangepc(fm.array, uintptr(n*int(width)), callerpc, pc) 165 } 166 if msanenabled { 167 msanwrite(to.array, uintptr(n*int(width))) 168 msanread(fm.array, uintptr(n*int(width))) 169 } 170 171 size := uintptr(n) * width 172 if size == 1 { // common case worth about 2x to do here 173 // TODO: is this still worth it with new memmove impl? 174 *(*byte)(to.array) = *(*byte)(fm.array) // known to be a byte pointer 175 } else { 176 memmove(to.array, fm.array, size) 177 } 178 return n 179 } 180 181 func slicestringcopy(to []byte, fm string) int { 182 if len(fm) == 0 || len(to) == 0 { 183 return 0 184 } 185 186 n := len(fm) 187 if len(to) < n { 188 n = len(to) 189 } 190 191 if raceenabled { 192 callerpc := getcallerpc(unsafe.Pointer(&to)) 193 pc := funcPC(slicestringcopy) 194 racewriterangepc(unsafe.Pointer(&to[0]), uintptr(n), callerpc, pc) 195 } 196 if msanenabled { 197 msanwrite(unsafe.Pointer(&to[0]), uintptr(n)) 198 } 199 200 memmove(unsafe.Pointer(&to[0]), stringStructOf(&fm).str, uintptr(n)) 201 return n 202 }