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