github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/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 // TODO: take uintptrs instead of int64s? 18 func makeslice(t *slicetype, len64, cap64 int64) slice { 19 // NOTE: The len > MaxMem/elemsize check here is not strictly necessary, 20 // but it produces a 'len out of range' error instead of a 'cap out of range' error 21 // when someone does make([]T, bignumber). 'cap out of range' is true too, 22 // but since the cap is only being supplied implicitly, saying len is clearer. 23 // See issue 4085. 24 len := int(len64) 25 if len64 < 0 || int64(len) != len64 || t.elem.size > 0 && uintptr(len) > _MaxMem/t.elem.size { 26 panic(errorString("makeslice: len out of range")) 27 } 28 cap := int(cap64) 29 if cap < len || int64(cap) != cap64 || t.elem.size > 0 && uintptr(cap) > _MaxMem/t.elem.size { 30 panic(errorString("makeslice: cap out of range")) 31 } 32 p := newarray(t.elem, uintptr(cap)) 33 return slice{p, len, cap} 34 } 35 36 // growslice handles slice growth during append. 37 // It is passed the slice type, the old slice, and the desired new minimum capacity, 38 // and it returns a new slice with at least that capacity, with the old data 39 // copied into it. 40 func growslice(t *slicetype, old slice, cap int) slice { 41 if raceenabled { 42 callerpc := getcallerpc(unsafe.Pointer(&t)) 43 racereadrangepc(old.array, uintptr(old.len*int(t.elem.size)), callerpc, funcPC(growslice)) 44 } 45 if msanenabled { 46 msanread(old.array, uintptr(old.len*int(t.elem.size))) 47 } 48 49 et := t.elem 50 if et.size == 0 { 51 if cap < old.cap { 52 panic(errorString("growslice: cap out of range")) 53 } 54 // append should not create a slice with nil pointer but non-zero len. 55 // We assume that append doesn't need to preserve old.array in this case. 56 return slice{unsafe.Pointer(&zerobase), old.len, cap} 57 } 58 59 newcap := old.cap 60 doublecap := newcap + newcap 61 if cap > doublecap { 62 newcap = cap 63 } else { 64 if old.len < 1024 { 65 newcap = doublecap 66 } else { 67 for newcap < cap { 68 newcap += newcap / 4 69 } 70 } 71 } 72 73 var lenmem, capmem, maxcap uintptr 74 const ptrSize = unsafe.Sizeof((*byte)(nil)) 75 switch et.size { 76 case 1: 77 lenmem = uintptr(old.len) 78 capmem = roundupsize(uintptr(newcap)) 79 newcap = int(capmem) 80 maxcap = _MaxMem 81 case ptrSize: 82 lenmem = uintptr(old.len) * ptrSize 83 capmem = roundupsize(uintptr(newcap) * ptrSize) 84 newcap = int(capmem / ptrSize) 85 maxcap = _MaxMem / ptrSize 86 default: 87 lenmem = uintptr(old.len) * et.size 88 capmem = roundupsize(uintptr(newcap) * et.size) 89 newcap = int(capmem / et.size) 90 maxcap = _MaxMem / et.size 91 } 92 93 if cap < old.cap || uintptr(newcap) > maxcap { 94 panic(errorString("growslice: cap out of range")) 95 } 96 97 var p unsafe.Pointer 98 if et.kind&kindNoPointers != 0 { 99 p = rawmem(capmem) 100 memmove(p, old.array, lenmem) 101 memclr(add(p, lenmem), capmem-lenmem) 102 } else { 103 // Note: can't use rawmem (which avoids zeroing of memory), because then GC can scan uninitialized memory. 104 p = newarray(et, uintptr(newcap)) 105 if !writeBarrier.enabled { 106 memmove(p, old.array, lenmem) 107 } else { 108 for i := uintptr(0); i < lenmem; i += et.size { 109 typedmemmove(et, add(p, i), add(old.array, i)) 110 } 111 } 112 } 113 114 return slice{p, old.len, newcap} 115 } 116 117 func slicecopy(to, fm slice, width uintptr) int { 118 if fm.len == 0 || to.len == 0 { 119 return 0 120 } 121 122 n := fm.len 123 if to.len < n { 124 n = to.len 125 } 126 127 if width == 0 { 128 return n 129 } 130 131 if raceenabled { 132 callerpc := getcallerpc(unsafe.Pointer(&to)) 133 pc := funcPC(slicecopy) 134 racewriterangepc(to.array, uintptr(n*int(width)), callerpc, pc) 135 racereadrangepc(fm.array, uintptr(n*int(width)), callerpc, pc) 136 } 137 if msanenabled { 138 msanwrite(to.array, uintptr(n*int(width))) 139 msanread(fm.array, uintptr(n*int(width))) 140 } 141 142 size := uintptr(n) * width 143 if size == 1 { // common case worth about 2x to do here 144 // TODO: is this still worth it with new memmove impl? 145 *(*byte)(to.array) = *(*byte)(fm.array) // known to be a byte pointer 146 } else { 147 memmove(to.array, fm.array, size) 148 } 149 return n 150 } 151 152 func slicestringcopy(to []byte, fm string) int { 153 if len(fm) == 0 || len(to) == 0 { 154 return 0 155 } 156 157 n := len(fm) 158 if len(to) < n { 159 n = len(to) 160 } 161 162 if raceenabled { 163 callerpc := getcallerpc(unsafe.Pointer(&to)) 164 pc := funcPC(slicestringcopy) 165 racewriterangepc(unsafe.Pointer(&to[0]), uintptr(n), callerpc, pc) 166 } 167 if msanenabled { 168 msanwrite(unsafe.Pointer(&to[0]), uintptr(n)) 169 } 170 171 memmove(unsafe.Pointer(&to[0]), stringStructOf(&fm).str, uintptr(n)) 172 return n 173 }