Use the new script to sort the includes of every file under lib.
[oota-llvm.git] / lib / Support / Windows / Memory.inc
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 "Windows.h"
16 #include "llvm/Support/DataTypes.h"
17 #include "llvm/Support/ErrorHandling.h"
18 #include "llvm/Support/Process.h"
19
20 namespace {
21
22 DWORD getWindowsProtectionFlags(unsigned Flags) {
23   switch (Flags) {
24   // Contrary to what you might expect, the Windows page protection flags
25   // are not a bitwise combination of RWX values
26   case llvm::sys::Memory::MF_READ:
27     return PAGE_READONLY;
28   case llvm::sys::Memory::MF_WRITE:
29     // Note: PAGE_WRITE is not supported by VirtualProtect
30     return PAGE_READWRITE;
31   case llvm::sys::Memory::MF_READ|llvm::sys::Memory::MF_WRITE:
32     return PAGE_READWRITE;
33   case llvm::sys::Memory::MF_READ|llvm::sys::Memory::MF_EXEC:
34     return PAGE_EXECUTE_READ;
35   case llvm::sys::Memory::MF_READ |
36          llvm::sys::Memory::MF_WRITE |
37          llvm::sys::Memory::MF_EXEC:
38     return PAGE_EXECUTE_READWRITE;
39   case llvm::sys::Memory::MF_EXEC:
40     return PAGE_EXECUTE;
41   default:
42     llvm_unreachable("Illegal memory protection flag specified!");
43   }
44   // Provide a default return value as required by some compilers.
45   return PAGE_NOACCESS;
46 }
47
48 size_t getAllocationGranularity() {
49   SYSTEM_INFO  Info;
50   ::GetSystemInfo(&Info);
51   if (Info.dwPageSize > Info.dwAllocationGranularity)
52     return Info.dwPageSize;
53   else
54     return Info.dwAllocationGranularity;
55 }
56
57 } // namespace
58
59 namespace llvm {
60 namespace sys {
61
62 //===----------------------------------------------------------------------===//
63 //=== WARNING: Implementation here must contain only Win32 specific code
64 //===          and must not be UNIX code
65 //===----------------------------------------------------------------------===//
66
67 MemoryBlock Memory::allocateMappedMemory(size_t NumBytes,
68                                          const MemoryBlock *const NearBlock,
69                                          unsigned Flags,
70                                          error_code &EC) {
71   EC = error_code::success();
72   if (NumBytes == 0)
73     return MemoryBlock();
74
75   // While we'd be happy to allocate single pages, the Windows allocation
76   // granularity may be larger than a single page (in practice, it is 64K)
77   // so mapping less than that will create an unreachable fragment of memory.
78   static const size_t Granularity = getAllocationGranularity();
79   const size_t NumBlocks = (NumBytes+Granularity-1)/Granularity;
80
81   uintptr_t Start = NearBlock ? reinterpret_cast<uintptr_t>(NearBlock->base()) +
82                                 NearBlock->size()
83                            : NULL;
84
85   // If the requested address is not aligned to the allocation granularity,
86   // round up to get beyond NearBlock. VirtualAlloc would have rounded down.
87   if (Start && Start % Granularity != 0)
88     Start += Granularity - Start % Granularity;
89
90   DWORD Protect = getWindowsProtectionFlags(Flags);
91
92   void *PA = ::VirtualAlloc(reinterpret_cast<void*>(Start),
93                             NumBlocks*Granularity,
94                             MEM_RESERVE | MEM_COMMIT, Protect);
95   if (PA == NULL) {
96     if (NearBlock) {
97       // Try again without the NearBlock hint
98       return allocateMappedMemory(NumBytes, NULL, Flags, EC);
99     }
100     EC = error_code(::GetLastError(), system_category());
101     return MemoryBlock();
102   }
103
104   MemoryBlock Result;
105   Result.Address = PA;
106   Result.Size = NumBlocks*Granularity;
107                                  ;
108   if (Flags & MF_EXEC)
109     Memory::InvalidateInstructionCache(Result.Address, Result.Size);
110
111   return Result;
112 }
113
114 error_code Memory::releaseMappedMemory(MemoryBlock &M) {
115   if (M.Address == 0 || M.Size == 0)
116     return error_code::success();
117
118   if (!VirtualFree(M.Address, 0, MEM_RELEASE))
119     return error_code(::GetLastError(), system_category());
120
121   M.Address = 0;
122   M.Size = 0;
123
124   return error_code::success();
125 }
126
127 error_code Memory::protectMappedMemory(const MemoryBlock &M,
128                                        unsigned Flags) {
129   if (M.Address == 0 || M.Size == 0)
130     return error_code::success();
131
132   DWORD Protect = getWindowsProtectionFlags(Flags);
133
134   DWORD OldFlags;
135   if (!VirtualProtect(M.Address, M.Size, Protect, &OldFlags))
136     return error_code(::GetLastError(), system_category());
137
138   if (Flags & MF_EXEC)
139     Memory::InvalidateInstructionCache(M.Address, M.Size);
140
141   return error_code::success();
142 }
143
144 /// InvalidateInstructionCache - Before the JIT can run a block of code
145 /// that has been emitted it must invalidate the instruction cache on some
146 /// platforms.
147 void Memory::InvalidateInstructionCache(
148     const void *Addr, size_t Len) {
149   FlushInstructionCache(GetCurrentProcess(), Addr, Len);
150 }
151
152
153 MemoryBlock Memory::AllocateRWX(size_t NumBytes,
154                                 const MemoryBlock *NearBlock,
155                                 std::string *ErrMsg) {
156   MemoryBlock MB;
157   error_code EC;
158   MB = allocateMappedMemory(NumBytes, NearBlock,
159                             MF_READ|MF_WRITE|MF_EXEC, EC);
160   if (EC != error_code::success() && ErrMsg) {
161     MakeErrMsg(ErrMsg, EC.message());
162   }
163   return MB;
164 }
165
166 bool Memory::ReleaseRWX(MemoryBlock &M, std::string *ErrMsg) {
167   error_code EC = releaseMappedMemory(M);
168   if (EC == error_code::success())
169     return false;
170   MakeErrMsg(ErrMsg, EC.message());
171   return true;
172 }
173
174 static DWORD getProtection(const void *addr) {
175   MEMORY_BASIC_INFORMATION info;
176   if (sizeof(info) == ::VirtualQuery(addr, &info, sizeof(info))) {
177     return info.Protect;
178   }
179   return 0;
180 }
181
182 bool Memory::setWritable(MemoryBlock &M, std::string *ErrMsg) {
183   if (!setRangeWritable(M.Address, M.Size)) {
184     return MakeErrMsg(ErrMsg, "Cannot set memory to writeable: ");
185   }
186   return true;
187 }
188
189 bool Memory::setExecutable(MemoryBlock &M, std::string *ErrMsg) {
190   if (!setRangeExecutable(M.Address, M.Size)) {
191     return MakeErrMsg(ErrMsg, "Cannot set memory to executable: ");
192   }
193   return true;
194 }
195
196 bool Memory::setRangeWritable(const void *Addr, size_t Size) {
197   DWORD prot = getProtection(Addr);
198   if (!prot)
199     return false;
200
201   if (prot == PAGE_EXECUTE || prot == PAGE_EXECUTE_READ) {
202     prot = PAGE_EXECUTE_READWRITE;
203   } else if (prot == PAGE_NOACCESS || prot == PAGE_READONLY) {
204     prot = PAGE_READWRITE;
205   }
206
207   DWORD oldProt;
208   Memory::InvalidateInstructionCache(Addr, Size);
209   return ::VirtualProtect(const_cast<LPVOID>(Addr), Size, prot, &oldProt)
210             == TRUE;
211 }
212
213 bool Memory::setRangeExecutable(const void *Addr, size_t Size) {
214   DWORD prot = getProtection(Addr);
215   if (!prot)
216     return false;
217
218   if (prot == PAGE_NOACCESS) {
219     prot = PAGE_EXECUTE;
220   } else if (prot == PAGE_READONLY) {
221     prot = PAGE_EXECUTE_READ;
222   } else if (prot == PAGE_READWRITE) {
223     prot = PAGE_EXECUTE_READWRITE;
224   }
225
226   DWORD oldProt;
227   Memory::InvalidateInstructionCache(Addr, Size);
228   return ::VirtualProtect(const_cast<LPVOID>(Addr), Size, prot, &oldProt)
229             == TRUE;
230 }
231
232 } // namespace sys
233 } // namespace llvm