From 041526c6ef669743afc6c4b757b95011f1475d1a Mon Sep 17 00:00:00 2001 From: =?utf8?q?Cl=C3=A9ment=20Chigot?= Date: Mon, 1 Oct 2018 09:58:40 +0200 Subject: [PATCH] runtime: handle 64bits addresses for AIX This commit allows the runtime to handle 64bits addresses returned by mmap syscall on AIX. Mmap syscall returns addresses on 59bits on AIX. But the Arena implementation only allows addresses with less than 48 bits. This commit increases the arena size up to 1<<60 for aix/ppc64. Update: #25893 Change-Id: Iea72e8a944d10d4f00be915785e33ae82dd6329e Reviewed-on: https://go-review.googlesource.com/c/138736 Reviewed-by: Austin Clements --- src/cmd/compile/internal/ppc64/galign.go | 2 +- src/runtime/lfstack_64bit.go | 14 ++++++++++ src/runtime/malloc.go | 34 +++++++++++++++++------- test/chancap.go | 4 ++- test/fixedbugs/bug273.go | 2 +- test/fixedbugs/issue4085b.go | 4 ++- 6 files changed, 47 insertions(+), 13 deletions(-) diff --git a/src/cmd/compile/internal/ppc64/galign.go b/src/cmd/compile/internal/ppc64/galign.go index ce805f4e0c..da971d864d 100644 --- a/src/cmd/compile/internal/ppc64/galign.go +++ b/src/cmd/compile/internal/ppc64/galign.go @@ -16,7 +16,7 @@ func Init(arch *gc.Arch) { arch.LinkArch = &ppc64.Linkppc64le } arch.REGSP = ppc64.REGSP - arch.MAXWIDTH = 1 << 50 + arch.MAXWIDTH = 1 << 60 arch.ZeroRange = zerorange arch.ZeroAuto = zeroAuto diff --git a/src/runtime/lfstack_64bit.go b/src/runtime/lfstack_64bit.go index 4ce7d2a098..ea3455a8c4 100644 --- a/src/runtime/lfstack_64bit.go +++ b/src/runtime/lfstack_64bit.go @@ -28,9 +28,20 @@ const ( // bottom, because node must be pointer-aligned, giving a total of 19 bits // of count. cntBits = 64 - addrBits + 3 + + // On AIX, 64-bit addresses are split into 36-bit segment number and 28-bit + // offset in segment. Segment numbers in the range 0x0A0000000-0x0AFFFFFFF(LSA) + // are available for mmap. + // We assume all lfnode addresses are from memory allocated with mmap. + // We use one bit to distinguish between the two ranges. + aixAddrBits = 57 + aixCntBits = 64 - aixAddrBits + 3 ) func lfstackPack(node *lfnode, cnt uintptr) uint64 { + if GOARCH == "ppc64" && GOOS == "aix" { + return uint64(uintptr(unsafe.Pointer(node)))<<(64-aixAddrBits) | uint64(cnt&(1<> cntBits << 3))) } + if GOARCH == "ppc64" && GOOS == "aix" { + return (*lfnode)(unsafe.Pointer(uintptr((val >> aixCntBits << 3) | 0xa<<56))) + } return (*lfnode)(unsafe.Pointer(uintptr(val >> cntBits << 3))) } diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index e827dbae93..678e689311 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -160,7 +160,7 @@ const ( // amd64, addresses are sign-extended beyond heapAddrBits. On // other arches, they are zero-extended. // - // On 64-bit platforms, we limit this to 48 bits based on a + // On most 64-bit platforms, we limit this to 48 bits based on a // combination of hardware and OS limitations. // // amd64 hardware limits addresses to 48 bits, sign-extended @@ -178,10 +178,9 @@ const ( // bits, in the range [0, 1<<48). // // ppc64, mips64, and s390x support arbitrary 64 bit addresses - // in hardware. However, since Go only supports Linux on - // these, we lean on OS limits. Based on Linux's processor.h, - // the user address space is limited as follows on 64-bit - // architectures: + // in hardware. On Linux, Go leans on stricter OS limits. Based + // on Linux's processor.h, the user address space is limited as + // follows on 64-bit architectures: // // Architecture Name Maximum Value (exclusive) // --------------------------------------------------------------------- @@ -198,13 +197,17 @@ const ( // exceed Go's 48 bit limit, it's extremely unlikely in // practice. // + // On aix/ppc64, the limits is increased to 1<<60 to accept addresses + // returned by mmap syscall. These are in range: + // 0x0a00000000000000 - 0x0afffffffffffff + // // On 32-bit platforms, we accept the full 32-bit address // space because doing so is cheap. // mips32 only has access to the low 2GB of virtual memory, so // we further limit it to 31 bits. // // WebAssembly currently has a limit of 4GB linear memory. - heapAddrBits = (_64bit*(1-sys.GoarchWasm))*48 + (1-_64bit+sys.GoarchWasm)*(32-(sys.GoarchMips+sys.GoarchMipsle)) + heapAddrBits = (_64bit*(1-sys.GoarchWasm)*(1-sys.GoosAix))*48 + (1-_64bit+sys.GoarchWasm)*(32-(sys.GoarchMips+sys.GoarchMipsle)) + 60*sys.GoosAix // maxAlloc is the maximum size of an allocation. On 64-bit, // it's theoretically possible to allocate 1<= 0; i-- { var p uintptr switch { @@ -425,6 +434,13 @@ func mallocinit() { p = uintptr(i)<<40 | uintptrMask&(0x0013<<28) case GOARCH == "arm64": p = uintptr(i)<<40 | uintptrMask&(0x0040<<32) + case GOOS == "aix": + if i == 0 { + // We don't use addresses directly after 0x0A00000000000000 + // to avoid collisions with others mmaps done by non-go programs. + continue + } + p = uintptr(i)<<40 | uintptrMask&(0xa0<<52) case raceenabled: // The TSAN runtime requires the heap // to be in the range [0x00c000000000, @@ -458,7 +474,7 @@ func mallocinit() { // 3. We try to stake out a reasonably large initial // heap reservation. - const arenaMetaSize = unsafe.Sizeof([1 << arenaBits]heapArena{}) + const arenaMetaSize = (1 << arenaBits) * unsafe.Sizeof(heapArena{}) meta := uintptr(sysReserve(nil, arenaMetaSize)) if meta != 0 { mheap_.heapArenaAlloc.init(meta, arenaMetaSize) diff --git a/test/chancap.go b/test/chancap.go index 9675e38bdb..8dce9247cd 100644 --- a/test/chancap.go +++ b/test/chancap.go @@ -42,8 +42,10 @@ func main() { shouldPanic("makechan: size out of range", func() { _ = make(T, n) }) shouldPanic("makechan: size out of range", func() { _ = make(T, int64(n)) }) if ptrSize == 8 { - var n2 int64 = 1 << 50 + // Test mem > maxAlloc + var n2 int64 = 1 << 59 shouldPanic("makechan: size out of range", func() { _ = make(T, int(n2)) }) + // Test elem.size*cap overflow n2 = 1<<63 - 1 shouldPanic("makechan: size out of range", func() { _ = make(T, int(n2)) }) } else { diff --git a/test/fixedbugs/bug273.go b/test/fixedbugs/bug273.go index 7305c6063c..2af8800171 100644 --- a/test/fixedbugs/bug273.go +++ b/test/fixedbugs/bug273.go @@ -14,7 +14,7 @@ var bug = false var minus1 = -1 var five = 5 -var big int64 = 10 | 1<<40 +var big int64 = 10 | 1<<46 type block [1 << 19]byte diff --git a/test/fixedbugs/issue4085b.go b/test/fixedbugs/issue4085b.go index 6bf315fcc2..6304ce073a 100644 --- a/test/fixedbugs/issue4085b.go +++ b/test/fixedbugs/issue4085b.go @@ -21,9 +21,11 @@ func main() { shouldPanic("cap out of range", func() { _ = make(T, 0, int64(n)) }) var t *byte if unsafe.Sizeof(t) == 8 { - var n2 int64 = 1 << 50 + // Test mem > maxAlloc + var n2 int64 = 1 << 59 shouldPanic("len out of range", func() { _ = make(T, int(n2)) }) shouldPanic("cap out of range", func() { _ = make(T, 0, int(n2)) }) + // Test elem.size*cap overflow n2 = 1<<63 - 1 shouldPanic("len out of range", func() { _ = make(T, int(n2)) }) shouldPanic("cap out of range", func() { _ = make(T, 0, int(n2)) }) -- 2.50.0