diff options
Diffstat (limited to 'libgo/go/runtime/slice.go')
-rw-r--r-- | libgo/go/runtime/slice.go | 77 |
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 |