| 1 | // Licensed to the .NET Foundation under one or more agreements. |
| 2 | // The .NET Foundation licenses this file to you under the MIT license. |
| 3 | // See the LICENSE file in the project root for more information. |
| 4 | |
| 5 | /*++ |
| 6 | |
| 7 | |
| 8 | |
| 9 | Module Name: |
| 10 | |
| 11 | include/pal/virtual.h |
| 12 | |
| 13 | Abstract: |
| 14 | Header file for virtual memory management. |
| 15 | |
| 16 | |
| 17 | |
| 18 | --*/ |
| 19 | |
| 20 | #ifndef _PAL_VIRTUAL_H_ |
| 21 | #define _PAL_VIRTUAL_H_ |
| 22 | |
| 23 | #ifdef __cplusplus |
| 24 | extern "C" |
| 25 | { |
| 26 | #endif // __cplusplus |
| 27 | |
| 28 | typedef struct _CMI { |
| 29 | |
| 30 | struct _CMI * pNext; /* Link to the next entry. */ |
| 31 | struct _CMI * pPrevious; /* Link to the previous entry. */ |
| 32 | |
| 33 | UINT_PTR startBoundary; /* Starting location of the region. */ |
| 34 | SIZE_T memSize; /* Size of the entire region.. */ |
| 35 | |
| 36 | DWORD accessProtection; /* Initial allocation access protection. */ |
| 37 | DWORD allocationType; /* Initial allocation type. */ |
| 38 | |
| 39 | BYTE * pAllocState; /* Individual allocation type tracking for each */ |
| 40 | /* page in the region. */ |
| 41 | |
| 42 | BYTE * pProtectionState; /* Individual allocation type tracking for each */ |
| 43 | /* page in the region. */ |
| 44 | |
| 45 | } CMI, * PCMI; |
| 46 | |
| 47 | enum VIRTUAL_CONSTANTS |
| 48 | { |
| 49 | /* Allocation type. */ |
| 50 | VIRTUAL_COMMIT_ALL_BITS = 0xFF, |
| 51 | VIRTUAL_RESERVE_ALL_BITS = 0x0, |
| 52 | |
| 53 | /* Protection Type. */ |
| 54 | VIRTUAL_READONLY, |
| 55 | VIRTUAL_READWRITE, |
| 56 | VIRTUAL_EXECUTE_READWRITE, |
| 57 | VIRTUAL_NOACCESS, |
| 58 | VIRTUAL_EXECUTE, |
| 59 | VIRTUAL_EXECUTE_READ, |
| 60 | |
| 61 | VIRTUAL_64KB = 0x10000 |
| 62 | }; |
| 63 | |
| 64 | size_t GetVirtualPageSize(); |
| 65 | |
| 66 | /*++ |
| 67 | Function : |
| 68 | VIRTUALInitialize |
| 69 | |
| 70 | Initialize the critical sections. |
| 71 | |
| 72 | Return value: |
| 73 | TRUE if initialization succeeded |
| 74 | FALSE otherwise. |
| 75 | --*/ |
| 76 | BOOL VIRTUALInitialize(bool initializeExecutableMemoryAllocator); |
| 77 | |
| 78 | /*++ |
| 79 | Function : |
| 80 | VIRTUALCleanup |
| 81 | |
| 82 | Deletes the critical sections. |
| 83 | |
| 84 | --*/ |
| 85 | void VIRTUALCleanup( void ); |
| 86 | |
| 87 | #ifdef __cplusplus |
| 88 | } |
| 89 | |
| 90 | /*++ |
| 91 | Class: |
| 92 | ExecutableMemoryAllocator |
| 93 | |
| 94 | This class implements a virtual memory allocator for JIT'ed code. |
| 95 | The purpose of this allocator is to opportunistically reserve a chunk of virtual memory |
| 96 | that is located near the coreclr library (within 2GB range) that can be later used by |
| 97 | JIT. Having executable memory close to the coreclr library allows JIT to generate more |
| 98 | efficient code (by avoiding usage of jump stubs) and thus it can significantly improve |
| 99 | performance of the application. |
| 100 | |
| 101 | This allocator is integrated with the VirtualAlloc/Reserve code. If VirtualAlloc has been |
| 102 | called with the MEM_RESERVE_EXECUTABLE flag then it will first try to obtain the requested size |
| 103 | of virtual memory from ExecutableMemoryAllocator. If ExecutableMemoryAllocator runs out of |
| 104 | the reserved memory (or fails to allocate it during initialization) then VirtualAlloc/Reserve code |
| 105 | will simply fall back to reserving memory using OS APIs. |
| 106 | |
| 107 | Notes: |
| 108 | - the memory allocated by this class is NOT committed by default. It is responsibility |
| 109 | of the caller to commit the virtual memory before accessing it. |
| 110 | - in addition, this class does not provide ability to free the reserved memory. The caller |
| 111 | has full control of the memory it got from this allocator (i.e. the caller becomes |
| 112 | the owner of the allocated memory), so it is caller's responsibility to free the memory |
| 113 | if it is no longer needed. |
| 114 | --*/ |
| 115 | class ExecutableMemoryAllocator |
| 116 | { |
| 117 | public: |
| 118 | /*++ |
| 119 | Function: |
| 120 | Initialize |
| 121 | |
| 122 | This function initializes the allocator. It should be called early during process startup |
| 123 | (when process address space is pretty much empty) in order to have a chance to reserve |
| 124 | sufficient amount of memory that is close to the coreclr library. |
| 125 | --*/ |
| 126 | void Initialize(); |
| 127 | |
| 128 | /*++ |
| 129 | Function: |
| 130 | AllocateMemory |
| 131 | |
| 132 | This function attempts to allocate the requested amount of memory from its reserved virtual |
| 133 | address space. The function will return null if the allocation request cannot |
| 134 | be satisfied by the memory that is currently available in the allocator. |
| 135 | --*/ |
| 136 | void* AllocateMemory(SIZE_T allocationSize); |
| 137 | |
| 138 | /*++ |
| 139 | Function: |
| 140 | AllocateMemory |
| 141 | |
| 142 | This function attempts to allocate the requested amount of memory from its reserved virtual |
| 143 | address space, if memory is available within the specified range. The function will return |
| 144 | null if the allocation request cannot satisfied by the memory that is currently available in |
| 145 | the allocator. |
| 146 | --*/ |
| 147 | void *AllocateMemoryWithinRange(const void *beginAddress, const void *endAddress, SIZE_T allocationSize); |
| 148 | |
| 149 | private: |
| 150 | /*++ |
| 151 | Function: |
| 152 | TryReserveInitialMemory |
| 153 | |
| 154 | This function is called during initialization. It opportunistically tries to reserve |
| 155 | a large chunk of virtual memory that can be later used to store JIT'ed code. |
| 156 | --*/ |
| 157 | void TryReserveInitialMemory(); |
| 158 | |
| 159 | /*++ |
| 160 | Function: |
| 161 | GenerateRandomStartOffset |
| 162 | |
| 163 | This function returns a random offset (in multiples of the virtual page size) |
| 164 | at which the allocator should start allocating memory from its reserved memory range. |
| 165 | --*/ |
| 166 | int32_t GenerateRandomStartOffset(); |
| 167 | |
| 168 | private: |
| 169 | // There does not seem to be an easy way find the size of a library on Unix. |
| 170 | // So this constant represents an approximation of the libcoreclr size (on debug build) |
| 171 | // that can be used to calculate an approximate location of the memory that |
| 172 | // is in 2GB range from the coreclr library. In addition, having precise size of libcoreclr |
| 173 | // is not necessary for the calculations. |
| 174 | static const int32_t CoreClrLibrarySize = 100 * 1024 * 1024; |
| 175 | |
| 176 | // This constant represent the max size of the virtual memory that this allocator |
| 177 | // will try to reserve during initialization. We want all JIT-ed code and the |
| 178 | // entire libcoreclr to be located in a 2GB range. |
| 179 | static const int32_t MaxExecutableMemorySize = 0x7FFF0000; |
| 180 | static const int32_t MaxExecutableMemorySizeNearCoreClr = MaxExecutableMemorySize - CoreClrLibrarySize; |
| 181 | |
| 182 | // Start address of the reserved virtual address space |
| 183 | void* m_startAddress; |
| 184 | |
| 185 | // Next available address in the reserved address space |
| 186 | void* m_nextFreeAddress; |
| 187 | |
| 188 | // Total size of the virtual memory that the allocator has been able to |
| 189 | // reserve during its initialization. |
| 190 | int32_t m_totalSizeOfReservedMemory; |
| 191 | |
| 192 | // Remaining size of the reserved virtual memory that can be used to satisfy allocation requests. |
| 193 | int32_t m_remainingReservedMemory; |
| 194 | }; |
| 195 | |
| 196 | #endif // __cplusplus |
| 197 | |
| 198 | /*++ |
| 199 | Function : |
| 200 | ReserveMemoryFromExecutableAllocator |
| 201 | |
| 202 | This function is used to reserve a region of virual memory (not commited) |
| 203 | that is located close to the coreclr library. The memory comes from the virtual |
| 204 | address range that is managed by ExecutableMemoryAllocator. |
| 205 | --*/ |
| 206 | void* ReserveMemoryFromExecutableAllocator(CorUnix::CPalThread* pthrCurrent, SIZE_T allocationSize); |
| 207 | |
| 208 | #endif /* _PAL_VIRTUAL_H_ */ |
| 209 | |
| 210 | |
| 211 | |
| 212 | |
| 213 | |
| 214 | |
| 215 | |
| 216 | |