blob: ebe78782b9043b2ecede515d0a5bf62fb70081d0 [file] [log] [blame]
Reid Spencer566ac282004-09-11 04:59:30 +00001//===- Win32/Memory.cpp - Win32 Memory Implementation -----------*- C++ -*-===//
Michael J. Spencer447762d2010-11-29 18:16:10 +00002//
Reid Spencer566ac282004-09-11 04:59:30 +00003// The LLVM Compiler Infrastructure
4//
Chris Lattnerf3ebc3f2007-12-29 20:36:04 +00005// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
Michael J. Spencer447762d2010-11-29 18:16:10 +00007//
Reid Spencer566ac282004-09-11 04:59:30 +00008//===----------------------------------------------------------------------===//
9//
10// This file provides the Win32 specific implementation of various Memory
11// management utilities
12//
13//===----------------------------------------------------------------------===//
14
Michael J. Spencer447762d2010-11-29 18:16:10 +000015#include "llvm/Support/DataTypes.h"
Andrew Kaylor1f661002012-09-19 20:46:12 +000016#include "llvm/Support/ErrorHandling.h"
Michael J. Spencer447762d2010-11-29 18:16:10 +000017#include "llvm/Support/Process.h"
Chandler Carruthdd7ca932012-12-04 07:04:57 +000018
19// The Windows.h header must be the last one included.
Reid Klecknerd59e2fa2014-02-12 21:26:20 +000020#include "WindowsSupport.h"
Andrew Kaylor1f661002012-09-19 20:46:12 +000021
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
Reid Spencer566ac282004-09-11 04:59:30 +000060
61namespace llvm {
Andrew Kaylor1f661002012-09-19 20:46:12 +000062namespace sys {
Reid Spencer566ac282004-09-11 04:59:30 +000063
64//===----------------------------------------------------------------------===//
Michael J. Spencer447762d2010-11-29 18:16:10 +000065//=== WARNING: Implementation here must contain only Win32 specific code
Reid Spencerb88212e2004-09-15 05:49:50 +000066//=== and must not be UNIX code
Reid Spencer566ac282004-09-11 04:59:30 +000067//===----------------------------------------------------------------------===//
68
Andrew Kaylor1f661002012-09-19 20:46:12 +000069MemoryBlock 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();
Reid Spencer566ac282004-09-11 04:59:30 +000076
Andrew Kaylor1f661002012-09-19 20:46:12 +000077 // 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;
Reid Spencerb88212e2004-09-15 05:49:50 +000082
Andrew Kaylor1f661002012-09-19 20:46:12 +000083 uintptr_t Start = NearBlock ? reinterpret_cast<uintptr_t>(NearBlock->base()) +
84 NearBlock->size()
Alp Toker42235db2013-10-18 07:53:25 +000085 : 0;
Andrew Lenharth09402182005-07-29 23:40:16 +000086
Andrew Kaylor1f661002012-09-19 20:46:12 +000087 // 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) {
NAKAMURA Takumi7bc976a2011-10-15 01:58:16 +000098 if (NearBlock) {
99 // Try again without the NearBlock hint
Andrew Kaylor1f661002012-09-19 20:46:12 +0000100 return allocateMappedMemory(NumBytes, NULL, Flags, EC);
NAKAMURA Takumi7bc976a2011-10-15 01:58:16 +0000101 }
Andrew Kaylor1f661002012-09-19 20:46:12 +0000102 EC = error_code(::GetLastError(), system_category());
Chris Lattner5a9d2e52006-07-07 17:32:37 +0000103 return MemoryBlock();
Reid Spencer566ac282004-09-11 04:59:30 +0000104 }
Reid Spencerb88212e2004-09-15 05:49:50 +0000105
Andrew Kaylor1f661002012-09-19 20:46:12 +0000106 MemoryBlock Result;
107 Result.Address = PA;
108 Result.Size = NumBlocks*Granularity;
Alp Toker42235db2013-10-18 07:53:25 +0000109
Andrew Kaylor1f661002012-09-19 20:46:12 +0000110 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;
Reid Spencer566ac282004-09-11 04:59:30 +0000166}
167
Chris Lattner5a9d2e52006-07-07 17:32:37 +0000168bool Memory::ReleaseRWX(MemoryBlock &M, std::string *ErrMsg) {
Andrew Kaylor1f661002012-09-19 20:46:12 +0000169 error_code EC = releaseMappedMemory(M);
170 if (EC == error_code::success())
171 return false;
172 MakeErrMsg(ErrMsg, EC.message());
173 return true;
Reid Spencer566ac282004-09-11 04:59:30 +0000174}
Reid Spencerb88212e2004-09-15 05:49:50 +0000175
Michael J. Spencera7a90bf2011-10-13 23:16:01 +0000176static 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
Jim Grosbach93960512008-10-20 21:39:23 +0000184bool Memory::setWritable(MemoryBlock &M, std::string *ErrMsg) {
Michael J. Spencera7a90bf2011-10-13 23:16:01 +0000185 if (!setRangeWritable(M.Address, M.Size)) {
186 return MakeErrMsg(ErrMsg, "Cannot set memory to writeable: ");
187 }
Argyrios Kyrtzidisa6f9bb72008-10-04 08:15:32 +0000188 return true;
189}
190
Jim Grosbach93960512008-10-20 21:39:23 +0000191bool Memory::setExecutable(MemoryBlock &M, std::string *ErrMsg) {
Michael J. Spencera7a90bf2011-10-13 23:16:01 +0000192 if (!setRangeExecutable(M.Address, M.Size)) {
193 return MakeErrMsg(ErrMsg, "Cannot set memory to executable: ");
194 }
Jim Grosbach93960512008-10-20 21:39:23 +0000195 return true;
196}
197
Michael J. Spencera7a90bf2011-10-13 23:16:01 +0000198bool 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;
Andrew Kaylor1f661002012-09-19 20:46:12 +0000210 Memory::InvalidateInstructionCache(Addr, Size);
Michael J. Spencera7a90bf2011-10-13 23:16:01 +0000211 return ::VirtualProtect(const_cast<LPVOID>(Addr), Size, prot, &oldProt)
212 == TRUE;
213}
214
Jim Grosbach93960512008-10-20 21:39:23 +0000215bool Memory::setRangeExecutable(const void *Addr, size_t Size) {
Michael J. Spencera7a90bf2011-10-13 23:16:01 +0000216 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;
Andrew Kaylor1f661002012-09-19 20:46:12 +0000229 Memory::InvalidateInstructionCache(Addr, Size);
Michael J. Spencera7a90bf2011-10-13 23:16:01 +0000230 return ::VirtualProtect(const_cast<LPVOID>(Addr), Size, prot, &oldProt)
231 == TRUE;
Argyrios Kyrtzidisa6f9bb72008-10-04 08:15:32 +0000232}
233
Andrew Kaylor1f661002012-09-19 20:46:12 +0000234} // namespace sys
235} // namespace llvm