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