slice.mx raw

   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