mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
runtime: use multiplication with overflow check for growslice
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>
This commit is contained in:
parent
e85b8db604
commit
3b091bf6cc
1 changed files with 11 additions and 10 deletions
|
|
@ -5,6 +5,7 @@
|
||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"runtime/internal/math"
|
||||||
"runtime/internal/sys"
|
"runtime/internal/sys"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
@ -104,10 +105,11 @@ func growslice(et *_type, old slice, cap int) slice {
|
||||||
msanread(old.array, uintptr(old.len*int(et.size)))
|
msanread(old.array, uintptr(old.len*int(et.size)))
|
||||||
}
|
}
|
||||||
|
|
||||||
if et.size == 0 {
|
|
||||||
if cap < old.cap {
|
if cap < old.cap {
|
||||||
panic(errorString("growslice: cap out of range"))
|
panic(errorString("growslice: cap out of range"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if et.size == 0 {
|
||||||
// append should not create a slice with nil pointer but non-zero len.
|
// 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.
|
// We assume that append doesn't need to preserve old.array in this case.
|
||||||
return slice{unsafe.Pointer(&zerobase), old.len, cap}
|
return slice{unsafe.Pointer(&zerobase), old.len, cap}
|
||||||
|
|
@ -169,15 +171,14 @@ func growslice(et *_type, old slice, cap int) slice {
|
||||||
default:
|
default:
|
||||||
lenmem = uintptr(old.len) * et.size
|
lenmem = uintptr(old.len) * et.size
|
||||||
newlenmem = uintptr(cap) * et.size
|
newlenmem = uintptr(cap) * et.size
|
||||||
capmem = roundupsize(uintptr(newcap) * et.size)
|
capmem, overflow = math.MulUintptr(et.size, uintptr(newcap))
|
||||||
overflow = uintptr(newcap) > maxSliceCap(et.size)
|
capmem = roundupsize(capmem)
|
||||||
newcap = int(capmem / et.size)
|
newcap = int(capmem / et.size)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The check of overflow (uintptr(newcap) > maxSliceCap(et.size))
|
// The check of overflow in addition to capmem > maxAlloc is needed
|
||||||
// in addition to capmem > _MaxMem is needed to prevent an overflow
|
// to prevent an overflow which can be used to trigger a segfault
|
||||||
// which can be used to trigger a segfault on 32bit architectures
|
// on 32bit architectures with this example program:
|
||||||
// with this example program:
|
|
||||||
//
|
//
|
||||||
// type T [1<<27 + 1]int64
|
// 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)
|
// s = append(s, d, d, d, d)
|
||||||
// print(len(s), "\n")
|
// print(len(s), "\n")
|
||||||
// }
|
// }
|
||||||
if cap < old.cap || overflow || capmem > maxAlloc {
|
if overflow || capmem > maxAlloc {
|
||||||
panic(errorString("growslice: cap out of range"))
|
panic(errorString("growslice: cap out of range"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue