Source file
src/runtime/slice.go
Documentation: runtime
1
2
3
4
5 package runtime
6
7 import (
8 "runtime/internal/math"
9 "runtime/internal/sys"
10 "unsafe"
11 )
12
13 type slice struct {
14 array unsafe.Pointer
15 len int
16 cap int
17 }
18
19
20 type notInHeapSlice struct {
21 array *notInHeap
22 len int
23 cap int
24 }
25
26 func panicmakeslicelen() {
27 panic(errorString("makeslice: len out of range"))
28 }
29
30 func panicmakeslicecap() {
31 panic(errorString("makeslice: cap out of range"))
32 }
33
34
35
36 func makeslicecopy(et *_type, tolen int, fromlen int, from unsafe.Pointer) unsafe.Pointer {
37 var tomem, copymem uintptr
38 if uintptr(tolen) > uintptr(fromlen) {
39 var overflow bool
40 tomem, overflow = math.MulUintptr(et.size, uintptr(tolen))
41 if overflow || tomem > maxAlloc || tolen < 0 {
42 panicmakeslicelen()
43 }
44 copymem = et.size * uintptr(fromlen)
45 } else {
46
47
48
49 tomem = et.size * uintptr(tolen)
50 copymem = tomem
51 }
52
53 var to unsafe.Pointer
54 if et.ptrdata == 0 {
55 to = mallocgc(tomem, nil, false)
56 if copymem < tomem {
57 memclrNoHeapPointers(add(to, copymem), tomem-copymem)
58 }
59 } else {
60
61 to = mallocgc(tomem, et, true)
62 if copymem > 0 && writeBarrier.enabled {
63
64
65 bulkBarrierPreWriteSrcOnly(uintptr(to), uintptr(from), copymem)
66 }
67 }
68
69 if raceenabled {
70 callerpc := getcallerpc()
71 pc := funcPC(makeslicecopy)
72 racereadrangepc(from, copymem, callerpc, pc)
73 }
74 if msanenabled {
75 msanread(from, copymem)
76 }
77
78 memmove(to, from, copymem)
79
80 return to
81 }
82
83 func makeslice(et *_type, len, cap int) unsafe.Pointer {
84 mem, overflow := math.MulUintptr(et.size, uintptr(cap))
85 if overflow || mem > maxAlloc || len < 0 || len > cap {
86
87
88
89
90
91 mem, overflow := math.MulUintptr(et.size, uintptr(len))
92 if overflow || mem > maxAlloc || len < 0 {
93 panicmakeslicelen()
94 }
95 panicmakeslicecap()
96 }
97
98 return mallocgc(mem, et, true)
99 }
100
101 func makeslice64(et *_type, len64, cap64 int64) unsafe.Pointer {
102 len := int(len64)
103 if int64(len) != len64 {
104 panicmakeslicelen()
105 }
106
107 cap := int(cap64)
108 if int64(cap) != cap64 {
109 panicmakeslicecap()
110 }
111
112 return makeslice(et, len, cap)
113 }
114
115 func unsafeslice(et *_type, ptr unsafe.Pointer, len int) {
116 if len == 0 {
117 return
118 }
119
120 if ptr == nil {
121 panic(errorString("unsafe.Slice: ptr is nil and len is not zero"))
122 }
123
124 mem, overflow := math.MulUintptr(et.size, uintptr(len))
125 if overflow || mem > maxAlloc || len < 0 {
126 panicunsafeslicelen()
127 }
128 }
129
130 func unsafeslice64(et *_type, ptr unsafe.Pointer, len64 int64) {
131 len := int(len64)
132 if int64(len) != len64 {
133 panicunsafeslicelen()
134 }
135 unsafeslice(et, ptr, len)
136 }
137
138 func unsafeslicecheckptr(et *_type, ptr unsafe.Pointer, len64 int64) {
139 unsafeslice64(et, ptr, len64)
140
141
142
143 if checkptrStraddles(ptr, uintptr(len64)*et.size) {
144 throw("checkptr: unsafe.Slice result straddles multiple allocations")
145 }
146 }
147
148 func panicunsafeslicelen() {
149 panic(errorString("unsafe.Slice: len out of range"))
150 }
151
152
153
154
155
156
157
158
159
160
161
162 func growslice(et *_type, old slice, cap int) slice {
163 if raceenabled {
164 callerpc := getcallerpc()
165 racereadrangepc(old.array, uintptr(old.len*int(et.size)), callerpc, funcPC(growslice))
166 }
167 if msanenabled {
168 msanread(old.array, uintptr(old.len*int(et.size)))
169 }
170
171 if cap < old.cap {
172 panic(errorString("growslice: cap out of range"))
173 }
174
175 if et.size == 0 {
176
177
178 return slice{unsafe.Pointer(&zerobase), old.len, cap}
179 }
180
181 newcap := old.cap
182 doublecap := newcap + newcap
183 if cap > doublecap {
184 newcap = cap
185 } else {
186 if old.cap < 1024 {
187 newcap = doublecap
188 } else {
189
190
191 for 0 < newcap && newcap < cap {
192 newcap += newcap / 4
193 }
194
195
196 if newcap <= 0 {
197 newcap = cap
198 }
199 }
200 }
201
202 var overflow bool
203 var lenmem, newlenmem, capmem uintptr
204
205
206
207
208 switch {
209 case et.size == 1:
210 lenmem = uintptr(old.len)
211 newlenmem = uintptr(cap)
212 capmem = roundupsize(uintptr(newcap))
213 overflow = uintptr(newcap) > maxAlloc
214 newcap = int(capmem)
215 case et.size == sys.PtrSize:
216 lenmem = uintptr(old.len) * sys.PtrSize
217 newlenmem = uintptr(cap) * sys.PtrSize
218 capmem = roundupsize(uintptr(newcap) * sys.PtrSize)
219 overflow = uintptr(newcap) > maxAlloc/sys.PtrSize
220 newcap = int(capmem / sys.PtrSize)
221 case isPowerOfTwo(et.size):
222 var shift uintptr
223 if sys.PtrSize == 8 {
224
225 shift = uintptr(sys.Ctz64(uint64(et.size))) & 63
226 } else {
227 shift = uintptr(sys.Ctz32(uint32(et.size))) & 31
228 }
229 lenmem = uintptr(old.len) << shift
230 newlenmem = uintptr(cap) << shift
231 capmem = roundupsize(uintptr(newcap) << shift)
232 overflow = uintptr(newcap) > (maxAlloc >> shift)
233 newcap = int(capmem >> shift)
234 default:
235 lenmem = uintptr(old.len) * et.size
236 newlenmem = uintptr(cap) * et.size
237 capmem, overflow = math.MulUintptr(et.size, uintptr(newcap))
238 capmem = roundupsize(capmem)
239 newcap = int(capmem / et.size)
240 }
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255 if overflow || capmem > maxAlloc {
256 panic(errorString("growslice: cap out of range"))
257 }
258
259 var p unsafe.Pointer
260 if et.ptrdata == 0 {
261 p = mallocgc(capmem, nil, false)
262
263
264 memclrNoHeapPointers(add(p, newlenmem), capmem-newlenmem)
265 } else {
266
267 p = mallocgc(capmem, et, true)
268 if lenmem > 0 && writeBarrier.enabled {
269
270
271 bulkBarrierPreWriteSrcOnly(uintptr(p), uintptr(old.array), lenmem-et.size+et.ptrdata)
272 }
273 }
274 memmove(p, old.array, lenmem)
275
276 return slice{p, old.len, newcap}
277 }
278
279 func isPowerOfTwo(x uintptr) bool {
280 return x&(x-1) == 0
281 }
282
283
284 func slicecopy(toPtr unsafe.Pointer, toLen int, fromPtr unsafe.Pointer, fromLen int, width uintptr) int {
285 if fromLen == 0 || toLen == 0 {
286 return 0
287 }
288
289 n := fromLen
290 if toLen < n {
291 n = toLen
292 }
293
294 if width == 0 {
295 return n
296 }
297
298 size := uintptr(n) * width
299 if raceenabled {
300 callerpc := getcallerpc()
301 pc := funcPC(slicecopy)
302 racereadrangepc(fromPtr, size, callerpc, pc)
303 racewriterangepc(toPtr, size, callerpc, pc)
304 }
305 if msanenabled {
306 msanread(fromPtr, size)
307 msanwrite(toPtr, size)
308 }
309
310 if size == 1 {
311
312 *(*byte)(toPtr) = *(*byte)(fromPtr)
313 } else {
314 memmove(toPtr, fromPtr, size)
315 }
316 return n
317 }
318
View as plain text