]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: use multiplication with overflow check for growslice
authorMartin Möhrmann <moehrmann@google.com>
Mon, 22 Oct 2018 18:22:55 +0000 (20:22 +0200)
committerMartin Möhrmann <martisch@uos.de>
Tue, 23 Oct 2018 06:42:56 +0000 (06:42 +0000)
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 <martisch@uos.de>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/runtime/slice.go

index 4206f4384af62b0b06e7f5cdad58a8b78e948d79..2c5c52a6e63d3c95dd552c0be69a4880418dd218 100644 (file)
@@ -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"))
        }