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