// 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 {arrayunsafe.Pointerlenintcapint}// A notInHeapSlice is a slice backed by runtime/internal/sys.NotInHeap memory.typenotInHeapSlicestruct {array *notInHeaplenintcapint}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 .PtrBytes == 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() := abi.FuncPCABIInternal()racereadrangepc(, , , ) }ifmsanenabled {msanread(, ) }ifasanenabled {asanread(, ) }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(, , )}// This is a wrapper over runtime/internal/math.MulUintptr,// so the compiler can recognize and treat it as an intrinsic.func (, uintptr) (uintptr, bool) {returnmath.MulUintptr(, )}// growslice allocates new backing store for a slice.//// arguments://// oldPtr = pointer to the slice's backing array// newLen = new length (= oldLen + num)// oldCap = original slice's capacity.// num = number of elements being added// et = element type//// return values://// newPtr = pointer to the new backing store// newLen = same value as the argument// newCap = capacity of the new backing store//// Requires that uint(newLen) > uint(oldCap).// Assumes the original slice length is newLen - num//// A new backing store is allocated with space for at least newLen elements.// Existing entries [0, oldLen) are copied over to the new backing store.// Added entries [oldLen, newLen) are not initialized by growslice// (although for pointer-containing element types, they are zeroed). They// must be initialized by the caller.// Trailing entries [newLen, newCap) are zeroed.//// growslice's odd calling convention makes the generated code that calls// this function simpler. In particular, it accepts and returns the// new length so that the old length is not live (does not need to be// spilled/restored) and the new length is returned (also does not need// to be spilled/restored).func ( unsafe.Pointer, , , int, *_type) slice { := - ifraceenabled { := getcallerpc()racereadrangepc(, uintptr(*int(.Size_)), , abi.FuncPCABIInternal()) }ifmsanenabled {msanread(, uintptr(*int(.Size_))) }ifasanenabled {asanread(, uintptr(*int(.Size_))) }if < 0 {panic(errorString("growslice: len 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 oldPtr in this case.returnslice{unsafe.Pointer(&zerobase), , } } := := + if > { = } else {const = 256if < { = } else {// Check 0 < newcap to detect overflow // and prevent an infinite loop.for0 < && < {// Transition from growing 2x for small slices // to growing 1.25x for large slices. This formula // gives a smooth-ish transition between the two. += ( + 3*) / 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 goarch.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() = uintptr() = roundupsize(uintptr()) = uintptr() > maxAlloc = int()case .Size_ == goarch.PtrSize: = uintptr() * goarch.PtrSize = uintptr() * goarch.PtrSize = roundupsize(uintptr() * goarch.PtrSize) = uintptr() > maxAlloc/goarch.PtrSize = int( / goarch.PtrSize)caseisPowerOfTwo(.Size_):varuintptrifgoarch.PtrSize == 8 {// Mask shift for better code generation. = uintptr(sys.TrailingZeros64(uint64(.Size_))) & 63 } else { = uintptr(sys.TrailingZeros32(uint32(.Size_))) & 31 } = uintptr() << = uintptr() << = roundupsize(uintptr() << ) = uintptr() > (maxAlloc >> ) = int( >> ) = uintptr() << default: = uintptr() * .Size_ = uintptr() * .Size_ , = math.MulUintptr(.Size_, uintptr()) = roundupsize() = int( / .Size_) = uintptr() * .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: len out of range")) }varunsafe.Pointerif .PtrBytes == 0 { = mallocgc(, nil, false)// The append() that calls growslice is going to overwrite from oldLen to newLen. // Only clear the part that will not be overwritten. // The reflect_growslice() that calls growslice will manually clear // the region not cleared here.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 oldPtr since we know the destination slice p // only contains nil pointers because it has been cleared during alloc.bulkBarrierPreWriteSrcOnly(uintptr(), uintptr(), -.Size_+.PtrBytes) } }memmove(, , )returnslice{, , }}//go:linkname reflect_growslice reflect.growslicefunc ( *_type, slice, int) slice {// Semantically equivalent to slices.Grow, except that the caller // is responsible for ensuring that old.len+num > old.cap. -= .cap - .len// preserve memory of old[old.len:old.cap] := growslice(.array, .cap+, .cap, , )// growslice does not zero out new[old.cap:new.len] since it assumes that // the memory will be overwritten by an append() that called growslice. // Since the caller of reflect_growslice is not append(), // zero out this region before returning the slice to the reflect package.if .PtrBytes == 0 { := uintptr(.cap) * .Size_ := uintptr(.len) * .Size_memclrNoHeapPointers(add(.array, ), -) } .len = .len// preserve the old lengthreturn}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() := abi.FuncPCABIInternal()racereadrangepc(, , , )racewriterangepc(, , , ) }ifmsanenabled {msanread(, )msanwrite(, ) }ifasanenabled {asanread(, )asanwrite(, ) }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}//go:linkname bytealg_MakeNoZero internal/bytealg.MakeNoZerofunc ( int) []byte {ifuintptr() > maxAlloc {panicmakeslicelen() }returnunsafe.Slice((*byte)(mallocgc(uintptr(), nil, false)), )}
The pages are generated with Goldsv0.6.7. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds.