Source file
src/runtime/slice.go
Documentation: runtime
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.ptrdata == 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 func unsafeslice(et *_type, ptr unsafe.Pointer, len int) {
128 if len < 0 {
129 panicunsafeslicelen()
130 }
131
132 mem, overflow := math.MulUintptr(et.size, uintptr(len))
133 if overflow || mem > -uintptr(ptr) {
134 if ptr == nil {
135 panicunsafeslicenilptr()
136 }
137 panicunsafeslicelen()
138 }
139 }
140
141
142 func unsafeslice64(et *_type, ptr unsafe.Pointer, len64 int64) {
143 len := int(len64)
144 if int64(len) != len64 {
145 panicunsafeslicelen()
146 }
147 unsafeslice(et, ptr, len)
148 }
149
150 func unsafeslicecheckptr(et *_type, ptr unsafe.Pointer, len64 int64) {
151 unsafeslice64(et, ptr, len64)
152
153
154
155 if checkptrStraddles(ptr, uintptr(len64)*et.size) {
156 throw("checkptr: unsafe.Slice result straddles multiple allocations")
157 }
158 }
159
160 func panicunsafeslicelen() {
161 panic(errorString("unsafe.Slice: len out of range"))
162 }
163
164 func panicunsafeslicenilptr() {
165 panic(errorString("unsafe.Slice: ptr is nil and len is not zero"))
166 }
167
168
169
170
171
172
173
174
175
176
177
178 func growslice(et *_type, old slice, cap int) slice {
179 if raceenabled {
180 callerpc := getcallerpc()
181 racereadrangepc(old.array, uintptr(old.len*int(et.size)), callerpc, abi.FuncPCABIInternal(growslice))
182 }
183 if msanenabled {
184 msanread(old.array, uintptr(old.len*int(et.size)))
185 }
186 if asanenabled {
187 asanread(old.array, uintptr(old.len*int(et.size)))
188 }
189
190 if cap < old.cap {
191 panic(errorString("growslice: cap out of range"))
192 }
193
194 if et.size == 0 {
195
196
197 return slice{unsafe.Pointer(&zerobase), old.len, cap}
198 }
199
200 newcap := old.cap
201 doublecap := newcap + newcap
202 if cap > doublecap {
203 newcap = cap
204 } else {
205 const threshold = 256
206 if old.cap < threshold {
207 newcap = doublecap
208 } else {
209
210
211 for 0 < newcap && newcap < cap {
212
213
214
215 newcap += (newcap + 3*threshold) / 4
216 }
217
218
219 if newcap <= 0 {
220 newcap = cap
221 }
222 }
223 }
224
225 var overflow bool
226 var lenmem, newlenmem, capmem uintptr
227
228
229
230
231 switch {
232 case et.size == 1:
233 lenmem = uintptr(old.len)
234 newlenmem = uintptr(cap)
235 capmem = roundupsize(uintptr(newcap))
236 overflow = uintptr(newcap) > maxAlloc
237 newcap = int(capmem)
238 case et.size == goarch.PtrSize:
239 lenmem = uintptr(old.len) * goarch.PtrSize
240 newlenmem = uintptr(cap) * goarch.PtrSize
241 capmem = roundupsize(uintptr(newcap) * goarch.PtrSize)
242 overflow = uintptr(newcap) > maxAlloc/goarch.PtrSize
243 newcap = int(capmem / goarch.PtrSize)
244 case isPowerOfTwo(et.size):
245 var shift uintptr
246 if goarch.PtrSize == 8 {
247
248 shift = uintptr(sys.Ctz64(uint64(et.size))) & 63
249 } else {
250 shift = uintptr(sys.Ctz32(uint32(et.size))) & 31
251 }
252 lenmem = uintptr(old.len) << shift
253 newlenmem = uintptr(cap) << shift
254 capmem = roundupsize(uintptr(newcap) << shift)
255 overflow = uintptr(newcap) > (maxAlloc >> shift)
256 newcap = int(capmem >> shift)
257 default:
258 lenmem = uintptr(old.len) * et.size
259 newlenmem = uintptr(cap) * et.size
260 capmem, overflow = math.MulUintptr(et.size, uintptr(newcap))
261 capmem = roundupsize(capmem)
262 newcap = int(capmem / et.size)
263 }
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278 if overflow || capmem > maxAlloc {
279 panic(errorString("growslice: cap out of range"))
280 }
281
282 var p unsafe.Pointer
283 if et.ptrdata == 0 {
284 p = mallocgc(capmem, nil, false)
285
286
287 memclrNoHeapPointers(add(p, newlenmem), capmem-newlenmem)
288 } else {
289
290 p = mallocgc(capmem, et, true)
291 if lenmem > 0 && writeBarrier.enabled {
292
293
294 bulkBarrierPreWriteSrcOnly(uintptr(p), uintptr(old.array), lenmem-et.size+et.ptrdata)
295 }
296 }
297 memmove(p, old.array, lenmem)
298
299 return slice{p, old.len, newcap}
300 }
301
302 func isPowerOfTwo(x uintptr) bool {
303 return x&(x-1) == 0
304 }
305
306
307 func slicecopy(toPtr unsafe.Pointer, toLen int, fromPtr unsafe.Pointer, fromLen int, width uintptr) int {
308 if fromLen == 0 || toLen == 0 {
309 return 0
310 }
311
312 n := fromLen
313 if toLen < n {
314 n = toLen
315 }
316
317 if width == 0 {
318 return n
319 }
320
321 size := uintptr(n) * width
322 if raceenabled {
323 callerpc := getcallerpc()
324 pc := abi.FuncPCABIInternal(slicecopy)
325 racereadrangepc(fromPtr, size, callerpc, pc)
326 racewriterangepc(toPtr, size, callerpc, pc)
327 }
328 if msanenabled {
329 msanread(fromPtr, size)
330 msanwrite(toPtr, size)
331 }
332 if asanenabled {
333 asanread(fromPtr, size)
334 asanwrite(toPtr, size)
335 }
336
337 if size == 1 {
338
339 *(*byte)(toPtr) = *(*byte)(fromPtr)
340 } else {
341 memmove(toPtr, fromPtr, size)
342 }
343 return n
344 }
345
View as plain text