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 for (auto &KV : SegBlocks) 42 if (auto EC = sys::Memory::releaseMappedMemory(KV.second)) 43 return errorCodeToError(EC); 44 return Error::success(); 45 } 46 47 private: 48 Error applyProtections() { 49 for (auto &KV : SegBlocks) { 50 auto &Prot = KV.first; 51 auto &Block = KV.second; 52 if (auto EC = sys::Memory::protectMappedMemory(Block, Prot)) 53 return errorCodeToError(EC); 54 if (Prot & sys::Memory::MF_EXEC) 55 sys::Memory::InvalidateInstructionCache(Block.base(), 56 Block.allocatedSize()); 57 } 58 return Error::success(); 59 } 60 61 AllocationMap SegBlocks; 62 }; 63 64 if (!isPowerOf2_64((uint64_t)sys::Process::getPageSizeEstimate())) 65 return make_error<StringError>("Page size is not a power of 2", 66 inconvertibleErrorCode()); 67 68 AllocationMap Blocks; 69 const sys::Memory::ProtectionFlags ReadWrite = 70 static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ | 71 sys::Memory::MF_WRITE); 72 73 for (auto &KV : Request) { 74 auto &Seg = KV.second; 75 76 if (Seg.getAlignment() > sys::Process::getPageSizeEstimate()) 77 return make_error<StringError>("Cannot request higher than page " 78 "alignment", 79 inconvertibleErrorCode()); 80 81 uint64_t SegmentSize = Seg.getContentSize() + Seg.getZeroFillSize(); 82 83 std::error_code EC; 84 auto SegMem = 85 sys::Memory::allocateMappedMemory(SegmentSize, nullptr, ReadWrite, EC); 86 87 if (EC) 88 return errorCodeToError(EC); 89 90 // Zero out the zero-fill memory. 91 memset(static_cast<char *>(SegMem.base()) + Seg.getContentSize(), 0, 92 Seg.getZeroFillSize()); 93 94 // Record the block for this segment. 95 Blocks[KV.first] = std::move(SegMem); 96 } 97 return std::unique_ptr<InProcessMemoryManager::Allocation>( 98 new IPMMAlloc(std::move(Blocks))); 99 } 100 101 } // end namespace jitlink 102 } // end namespace llvm 103