diff --git a/src/runtime/append_test.go b/src/runtime/append_test.go index a67dc9b494..4b647f70a0 100644 --- a/src/runtime/append_test.go +++ b/src/runtime/append_test.go @@ -7,6 +7,24 @@ import "testing" const N = 20 +func BenchmarkGrowSliceBytes(b *testing.B) { + b.StopTimer() + var x = make([]byte, 8) + b.StartTimer() + for i := 0; i < b.N; i++ { + _ = append([]byte(nil), x...) + } +} + +func BenchmarkGrowSliceInts(b *testing.B) { + b.StopTimer() + var x = make([]int, 8) + b.StartTimer() + for i := 0; i < b.N; i++ { + _ = append([]int(nil), x...) + } +} + func BenchmarkAppend(b *testing.B) { b.StopTimer() x := make([]int, 0, N) diff --git a/src/runtime/slice.go b/src/runtime/slice.go index c67862ebac..5e88ed9453 100644 --- a/src/runtime/slice.go +++ b/src/runtime/slice.go @@ -38,10 +38,6 @@ func makeslice(t *slicetype, len64, cap64 int64) slice { // and it returns a new slice with at least that capacity, with the old data // copied into it. func growslice(t *slicetype, old slice, cap int) slice { - if cap < old.cap || t.elem.size > 0 && uintptr(cap) > _MaxMem/t.elem.size { - panic(errorString("growslice: cap out of range")) - } - if raceenabled { callerpc := getcallerpc(unsafe.Pointer(&t)) racereadrangepc(old.array, uintptr(old.len*int(t.elem.size)), callerpc, funcPC(growslice)) @@ -52,11 +48,19 @@ func growslice(t *slicetype, old slice, cap int) slice { et := t.elem 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} } + maxcap := _MaxMem / et.size + if cap < old.cap || uintptr(cap) > maxcap { + panic(errorString("growslice: cap out of range")) + } + newcap := old.cap if newcap+newcap < cap { newcap = cap @@ -73,12 +77,18 @@ func growslice(t *slicetype, old slice, cap int) slice { } } - if uintptr(newcap) >= _MaxMem/et.size { + if uintptr(newcap) >= maxcap { panic(errorString("growslice: cap out of range")) } + lenmem := uintptr(old.len) * et.size capmem := roundupsize(uintptr(newcap) * et.size) - newcap = int(capmem / et.size) + if et.size == 1 { + newcap = int(capmem) + } else { + newcap = int(capmem / et.size) + } + var p unsafe.Pointer if et.kind&kindNoPointers != 0 { p = rawmem(capmem)