10b57cec5SDimitry Andric //===--- JITLinkMemoryManager.cpp - JITLinkMemoryManager implementation ---===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric //                     The LLVM Compiler Infrastructure
40b57cec5SDimitry Andric //
50b57cec5SDimitry Andric // This file is distributed under the University of Illinois Open Source
60b57cec5SDimitry Andric // License. See LICENSE.TXT for details.
70b57cec5SDimitry Andric //
80b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
90b57cec5SDimitry Andric 
100b57cec5SDimitry Andric #include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
110b57cec5SDimitry Andric #include "llvm/Support/Process.h"
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric namespace llvm {
140b57cec5SDimitry Andric namespace jitlink {
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric JITLinkMemoryManager::~JITLinkMemoryManager() = default;
170b57cec5SDimitry Andric JITLinkMemoryManager::Allocation::~Allocation() = default;
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric Expected<std::unique_ptr<JITLinkMemoryManager::Allocation>>
200b57cec5SDimitry Andric InProcessMemoryManager::allocate(const SegmentsRequestMap &Request) {
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric   using AllocationMap = DenseMap<unsigned, sys::MemoryBlock>;
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric   // Local class for allocation.
250b57cec5SDimitry Andric   class IPMMAlloc : public Allocation {
260b57cec5SDimitry Andric   public:
270b57cec5SDimitry Andric     IPMMAlloc(AllocationMap SegBlocks) : SegBlocks(std::move(SegBlocks)) {}
280b57cec5SDimitry Andric     MutableArrayRef<char> getWorkingMemory(ProtectionFlags Seg) override {
290b57cec5SDimitry Andric       assert(SegBlocks.count(Seg) && "No allocation for segment");
300b57cec5SDimitry Andric       return {static_cast<char *>(SegBlocks[Seg].base()),
310b57cec5SDimitry Andric               SegBlocks[Seg].allocatedSize()};
320b57cec5SDimitry Andric     }
330b57cec5SDimitry Andric     JITTargetAddress getTargetMemory(ProtectionFlags Seg) override {
340b57cec5SDimitry Andric       assert(SegBlocks.count(Seg) && "No allocation for segment");
350b57cec5SDimitry Andric       return reinterpret_cast<JITTargetAddress>(SegBlocks[Seg].base());
360b57cec5SDimitry Andric     }
370b57cec5SDimitry Andric     void finalizeAsync(FinalizeContinuation OnFinalize) override {
380b57cec5SDimitry Andric       OnFinalize(applyProtections());
390b57cec5SDimitry Andric     }
400b57cec5SDimitry Andric     Error deallocate() override {
418bcb0991SDimitry Andric       if (SegBlocks.empty())
428bcb0991SDimitry Andric         return Error::success();
438bcb0991SDimitry Andric       void *SlabStart = SegBlocks.begin()->second.base();
448bcb0991SDimitry Andric       char *SlabEnd = (char *)SlabStart;
458bcb0991SDimitry Andric       for (auto &KV : SegBlocks) {
468bcb0991SDimitry Andric         SlabStart = std::min(SlabStart, KV.second.base());
478bcb0991SDimitry Andric         SlabEnd = std::max(SlabEnd, (char *)(KV.second.base()) +
488bcb0991SDimitry Andric                                         KV.second.allocatedSize());
498bcb0991SDimitry Andric       }
508bcb0991SDimitry Andric       size_t SlabSize = SlabEnd - (char *)SlabStart;
518bcb0991SDimitry Andric       assert((SlabSize % sys::Process::getPageSizeEstimate()) == 0 &&
528bcb0991SDimitry Andric              "Slab size is not a multiple of page size");
538bcb0991SDimitry Andric       sys::MemoryBlock Slab(SlabStart, SlabSize);
548bcb0991SDimitry Andric       if (auto EC = sys::Memory::releaseMappedMemory(Slab))
550b57cec5SDimitry Andric         return errorCodeToError(EC);
560b57cec5SDimitry Andric       return Error::success();
570b57cec5SDimitry Andric     }
580b57cec5SDimitry Andric 
590b57cec5SDimitry Andric   private:
600b57cec5SDimitry Andric     Error applyProtections() {
610b57cec5SDimitry Andric       for (auto &KV : SegBlocks) {
620b57cec5SDimitry Andric         auto &Prot = KV.first;
630b57cec5SDimitry Andric         auto &Block = KV.second;
640b57cec5SDimitry Andric         if (auto EC = sys::Memory::protectMappedMemory(Block, Prot))
650b57cec5SDimitry Andric           return errorCodeToError(EC);
660b57cec5SDimitry Andric         if (Prot & sys::Memory::MF_EXEC)
670b57cec5SDimitry Andric           sys::Memory::InvalidateInstructionCache(Block.base(),
680b57cec5SDimitry Andric                                                   Block.allocatedSize());
690b57cec5SDimitry Andric       }
700b57cec5SDimitry Andric       return Error::success();
710b57cec5SDimitry Andric     }
720b57cec5SDimitry Andric 
730b57cec5SDimitry Andric     AllocationMap SegBlocks;
740b57cec5SDimitry Andric   };
750b57cec5SDimitry Andric 
768bcb0991SDimitry Andric   if (!isPowerOf2_64((uint64_t)sys::Process::getPageSizeEstimate()))
778bcb0991SDimitry Andric     return make_error<StringError>("Page size is not a power of 2",
788bcb0991SDimitry Andric                                    inconvertibleErrorCode());
798bcb0991SDimitry Andric 
800b57cec5SDimitry Andric   AllocationMap Blocks;
810b57cec5SDimitry Andric   const sys::Memory::ProtectionFlags ReadWrite =
820b57cec5SDimitry Andric       static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
830b57cec5SDimitry Andric                                                 sys::Memory::MF_WRITE);
840b57cec5SDimitry Andric 
858bcb0991SDimitry Andric   // Compute the total number of pages to allocate.
868bcb0991SDimitry Andric   size_t TotalSize = 0;
870b57cec5SDimitry Andric   for (auto &KV : Request) {
888bcb0991SDimitry Andric     const auto &Seg = KV.second;
890b57cec5SDimitry Andric 
908bcb0991SDimitry Andric     if (Seg.getAlignment() > sys::Process::getPageSizeEstimate())
910b57cec5SDimitry Andric       return make_error<StringError>("Cannot request higher than page "
920b57cec5SDimitry Andric                                      "alignment",
930b57cec5SDimitry Andric                                      inconvertibleErrorCode());
940b57cec5SDimitry Andric 
958bcb0991SDimitry Andric     TotalSize = alignTo(TotalSize, sys::Process::getPageSizeEstimate());
968bcb0991SDimitry Andric     TotalSize += Seg.getContentSize();
978bcb0991SDimitry Andric     TotalSize += Seg.getZeroFillSize();
988bcb0991SDimitry Andric   }
990b57cec5SDimitry Andric 
1008bcb0991SDimitry Andric   // Allocate one slab to cover all the segments.
1010b57cec5SDimitry Andric   std::error_code EC;
1028bcb0991SDimitry Andric   auto SlabRemaining =
1038bcb0991SDimitry Andric       sys::Memory::allocateMappedMemory(TotalSize, nullptr, ReadWrite, EC);
1040b57cec5SDimitry Andric 
1050b57cec5SDimitry Andric   if (EC)
1060b57cec5SDimitry Andric     return errorCodeToError(EC);
1070b57cec5SDimitry Andric 
1088bcb0991SDimitry Andric   // Allocate segment memory from the slab.
1098bcb0991SDimitry Andric   for (auto &KV : Request) {
1108bcb0991SDimitry Andric 
1118bcb0991SDimitry Andric     const auto &Seg = KV.second;
1128bcb0991SDimitry Andric 
1138bcb0991SDimitry Andric     uint64_t SegmentSize = alignTo(Seg.getContentSize() + Seg.getZeroFillSize(),
1148bcb0991SDimitry Andric                                    sys::Process::getPageSizeEstimate());
1158bcb0991SDimitry Andric 
1168bcb0991SDimitry Andric     sys::MemoryBlock SegMem(SlabRemaining.base(), SegmentSize);
1178bcb0991SDimitry Andric     SlabRemaining = sys::MemoryBlock((char *)SlabRemaining.base() + SegmentSize,
1188bcb0991SDimitry Andric                                      SegmentSize);
1198bcb0991SDimitry Andric 
1200b57cec5SDimitry Andric     // Zero out the zero-fill memory.
1218bcb0991SDimitry Andric     memset(static_cast<char *>(SegMem.base()) + Seg.getContentSize(), 0,
1220b57cec5SDimitry Andric            Seg.getZeroFillSize());
1230b57cec5SDimitry Andric 
1240b57cec5SDimitry Andric     // Record the block for this segment.
1250b57cec5SDimitry Andric     Blocks[KV.first] = std::move(SegMem);
1260b57cec5SDimitry Andric   }
1270b57cec5SDimitry Andric   return std::unique_ptr<InProcessMemoryManager::Allocation>(
1280b57cec5SDimitry Andric       new IPMMAlloc(std::move(Blocks)));
1290b57cec5SDimitry Andric }
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric } // end namespace jitlink
1320b57cec5SDimitry Andric } // end namespace llvm
133