From 3b091bf6cceca868e2063a2c8b3cec90411ea18e Mon Sep 17 00:00:00 2001 From: =?utf8?q?Martin=20M=C3=B6hrmann?= Date: Mon, 22 Oct 2018 20:22:55 +0200 Subject: [PATCH] runtime: use multiplication with overflow check for growslice MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This improves performance for slices with an element size larger than 32 bytes and removes loading a value from the maxElems array for smaller element sizes. name old time/op new time/op delta GrowSlice/Byte 41.4ns ± 2% 41.5ns ± 1% ~ (p=0.366 n=10+9) GrowSlice/Int16 51.1ns ± 2% 51.0ns ± 2% ~ (p=0.985 n=10+10) GrowSlice/Int 64.0ns ± 1% 64.2ns ± 1% ~ (p=0.180 n=10+10) GrowSlice/Ptr 90.8ns ± 1% 90.7ns ± 1% ~ (p=0.858 n=9+10) GrowSlice/Struct/24 108ns ± 0% 108ns ± 2% ~ (p=0.488 n=8+9) GrowSlice/Struct/32 118ns ± 2% 117ns ± 2% ~ (p=0.327 n=10+10) GrowSlice/Struct/40 159ns ± 1% 148ns ± 1% -6.87% (p=0.000 n=10+9) Updates #21588 Change-Id: I443b82972d379b1befa791f9ee468b3adc6bb760 Reviewed-on: https://go-review.googlesource.com/c/143798 Run-TryBot: Martin Möhrmann TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- src/runtime/slice.go | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/runtime/slice.go b/src/runtime/slice.go index 4206f4384a..2c5c52a6e6 100644 --- a/src/runtime/slice.go +++ b/src/runtime/slice.go @@ -5,6 +5,7 @@ package runtime import ( + "runtime/internal/math" "runtime/internal/sys" "unsafe" ) @@ -104,10 +105,11 @@ func growslice(et *_type, old slice, cap int) slice { msanread(old.array, uintptr(old.len*int(et.size))) } + if cap < old.cap { + panic(errorString("growslice: cap out of range")) + } + if et.size == 0 { - if cap < old.cap { - panic(errorString("growslice: cap out of range")) - } // append should not create a slice with nil pointer but non-zero len. // We assume that append doesn't need to preserve old.array in this case. return slice{unsafe.Pointer(&zerobase), old.len, cap} @@ -169,15 +171,14 @@ func growslice(et *_type, old slice, cap int) slice { default: lenmem = uintptr(old.len) * et.size newlenmem = uintptr(cap) * et.size - capmem = roundupsize(uintptr(newcap) * et.size) - overflow = uintptr(newcap) > maxSliceCap(et.size) + capmem, overflow = math.MulUintptr(et.size, uintptr(newcap)) + capmem = roundupsize(capmem) newcap = int(capmem / et.size) } - // The check of overflow (uintptr(newcap) > maxSliceCap(et.size)) - // in addition to capmem > _MaxMem is needed to prevent an overflow - // which can be used to trigger a segfault on 32bit architectures - // with this example program: + // The check of overflow in addition to capmem > maxAlloc is needed + // to prevent an overflow which can be used to trigger a segfault + // on 32bit architectures with this example program: // // type T [1<<27 + 1]int64 // @@ -188,7 +189,7 @@ func growslice(et *_type, old slice, cap int) slice { // s = append(s, d, d, d, d) // print(len(s), "\n") // } - if cap < old.cap || overflow || capmem > maxAlloc { + if overflow || capmem > maxAlloc { panic(errorString("growslice: cap out of range")) } -- 2.50.0