1 //===- Win32/Memory.cpp - Win32 Memory Implementation -----------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file provides the Win32 specific implementation of various Memory
11 // management utilities
13 //===----------------------------------------------------------------------===//
15 #include "llvm/Support/DataTypes.h"
16 #include "llvm/Support/ErrorHandling.h"
17 #include "llvm/Support/Process.h"
18 #include "llvm/Support/WindowsError.h"
20 // The Windows.h header must be the last one included.
21 #include "WindowsSupport.h"
22 using std::error_code;
26 DWORD getWindowsProtectionFlags(unsigned Flags) {
28 // Contrary to what you might expect, the Windows page protection flags
29 // are not a bitwise combination of RWX values
30 case llvm::sys::Memory::MF_READ:
32 case llvm::sys::Memory::MF_WRITE:
33 // Note: PAGE_WRITE is not supported by VirtualProtect
34 return PAGE_READWRITE;
35 case llvm::sys::Memory::MF_READ|llvm::sys::Memory::MF_WRITE:
36 return PAGE_READWRITE;
37 case llvm::sys::Memory::MF_READ|llvm::sys::Memory::MF_EXEC:
38 return PAGE_EXECUTE_READ;
39 case llvm::sys::Memory::MF_READ |
40 llvm::sys::Memory::MF_WRITE |
41 llvm::sys::Memory::MF_EXEC:
42 return PAGE_EXECUTE_READWRITE;
43 case llvm::sys::Memory::MF_EXEC:
46 llvm_unreachable("Illegal memory protection flag specified!");
48 // Provide a default return value as required by some compilers.
52 size_t getAllocationGranularity() {
54 ::GetSystemInfo(&Info);
55 if (Info.dwPageSize > Info.dwAllocationGranularity)
56 return Info.dwPageSize;
58 return Info.dwAllocationGranularity;
66 //===----------------------------------------------------------------------===//
67 //=== WARNING: Implementation here must contain only Win32 specific code
68 //=== and must not be UNIX code
69 //===----------------------------------------------------------------------===//
71 MemoryBlock Memory::allocateMappedMemory(size_t NumBytes,
72 const MemoryBlock *const NearBlock,
79 // While we'd be happy to allocate single pages, the Windows allocation
80 // granularity may be larger than a single page (in practice, it is 64K)
81 // so mapping less than that will create an unreachable fragment of memory.
82 static const size_t Granularity = getAllocationGranularity();
83 const size_t NumBlocks = (NumBytes+Granularity-1)/Granularity;
85 uintptr_t Start = NearBlock ? reinterpret_cast<uintptr_t>(NearBlock->base()) +
89 // If the requested address is not aligned to the allocation granularity,
90 // round up to get beyond NearBlock. VirtualAlloc would have rounded down.
91 if (Start && Start % Granularity != 0)
92 Start += Granularity - Start % Granularity;
94 DWORD Protect = getWindowsProtectionFlags(Flags);
96 void *PA = ::VirtualAlloc(reinterpret_cast<void*>(Start),
97 NumBlocks*Granularity,
98 MEM_RESERVE | MEM_COMMIT, Protect);
101 // Try again without the NearBlock hint
102 return allocateMappedMemory(NumBytes, NULL, Flags, EC);
104 EC = mapWindowsError(::GetLastError());
105 return MemoryBlock();
110 Result.Size = NumBlocks*Granularity;
113 Memory::InvalidateInstructionCache(Result.Address, Result.Size);
118 error_code Memory::releaseMappedMemory(MemoryBlock &M) {
119 if (M.Address == 0 || M.Size == 0)
122 if (!VirtualFree(M.Address, 0, MEM_RELEASE))
123 return mapWindowsError(::GetLastError());
131 error_code Memory::protectMappedMemory(const MemoryBlock &M,
133 if (M.Address == 0 || M.Size == 0)
136 DWORD Protect = getWindowsProtectionFlags(Flags);
139 if (!VirtualProtect(M.Address, M.Size, Protect, &OldFlags))
140 return mapWindowsError(::GetLastError());
143 Memory::InvalidateInstructionCache(M.Address, M.Size);
148 /// InvalidateInstructionCache - Before the JIT can run a block of code
149 /// that has been emitted it must invalidate the instruction cache on some
151 void Memory::InvalidateInstructionCache(
152 const void *Addr, size_t Len) {
153 FlushInstructionCache(GetCurrentProcess(), Addr, Len);
157 MemoryBlock Memory::AllocateRWX(size_t NumBytes,
158 const MemoryBlock *NearBlock,
159 std::string *ErrMsg) {
162 MB = allocateMappedMemory(NumBytes, NearBlock,
163 MF_READ|MF_WRITE|MF_EXEC, EC);
164 if (EC != error_code() && ErrMsg) {
165 MakeErrMsg(ErrMsg, EC.message());
170 bool Memory::ReleaseRWX(MemoryBlock &M, std::string *ErrMsg) {
171 error_code EC = releaseMappedMemory(M);
172 if (EC == error_code())
174 MakeErrMsg(ErrMsg, EC.message());
178 static DWORD getProtection(const void *addr) {
179 MEMORY_BASIC_INFORMATION info;
180 if (sizeof(info) == ::VirtualQuery(addr, &info, sizeof(info))) {
186 bool Memory::setWritable(MemoryBlock &M, std::string *ErrMsg) {
187 if (!setRangeWritable(M.Address, M.Size)) {
188 return MakeErrMsg(ErrMsg, "Cannot set memory to writeable: ");
193 bool Memory::setExecutable(MemoryBlock &M, std::string *ErrMsg) {
194 if (!setRangeExecutable(M.Address, M.Size)) {
195 return MakeErrMsg(ErrMsg, "Cannot set memory to executable: ");
200 bool Memory::setRangeWritable(const void *Addr, size_t Size) {
201 DWORD prot = getProtection(Addr);
205 if (prot == PAGE_EXECUTE || prot == PAGE_EXECUTE_READ) {
206 prot = PAGE_EXECUTE_READWRITE;
207 } else if (prot == PAGE_NOACCESS || prot == PAGE_READONLY) {
208 prot = PAGE_READWRITE;
212 Memory::InvalidateInstructionCache(Addr, Size);
213 return ::VirtualProtect(const_cast<LPVOID>(Addr), Size, prot, &oldProt)
217 bool Memory::setRangeExecutable(const void *Addr, size_t Size) {
218 DWORD prot = getProtection(Addr);
222 if (prot == PAGE_NOACCESS) {
224 } else if (prot == PAGE_READONLY) {
225 prot = PAGE_EXECUTE_READ;
226 } else if (prot == PAGE_READWRITE) {
227 prot = PAGE_EXECUTE_READWRITE;
231 Memory::InvalidateInstructionCache(Addr, Size);
232 return ::VirtualProtect(const_cast<LPVOID>(Addr), Size, prot, &oldProt)