From c56f463412428f8a4d06bf67da9059b389c8d526 Mon Sep 17 00:00:00 2001 From: Egon Elbre Date: Tue, 9 May 2023 11:29:51 +0300 Subject: [PATCH] runtime: optimize growslice This is tiny optimization for growslice, which is probably too small to measure easily. Move the for loop to avoid multiple checks inside the loop. Also, use >> 2 instead of /4, which generates fewer instructions. Change-Id: I9ab09bdccb56f98ab22073f23d9e102c252238c7 Reviewed-on: https://go-review.googlesource.com/c/go/+/493795 Reviewed-by: Keith Randall Reviewed-by: Matthew Dempsky TryBot-Result: Gopher Robot Run-TryBot: Egon Elbre Auto-Submit: Ian Lance Taylor Reviewed-by: Keith Randall --- src/runtime/slice.go | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/runtime/slice.go b/src/runtime/slice.go index 228697a708..29e2fd5cbd 100644 --- a/src/runtime/slice.go +++ b/src/runtime/slice.go @@ -186,14 +186,21 @@ func growslice(oldPtr unsafe.Pointer, newLen, oldCap, num int, et *_type) slice if oldCap < threshold { newcap = doublecap } else { - // Check 0 < newcap to detect overflow - // and prevent an infinite loop. - for 0 < newcap && newcap < newLen { + 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) / 4 + 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 { -- 2.50.0