/3rd_party/llvm/lib/Support/Windows/Memory.inc

https://code.google.com/p/softart/ · Unknown · 235 lines · 195 code · 40 blank · 0 comment · 0 complexity · 5cf95416658cc5ebe2d7a9510e044f57 MD5 · raw file

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