1 package runtime
2 3 // This file implements compiler builtins for slices: append() and copy().
4 5 import (
6 "internal/gclayout"
7 "math/bits"
8 "unsafe"
9 )
10 11 // Builtin append(src, elements...) function: append elements to src and return
12 // the modified (possibly expanded) slice.
13 func sliceAppend(srcBuf, elemsBuf unsafe.Pointer, srcLen, srcCap, elemsLen, elemSize uintptr) (unsafe.Pointer, uintptr, uintptr) {
14 newLen := srcLen + elemsLen
15 if elemsLen > 0 {
16 // Allocate a new slice with capacity for elemsLen more elements, if necessary;
17 // otherwise, reuse the passed slice.
18 srcBuf, _, srcCap = sliceGrow(srcBuf, srcLen, srcCap, newLen, elemSize)
19 20 // Append the new elements in-place.
21 memmove(unsafe.Add(srcBuf, srcLen*elemSize), elemsBuf, elemsLen*elemSize)
22 }
23 24 return srcBuf, newLen, srcCap
25 }
26 27 // Builtin copy(dst, src) function: copy bytes from dst to src.
28 func sliceCopy(dst, src unsafe.Pointer, dstLen, srcLen uintptr, elemSize uintptr) int {
29 // n = min(srcLen, dstLen)
30 n := srcLen
31 if n > dstLen {
32 n = dstLen
33 }
34 memmove(dst, src, n*elemSize)
35 return int(n)
36 }
37 38 // sliceGrow returns a new slice with space for at least newCap elements
39 func sliceGrow(oldBuf unsafe.Pointer, oldLen, oldCap, newCap, elemSize uintptr) (unsafe.Pointer, uintptr, uintptr) {
40 if oldCap >= newCap {
41 // No need to grow, return the input slice.
42 return oldBuf, oldLen, oldCap
43 }
44 45 // This can be made more memory-efficient by multiplying by some other constant, such as 1.5,
46 // which seems to be allowed by the Go language specification (but this can be observed by
47 // programs); however, due to memory fragmentation and the current state of the Moxie
48 // memory allocators, this causes some difficult to debug issues.
49 newCap = 1 << bits.Len(uint(newCap))
50 51 var layout unsafe.Pointer
52 // less type info here; can only go off element size
53 if elemSize < unsafe.Sizeof(uintptr(0)) {
54 layout = gclayout.NoPtrs.AsPtr()
55 }
56 57 buf := alloc(newCap*elemSize, layout)
58 if oldLen > 0 {
59 // copy any data to new slice
60 memmove(buf, oldBuf, oldLen*elemSize)
61 }
62 63 return buf, oldLen, newCap
64 }
65