Memory.inc revision 355940
1//===- Win32/Memory.cpp - Win32 Memory Implementation -----------*- C++ -*-===// 2// 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6// 7//===----------------------------------------------------------------------===// 8// 9// This file provides the Win32 specific implementation of various Memory 10// management utilities 11// 12//===----------------------------------------------------------------------===// 13 14#include "llvm/Support/DataTypes.h" 15#include "llvm/Support/ErrorHandling.h" 16#include "llvm/Support/Process.h" 17#include "llvm/Support/WindowsError.h" 18 19// The Windows.h header must be the last one included. 20#include "WindowsSupport.h" 21 22namespace { 23 24DWORD getWindowsProtectionFlags(unsigned Flags) { 25 switch (Flags & llvm::sys::Memory::MF_RWE_MASK) { 26 // Contrary to what you might expect, the Windows page protection flags 27 // are not a bitwise combination of RWX values 28 case llvm::sys::Memory::MF_READ: 29 return PAGE_READONLY; 30 case llvm::sys::Memory::MF_WRITE: 31 // Note: PAGE_WRITE is not supported by VirtualProtect 32 return PAGE_READWRITE; 33 case llvm::sys::Memory::MF_READ|llvm::sys::Memory::MF_WRITE: 34 return PAGE_READWRITE; 35 case llvm::sys::Memory::MF_READ|llvm::sys::Memory::MF_EXEC: 36 return PAGE_EXECUTE_READ; 37 case llvm::sys::Memory::MF_READ | 38 llvm::sys::Memory::MF_WRITE | 39 llvm::sys::Memory::MF_EXEC: 40 return PAGE_EXECUTE_READWRITE; 41 case llvm::sys::Memory::MF_EXEC: 42 return PAGE_EXECUTE; 43 default: 44 llvm_unreachable("Illegal memory protection flag specified!"); 45 } 46 // Provide a default return value as required by some compilers. 47 return PAGE_NOACCESS; 48} 49 50// While we'd be happy to allocate single pages, the Windows allocation 51// granularity may be larger than a single page (in practice, it is 64K) 52// so mapping less than that will create an unreachable fragment of memory. 53size_t getAllocationGranularity() { 54 SYSTEM_INFO Info; 55 ::GetSystemInfo(&Info); 56 if (Info.dwPageSize > Info.dwAllocationGranularity) 57 return Info.dwPageSize; 58 else 59 return Info.dwAllocationGranularity; 60} 61 62// Large/huge memory pages need explicit process permissions in order to be 63// used. See https://blogs.msdn.microsoft.com/oldnewthing/20110128-00/?p=11643 64// Also large pages need to be manually enabled on your OS. If all this is 65// sucessfull, we return the minimal large memory page size. 66static size_t enableProcessLargePages() { 67 HANDLE Token = 0; 68 size_t LargePageMin = GetLargePageMinimum(); 69 if (LargePageMin) 70 OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, 71 &Token); 72 if (!Token) 73 return 0; 74 LUID Luid; 75 if (!LookupPrivilegeValue(0, SE_LOCK_MEMORY_NAME, &Luid)) { 76 CloseHandle(Token); 77 return 0; 78 } 79 TOKEN_PRIVILEGES TP{}; 80 TP.PrivilegeCount = 1; 81 TP.Privileges[0].Luid = Luid; 82 TP.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 83 if (!AdjustTokenPrivileges(Token, FALSE, &TP, 0, 0, 0)) { 84 CloseHandle(Token); 85 return 0; 86 } 87 DWORD E = GetLastError(); 88 CloseHandle(Token); 89 if (E == ERROR_SUCCESS) 90 return LargePageMin; 91 return 0; 92} 93 94} // namespace 95 96namespace llvm { 97namespace sys { 98 99//===----------------------------------------------------------------------===// 100//=== WARNING: Implementation here must contain only Win32 specific code 101//=== and must not be UNIX code 102//===----------------------------------------------------------------------===// 103 104MemoryBlock Memory::allocateMappedMemory(size_t NumBytes, 105 const MemoryBlock *const NearBlock, 106 unsigned Flags, 107 std::error_code &EC) { 108 EC = std::error_code(); 109 if (NumBytes == 0) 110 return MemoryBlock(); 111 112 static size_t DefaultGranularity = getAllocationGranularity(); 113 static size_t LargePageGranularity = enableProcessLargePages(); 114 115 DWORD AllocType = MEM_RESERVE | MEM_COMMIT; 116 bool HugePages = false; 117 size_t Granularity = DefaultGranularity; 118 119 if ((Flags & MF_HUGE_HINT) && LargePageGranularity > 0) { 120 AllocType |= MEM_LARGE_PAGES; 121 HugePages = true; 122 Granularity = LargePageGranularity; 123 } 124 125 size_t NumBlocks = (NumBytes + Granularity - 1) / Granularity; 126 127 uintptr_t Start = NearBlock ? reinterpret_cast<uintptr_t>(NearBlock->base()) + 128 NearBlock->allocatedSize() 129 : 0; 130 131 // If the requested address is not aligned to the allocation granularity, 132 // round up to get beyond NearBlock. VirtualAlloc would have rounded down. 133 if (Start && Start % Granularity != 0) 134 Start += Granularity - Start % Granularity; 135 136 DWORD Protect = getWindowsProtectionFlags(Flags); 137 138 size_t AllocSize = NumBlocks * Granularity; 139 void *PA = ::VirtualAlloc(reinterpret_cast<void *>(Start), 140 AllocSize, AllocType, Protect); 141 if (PA == NULL) { 142 if (NearBlock || HugePages) { 143 // Try again without the NearBlock hint and without large memory pages 144 return allocateMappedMemory(NumBytes, NULL, Flags & ~MF_HUGE_HINT, EC); 145 } 146 EC = mapWindowsError(::GetLastError()); 147 return MemoryBlock(); 148 } 149 150 MemoryBlock Result; 151 Result.Address = PA; 152 Result.AllocatedSize = AllocSize; 153 Result.Flags = (Flags & ~MF_HUGE_HINT) | (HugePages ? MF_HUGE_HINT : 0); 154 155 if (Flags & MF_EXEC) 156 Memory::InvalidateInstructionCache(Result.Address, AllocSize); 157 158 return Result; 159} 160 161 std::error_code Memory::releaseMappedMemory(MemoryBlock &M) { 162 if (M.Address == 0 || M.AllocatedSize == 0) 163 return std::error_code(); 164 165 if (!VirtualFree(M.Address, 0, MEM_RELEASE)) 166 return mapWindowsError(::GetLastError()); 167 168 M.Address = 0; 169 M.AllocatedSize = 0; 170 171 return std::error_code(); 172} 173 174 std::error_code Memory::protectMappedMemory(const MemoryBlock &M, 175 unsigned Flags) { 176 if (M.Address == 0 || M.AllocatedSize == 0) 177 return std::error_code(); 178 179 DWORD Protect = getWindowsProtectionFlags(Flags); 180 181 DWORD OldFlags; 182 if (!VirtualProtect(M.Address, M.AllocatedSize, Protect, &OldFlags)) 183 return mapWindowsError(::GetLastError()); 184 185 if (Flags & MF_EXEC) 186 Memory::InvalidateInstructionCache(M.Address, M.AllocatedSize); 187 188 return std::error_code(); 189} 190 191/// InvalidateInstructionCache - Before the JIT can run a block of code 192/// that has been emitted it must invalidate the instruction cache on some 193/// platforms. 194void Memory::InvalidateInstructionCache( 195 const void *Addr, size_t Len) { 196 FlushInstructionCache(GetCurrentProcess(), Addr, Len); 197} 198 199} // namespace sys 200} // namespace llvm 201