mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
runtime: introduce nextslicecap
This allows to reuse the slice cap computation across specialized growslice funcs. Updates #49480 Change-Id: Ie075d9c3075659ea14c11d51a9cd4ed46aa0e961 Reviewed-on: https://go-review.googlesource.com/c/go/+/495876 Reviewed-by: Keith Randall <khr@google.com> Reviewed-by: Matthew Dempsky <mdempsky@google.com> Run-TryBot: Egon Elbre <egonelbre@gmail.com> Reviewed-by: Keith Randall <khr@golang.org> TryBot-Result: Gopher Robot <gobot@golang.org> Auto-Submit: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
parent
c56f463412
commit
1d84b02b22
2 changed files with 37 additions and 31 deletions
|
|
@ -51,6 +51,7 @@ func TestIntendedInlining(t *testing.T) {
|
||||||
"getMCache",
|
"getMCache",
|
||||||
"isDirectIface",
|
"isDirectIface",
|
||||||
"itabHashFunc",
|
"itabHashFunc",
|
||||||
|
"nextslicecap",
|
||||||
"noescape",
|
"noescape",
|
||||||
"pcvalueCacheKey",
|
"pcvalueCacheKey",
|
||||||
"readUnaligned32",
|
"readUnaligned32",
|
||||||
|
|
|
||||||
|
|
@ -177,37 +177,7 @@ func growslice(oldPtr unsafe.Pointer, newLen, oldCap, num int, et *_type) slice
|
||||||
return slice{unsafe.Pointer(&zerobase), newLen, newLen}
|
return slice{unsafe.Pointer(&zerobase), newLen, newLen}
|
||||||
}
|
}
|
||||||
|
|
||||||
newcap := oldCap
|
newcap := nextslicecap(newLen, oldCap)
|
||||||
doublecap := newcap + newcap
|
|
||||||
if newLen > doublecap {
|
|
||||||
newcap = newLen
|
|
||||||
} else {
|
|
||||||
const threshold = 256
|
|
||||||
if oldCap < threshold {
|
|
||||||
newcap = doublecap
|
|
||||||
} else {
|
|
||||||
for {
|
|
||||||
// Transition from growing 2x for small slices
|
|
||||||
// to growing 1.25x for large slices. This formula
|
|
||||||
// gives a smooth-ish transition between the two.
|
|
||||||
newcap += (newcap + 3*threshold) >> 2
|
|
||||||
|
|
||||||
// We need to check `newcap >= newLen` and whether `newcap` overflowed.
|
|
||||||
// newLen is guaranteed to be larger than zero, hence
|
|
||||||
// when newcap overflows then `uint(newcap) > uint(newLen)`.
|
|
||||||
// This allows to check for both with the same comparison.
|
|
||||||
if uint(newcap) >= uint(newLen) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set newcap to the requested cap when
|
|
||||||
// the newcap calculation overflowed.
|
|
||||||
if newcap <= 0 {
|
|
||||||
newcap = newLen
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var overflow bool
|
var overflow bool
|
||||||
var lenmem, newlenmem, capmem uintptr
|
var lenmem, newlenmem, capmem uintptr
|
||||||
|
|
@ -290,6 +260,41 @@ func growslice(oldPtr unsafe.Pointer, newLen, oldCap, num int, et *_type) slice
|
||||||
return slice{p, newLen, newcap}
|
return slice{p, newLen, newcap}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nextslicecap computes the next appropriate slice length.
|
||||||
|
func nextslicecap(newLen, oldCap int) int {
|
||||||
|
newcap := oldCap
|
||||||
|
doublecap := newcap + newcap
|
||||||
|
if newLen > doublecap {
|
||||||
|
return newLen
|
||||||
|
}
|
||||||
|
|
||||||
|
const threshold = 256
|
||||||
|
if oldCap < threshold {
|
||||||
|
return doublecap
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
// Transition from growing 2x for small slices
|
||||||
|
// to growing 1.25x for large slices. This formula
|
||||||
|
// gives a smooth-ish transition between the two.
|
||||||
|
newcap += (newcap + 3*threshold) >> 2
|
||||||
|
|
||||||
|
// We need to check `newcap >= newLen` and whether `newcap` overflowed.
|
||||||
|
// newLen is guaranteed to be larger than zero, hence
|
||||||
|
// when newcap overflows then `uint(newcap) > uint(newLen)`.
|
||||||
|
// This allows to check for both with the same comparison.
|
||||||
|
if uint(newcap) >= uint(newLen) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set newcap to the requested cap when
|
||||||
|
// the newcap calculation overflowed.
|
||||||
|
if newcap <= 0 {
|
||||||
|
return newLen
|
||||||
|
}
|
||||||
|
return newcap
|
||||||
|
}
|
||||||
|
|
||||||
//go:linkname reflect_growslice reflect.growslice
|
//go:linkname reflect_growslice reflect.growslice
|
||||||
func reflect_growslice(et *_type, old slice, num int) slice {
|
func reflect_growslice(et *_type, old slice, num int) slice {
|
||||||
// Semantically equivalent to slices.Grow, except that the caller
|
// Semantically equivalent to slices.Grow, except that the caller
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue