diff --git a/src/runtime/lfstack_64bit.go b/src/runtime/lfstack_64bit.go index 19d8045203..9524d651a1 100644 --- a/src/runtime/lfstack_64bit.go +++ b/src/runtime/lfstack_64bit.go @@ -11,7 +11,7 @@ import "unsafe" const ( // addrBits is the number of bits needed to represent a virtual address. // - // See memLimitBits for a table of address space sizes on + // See heapAddrBits for a table of address space sizes on // various architectures. 48 bits is enough for all // architectures except s390x. // diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index b6e3337d67..6c36e1eea3 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -156,12 +156,32 @@ const ( // plan9 | 4KB | 3 _NumStackOrders = 4 - sys.PtrSize/4*sys.GoosWindows - 1*sys.GoosPlan9 - // memLimitBits is the maximum number of bits in a heap address. + // heapAddrBits is the number of bits in a heap address. On + // amd64, addresses are sign-extended beyond heapAddrBits. On + // other arches, they are zero-extended. // - // On 64-bit platforms, we limit this to 48 bits because that - // is the maximum supported by Linux across all 64-bit - // architectures, with the exception of s390x. Based on - // processor.h: + // On 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 + // to 64 bits. Addresses where the top 16 bits are not either + // all 0 or all 1 are "non-canonical" and invalid. Because of + // these "negative" addresses, we offset addresses by 1<<47 + // (arenaBaseOffset) on amd64 before computing indexes into + // the heap arenas index. In 2017, amd64 hardware added + // support for 57 bit addresses; however, currently only Linux + // supports this extension and the kernel will never choose an + // address above 1<<47 unless mmap is called with a hint + // address above 1<<47 (which we never do). + // + // arm64 hardware (as of ARMv8) limits user addresses to 48 + // 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: // // Architecture Name Maximum Value (exclusive) // --------------------------------------------------------------------- @@ -171,15 +191,12 @@ const ( // mips64{,le} TASK_SIZE64 0x00010000000000 (40 bit addresses) // s390x TASK_SIZE 1<<64 (64 bit addresses) // - // These values may increase over time. In particular, ppc64 - // and mips64 support arbitrary 64-bit addresses in hardware, - // but Linux imposes the above limits. amd64 has hardware - // support for 57 bit addresses as of 2017 (56 bits for user - // space), but Linux only uses addresses above 1<<47 for - // mappings that explicitly pass a high hint address. - // - // s390x supports full 64-bit addresses, but the allocator - // will panic in the unlikely event we exceed 48 bits. + // These limits may increase over time, but are currently at + // most 48 bits except on s390x. On all architectures, Linux + // starts placing mmap'd regions at addresses that are + // significantly below 48 bits, so even if it's possible to + // exceed Go's 48 bit limit, it's extremely unlikely in + // practice. // // On 32-bit platforms, we accept the full 32-bit address // space because doing so is cheap. @@ -187,22 +204,17 @@ const ( // we further limit it to 31 bits. // // The size of the arena index is proportional to - // 1<