]> Cypherpunks repositories - gostls13.git/commitdiff
[release-branch.go1.17] runtime: set iOS addr space to 40 bits with incremental pagealloc
authorMichael Anthony Knyszek <mknyszek@google.com>
Mon, 23 Aug 2021 17:27:40 +0000 (17:27 +0000)
committerDmitri Shuralyov <dmitshur@golang.org>
Wed, 22 Dec 2021 22:05:22 +0000 (22:05 +0000)
In iOS <14, the address space is strictly limited to 8 GiB, or 33 bits.
As a result, the page allocator also assumes all heap memory lives in
this region. This is especially necessary because the page allocator has
a PROT_NONE mapping proportional to the size of the usable address
space, so this keeps that mapping very small.

However starting with iOS 14, this restriction is relaxed, and mmap may
start returning addresses outside of the <14 range. Today this means
that in iOS 14 and later, users experience an error in the page
allocator when a heap arena is mapped outside of the old range.

This change increases the ios/arm64 heapAddrBits to 40 while
simultaneously making ios/arm64 use the 64-bit pagealloc implementation
(with reservations and incremental mapping) to accommodate both iOS
versions <14 and 14+.

Once iOS <14 is deprecated, we can remove these exceptions and treat
ios/arm64 like any other arm64 platform.

This change also makes the BaseChunkIdx expression a little bit easier
to read, while we're here.

For #46860.
Fixes #48116.

Change-Id: I13865f799777739109585f14f1cc49d6d57e096b
Reviewed-on: https://go-review.googlesource.com/c/go/+/344401
Trust: Michael Knyszek <mknyszek@google.com>
Run-TryBot: Michael Knyszek <mknyszek@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Austin Clements <austin@google.com>
(cherry picked from commit af368da0b137116faba81ca249a8d964297e6e45)
Reviewed-on: https://go-review.googlesource.com/c/go/+/369737

src/runtime/export_test.go
src/runtime/malloc.go
src/runtime/mgcscavenge_test.go
src/runtime/mpagealloc_32bit.go
src/runtime/mpagealloc_64bit.go
src/runtime/mpagealloc_test.go
src/runtime/mpagecache_test.go

index c8d01fbb1574de6b78faff16ed63b8d8c7362d52..b49bc50f97d594fde94121c027ea5afa38c79f3a 100644 (file)
@@ -1066,7 +1066,19 @@ func FreePageAlloc(pp *PageAlloc) {
 //
 // This should not be higher than 0x100*pallocChunkBytes to support
 // mips and mipsle, which only have 31-bit address spaces.
-var BaseChunkIdx = ChunkIdx(chunkIndex(((0xc000*pageAlloc64Bit + 0x100*pageAlloc32Bit) * pallocChunkBytes) + arenaBaseOffset*sys.GoosAix))
+var BaseChunkIdx = func() ChunkIdx {
+       var prefix uintptr
+       if pageAlloc64Bit != 0 {
+               prefix = 0xc000
+       } else {
+               prefix = 0x100
+       }
+       baseAddr := prefix * pallocChunkBytes
+       if sys.GoosAix != 0 {
+               baseAddr += arenaBaseOffset
+       }
+       return ChunkIdx(chunkIndex(baseAddr))
+}()
 
 // PageBase returns an address given a chunk index and a page index
 // relative to that chunk.
index cc22b0f276597e94b5e6138a4fcddb8d5e20bb5b..0341bf2c1c81e622345f18cfcb6b7c0c49f7fa70 100644 (file)
@@ -199,15 +199,21 @@ const (
        // we further limit it to 31 bits.
        //
        // On ios/arm64, although 64-bit pointers are presumably
-       // available, pointers are truncated to 33 bits. Furthermore,
-       // only the top 4 GiB of the address space are actually available
-       // to the application, but we allow the whole 33 bits anyway for
-       // simplicity.
-       // TODO(mknyszek): Consider limiting it to 32 bits and using
-       // arenaBaseOffset to offset into the top 4 GiB.
+       // available, pointers are truncated to 33 bits in iOS <14.
+       // Furthermore, only the top 4 GiB of the address space are
+       // actually available to the application. In iOS >=14, more
+       // of the address space is available, and the OS can now
+       // provide addresses outside of those 33 bits. Pick 40 bits
+       // as a reasonable balance between address space usage by the
+       // page allocator, and flexibility for what mmap'd regions
+       // we'll accept for the heap. We can't just move to the full
+       // 48 bits because this uses too much address space for older
+       // iOS versions.
+       // TODO(mknyszek): Once iOS <14 is deprecated, promote ios/arm64
+       // to a 48-bit address space like every other arm64 platform.
        //
        // WebAssembly currently has a limit of 4GB linear memory.
-       heapAddrBits = (_64bit*(1-sys.GoarchWasm)*(1-sys.GoosIos*sys.GoarchArm64))*48 + (1-_64bit+sys.GoarchWasm)*(32-(sys.GoarchMips+sys.GoarchMipsle)) + 33*sys.GoosIos*sys.GoarchArm64
+       heapAddrBits = (_64bit*(1-sys.GoarchWasm)*(1-sys.GoosIos*sys.GoarchArm64))*48 + (1-_64bit+sys.GoarchWasm)*(32-(sys.GoarchMips+sys.GoarchMipsle)) + 40*sys.GoosIos*sys.GoarchArm64
 
        // maxAlloc is the maximum size of an allocation. On 64-bit,
        // it's theoretically possible to allocate 1<<heapAddrBits bytes. On
index 3b12a2e1e631524e4ea267025214f34966fa42a0..221bff17469368eb8814a49c3c6ba069666150b7 100644 (file)
@@ -8,6 +8,7 @@ import (
        "fmt"
        "math/rand"
        . "runtime"
+       "runtime/internal/sys"
        "testing"
 )
 
@@ -408,7 +409,9 @@ func TestPageAllocScavenge(t *testing.T) {
                        },
                },
        }
