// Copyright 2009 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package runtimeimport ()typeslicestruct { array unsafe.Pointer len int cap int}// A notInHeapSlice is a slice backed by go:notinheap memory.typenotInHeapSlicestruct { array *notInHeap len int cap int}func () {panic(errorString("makeslice: len out of range"))}func () {panic(errorString("makeslice: cap out of range"))}// makeslicecopy allocates a slice of "tolen" elements of type "et",// then copies "fromlen" elements of type "et" into that new allocation from "from".func ( *_type, int, int, unsafe.Pointer) unsafe.Pointer {var , uintptrifuintptr() > uintptr() {varbool , = math.MulUintptr(.size, uintptr())if || > maxAlloc || < 0 {panicmakeslicelen() } = .size * uintptr() } else {// fromlen is a known good length providing and equal or greater than tolen, // thereby making tolen a good slice length too as from and to slices have the // same element width. = .size * uintptr() = }varunsafe.Pointerif .ptrdata == 0 { = mallocgc(, nil, false)if < {memclrNoHeapPointers(add(, ), -) } } else {// Note: can't use rawmem (which avoids zeroing of memory), because then GC can scan uninitialized memory. = mallocgc(, , true)if > 0 && writeBarrier.enabled {// Only shade the pointers in old.array since we know the destination slice to // only contains nil pointers because it has been cleared during alloc.bulkBarrierPreWriteSrcOnly(uintptr(), uintptr(), ) } }ifraceenabled { := getcallerpc() := funcPC()racereadrangepc(, , , ) }ifmsanenabled {msanread(, ) }memmove(, , )return}func ( *_type, , int) unsafe.Pointer { , := math.MulUintptr(.size, uintptr())if || > maxAlloc || < 0 || > {// NOTE: Produce a 'len out of range' error instead of a // 'cap out of range' error when someone does make([]T, bignumber). // 'cap out of range' is true too, but since the cap is only being // supplied implicitly, saying len is clearer. // See golang.org/issue/4085. , := math.MulUintptr(.size, uintptr())if || > maxAlloc || < 0 {panicmakeslicelen() }panicmakeslicecap() }returnmallocgc(, , true)}func ( *_type, , int64) unsafe.Pointer { := int()ifint64() != {panicmakeslicelen() } := int()ifint64() != {panicmakeslicecap() }returnmakeslice(, , )}// growslice handles slice growth during append.// It is passed the slice element type, the old slice, and the desired new minimum capacity,// and it returns a new slice with at least that capacity, with the old data// copied into it.// The new slice's length is set to the old slice's length,// NOT to the new requested capacity.// This is for codegen convenience. The old slice's length is used immediately// to calculate where to write new values during an append.// TODO: When the old backend is gone, reconsider this decision.// The SSA backend might prefer the new length or to return only ptr/cap and save stack space.func ( *_type, slice, int) slice {ifraceenabled { := getcallerpc()racereadrangepc(.array, uintptr(.len*int(.size)), , funcPC()) }ifmsanenabled {msanread(.array, uintptr(.len*int(.size))) }if < .cap {panic(errorString("growslice: cap out of range")) }if .size == 0 {// append should not create a slice with nil pointer but non-zero len. // We assume that append doesn't need to preserve old.array in this case.returnslice{unsafe.Pointer(&zerobase), .len, } } := .cap := + if > { = } else {if .cap < 1024 { = } else {// Check 0 < newcap to detect overflow // and prevent an infinite loop.for0 < && < { += / 4 }// Set newcap to the requested cap when // the newcap calculation overflowed.if <= 0 { = } } }varboolvar , , uintptr// Specialize for common values of et.size. // For 1 we don't need any division/multiplication. // For sys.PtrSize, compiler will optimize division/multiplication into a shift by a constant. // For powers of 2, use a variable shift.switch {case .size == 1: = uintptr(.len) = uintptr() = roundupsize(uintptr()) = uintptr() > maxAlloc = int()case .size == sys.PtrSize: = uintptr(.len) * sys.PtrSize = uintptr() * sys.PtrSize = roundupsize(uintptr() * sys.PtrSize) = uintptr() > maxAlloc/sys.PtrSize = int( / sys.PtrSize)caseisPowerOfTwo(.size):varuintptrifsys.PtrSize == 8 {// Mask shift for better code generation. = uintptr(sys.Ctz64(uint64(.size))) & 63 } else { = uintptr(sys.Ctz32(uint32(.size))) & 31 } = uintptr(.len) << = uintptr() << = roundupsize(uintptr() << ) = uintptr() > (maxAlloc >> ) = int( >> )default: = uintptr(.len) * .size = uintptr() * .size , = math.MulUintptr(.size, uintptr()) = roundupsize() = int( / .size) }// The check of overflow in addition to capmem > maxAlloc is needed // to prevent an overflow which can be used to trigger a segfault // on 32bit architectures with this example program: // // type T [1<<27 + 1]int64 // // var d T // var s []T // // func main() { // s = append(s, d, d, d, d) // print(len(s), "\n") // }if || > maxAlloc {panic(errorString("growslice: cap out of range")) }varunsafe.Pointerif .ptrdata == 0 { = mallocgc(, nil, false)// The append() that calls growslice is going to overwrite from old.len to cap (which will be the new length). // Only clear the part that will not be overwritten.memclrNoHeapPointers(add(, ), -) } else {// Note: can't use rawmem (which avoids zeroing of memory), because then GC can scan uninitialized memory. = mallocgc(, , true)if > 0 && writeBarrier.enabled {// Only shade the pointers in old.array since we know the destination slice p // only contains nil pointers because it has been cleared during alloc.bulkBarrierPreWriteSrcOnly(uintptr(), uintptr(.array), -.size+.ptrdata) } }memmove(, .array, )returnslice{, .len, }}func ( uintptr) bool {return &(-1) == 0}// slicecopy is used to copy from a string or slice of pointerless elements into a slice.func ( unsafe.Pointer, int, unsafe.Pointer, int, uintptr) int {if == 0 || == 0 {return0 } := if < { = }if == 0 {return } := uintptr() * ifraceenabled { := getcallerpc() := funcPC()racereadrangepc(, , , )racewriterangepc(, , , ) }ifmsanenabled {msanread(, )msanwrite(, ) }if == 1 { // common case worth about 2x to do here// TODO: is this still worth it with new memmove impl? *(*byte)() = *(*byte)() // known to be a byte pointer } else {memmove(, , ) }return}