Memory.inc revision 261991
1//===- Win32/Memory.cpp - Win32 Memory Implementation -----------*- C++ -*-===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file provides the Win32 specific implementation of various Memory 11// management utilities 12// 13//===----------------------------------------------------------------------===// 14 15#include "llvm/Support/DataTypes.h" 16#include "llvm/Support/ErrorHandling.h" 17#include "llvm/Support/Process.h" 18 19// The Windows.h header must be the last one included. 20#include "Windows.h" 21 22namespace { 23 24DWORD getWindowsProtectionFlags(unsigned Flags) { 25 switch (Flags) { 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 50size_t getAllocationGranularity() { 51 SYSTEM_INFO Info; 52 ::GetSystemInfo(&Info); 53 if (Info.dwPageSize > Info.dwAllocationGranularity) 54 return Info.dwPageSize; 55 else 56 return Info.dwAllocationGranularity; 57} 58 59} // namespace 60 61namespace llvm { 62namespace sys { 63 64//===----------------------------------------------------------------------===// 65//=== WARNING: Implementation here must contain only Win32 specific code 66//=== and must not be UNIX code 67//===----------------------------------------------------------------------===// 68 69MemoryBlock Memory::allocateMappedMemory(size_t NumBytes, 70 const MemoryBlock *const NearBlock, 71 unsigned Flags, 72 error_code &EC) { 73 EC = error_code::success(); 74 if (NumBytes == 0) 75 return MemoryBlock(); 76 77 // While we'd be happy to allocate single pages, the Windows allocation 78 // granularity may be larger than a single page (in practice, it is 64K) 79 // so mapping less than that will create an unreachable fragment of memory. 80 static const size_t Granularity = getAllocationGranularity(); 81 const size_t NumBlocks = (NumBytes+Granularity-1)/Granularity; 82 83 uintptr_t Start = NearBlock ? reinterpret_cast<uintptr_t>(NearBlock->base()) + 84 NearBlock->size() 85 : 0; 86 87 // If the requested address is not aligned to the allocation granularity, 88 // round up to get beyond NearBlock. VirtualAlloc would have rounded down. 89 if (Start && Start % Granularity != 0) 90 Start += Granularity - Start % Granularity; 91 92 DWORD Protect = getWindowsProtectionFlags(Flags); 93 94 void *PA = ::VirtualAlloc(reinterpret_cast<void*>(Start), 95 NumBlocks*Granularity, 96 MEM_RESERVE | MEM_COMMIT, Protect); 97 if (PA == NULL) { 98 if (NearBlock) { 99 // Try again without the NearBlock hint 100 return allocateMappedMemory(NumBytes, NULL, Flags, EC); 101 } 102 EC = error_code(::GetLastError(), system_category()); 103 return MemoryBlock(); 104 } 105 106 MemoryBlock Result; 107 Result.Address = PA; 108 Result.Size = NumBlocks*Granularity; 109 110 if (Flags & MF_EXEC) 111 Memory::InvalidateInstructionCache(Result.Address, Result.Size); 112 113 return Result; 114} 115 116error_code Memory::releaseMappedMemory(MemoryBlock &M) { 117 if (M.Address == 0 || M.Size == 0) 118 return error_code::success(); 119 120 if (!VirtualFree(M.Address, 0, MEM_RELEASE)) 121 return error_code(::GetLastError(), system_category()); 122 123 M.Address = 0; 124 M.Size = 0; 125 126 return error_code::success(); 127} 128 129error_code Memory::protectMappedMemory(const MemoryBlock &M, 130 unsigned Flags) { 131 if (M.Address == 0 || M.Size == 0) 132 return error_code::success(); 133 134 DWORD Protect = getWindowsProtectionFlags(Flags); 135 136 DWORD OldFlags; 137 if (!VirtualProtect(M.Address, M.Size, Protect, &OldFlags)) 138 return error_code(::GetLastError(), system_category()); 139 140 if (Flags & MF_EXEC) 141 Memory::InvalidateInstructionCache(M.Address, M.Size); 142 143 return error_code::success(); 144} 145 146/// InvalidateInstructionCache - Before the JIT can run a block of code 147/// that has been emitted it must invalidate the instruction cache on some 148/// platforms. 149void Memory::InvalidateInstructionCache( 150 const void *Addr, size_t Len) { 151 FlushInstructionCache(GetCurrentProcess(), Addr, Len); 152} 153 154 155MemoryBlock Memory::AllocateRWX(size_t NumBytes, 156 const MemoryBlock *NearBlock, 157 std::string *ErrMsg) { 158 MemoryBlock MB; 159 error_code EC; 160 MB = allocateMappedMemory(NumBytes, NearBlock, 161 MF_READ|MF_WRITE|MF_EXEC, EC); 162 if (EC != error_code::success() && ErrMsg) { 163 MakeErrMsg(ErrMsg, EC.message()); 164 } 165 return MB; 166} 167 168bool Memory::ReleaseRWX(MemoryBlock &M, std::string *ErrMsg) { 169 error_code EC = releaseMappedMemory(M); 170 if (EC == error_code::success()) 171 return false; 172 MakeErrMsg(ErrMsg, EC.message()); 173 return true; 174} 175 176static DWORD getProtection(const void *addr) { 177 MEMORY_BASIC_INFORMATION info; 178 if (sizeof(info) == ::VirtualQuery(addr, &info, sizeof(info))) { 179 return info.Protect; 180 } 181 return 0; 182} 183 184bool Memory::setWritable(MemoryBlock &M, std::string *ErrMsg) { 185 if (!setRangeWritable(M.Address, M.Size)) { 186 return MakeErrMsg(ErrMsg, "Cannot set memory to writeable: "); 187 } 188 return true; 189} 190 191bool Memory::setExecutable(MemoryBlock &M, std::string *ErrMsg) { 192 if (!setRangeExecutable(M.Address, M.Size)) { 193 return MakeErrMsg(ErrMsg, "Cannot set memory to executable: "); 194 } 195 return true; 196} 197 198bool Memory::setRangeWritable(const void *Addr, size_t Size) { 199 DWORD prot = getProtection(Addr); 200 if (!prot) 201 return false; 202 203 if (prot == PAGE_EXECUTE || prot == PAGE_EXECUTE_READ) { 204 prot = PAGE_EXECUTE_READWRITE; 205 } else if (prot == PAGE_NOACCESS || prot == PAGE_READONLY) { 206 prot = PAGE_READWRITE; 207 } 208 209 DWORD oldProt; 210 Memory::InvalidateInstructionCache(Addr, Size); 211 return ::VirtualProtect(const_cast<LPVOID>(Addr), Size, prot, &oldProt) 212 == TRUE; 213} 214 215bool Memory::setRangeExecutable(const void *Addr, size_t Size) { 216 DWORD prot = getProtection(Addr); 217 if (!prot) 218 return false; 219 220 if (prot == PAGE_NOACCESS) { 221 prot = PAGE_EXECUTE; 222 } else if (prot == PAGE_READONLY) { 223 prot = PAGE_EXECUTE_READ; 224 } else if (prot == PAGE_READWRITE) { 225 prot = PAGE_EXECUTE_READWRITE; 226 } 227 228 DWORD oldProt; 229 Memory::InvalidateInstructionCache(Addr, Size); 230 return ::VirtualProtect(const_cast<LPVOID>(Addr), Size, prot, &oldProt) 231 == TRUE; 232} 233 234} // namespace sys 235} // namespace llvm 236