]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: introduce nextslicecap
authorEgon Elbre <egonelbre@gmail.com>
Wed, 17 May 2023 14:33:15 +0000 (17:33 +0300)
committerGopher Robot <gobot@golang.org>
Mon, 4 Sep 2023 17:50:50 +0000 (17:50 +0000)
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>

src/cmd/compile/internal/test/inl_test.go
src/runtime/slice.go

index 205b746dd8925f31c4ca0a9f56e597949793bcc9..4e34631d9b1dcf7e2fc0f52db0fe1b332d6fa6a6 100644 (file)
@@ -51,6 +51,7 @@ func TestIntendedInlining(t *testing.T) {
                        "getMCache",
                        "isDirectIface",
                        "itabHashFunc",
+                       "nextslicecap",
                        "noescape",
                        "pcvalueCacheKey",
                        "readUnaligned32",
index 29e2fd5cbd5c436bd7a32b180ee01af7db56ed6a..a7d5769f473f28530e828fe48567d0a5780c7a25 100644 (file)
@@ -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