1218885Sdim//===- Win32/Memory.cpp - Win32 Memory Implementation -----------*- C++ -*-===//
2218885Sdim//
3218885Sdim//                     The LLVM Compiler Infrastructure
4218885Sdim//
5218885Sdim// This file is distributed under the University of Illinois Open Source
6218885Sdim// License. See LICENSE.TXT for details.
7218885Sdim//
8218885Sdim//===----------------------------------------------------------------------===//
9218885Sdim//
10218885Sdim// This file provides the Win32 specific implementation of various Memory
11218885Sdim// management utilities
12218885Sdim//
13218885Sdim//===----------------------------------------------------------------------===//
14218885Sdim
15218885Sdim#include "llvm/Support/DataTypes.h"
16243830Sdim#include "llvm/Support/ErrorHandling.h"
17218885Sdim#include "llvm/Support/Process.h"
18249423Sdim
19249423Sdim// The Windows.h header must be the last one included.
20243830Sdim#include "Windows.h"
21218885Sdim
22243830Sdimnamespace {
23243830Sdim
24243830SdimDWORD getWindowsProtectionFlags(unsigned Flags) {
25243830Sdim  switch (Flags) {
26243830Sdim  // Contrary to what you might expect, the Windows page protection flags
27243830Sdim  // are not a bitwise combination of RWX values
28243830Sdim  case llvm::sys::Memory::MF_READ:
29243830Sdim    return PAGE_READONLY;
30243830Sdim  case llvm::sys::Memory::MF_WRITE:
31243830Sdim    // Note: PAGE_WRITE is not supported by VirtualProtect
32243830Sdim    return PAGE_READWRITE;
33243830Sdim  case llvm::sys::Memory::MF_READ|llvm::sys::Memory::MF_WRITE:
34243830Sdim    return PAGE_READWRITE;
35243830Sdim  case llvm::sys::Memory::MF_READ|llvm::sys::Memory::MF_EXEC:
36243830Sdim    return PAGE_EXECUTE_READ;
37243830Sdim  case llvm::sys::Memory::MF_READ |
38243830Sdim         llvm::sys::Memory::MF_WRITE |
39243830Sdim         llvm::sys::Memory::MF_EXEC:
40243830Sdim    return PAGE_EXECUTE_READWRITE;
41243830Sdim  case llvm::sys::Memory::MF_EXEC:
42243830Sdim    return PAGE_EXECUTE;
43243830Sdim  default:
44243830Sdim    llvm_unreachable("Illegal memory protection flag specified!");
45243830Sdim  }
46243830Sdim  // Provide a default return value as required by some compilers.
47243830Sdim  return PAGE_NOACCESS;
48243830Sdim}
49243830Sdim
50243830Sdimsize_t getAllocationGranularity() {
51243830Sdim  SYSTEM_INFO  Info;
52243830Sdim  ::GetSystemInfo(&Info);
53243830Sdim  if (Info.dwPageSize > Info.dwAllocationGranularity)
54243830Sdim    return Info.dwPageSize;
55243830Sdim  else
56243830Sdim    return Info.dwAllocationGranularity;
57243830Sdim}
58243830Sdim
59243830Sdim} // namespace
60243830Sdim
61218885Sdimnamespace llvm {
62243830Sdimnamespace sys {
63218885Sdim
64218885Sdim//===----------------------------------------------------------------------===//
65218885Sdim//=== WARNING: Implementation here must contain only Win32 specific code
66218885Sdim//===          and must not be UNIX code
67218885Sdim//===----------------------------------------------------------------------===//
68218885Sdim
69243830SdimMemoryBlock Memory::allocateMappedMemory(size_t NumBytes,
70243830Sdim                                         const MemoryBlock *const NearBlock,
71243830Sdim                                         unsigned Flags,
72243830Sdim                                         error_code &EC) {
73243830Sdim  EC = error_code::success();
74243830Sdim  if (NumBytes == 0)
75243830Sdim    return MemoryBlock();
76218885Sdim
77243830Sdim  // While we'd be happy to allocate single pages, the Windows allocation
78243830Sdim  // granularity may be larger than a single page (in practice, it is 64K)
79243830Sdim  // so mapping less than that will create an unreachable fragment of memory.
80243830Sdim  static const size_t Granularity = getAllocationGranularity();
81243830Sdim  const size_t NumBlocks = (NumBytes+Granularity-1)/Granularity;
82218885Sdim
83243830Sdim  uintptr_t Start = NearBlock ? reinterpret_cast<uintptr_t>(NearBlock->base()) +
84243830Sdim                                NearBlock->size()
85263508Sdim                           : 0;
86218885Sdim
87243830Sdim  // If the requested address is not aligned to the allocation granularity,
88243830Sdim  // round up to get beyond NearBlock. VirtualAlloc would have rounded down.
89243830Sdim  if (Start && Start % Granularity != 0)
90243830Sdim    Start += Granularity - Start % Granularity;
91243830Sdim
92243830Sdim  DWORD Protect = getWindowsProtectionFlags(Flags);
93243830Sdim
94243830Sdim  void *PA = ::VirtualAlloc(reinterpret_cast<void*>(Start),
95243830Sdim                            NumBlocks*Granularity,
96243830Sdim                            MEM_RESERVE | MEM_COMMIT, Protect);
97243830Sdim  if (PA == NULL) {
98226633Sdim    if (NearBlock) {
99226633Sdim      // Try again without the NearBlock hint
100243830Sdim      return allocateMappedMemory(NumBytes, NULL, Flags, EC);
101226633Sdim    }
102243830Sdim    EC = error_code(::GetLastError(), system_category());
103218885Sdim    return MemoryBlock();
104218885Sdim  }
105218885Sdim
106243830Sdim  MemoryBlock Result;
107243830Sdim  Result.Address = PA;
108243830Sdim  Result.Size = NumBlocks*Granularity;
109263508Sdim
110243830Sdim  if (Flags & MF_EXEC)
111243830Sdim    Memory::InvalidateInstructionCache(Result.Address, Result.Size);
112243830Sdim
113243830Sdim  return Result;
114218885Sdim}
115218885Sdim
116243830Sdimerror_code Memory::releaseMappedMemory(MemoryBlock &M) {
117243830Sdim  if (M.Address == 0 || M.Size == 0)
118243830Sdim    return error_code::success();
119243830Sdim
120218885Sdim  if (!VirtualFree(M.Address, 0, MEM_RELEASE))
121243830Sdim    return error_code(::GetLastError(), system_category());
122243830Sdim
123243830Sdim  M.Address = 0;
124243830Sdim  M.Size = 0;
125243830Sdim
126243830Sdim  return error_code::success();
127218885Sdim}
128218885Sdim
129243830Sdimerror_code Memory::protectMappedMemory(const MemoryBlock &M,
130243830Sdim                                       unsigned Flags) {
131243830Sdim  if (M.Address == 0 || M.Size == 0)
132243830Sdim    return error_code::success();
133243830Sdim
134243830Sdim  DWORD Protect = getWindowsProtectionFlags(Flags);
135243830Sdim
136243830Sdim  DWORD OldFlags;
137243830Sdim  if (!VirtualProtect(M.Address, M.Size, Protect, &OldFlags))
138243830Sdim    return error_code(::GetLastError(), system_category());
139243830Sdim
140243830Sdim  if (Flags & MF_EXEC)
141243830Sdim    Memory::InvalidateInstructionCache(M.Address, M.Size);
142243830Sdim
143243830Sdim  return error_code::success();
144243830Sdim}
145243830Sdim
146243830Sdim/// InvalidateInstructionCache - Before the JIT can run a block of code
147243830Sdim/// that has been emitted it must invalidate the instruction cache on some
148243830Sdim/// platforms.
149243830Sdimvoid Memory::InvalidateInstructionCache(
150243830Sdim    const void *Addr, size_t Len) {
151243830Sdim  FlushInstructionCache(GetCurrentProcess(), Addr, Len);
152243830Sdim}
153243830Sdim
154243830Sdim
155243830SdimMemoryBlock Memory::AllocateRWX(size_t NumBytes,
156243830Sdim                                const MemoryBlock *NearBlock,
157243830Sdim                                std::string *ErrMsg) {
158243830Sdim  MemoryBlock MB;
159243830Sdim  error_code EC;
160243830Sdim  MB = allocateMappedMemory(NumBytes, NearBlock,
161243830Sdim                            MF_READ|MF_WRITE|MF_EXEC, EC);
162243830Sdim  if (EC != error_code::success() && ErrMsg) {
163243830Sdim    MakeErrMsg(ErrMsg, EC.message());
164243830Sdim  }
165243830Sdim  return MB;
166243830Sdim}
167243830Sdim
168243830Sdimbool Memory::ReleaseRWX(MemoryBlock &M, std::string *ErrMsg) {
169243830Sdim  error_code EC = releaseMappedMemory(M);
170243830Sdim  if (EC == error_code::success())
171243830Sdim    return false;
172243830Sdim  MakeErrMsg(ErrMsg, EC.message());
173243830Sdim  return true;
174243830Sdim}
175243830Sdim
176226633Sdimstatic DWORD getProtection(const void *addr) {
177226633Sdim  MEMORY_BASIC_INFORMATION info;
178226633Sdim  if (sizeof(info) == ::VirtualQuery(addr, &info, sizeof(info))) {
179226633Sdim    return info.Protect;
180226633Sdim  }
181226633Sdim  return 0;
182226633Sdim}
183226633Sdim
184218885Sdimbool Memory::setWritable(MemoryBlock &M, std::string *ErrMsg) {
185226633Sdim  if (!setRangeWritable(M.Address, M.Size)) {
186226633Sdim    return MakeErrMsg(ErrMsg, "Cannot set memory to writeable: ");
187226633Sdim  }
188218885Sdim  return true;
189218885Sdim}
190218885Sdim
191218885Sdimbool Memory::setExecutable(MemoryBlock &M, std::string *ErrMsg) {
192226633Sdim  if (!setRangeExecutable(M.Address, M.Size)) {
193226633Sdim    return MakeErrMsg(ErrMsg, "Cannot set memory to executable: ");
194226633Sdim  }
195226633Sdim  return true;
196218885Sdim}
197218885Sdim
198218885Sdimbool Memory::setRangeWritable(const void *Addr, size_t Size) {
199226633Sdim  DWORD prot = getProtection(Addr);
200226633Sdim  if (!prot)
201226633Sdim    return false;
202226633Sdim
203226633Sdim  if (prot == PAGE_EXECUTE || prot == PAGE_EXECUTE_READ) {
204226633Sdim    prot = PAGE_EXECUTE_READWRITE;
205226633Sdim  } else if (prot == PAGE_NOACCESS || prot == PAGE_READONLY) {
206226633Sdim    prot = PAGE_READWRITE;
207226633Sdim  }
208226633Sdim
209226633Sdim  DWORD oldProt;
210243830Sdim  Memory::InvalidateInstructionCache(Addr, Size);
211226633Sdim  return ::VirtualProtect(const_cast<LPVOID>(Addr), Size, prot, &oldProt)
212226633Sdim            == TRUE;
213218885Sdim}
214218885Sdim
215218885Sdimbool Memory::setRangeExecutable(const void *Addr, size_t Size) {
216226633Sdim  DWORD prot = getProtection(Addr);
217226633Sdim  if (!prot)
218226633Sdim    return false;
219226633Sdim
220226633Sdim  if (prot == PAGE_NOACCESS) {
221226633Sdim    prot = PAGE_EXECUTE;
222226633Sdim  } else if (prot == PAGE_READONLY) {
223226633Sdim    prot = PAGE_EXECUTE_READ;
224226633Sdim  } else if (prot == PAGE_READWRITE) {
225226633Sdim    prot = PAGE_EXECUTE_READWRITE;
226226633Sdim  }
227226633Sdim
228226633Sdim  DWORD oldProt;
229243830Sdim  Memory::InvalidateInstructionCache(Addr, Size);
230226633Sdim  return ::VirtualProtect(const_cast<LPVOID>(Addr), Size, prot, &oldProt)
231226633Sdim            == TRUE;
232218885Sdim}
233218885Sdim
234243830Sdim} // namespace sys
235243830Sdim} // namespace llvm
236