-       if PageAlloc64Bit != 0 {
+       // Disable these tests on iOS since we have a small address space.
+       // See #46860.
+       if PageAlloc64Bit != 0 && sys.GoosIos == 0 {
                tests["ScavAllVeryDiscontiguous"] = setup{
                        beforeAlloc: map[ChunkIdx][]BitRange{
                                BaseChunkIdx:          {},
index fceb4e7a187b7a6d3a0ff060da84ea92a02e8277..41c8239644ef16f5c30b54e1c20bb1a2d8e0aeee 100644 (file)
@@ -2,20 +2,14 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:build 386 || arm || mips || mipsle || wasm || (ios && arm64)
-// +build 386 arm mips mipsle wasm ios,arm64
+//go:build 386 || arm || mips || mipsle || wasm
+// +build 386 arm mips mipsle wasm
 
 // wasm is a treated as a 32-bit architecture for the purposes of the page
 // allocator, even though it has 64-bit pointers. This is because any wasm
 // pointer always has its top 32 bits as zero, so the effective heap address
 // space is only 2^32 bytes in size (see heapAddrBits).
 
-// ios/arm64 is treated as a 32-bit architecture for the purposes of the
-// page allocator, even though it has 64-bit pointers and a 33-bit address
-// space (see heapAddrBits). The 33 bit address space cannot be rounded up
-// to 64 bits because there are too many summary levels to fit in just 33
-// bits.
-
 package runtime
 
 import "unsafe"
index 16577346a7fbe2c30742875f56b4c6b6d4cac0af..8b72c25ffa3ad096026c189ee35489bcae3d1a72 100644 (file)
@@ -2,10 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:build amd64 || (!ios && arm64) || mips64 || mips64le || ppc64 || ppc64le || riscv64 || s390x
-// +build amd64 !ios,arm64 mips64 mips64le ppc64 ppc64le riscv64 s390x
-
-// See mpagealloc_32bit.go for why ios/arm64 is excluded here.
+//go:build amd64 || arm64 || mips64 || mips64le || ppc64 || ppc64le || riscv64 || s390x
+// +build amd64 arm64 mips64 mips64le ppc64 ppc64le riscv64 s390x
 
 package runtime
 
index 5d979fa95b9ef55a9beabe0404cf1a178d621f6a..857fc140d86d354ed563b0831e44435e90a94dfb 100644 (file)
@@ -7,6 +7,7 @@ package runtime_test
 import (
        "fmt"
        . "runtime"
+       "runtime/internal/sys"
        "testing"
 )
 
@@ -165,7 +166,9 @@ func TestPageAllocGrow(t *testing.T) {
                        },
                },
        }
-       if PageAlloc64Bit != 0 {
+       // Disable these tests on iOS since we have a small address space.
+       // See #46860.
+       if PageAlloc64Bit != 0 && sys.GoosIos == 0 {
                tests["ExtremelyDiscontiguous"] = test{
                        chunks: []ChunkIdx{
                                BaseChunkIdx,
@@ -571,7 +574,9 @@ func TestPageAllocAlloc(t *testing.T) {
                        },
                },
        }
-       if PageAlloc64Bit != 0 {
+       // Disable these tests on iOS since we have a small address space.
+       // See #46860.
+       if PageAlloc64Bit != 0 && sys.GoosIos == 0 {
                const chunkIdxBigJump = 0x100000 // chunk index offset which translates to O(TiB)
 
                // This test attempts to trigger a bug wherein we look at unmapped summary
index 2ed0c0aa6a0ba82da5c78a1601514120840b5b0b..9cbf0dd7ded2829632544624c43b761a08b36265 100644 (file)
@@ -7,6 +7,7 @@ package runtime_test
 import (
        "math/rand"
        . "runtime"
+       "runtime/internal/sys"
        "testing"
 )
 
@@ -350,7 +351,9 @@ func TestPageAllocAllocToCache(t *testing.T) {
                        },
                },
        }
-       if PageAlloc64Bit != 0 {
+       // Disable these tests on iOS since we have a small address space.
+       // See #46860.
+       if PageAlloc64Bit != 0 && sys.GoosIos == 0 {
                const chunkIdxBigJump = 0x100000 // chunk index offset which translates to O(TiB)
 
                // This test is similar to the one with the same name for