JITLinkMemoryManager.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. //===--- JITLinkMemoryManager.cpp - JITLinkMemoryManager implementation ---===//
  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. #include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
  10. #include "llvm/Support/Process.h"
  11. namespace llvm {
  12. namespace jitlink {
  13. JITLinkMemoryManager::~JITLinkMemoryManager() = default;
  14. JITLinkMemoryManager::Allocation::~Allocation() = default;
  15. Expected<std::unique_ptr<JITLinkMemoryManager::Allocation>>
  16. InProcessMemoryManager::allocate(const JITLinkDylib *JD,
  17. const SegmentsRequestMap &Request) {
  18. using AllocationMap = DenseMap<unsigned, sys::MemoryBlock>;
  19. // Local class for allocation.
  20. class IPMMAlloc : public Allocation {
  21. public:
  22. IPMMAlloc(AllocationMap SegBlocks) : SegBlocks(std::move(SegBlocks)) {}
  23. MutableArrayRef<char> getWorkingMemory(ProtectionFlags Seg) override {
  24. assert(SegBlocks.count(Seg) && "No allocation for segment");
  25. return {static_cast<char *>(SegBlocks[Seg].base()),
  26. SegBlocks[Seg].allocatedSize()};
  27. }
  28. JITTargetAddress getTargetMemory(ProtectionFlags Seg) override {
  29. assert(SegBlocks.count(Seg) && "No allocation for segment");
  30. return pointerToJITTargetAddress(SegBlocks[Seg].base());
  31. }
  32. void finalizeAsync(FinalizeContinuation OnFinalize) override {
  33. OnFinalize(applyProtections());
  34. }
  35. Error deallocate() override {
  36. if (SegBlocks.empty())
  37. return Error::success();
  38. void *SlabStart = SegBlocks.begin()->second.base();
  39. char *SlabEnd = (char *)SlabStart;
  40. for (auto &KV : SegBlocks) {
  41. SlabStart = std::min(SlabStart, KV.second.base());
  42. SlabEnd = std::max(SlabEnd, (char *)(KV.second.base()) +
  43. KV.second.allocatedSize());
  44. }
  45. size_t SlabSize = SlabEnd - (char *)SlabStart;
  46. assert((SlabSize % sys::Process::getPageSizeEstimate()) == 0 &&
  47. "Slab size is not a multiple of page size");
  48. sys::MemoryBlock Slab(SlabStart, SlabSize);
  49. if (auto EC = sys::Memory::releaseMappedMemory(Slab))
  50. return errorCodeToError(EC);
  51. return Error::success();
  52. }
  53. private:
  54. Error applyProtections() {
  55. for (auto &KV : SegBlocks) {
  56. auto &Prot = KV.first;
  57. auto &Block = KV.second;
  58. if (auto EC = sys::Memory::protectMappedMemory(Block, Prot))
  59. return errorCodeToError(EC);
  60. if (Prot & sys::Memory::MF_EXEC)
  61. sys::Memory::InvalidateInstructionCache(Block.base(),
  62. Block.allocatedSize());
  63. }
  64. return Error::success();
  65. }
  66. AllocationMap SegBlocks;
  67. };
  68. if (!isPowerOf2_64((uint64_t)sys::Process::getPageSizeEstimate()))
  69. return make_error<StringError>("Page size is not a power of 2",
  70. inconvertibleErrorCode());
  71. AllocationMap Blocks;
  72. const sys::Memory::ProtectionFlags ReadWrite =
  73. static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
  74. sys::Memory::MF_WRITE);
  75. // Compute the total number of pages to allocate.
  76. size_t TotalSize = 0;
  77. for (auto &KV : Request) {
  78. const auto &Seg = KV.second;
  79. if (Seg.getAlignment() > sys::Process::getPageSizeEstimate())
  80. return make_error<StringError>("Cannot request higher than page "
  81. "alignment",
  82. inconvertibleErrorCode());
  83. TotalSize = alignTo(TotalSize, sys::Process::getPageSizeEstimate());
  84. TotalSize += Seg.getContentSize();
  85. TotalSize += Seg.getZeroFillSize();
  86. }
  87. // Allocate one slab to cover all the segments.
  88. std::error_code EC;
  89. auto SlabRemaining =
  90. sys::Memory::allocateMappedMemory(TotalSize, nullptr, ReadWrite, EC);
  91. if (EC)
  92. return errorCodeToError(EC);
  93. // Allocate segment memory from the slab.
  94. for (auto &KV : Request) {
  95. const auto &Seg = KV.second;
  96. uint64_t SegmentSize = alignTo(Seg.getContentSize() + Seg.getZeroFillSize(),
  97. sys::Process::getPageSizeEstimate());
  98. sys::MemoryBlock SegMem(SlabRemaining.base(), SegmentSize);
  99. SlabRemaining = sys::MemoryBlock((char *)SlabRemaining.base() + SegmentSize,
  100. SegmentSize);
  101. // Zero out the zero-fill memory.
  102. memset(static_cast<char *>(SegMem.base()) + Seg.getContentSize(), 0,
  103. Seg.getZeroFillSize());
  104. // Record the block for this segment.
  105. Blocks[KV.first] = std::move(SegMem);
  106. }
  107. return std::unique_ptr<InProcessMemoryManager::Allocation>(
  108. new IPMMAlloc(std::move(Blocks)));
  109. }
  110. } // end namespace jitlink
  111. } // end namespace llvm