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