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