aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEgon Elbre <egonelbre@gmail.com>2023-05-17 17:33:15 +0300
committerGopher Robot <gobot@golang.org>2023-09-04 17:50:50 +0000
commit1d84b02b228cbd35660e168d26fd2801daed08fe (patch)
tree39a5439598a3cb6481c2365654c3b0f9f3cb683f /src
parentc56f463412428f8a4d06bf67da9059b389c8d526 (diff)
downloadgo-1d84b02b228cbd35660e168d26fd2801daed08fe.tar.xz
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>
Diffstat (limited to 'src')
-rw-r--r--src/cmd/compile/internal/test/inl_test.go1
-rw-r--r--src/runtime/slice.go67
2 files changed, 37 insertions, 31 deletions
diff --git a/src/cmd/compile/internal/test/inl_test.go b/src/cmd/compile/internal/test/inl_test.go
index 205b746dd8..4e34631d9b 100644
--- a/src/cmd/compile/internal/test/inl_test.go
+++ b/src/cmd/compile/internal/test/inl_test.go
@@ -51,6 +51,7 @@ func TestIntendedInlining(t *testing.T) {
"getMCache",
"isDirectIface",
"itabHashFunc",
+ "nextslicecap",
"noescape",
"pcvalueCacheKey",
"readUnaligned32",
diff --git a/src/runtime/slice.go b/src/runtime/slice.go
index 29e2fd5cbd..a7d5769f47 100644
--- a/src/runtime/slice.go
+++ b/src/runtime/slice.go
@@ -177,37 +177,7 @@ func growslice(oldPtr unsafe.Pointer, newLen, oldCap, num int, et *_type) slice
return slice{unsafe.Pointer(&zerobase), newLen, newLen}
}
- newcap := 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
- }
- }
- }
+ newcap := nextslicecap(newLen, oldCap)
var overflow bool
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}
}
+// 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
func reflect_growslice(et *_type, old slice, num int) slice {
// Semantically equivalent to slices.Grow, except that the caller