aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/runtime/slice.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/runtime/slice.go')
-rw-r--r--libgo/go/runtime/slice.go77
1 files changed, 53 insertions, 24 deletions
diff --git a/libgo/go/runtime/slice.go b/libgo/go/runtime/slice.go
index ec5aa64..2e874cc 100644
--- a/libgo/go/runtime/slice.go
+++ b/libgo/go/runtime/slice.go
@@ -5,6 +5,7 @@
package runtime
import (
+ "runtime/internal/sys"
"unsafe"
)
@@ -34,14 +35,14 @@ type notInHeapSlice struct {
// The index is the size of the slice element.
var maxElems = [...]uintptr{
^uintptr(0),
- _MaxMem / 1, _MaxMem / 2, _MaxMem / 3, _MaxMem / 4,
- _MaxMem / 5, _MaxMem / 6, _MaxMem / 7, _MaxMem / 8,
- _MaxMem / 9, _MaxMem / 10, _MaxMem / 11, _MaxMem / 12,
- _MaxMem / 13, _MaxMem / 14, _MaxMem / 15, _MaxMem / 16,
- _MaxMem / 17, _MaxMem / 18, _MaxMem / 19, _MaxMem / 20,
- _MaxMem / 21, _MaxMem / 22, _MaxMem / 23, _MaxMem / 24,
- _MaxMem / 25, _MaxMem / 26, _MaxMem / 27, _MaxMem / 28,
- _MaxMem / 29, _MaxMem / 30, _MaxMem / 31, _MaxMem / 32,
+ maxAlloc / 1, maxAlloc / 2, maxAlloc / 3, maxAlloc / 4,
+ maxAlloc / 5, maxAlloc / 6, maxAlloc / 7, maxAlloc / 8,
+ maxAlloc / 9, maxAlloc / 10, maxAlloc / 11, maxAlloc / 12,
+ maxAlloc / 13, maxAlloc / 14, maxAlloc / 15, maxAlloc / 16,
+ maxAlloc / 17, maxAlloc / 18, maxAlloc / 19, maxAlloc / 20,
+ maxAlloc / 21, maxAlloc / 22, maxAlloc / 23, maxAlloc / 24,
+ maxAlloc / 25, maxAlloc / 26, maxAlloc / 27, maxAlloc / 28,
+ maxAlloc / 29, maxAlloc / 30, maxAlloc / 31, maxAlloc / 32,
}
// maxSliceCap returns the maximum capacity for a slice.
@@ -49,7 +50,15 @@ func maxSliceCap(elemsize uintptr) uintptr {
if elemsize < uintptr(len(maxElems)) {
return maxElems[elemsize]
}
- return _MaxMem / elemsize
+ return maxAlloc / elemsize
+}
+
+func panicmakeslicelen() {
+ panic(errorString("makeslice: len out of range"))
+}
+
+func panicmakeslicecap() {
+ panic(errorString("makeslice: cap out of range"))
}
func makeslice(et *_type, len, cap int) slice {
@@ -60,11 +69,11 @@ func makeslice(et *_type, len, cap int) slice {
// See issue 4085.
maxElements := maxSliceCap(et.size)
if len < 0 || uintptr(len) > maxElements {
- panic(errorString("makeslice: len out of range"))
+ panicmakeslicelen()
}
if cap < len || uintptr(cap) > maxElements {
- panic(errorString("makeslice: cap out of range"))
+ panicmakeslicecap()
}
p := mallocgc(et.size*uintptr(cap), et, true)
@@ -74,12 +83,12 @@ func makeslice(et *_type, len, cap int) slice {
func makeslice64(et *_type, len64, cap64 int64) slice {
len := int(len64)
if int64(len) != len64 {
- panic(errorString("makeslice: len out of range"))
+ panicmakeslicelen()
}
cap := int(cap64)
if int64(cap) != cap64 {
- panic(errorString("makeslice: cap out of range"))
+ panicmakeslicecap()
}
return makeslice(et, len, cap)
@@ -131,20 +140,36 @@ func growslice(et *_type, old slice, cap int) slice {
var overflow bool
var lenmem, newlenmem, capmem uintptr
- const ptrSize = unsafe.Sizeof((*byte)(nil))
- switch et.size {
- case 1:
+ // Specialize for common values of et.size.
+ // For 1 we don't need any division/multiplication.
+ // For sys.PtrSize, compiler will optimize division/multiplication into a shift by a constant.
+ // For powers of 2, use a variable shift.
+ switch {
+ case et.size == 1:
lenmem = uintptr(old.len)
newlenmem = uintptr(cap)
capmem = roundupsize(uintptr(newcap))
- overflow = uintptr(newcap) > _MaxMem
+ overflow = uintptr(newcap) > maxAlloc
newcap = int(capmem)
- case ptrSize:
- lenmem = uintptr(old.len) * ptrSize
- newlenmem = uintptr(cap) * ptrSize
- capmem = roundupsize(uintptr(newcap) * ptrSize)
- overflow = uintptr(newcap) > _MaxMem/ptrSize
- newcap = int(capmem / ptrSize)
+ case et.size == sys.PtrSize:
+ lenmem = uintptr(old.len) * sys.PtrSize
+ newlenmem = uintptr(cap) * sys.PtrSize
+ capmem = roundupsize(uintptr(newcap) * sys.PtrSize)
+ overflow = uintptr(newcap) > maxAlloc/sys.PtrSize
+ newcap = int(capmem / sys.PtrSize)
+ case isPowerOfTwo(et.size):
+ var shift uintptr
+ if sys.PtrSize == 8 {
+ // Mask shift for better code generation.
+ shift = uintptr(sys.Ctz64(uint64(et.size))) & 63
+ } else {
+ shift = uintptr(sys.Ctz32(uint32(et.size))) & 31
+ }
+ lenmem = uintptr(old.len) << shift
+ newlenmem = uintptr(cap) << shift
+ capmem = roundupsize(uintptr(newcap) << shift)
+ overflow = uintptr(newcap) > (maxAlloc >> shift)
+ newcap = int(capmem >> shift)
default:
lenmem = uintptr(old.len) * et.size
newlenmem = uintptr(cap) * et.size
@@ -167,7 +192,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 > _MaxMem {
+ if cap < old.cap || overflow || capmem > maxAlloc {
panic(errorString("growslice: cap out of range"))
}
@@ -193,6 +218,10 @@ func growslice(et *_type, old slice, cap int) slice {
return slice{p, cap, newcap}
}
+func isPowerOfTwo(x uintptr) bool {
+ return x&(x-1) == 0
+}
+
func slicecopy(to, fm slice, width uintptr) int {
if fm.len == 0 || to.len == 0 {
return 0