SectionMemoryManager.cpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. //===- SectionMemoryManager.cpp - Memory manager for MCJIT/RtDyld *- C++ -*-==//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // This file implements the section-based memory manager used by the MCJIT
  10. // execution engine and RuntimeDyld
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #include "llvm/ExecutionEngine/SectionMemoryManager.h"
  14. #include "llvm/Config/config.h"
  15. #include "llvm/Support/MathExtras.h"
  16. #include "llvm/Support/Process.h"
  17. namespace llvm {
  18. uint8_t *SectionMemoryManager::allocateDataSection(uintptr_t Size,
  19. unsigned Alignment,
  20. unsigned SectionID,
  21. StringRef SectionName,
  22. bool IsReadOnly) {
  23. if (IsReadOnly)
  24. return allocateSection(SectionMemoryManager::AllocationPurpose::ROData,
  25. Size, Alignment);
  26. return allocateSection(SectionMemoryManager::AllocationPurpose::RWData, Size,
  27. Alignment);
  28. }
  29. uint8_t *SectionMemoryManager::allocateCodeSection(uintptr_t Size,
  30. unsigned Alignment,
  31. unsigned SectionID,
  32. StringRef SectionName) {
  33. return allocateSection(SectionMemoryManager::AllocationPurpose::Code, Size,
  34. Alignment);
  35. }
  36. uint8_t *SectionMemoryManager::allocateSection(
  37. SectionMemoryManager::AllocationPurpose Purpose, uintptr_t Size,
  38. unsigned Alignment) {
  39. if (!Alignment)
  40. Alignment = 16;
  41. assert(!(Alignment & (Alignment - 1)) && "Alignment must be a power of two.");
  42. uintptr_t RequiredSize = Alignment * ((Size + Alignment - 1) / Alignment + 1);
  43. uintptr_t Addr = 0;
  44. MemoryGroup &MemGroup = [&]() -> MemoryGroup & {
  45. switch (Purpose) {
  46. case AllocationPurpose::Code:
  47. return CodeMem;
  48. case AllocationPurpose::ROData:
  49. return RODataMem;
  50. case AllocationPurpose::RWData:
  51. return RWDataMem;
  52. }
  53. llvm_unreachable("Unknown SectionMemoryManager::AllocationPurpose");
  54. }();
  55. // Look in the list of free memory regions and use a block there if one
  56. // is available.
  57. for (FreeMemBlock &FreeMB : MemGroup.FreeMem) {
  58. if (FreeMB.Free.allocatedSize() >= RequiredSize) {
  59. Addr = (uintptr_t)FreeMB.Free.base();
  60. uintptr_t EndOfBlock = Addr + FreeMB.Free.allocatedSize();
  61. // Align the address.
  62. Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1);
  63. if (FreeMB.PendingPrefixIndex == (unsigned)-1) {
  64. // The part of the block we're giving out to the user is now pending
  65. MemGroup.PendingMem.push_back(sys::MemoryBlock((void *)Addr, Size));
  66. // Remember this pending block, such that future allocations can just
  67. // modify it rather than creating a new one
  68. FreeMB.PendingPrefixIndex = MemGroup.PendingMem.size() - 1;
  69. } else {
  70. sys::MemoryBlock &PendingMB =
  71. MemGroup.PendingMem[FreeMB.PendingPrefixIndex];
  72. PendingMB = sys::MemoryBlock(PendingMB.base(),
  73. Addr + Size - (uintptr_t)PendingMB.base());
  74. }
  75. // Remember how much free space is now left in this block
  76. FreeMB.Free =
  77. sys::MemoryBlock((void *)(Addr + Size), EndOfBlock - Addr - Size);
  78. return (uint8_t *)Addr;
  79. }
  80. }
  81. // No pre-allocated free block was large enough. Allocate a new memory region.
  82. // Note that all sections get allocated as read-write. The permissions will
  83. // be updated later based on memory group.
  84. //
  85. // FIXME: It would be useful to define a default allocation size (or add
  86. // it as a constructor parameter) to minimize the number of allocations.
  87. //
  88. // FIXME: Initialize the Near member for each memory group to avoid
  89. // interleaving.
  90. std::error_code ec;
  91. sys::MemoryBlock MB = MMapper.allocateMappedMemory(
  92. Purpose, RequiredSize, &MemGroup.Near,
  93. sys::Memory::MF_READ | sys::Memory::MF_WRITE, ec);
  94. if (ec) {
  95. // FIXME: Add error propagation to the interface.
  96. return nullptr;
  97. }
  98. // Save this address as the basis for our next request
  99. MemGroup.Near = MB;
  100. // Copy the address to all the other groups, if they have not
  101. // been initialized.
  102. if (CodeMem.Near.base() == nullptr)
  103. CodeMem.Near = MB;
  104. if (RODataMem.Near.base() == nullptr)
  105. RODataMem.Near = MB;
  106. if (RWDataMem.Near.base() == nullptr)
  107. RWDataMem.Near = MB;
  108. // Remember that we allocated this memory
  109. MemGroup.AllocatedMem.push_back(MB);
  110. Addr = (uintptr_t)MB.base();
  111. uintptr_t EndOfBlock = Addr + MB.allocatedSize();
  112. // Align the address.
  113. Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1);
  114. // The part of the block we're giving out to the user is now pending
  115. MemGroup.PendingMem.push_back(sys::MemoryBlock((void *)Addr, Size));
  116. // The allocateMappedMemory may allocate much more memory than we need. In
  117. // this case, we store the unused memory as a free memory block.
  118. unsigned FreeSize = EndOfBlock - Addr - Size;
  119. if (FreeSize > 16) {
  120. FreeMemBlock FreeMB;
  121. FreeMB.Free = sys::MemoryBlock((void *)(Addr + Size), FreeSize);
  122. FreeMB.PendingPrefixIndex = (unsigned)-1;
  123. MemGroup.FreeMem.push_back(FreeMB);
  124. }
  125. // Return aligned address
  126. return (uint8_t *)Addr;
  127. }
  128. bool SectionMemoryManager::finalizeMemory(std::string *ErrMsg) {
  129. // FIXME: Should in-progress permissions be reverted if an error occurs?
  130. std::error_code ec;
  131. // Make code memory executable.
  132. ec = applyMemoryGroupPermissions(CodeMem,
  133. sys::Memory::MF_READ | sys::Memory::MF_EXEC);
  134. if (ec) {
  135. if (ErrMsg) {
  136. *ErrMsg = ec.message();
  137. }
  138. return true;
  139. }
  140. // Make read-only data memory read-only.
  141. ec = applyMemoryGroupPermissions(RODataMem, sys::Memory::MF_READ);
  142. if (ec) {
  143. if (ErrMsg) {
  144. *ErrMsg = ec.message();
  145. }
  146. return true;
  147. }
  148. // Read-write data memory already has the correct permissions
  149. // Some platforms with separate data cache and instruction cache require
  150. // explicit cache flush, otherwise JIT code manipulations (like resolved
  151. // relocations) will get to the data cache but not to the instruction cache.
  152. invalidateInstructionCache();
  153. return false;
  154. }
  155. static sys::MemoryBlock trimBlockToPageSize(sys::MemoryBlock M) {
  156. static const size_t PageSize = sys::Process::getPageSizeEstimate();
  157. size_t StartOverlap =
  158. (PageSize - ((uintptr_t)M.base() % PageSize)) % PageSize;
  159. size_t TrimmedSize = M.allocatedSize();
  160. TrimmedSize -= StartOverlap;
  161. TrimmedSize -= TrimmedSize % PageSize;
  162. sys::MemoryBlock Trimmed((void *)((uintptr_t)M.base() + StartOverlap),
  163. TrimmedSize);
  164. assert(((uintptr_t)Trimmed.base() % PageSize) == 0);
  165. assert((Trimmed.allocatedSize() % PageSize) == 0);
  166. assert(M.base() <= Trimmed.base() &&
  167. Trimmed.allocatedSize() <= M.allocatedSize());
  168. return Trimmed;
  169. }
  170. std::error_code
  171. SectionMemoryManager::applyMemoryGroupPermissions(MemoryGroup &MemGroup,
  172. unsigned Permissions) {
  173. for (sys::MemoryBlock &MB : MemGroup.PendingMem)
  174. if (std::error_code EC = MMapper.protectMappedMemory(MB, Permissions))
  175. return EC;
  176. MemGroup.PendingMem.clear();
  177. // Now go through free blocks and trim any of them that don't span the entire
  178. // page because one of the pending blocks may have overlapped it.
  179. for (FreeMemBlock &FreeMB : MemGroup.FreeMem) {
  180. FreeMB.Free = trimBlockToPageSize(FreeMB.Free);
  181. // We cleared the PendingMem list, so all these pointers are now invalid
  182. FreeMB.PendingPrefixIndex = (unsigned)-1;
  183. }
  184. // Remove all blocks which are now empty
  185. erase_if(MemGroup.FreeMem, [](FreeMemBlock &FreeMB) {
  186. return FreeMB.Free.allocatedSize() == 0;
  187. });
  188. return std::error_code();
  189. }
  190. void SectionMemoryManager::invalidateInstructionCache() {
  191. for (sys::MemoryBlock &Block : CodeMem.PendingMem)
  192. sys::Memory::InvalidateInstructionCache(Block.base(),
  193. Block.allocatedSize());
  194. }
  195. SectionMemoryManager::~SectionMemoryManager() {
  196. for (MemoryGroup *Group : {&CodeMem, &RWDataMem, &RODataMem}) {
  197. for (sys::MemoryBlock &Block : Group->AllocatedMem)
  198. MMapper.releaseMappedMemory(Block);
  199. }
  200. }
  201. SectionMemoryManager::MemoryMapper::~MemoryMapper() {}
  202. void SectionMemoryManager::anchor() {}
  203. namespace {
  204. // Trivial implementation of SectionMemoryManager::MemoryMapper that just calls
  205. // into sys::Memory.
  206. class DefaultMMapper final : public SectionMemoryManager::MemoryMapper {
  207. public:
  208. sys::MemoryBlock
  209. allocateMappedMemory(SectionMemoryManager::AllocationPurpose Purpose,
  210. size_t NumBytes, const sys::MemoryBlock *const NearBlock,
  211. unsigned Flags, std::error_code &EC) override {
  212. return sys::Memory::allocateMappedMemory(NumBytes, NearBlock, Flags, EC);
  213. }
  214. std::error_code protectMappedMemory(const sys::MemoryBlock &Block,
  215. unsigned Flags) override {
  216. return sys::Memory::protectMappedMemory(Block, Flags);
  217. }
  218. std::error_code releaseMappedMemory(sys::MemoryBlock &M) override {
  219. return sys::Memory::releaseMappedMemory(M);
  220. }
  221. };
  222. DefaultMMapper DefaultMMapperInstance;
  223. } // namespace
  224. SectionMemoryManager::SectionMemoryManager(MemoryMapper *MM)
  225. : MMapper(MM ? *MM : DefaultMMapperInstance) {}
  226. } // namespace llvm