Skip to content

Commit 8bf03a6

Browse files
VSadovfilipnavara
andauthored
[NativeAOT] Support variable page size on Linux Arm64 (#88710)
* stack probe * probe size on x86 * OS_PAGE_SIZE * call sysconf(_SC_PAGESIZE) unconditionally * initialize OS page in PalInit Co-authored-by: Filip Navara <[email protected]>
1 parent ae99bb2 commit 8bf03a6

File tree

14 files changed

+80
-60
lines changed

14 files changed

+80
-60
lines changed

src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ThunkPool.cs

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
//
2626
// With FEATURE_RX_THUNKS, thunks are created by allocating new virtual memory space, where the first half of
2727
// that space is filled with thunk stubs, and gets RX permissions, and the second half is for the thunks data,
28-
// and gets RW permissions. The thunk stubs and data blocks are not in groupped in pairs:
28+
// and gets RW permissions. The thunk stubs and data blocks are not grouped in pairs:
2929
// all the thunk stubs blocks are groupped at the beginning of the allocated virtual memory space, and all the
3030
// thunk data blocks are groupped in the second half of the virtual space.
3131
//
@@ -40,20 +40,12 @@ namespace System.Runtime
4040
{
4141
internal static class Constants
4242
{
43-
#if TARGET_ARM64 && (TARGET_OSX || TARGET_MACCATALYST || TARGET_IOS || TARGET_TVOS)
44-
public const uint PageSize = 0x4000; // 16k
45-
public const nuint PageSizeMask = 0x3FFF;
46-
#else
47-
public const uint PageSize = 0x1000; // 4k
48-
public const nuint PageSizeMask = 0xFFF;
49-
#endif
50-
public const uint AllocationGranularity = 0x10000; // 64k
51-
public const nuint AllocationGranularityMask = 0xFFFF;
52-
5343
public static readonly int ThunkDataSize = 2 * IntPtr.Size;
5444
public static readonly int ThunkCodeSize = InternalCalls.RhpGetThunkSize();
5545
public static readonly int NumThunksPerBlock = InternalCalls.RhpGetNumThunksPerBlock();
5646
public static readonly int NumThunkBlocksPerMapping = InternalCalls.RhpGetNumThunkBlocksPerMapping();
47+
public static readonly uint ThunkBlockSize = (uint)InternalCalls.RhpGetThunkBlockSize();
48+
public static readonly nuint ThunkBlockSizeMask = ThunkBlockSize - 1;
5749
}
5850

5951
internal class ThunksHeap
@@ -105,11 +97,11 @@ private unsafe ThunksHeap(IntPtr commonStubAddress)
10597
IntPtr thunkDataBlock = InternalCalls.RhpGetThunkDataBlockAddress(thunkStubsBlock);
10698

10799
// Address of the first thunk data cell should be at the beginning of the thunks data block (page-aligned)
108-
Debug.Assert(((nuint)(nint)thunkDataBlock % Constants.PageSize) == 0);
100+
Debug.Assert(((nuint)(nint)thunkDataBlock % Constants.ThunkBlockSize) == 0);
109101

110102
// Update the last pointer value in the thunks data section with the value of the common stub address
111-
*(IntPtr*)(thunkDataBlock + (int)(Constants.PageSize - IntPtr.Size)) = commonStubAddress;
112-
Debug.Assert(*(IntPtr*)(thunkDataBlock + (int)(Constants.PageSize - IntPtr.Size)) == commonStubAddress);
103+
*(IntPtr*)(thunkDataBlock + (int)(Constants.ThunkBlockSize - IntPtr.Size)) = commonStubAddress;
104+
Debug.Assert(*(IntPtr*)(thunkDataBlock + (int)(Constants.ThunkBlockSize - IntPtr.Size)) == commonStubAddress);
113105

114106
// Set the head and end of the linked list
115107
_nextAvailableThunkPtr = thunkDataBlock;
@@ -161,11 +153,11 @@ private unsafe bool ExpandHeap()
161153
IntPtr thunkDataBlock = InternalCalls.RhpGetThunkDataBlockAddress(thunkStubsBlock);
162154

163155
// Address of the first thunk data cell should be at the beginning of the thunks data block (page-aligned)
164-
Debug.Assert(((nuint)(nint)thunkDataBlock % Constants.PageSize) == 0);
156+
Debug.Assert(((nuint)(nint)thunkDataBlock % Constants.ThunkBlockSize) == 0);
165157

166158
// Update the last pointer value in the thunks data section with the value of the common stub address
167-
*(IntPtr*)(thunkDataBlock + (int)(Constants.PageSize - IntPtr.Size)) = _commonStubAddress;
168-
Debug.Assert(*(IntPtr*)(thunkDataBlock + (int)(Constants.PageSize - IntPtr.Size)) == _commonStubAddress);
159+
*(IntPtr*)(thunkDataBlock + (int)(Constants.ThunkBlockSize - IntPtr.Size)) = _commonStubAddress;
160+
Debug.Assert(*(IntPtr*)(thunkDataBlock + (int)(Constants.ThunkBlockSize - IntPtr.Size)) == _commonStubAddress);
169161

170162
// Link the last entry in the old list to the first entry in the new list
171163
*((IntPtr*)_lastThunkPtr) = thunkDataBlock;
@@ -220,7 +212,7 @@ public unsafe IntPtr AllocateThunk()
220212
*((IntPtr*)(nextAvailableThunkPtr + IntPtr.Size)) = IntPtr.Zero;
221213
#endif
222214

223-
int thunkIndex = (int)(((nuint)(nint)nextAvailableThunkPtr) - ((nuint)(nint)nextAvailableThunkPtr & ~Constants.PageSizeMask));
215+
int thunkIndex = (int)(((nuint)(nint)nextAvailableThunkPtr) - ((nuint)(nint)nextAvailableThunkPtr & ~Constants.ThunkBlockSizeMask));
224216
Debug.Assert((thunkIndex % Constants.ThunkDataSize) == 0);
225217
thunkIndex /= Constants.ThunkDataSize;
226218

@@ -279,7 +271,7 @@ private static IntPtr TryGetThunkDataAddress(IntPtr thunkAddress)
279271
nuint thunkAddressValue = (nuint)(nint)ClearThumbBit(thunkAddress);
280272

281273
// Compute the base address of the thunk's mapping
282-
nuint currentThunksBlockAddress = thunkAddressValue & ~Constants.PageSizeMask;
274+
nuint currentThunksBlockAddress = thunkAddressValue & ~Constants.ThunkBlockSizeMask;
283275

284276
// Make sure the thunk address is valid by checking alignment
285277
if ((thunkAddressValue - currentThunksBlockAddress) % (nuint)Constants.ThunkCodeSize != 0)

src/coreclr/nativeaot/Runtime/CommonMacros.h

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -132,42 +132,32 @@ inline bool IS_ALIGNED(T* val, uintptr_t alignment);
132132
#endif
133133

134134
#ifndef __GCENV_BASE_INCLUDED__
135+
136+
#if defined(HOST_WASM)
137+
#define OS_PAGE_SIZE 0x4
138+
#else
139+
#define OS_PAGE_SIZE PalOsPageSize()
140+
#endif
141+
135142
#if defined(HOST_AMD64)
136143

137144
#define DATA_ALIGNMENT 8
138-
#define OS_PAGE_SIZE 0x1000
139145

140146
#elif defined(HOST_X86)
141147

142148
#define DATA_ALIGNMENT 4
143-
#ifndef OS_PAGE_SIZE
144-
#define OS_PAGE_SIZE 0x1000
145-
#endif
146149

147150
#elif defined(HOST_ARM)
148151

149152
#define DATA_ALIGNMENT 4
150-
#ifndef OS_PAGE_SIZE
151-
#define OS_PAGE_SIZE 0x1000
152-
#endif
153153

154154
#elif defined(HOST_ARM64)
155155

156156
#define DATA_ALIGNMENT 8
157-
#ifndef OS_PAGE_SIZE
158-
#ifdef HOST_APPLE
159-
#define OS_PAGE_SIZE 0x4000
160-
#else
161-
#define OS_PAGE_SIZE 0x1000
162-
#endif
163-
#endif
164157

165158
#elif defined(HOST_WASM)
166159

167160
#define DATA_ALIGNMENT 4
168-
#ifndef OS_PAGE_SIZE
169-
#define OS_PAGE_SIZE 0x4
170-
#endif
171161

172162
#else
173163
#error Unsupported target architecture

src/coreclr/nativeaot/Runtime/PalRedhawk.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,7 @@ struct UNIX_CONTEXT;
731731
#endif
732732

733733
#ifdef TARGET_UNIX
734+
REDHAWK_PALIMPORT uint32_t REDHAWK_PALAPI PalGetOsPageSize();
734735
REDHAWK_PALIMPORT void REDHAWK_PALAPI PalSetHardwareExceptionHandler(PHARDWARE_EXCEPTION_HANDLER handler);
735736
#else
736737
REDHAWK_PALIMPORT void* REDHAWK_PALAPI PalAddVectoredExceptionHandler(uint32_t firstHandler, _In_ PVECTORED_EXCEPTION_HANDLER vectoredHandler);

src/coreclr/nativeaot/Runtime/ThunksMapping.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@
2828

2929
static_assert((THUNK_SIZE % 4) == 0, "Thunk stubs size not aligned correctly. This will cause runtime failures.");
3030

31-
#define THUNKS_MAP_SIZE 0x8000 // 32 K
31+
// 32 K or OS page
32+
#define THUNKS_MAP_SIZE (max(0x8000, OS_PAGE_SIZE))
3233

3334
#ifdef TARGET_ARM
3435
//*****************************************************************************
@@ -56,7 +57,7 @@ void EncodeThumb2Mov32(uint16_t * pCode, uint32_t value, uint8_t rDestination)
5657

5758
COOP_PINVOKE_HELPER(int, RhpGetNumThunkBlocksPerMapping, ())
5859
{
59-
static_assert((THUNKS_MAP_SIZE % OS_PAGE_SIZE) == 0, "Thunks map size should be in multiples of pages");
60+
ASSERT_MSG((THUNKS_MAP_SIZE % OS_PAGE_SIZE) == 0, "Thunks map size should be in multiples of pages");
6061

6162
return THUNKS_MAP_SIZE / OS_PAGE_SIZE;
6263
}

src/coreclr/nativeaot/Runtime/allocheap.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ uint8_t * AllocHeap::_Alloc(
137137
#endif // FEATURE_RWX_MEMORY
138138

139139
ASSERT((alignment & (alignment - 1)) == 0); // Power of 2 only.
140-
ASSERT(alignment <= OS_PAGE_SIZE); // Can't handle this right now.
140+
ASSERT((int32_t)alignment <= OS_PAGE_SIZE); // Can't handle this right now.
141141
ASSERT((m_rwProtectType == m_roProtectType) == (pRWAccessHolder == NULL));
142142
ASSERT(!_UseAccessManager() || pRWAccessHolder != NULL);
143143

@@ -276,7 +276,7 @@ bool AllocHeap::_UpdateMemPtrs(uint8_t* pNextFree)
276276
//-------------------------------------------------------------------------------------------------
277277
bool AllocHeap::_AllocNewBlock(uintptr_t cbMem)
278278
{
279-
cbMem = ALIGN_UP(max(cbMem, s_minBlockSize), OS_PAGE_SIZE);;
279+
cbMem = ALIGN_UP(cbMem, OS_PAGE_SIZE);
280280

281281
uint8_t * pbMem = reinterpret_cast<uint8_t*>
282282
(PalVirtualAlloc(NULL, cbMem, MEM_COMMIT, m_roProtectType));

src/coreclr/nativeaot/Runtime/allocheap.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,6 @@ class AllocHeap
7474
bool _UpdateMemPtrs(uint8_t* pNextFree);
7575
bool _UseAccessManager() { return m_rwProtectType != m_roProtectType; }
7676

77-
static const uintptr_t s_minBlockSize = OS_PAGE_SIZE;
78-
7977
typedef rh::util::MemRange Block;
8078
typedef DPTR(Block) PTR_Block;
8179
struct BlockListElem : public Block

src/coreclr/nativeaot/Runtime/amd64/MiscStubs.S

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
//
1616
// See also https://github.com/dotnet/runtime/issues/9899 for more information.
1717

18-
#define PAGE_SIZE 0x1000
18+
#define PROBE_STEP 0x1000
1919

2020
NESTED_ENTRY RhpStackProbe, _TEXT, NoHandler
2121
// On entry:
@@ -32,11 +32,11 @@ NESTED_ENTRY RhpStackProbe, _TEXT, NoHandler
3232

3333
END_PROLOGUE
3434

35-
and rsp, -PAGE_SIZE // rsp points to the **lowest address** on the last probed page
35+
and rsp, -PROBE_STEP // rsp points to the **lowest address** on the last probed page
3636
// This is done to make the following loop end condition simpler.
3737

3838
LOCAL_LABEL(ProbeLoop):
39-
sub rsp, PAGE_SIZE // rsp points to the lowest address of the **next page** to probe
39+
sub rsp, PROBE_STEP // rsp points to the lowest address of the **next page** to probe
4040
test dword ptr [rsp], eax // rsp points to the lowest address on the **last probed** page
4141
cmp rsp, r11
4242
jg LOCAL_LABEL(ProbeLoop) // if (rsp > r11), then we need to probe at least one more page.

src/coreclr/nativeaot/Runtime/amd64/MiscStubs.asm

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ include AsmMacros.inc
1111
;
1212
; NOTE: this helper will NOT modify a value of rsp and can be defined as a leaf function.
1313

14-
PAGE_SIZE equ 1000h
14+
PROBE_STEP equ 1000h
1515

1616
LEAF_ENTRY RhpStackProbe, _TEXT
1717
; On entry:
@@ -24,11 +24,11 @@ LEAF_ENTRY RhpStackProbe, _TEXT
2424
; NOTE: this helper will probe at least one page below the one pointed by rsp.
2525

2626
mov rax, rsp ; rax points to some byte on the last probed page
27-
and rax, -PAGE_SIZE ; rax points to the **lowest address** on the last probed page
27+
and rax, -PROBE_STEP ; rax points to the **lowest address** on the last probed page
2828
; This is done to make the following loop end condition simpler.
2929

3030
ProbeLoop:
31-
sub rax, PAGE_SIZE ; rax points to the lowest address of the **next page** to probe
31+
sub rax, PROBE_STEP ; rax points to the lowest address of the **next page** to probe
3232
test dword ptr [rax], eax ; rax points to the lowest address on the **last probed** page
3333
cmp rax, r11
3434
jg ProbeLoop ; If (rax > r11), then we need to probe at least one more page.

src/coreclr/nativeaot/Runtime/arm/MiscStubs.S

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,20 @@
2020
// r5 - is not preserved
2121
//
2222
// NOTE: this helper will probe at least one page below the one pointed to by sp.
23-
#define PROBE_PAGE_SIZE 4096
24-
#define PROBE_PAGE_SIZE_LOG2 12
23+
#define PROBE_STEP 4096
24+
#define PROBE_STEP_LOG2 12
2525

2626
LEAF_ENTRY RhpStackProbe, _TEXT
2727
PROLOG_PUSH "{r7}"
2828
PROLOG_STACK_SAVE r7
2929

3030
mov r5, sp // r5 points to some byte on the last probed page
31-
bfc r5, #0, #PROBE_PAGE_SIZE_LOG2 // r5 points to the **lowest address** on the last probed page
31+
bfc r5, #0, #PROBE_STEP_LOG2 // r5 points to the **lowest address** on the last probed page
3232
mov sp, r5
3333

3434
ProbeLoop:
3535
// Immediate operand for the following instruction can not be greater than 4095.
36-
sub sp, #(PROBE_PAGE_SIZE - 4) // sp points to the **fourth** byte on the **next page** to probe
36+
sub sp, #(PROBE_STEP - 4) // sp points to the **fourth** byte on the **next page** to probe
3737
ldr r5, [sp, #-4]! // sp points to the lowest address on the **last probed** page
3838
cmp sp, r4
3939
bhi ProbeLoop // If (sp > r4), then we need to probe at least one more page.

src/coreclr/nativeaot/Runtime/i386/MiscStubs.S

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
// NOTE: this helper will modify a value of esp and must establish the frame pointer.
1717
// NOTE: On Linux we must advance the stack pointer as we probe - it is not allowed to access 65535 bytes below esp.
1818
//
19-
#define PAGE_SIZE 0x1000
19+
#define PROBE_STEP 0x1000
2020
NESTED_ENTRY RhpStackProbe, _TEXT, NoHandler
2121
// On entry:
2222
// eax - the lowest address of the stack frame being allocated (i.e. [InitialSp - FrameSize])
@@ -25,11 +25,11 @@ NESTED_ENTRY RhpStackProbe, _TEXT, NoHandler
2525
PROLOG_BEG
2626
PROLOG_END
2727

28-
and esp, -PAGE_SIZE // esp points to the **lowest address** on the last probed page
28+
and esp, -PROBE_STEP // esp points to the **lowest address** on the last probed page
2929
// This is done to make the loop end condition simpler.
3030

3131
LOCAL_LABEL(ProbeLoop):
32-
sub esp, PAGE_SIZE // esp points to the lowest address of the **next page** to probe
32+
sub esp, PROBE_STEP // esp points to the lowest address of the **next page** to probe
3333
test [esp], eax // esp points to the lowest address on the **last probed** page
3434
cmp esp, eax
3535
jg LOCAL_LABEL(ProbeLoop) // if esp > eax, then we need to probe at least one more page.

0 commit comments

Comments
 (0)