// /usr/local/go/src/runtime/slice.go
newcap:=old.capdoublecap:=newcap+newcapifcap>doublecap{newcap=cap}else{ifold.cap<1024{newcap=doublecap}else{// Check 0 < newcap to detect overflow
// and prevent an infinite loop.
for0<newcap&&newcap<cap{newcap+=newcap/4}// Set newcap to the requested cap when
// the newcap calculation overflowed.
ifnewcap<=0{newcap=cap}}}
varoverflowboolvarlenmem,newlenmem,capmemuintptr// 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{caseet.size==1:lenmem=uintptr(old.len)newlenmem=uintptr(cap)capmem=roundupsize(uintptr(newcap))overflow=uintptr(newcap)>maxAllocnewcap=int(capmem)caseet.size==sys.PtrSize:lenmem=uintptr(old.len)*sys.PtrSizenewlenmem=uintptr(cap)*sys.PtrSizecapmem=roundupsize(uintptr(newcap)*sys.PtrSize)overflow=uintptr(newcap)>maxAlloc/sys.PtrSizenewcap=int(capmem/sys.PtrSize)caseisPowerOfTwo(et.size):varshiftuintptrifsys.PtrSize==8{// Mask shift for better code generation.
shift=uintptr(sys.Ctz64(uint64(et.size)))&63}else{shift=uintptr(sys.Ctz32(uint32(et.size)))&31}lenmem=uintptr(old.len)<<shiftnewlenmem=uintptr(cap)<<shiftcapmem=roundupsize(uintptr(newcap)<<shift)overflow=uintptr(newcap)>(maxAlloc>>shift)newcap=int(capmem>>shift)default:lenmem=uintptr(old.len)*et.sizenewlenmem=uintptr(cap)*et.sizecapmem,overflow=math.MulUintptr(et.size,uintptr(newcap))capmem=roundupsize(capmem)newcap=int(capmem/et.size)}
cat3306/gosrclearn/slice
▶ dlv debug
Type 'help' for list of commands.
(dlv)
1
2
3
4
5
▶ dlv debug
Type 'help' for list of commands.
(dlv) break runtime.growslice
Breakpoint 1 set at 0x1047fea for runtime.growslice() /usr/local/go/src/runtime/slice.go:162
(dlv)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
(dlv)continue>runtime.growslice()/usr/local/go/src/runtime/slice.go:162(hitsgoroutine(1):5total:9)(PC:0x1047fea)Warning:debuggingoptimizedfunction157://NOTtothenewrequestedcapacity.158://Thisisforcodegenconvenience.Theoldslice's length is used immediately159://tocalculatewheretowritenewvaluesduringanappend.160://TODO:Whentheoldbackendisgone,reconsiderthisdecision.161://TheSSAbackendmightpreferthenewlengthortoreturnonlyptr/capandsavestackspace.=>162:funcgrowslice(et*_type,oldslice,capint)slice{163:ifraceenabled{164:callerpc:=getcallerpc()165:racereadrangepc(old.array,uintptr(old.len*int(et.size)),callerpc,funcPC(growslice))166:}167:ifmsanenabled{
1
2
3
4
5
(dlv) print old
runtime.slice {array: unsafe.Pointer(0x0), len: 0, cap: 0}
(dlv) print cap
5
(dlv)
(dlv)>runtime.growslice()/usr/local/go/src/runtime/slice.go:255(PC:0x10481eb)Warning:debuggingoptimizedfunction250://251://funcmain(){252://s=append(s,d,d,d,d)253://print(len(s),"\n")254://}=>255:ifoverflow||capmem>maxAlloc{256:panic(errorString("growslice: cap out of range"))257:}258:259:varpunsafe.Pointer260:ifet.ptrdata==0{(dlv)printnewcap6
// /usr/local/go/src/runtime/slice.go
funcslicecopy(toPtrunsafe.Pointer,toLenint,fromPtrunsafe.Pointer,fromLenint,widthuintptr)int{iffromLen==0||toLen==0{return0}n:=fromLeniftoLen<n{n=toLen}ifwidth==0{returnn}size:=uintptr(n)*widthifraceenabled{callerpc:=getcallerpc()pc:=funcPC(slicecopy)racereadrangepc(fromPtr,size,callerpc,pc)racewriterangepc(toPtr,size,callerpc,pc)}ifmsanenabled{msanread(fromPtr,size)msanwrite(toPtr,size)}ifsize==1{// common case worth about 2x to do here
// TODO: is this still worth it with new memmove impl?
*(*byte)(toPtr)=*(*byte)(fromPtr)// known to be a byte pointer
}else{memmove(toPtr,fromPtr,size)}returnn}