cmd/compile,runtime: open code unsafe.Slice

So prevent heavy runtime call overhead, and the compiler will have a
chance to optimize the bound check.

With this optimization, changing runtime/stack.go to use unsafe.Slice
no longer negatively impacts stack copying performance:

name                   old time/op    new time/op    delta
StackCopyWithStkobj-8    16.3ms ± 6%    16.5ms ± 5%   ~     (p=0.382 n=8+8)

name                   old alloc/op   new alloc/op   delta
StackCopyWithStkobj-8     17.0B ± 0%     17.0B ± 0%   ~     (all equal)

name                   old allocs/op  new allocs/op  delta
StackCopyWithStkobj-8      1.00 ± 0%      1.00 ± 0%   ~     (all equal)

Fixes #48798

Change-Id: I731a9a4abd6dd6846f44eece7f86025b7bb1141b
Reviewed-on: https://go-review.googlesource.com/c/go/+/362934
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Keith Randall <khr@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com>
This commit is contained in:
Cuong Manh Le 2021-11-10 19:20:57 +07:00
parent ccb798741b
commit 579902d0b1
5 changed files with 76 additions and 21 deletions

View file

@ -117,6 +117,13 @@ func makeslice64(et *_type, len64, cap64 int64) unsafe.Pointer {
return makeslice(et, len, cap)
}
// This is a wrapper over runtime/internal/math.MulUintptr,
// so the compiler can recognize and treat it as an intrinsic.
func mulUintptr(a, b uintptr) (uintptr, bool) {
return math.MulUintptr(a, b)
}
// Keep this code in sync with cmd/compile/internal/walk/builtin.go:walkUnsafeSlice
func unsafeslice(et *_type, ptr unsafe.Pointer, len int) {
if len < 0 {
panicunsafeslicelen()
@ -125,12 +132,13 @@ func unsafeslice(et *_type, ptr unsafe.Pointer, len int) {
mem, overflow := math.MulUintptr(et.size, uintptr(len))
if overflow || mem > -uintptr(ptr) {
if ptr == nil {
panic(errorString("unsafe.Slice: ptr is nil and len is not zero"))
panicunsafeslicenilptr()
}
panicunsafeslicelen()
}
}
// Keep this code in sync with cmd/compile/internal/walk/builtin.go:walkUnsafeSlice
func unsafeslice64(et *_type, ptr unsafe.Pointer, len64 int64) {
len := int(len64)
if int64(len) != len64 {
@ -153,6 +161,10 @@ func panicunsafeslicelen() {
panic(errorString("unsafe.Slice: len out of range"))
}
func panicunsafeslicenilptr() {
panic(errorString("unsafe.Slice: ptr is nil and len is not zero"))
}
// growslice handles slice growth during append.
// It is passed the slice element type, the old slice, and the desired new minimum capacity,
// and it returns a new slice with at least that capacity, with the old data