Skip to content

Commit c27a359

Browse files
committed
runtime: set iOS addr space to 40 bits with incremental pagealloc
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. Fixes #46860. Change-Id: I13865f799777739109585f14f1cc49d6d57e096b Reviewed-on: https://go-review.googlesource.com/c/go/+/344401 Trust: Michael Knyszek <[email protected]> Run-TryBot: Michael Knyszek <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Cherry Mui <[email protected]> Reviewed-by: Austin Clements <[email protected]>
1 parent 7a84066 commit c27a359

7 files changed

+43
-22
lines changed

src/runtime/export_test.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1048,7 +1048,19 @@ func FreePageAlloc(pp *PageAlloc) {
10481048
//
10491049
// This should not be higher than 0x100*pallocChunkBytes to support
10501050
// mips and mipsle, which only have 31-bit address spaces.
1051-
var BaseChunkIdx = ChunkIdx(chunkIndex(((0xc000*pageAlloc64Bit + 0x100*pageAlloc32Bit) * pallocChunkBytes) + arenaBaseOffset*goos.IsAix))
1051+
var BaseChunkIdx = func() ChunkIdx {
1052+
var prefix uintptr
1053+
if pageAlloc64Bit != 0 {
1054+
prefix = 0xc000
1055+
} else {
1056+
prefix = 0x100
1057+
}
1058+
baseAddr := prefix * pallocChunkBytes
1059+
if goos.IsAix != 0 {
1060+
baseAddr += arenaBaseOffset
1061+
}
1062+
return ChunkIdx(chunkIndex(baseAddr))
1063+
}()
10521064

10531065
// PageBase returns an address given a chunk index and a page index
10541066
// relative to that chunk.

src/runtime/malloc.go

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -201,15 +201,21 @@ const (
201201
// we further limit it to 31 bits.
202202
//
203203
// On ios/arm64, although 64-bit pointers are presumably
204-
// available, pointers are truncated to 33 bits. Furthermore,
205-
// only the top 4 GiB of the address space are actually available
206-
// to the application, but we allow the whole 33 bits anyway for
207-
// simplicity.
208-
// TODO(mknyszek): Consider limiting it to 32 bits and using
209-
// arenaBaseOffset to offset into the top 4 GiB.
204+
// available, pointers are truncated to 33 bits in iOS <14.
205+
// Furthermore, only the top 4 GiB of the address space are
206+
// actually available to the application. In iOS >=14, more
207+
// of the address space is available, and the OS can now
208+
// provide addresses outside of those 33 bits. Pick 40 bits
209+
// as a reasonable balance between address space usage by the
210+
// page allocator, and flexibility for what mmap'd regions
211+
// we'll accept for the heap. We can't just move to the full
212+
// 48 bits because this uses too much address space for older
213+
// iOS versions.
214+
// TODO(mknyszek): Once iOS <14 is deprecated, promote ios/arm64
215+
// to a 48-bit address space like every other arm64 platform.
210216
//
211217
// WebAssembly currently has a limit of 4GB linear memory.
212-
heapAddrBits = (_64bit*(1-goarch.IsWasm)*(1-goos.IsIos*goarch.IsArm64))*48 + (1-_64bit+goarch.IsWasm)*(32-(goarch.IsMips+goarch.IsMipsle)) + 33*goos.IsIos*goarch.IsArm64
218+
heapAddrBits = (_64bit*(1-goarch.IsWasm)*(1-goos.IsIos*goarch.IsArm64))*48 + (1-_64bit+goarch.IsWasm)*(32-(goarch.IsMips+goarch.IsMipsle)) + 40*goos.IsIos*goarch.IsArm64
213219

214220
// maxAlloc is the maximum size of an allocation. On 64-bit,
215221
// it's theoretically possible to allocate 1<<heapAddrBits bytes. On

src/runtime/mgcscavenge_test.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package runtime_test
66

77
import (
88
"fmt"
9+
"internal/goos"
910
"math/rand"
1011
. "runtime"
1112
"testing"
@@ -408,7 +409,9 @@ func TestPageAllocScavenge(t *testing.T) {
408409
},
409410
},
410411
}
411-
if PageAlloc64Bit != 0 {
412+
// Disable these tests on iOS since we have a small address space.
413+
// See #46860.
414+
if PageAlloc64Bit != 0 && goos.IsIos == 0 {
412415
tests["ScavAllVeryDiscontiguous"] = setup{
413416
beforeAlloc: map[ChunkIdx][]BitRange{
414417
BaseChunkIdx: {},

src/runtime/mpagealloc_32bit.go

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,13 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5-
//go:build 386 || arm || mips || mipsle || wasm || (ios && arm64)
5+
//go:build 386 || arm || mips || mipsle || wasm
66

77
// wasm is a treated as a 32-bit architecture for the purposes of the page
88
// allocator, even though it has 64-bit pointers. This is because any wasm
99
// pointer always has its top 32 bits as zero, so the effective heap address
1010
// space is only 2^32 bytes in size (see heapAddrBits).
1111

12-
// ios/arm64 is treated as a 32-bit architecture for the purposes of the
13-
// page allocator, even though it has 64-bit pointers and a 33-bit address
14-
// space (see heapAddrBits). The 33 bit address space cannot be rounded up
15-
// to 64 bits because there are too many summary levels to fit in just 33
16-
// bits.
17-
1812
package runtime
1913

2014
import "unsafe"

src/runtime/mpagealloc_64bit.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5-
//go:build amd64 || (!ios && arm64) || mips64 || mips64le || ppc64 || ppc64le || riscv64 || s390x
6-
7-
// See mpagealloc_32bit.go for why ios/arm64 is excluded here.
5+
//go:build amd64 || arm64 || mips64 || mips64le || ppc64 || ppc64le || riscv64 || s390x
86

97
package runtime
108

src/runtime/mpagealloc_test.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package runtime_test
66

77
import (
88
"fmt"
9+
"internal/goos"
910
. "runtime"
1011
"testing"
1112
)
@@ -165,7 +166,9 @@ func TestPageAllocGrow(t *testing.T) {
165166
},
166167
},
167168
}
168-
if PageAlloc64Bit != 0 {
169+
// Disable these tests on iOS since we have a small address space.
170+
// See #46860.
171+
if PageAlloc64Bit != 0 && goos.IsIos == 0 {
169172
tests["ExtremelyDiscontiguous"] = test{
170173
chunks: []ChunkIdx{
171174
BaseChunkIdx,
@@ -571,7 +574,9 @@ func TestPageAllocAlloc(t *testing.T) {
571574
},
572575
},
573576
}
574-
if PageAlloc64Bit != 0 {
577+
// Disable these tests on iOS since we have a small address space.
578+
// See #46860.
579+
if PageAlloc64Bit != 0 && goos.IsIos == 0 {
575580
const chunkIdxBigJump = 0x100000 // chunk index offset which translates to O(TiB)
576581

577582
// This test attempts to trigger a bug wherein we look at unmapped summary

src/runtime/mpagecache_test.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
package runtime_test
66

77
import (
8+
"internal/goos"
89
"math/rand"
910
. "runtime"
1011
"testing"
@@ -372,7 +373,9 @@ func TestPageAllocAllocToCache(t *testing.T) {
372373
},
373374
},
374375
}
375-
if PageAlloc64Bit != 0 {
376+
// Disable these tests on iOS since we have a small address space.
377+
// See #46860.
378+
if PageAlloc64Bit != 0 && goos.IsIos == 0 {
376379
const chunkIdxBigJump = 0x100000 // chunk index offset which translates to O(TiB)
377380

378381
// This test is similar to the one with the same name for

0 commit comments

Comments
 (0)