]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: handle 64bits addresses for AIX
authorClément Chigot <clement.chigot@atos.net>
Mon, 1 Oct 2018 07:58:40 +0000 (09:58 +0200)
committerLynn Boger <laboger@linux.vnet.ibm.com>
Mon, 26 Nov 2018 14:06:28 +0000 (14:06 +0000)
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 <austin@google.com>
src/cmd/compile/internal/ppc64/galign.go
src/runtime/lfstack_64bit.go
src/runtime/malloc.go
test/chancap.go
test/fixedbugs/bug273.go
test/fixedbugs/issue4085b.go

index ce805f4e0cf838ab5c99b0d416539b580c8ee3d2..da971d864dbe794307f92a69c69fd43ad21848ec 100644 (file)
@@ -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
index 4ce7d2a0988273bca1eebe2010f545696de6dafb..ea3455a8c4c93243c0281001aeff29328613111a 100644 (file)
@@ -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<<aixCntBits-1))
+       }
        return uint64(uintptr(unsafe.Pointer(node)))<<(64-addrBits) | uint64(cnt&(1<<cntBits-1))
 }
 
@@ -40,5 +51,8 @@ func lfstackUnpack(val uint64) *lfnode {
                // val before unpacking.
                return (*lfnode)(unsafe.Pointer(uintptr(int64(val) >> 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)))
 }
index e827dbae93d5b505d5cb07698419bb5297afc028..678e68931150bd63fdc040ebd114f8caad7ab56c 100644 (file)
@@ -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<<heapAddrBits bytes. On
@@ -223,6 +226,7 @@ const (
        //       Platform  Addr bits  Arena size  L1 entries   L2 entries
        // --------------  ---------  ----------  ----------  -----------
        //       */64-bit         48        64MB           1    4M (32MB)
+       //     aix/64-bit         60       256MB        4096    4M (32MB)
        // windows/64-bit         48         4MB          64    1M  (8MB)
        //       */32-bit         32         4MB           1  1024  (4KB)
        //     */mips(le)         31         4MB           1   512  (2KB)
@@ -244,7 +248,7 @@ const (
        // logHeapArenaBytes is log_2 of heapArenaBytes. For clarity,
        // prefer using heapArenaBytes where possible (we need the
        // constant to compute some other constants).
-       logHeapArenaBytes = (6+20)*(_64bit*(1-sys.GoosWindows)) + (2+20)*(_64bit*sys.GoosWindows) + (2+20)*(1-_64bit)
+       logHeapArenaBytes = (6+20)*(_64bit*(1-sys.GoosWindows)*(1-sys.GoosAix)) + (2+20)*(_64bit*sys.GoosWindows) + (2+20)*(1-_64bit) + (8+20)*sys.GoosAix
 
        // heapArenaBitmapBytes is the size of each heap arena's bitmap.
        heapArenaBitmapBytes = heapArenaBytes / (sys.PtrSize * 8 / 2)
@@ -264,7 +268,10 @@ const (
        // We use the L1 map on 64-bit Windows because the arena size
        // is small, but the address space is still 48 bits, and
        // there's a high cost to having a large L2.
-       arenaL1Bits = 6 * (_64bit * sys.GoosWindows)
+       //
+       // We use the L1 map on aix/ppc64 to keep the same L2 value
+       // as on Linux.
+       arenaL1Bits = 6*(_64bit*sys.GoosWindows) + 12*sys.GoosAix
 
        // arenaL2Bits is the number of bits of the arena number
        // covered by the second level arena index.
@@ -418,6 +425,8 @@ func mallocinit() {
                // allocation at 0x40 << 32 because when using 4k pages with 3-level
                // translation buffers, the user address space is limited to 39 bits
                // On darwin/arm64, the address space is even smaller.
+               // On AIX, mmaps starts at 0x0A00000000000000 for 64-bit.
+               // processes.
                for i := 0x7f; i >= 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)
index 9675e38bdb1a76922fcd83ffa4b15edbe64a7b9a..8dce9247cd45ef710ef728c1d85d1e2d7c28e9e4 100644 (file)
@@ -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 {
index 7305c6063ccdc8193e9f7a9d525c445f1369019e..2af8800171ed4f7991006c6fbc999644ee178813 100644 (file)
@@ -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
 
index 6bf315fcc2f0603835911f4739969d751ec92655..6304ce073aa9e558dbc884b2d71a382e600f2ebd 100644 (file)
@@ -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)) })