|  | //===--- JITLinkMemoryManager.cpp - JITLinkMemoryManager implementation ---===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h" | 
|  | #include "llvm/Support/Process.h" | 
|  |  | 
|  | namespace llvm { | 
|  | namespace jitlink { | 
|  |  | 
|  | JITLinkMemoryManager::~JITLinkMemoryManager() = default; | 
|  | JITLinkMemoryManager::Allocation::~Allocation() = default; | 
|  |  | 
|  | Expected<std::unique_ptr<JITLinkMemoryManager::Allocation>> | 
|  | InProcessMemoryManager::allocate(const SegmentsRequestMap &Request) { | 
|  |  | 
|  | using AllocationMap = DenseMap<unsigned, sys::MemoryBlock>; | 
|  |  | 
|  | // Local class for allocation. | 
|  | class IPMMAlloc : public Allocation { | 
|  | public: | 
|  | IPMMAlloc(AllocationMap SegBlocks) : SegBlocks(std::move(SegBlocks)) {} | 
|  | MutableArrayRef<char> getWorkingMemory(ProtectionFlags Seg) override { | 
|  | assert(SegBlocks.count(Seg) && "No allocation for segment"); | 
|  | return {static_cast<char *>(SegBlocks[Seg].base()), | 
|  | SegBlocks[Seg].allocatedSize()}; | 
|  | } | 
|  | JITTargetAddress getTargetMemory(ProtectionFlags Seg) override { | 
|  | assert(SegBlocks.count(Seg) && "No allocation for segment"); | 
|  | return reinterpret_cast<JITTargetAddress>(SegBlocks[Seg].base()); | 
|  | } | 
|  | void finalizeAsync(FinalizeContinuation OnFinalize) override { | 
|  | OnFinalize(applyProtections()); | 
|  | } | 
|  | Error deallocate() override { | 
|  | for (auto &KV : SegBlocks) | 
|  | if (auto EC = sys::Memory::releaseMappedMemory(KV.second)) | 
|  | return errorCodeToError(EC); | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | private: | 
|  | Error applyProtections() { | 
|  | for (auto &KV : SegBlocks) { | 
|  | auto &Prot = KV.first; | 
|  | auto &Block = KV.second; | 
|  | if (auto EC = sys::Memory::protectMappedMemory(Block, Prot)) | 
|  | return errorCodeToError(EC); | 
|  | if (Prot & sys::Memory::MF_EXEC) | 
|  | sys::Memory::InvalidateInstructionCache(Block.base(), | 
|  | Block.allocatedSize()); | 
|  | } | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | AllocationMap SegBlocks; | 
|  | }; | 
|  |  | 
|  | AllocationMap Blocks; | 
|  | const sys::Memory::ProtectionFlags ReadWrite = | 
|  | static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ | | 
|  | sys::Memory::MF_WRITE); | 
|  |  | 
|  | for (auto &KV : Request) { | 
|  | auto &Seg = KV.second; | 
|  |  | 
|  | if (Seg.getContentAlignment() > sys::Process::getPageSizeEstimate()) | 
|  | return make_error<StringError>("Cannot request higher than page " | 
|  | "alignment", | 
|  | inconvertibleErrorCode()); | 
|  |  | 
|  | if (sys::Process::getPageSizeEstimate() % Seg.getContentAlignment() != 0) | 
|  | return make_error<StringError>("Page size is not a multiple of " | 
|  | "alignment", | 
|  | inconvertibleErrorCode()); | 
|  |  | 
|  | uint64_t ZeroFillStart = | 
|  | alignTo(Seg.getContentSize(), Seg.getZeroFillAlignment()); | 
|  | uint64_t SegmentSize = ZeroFillStart + Seg.getZeroFillSize(); | 
|  |  | 
|  | std::error_code EC; | 
|  | auto SegMem = | 
|  | sys::Memory::allocateMappedMemory(SegmentSize, nullptr, ReadWrite, EC); | 
|  |  | 
|  | if (EC) | 
|  | return errorCodeToError(EC); | 
|  |  | 
|  | // Zero out the zero-fill memory. | 
|  | memset(static_cast<char *>(SegMem.base()) + ZeroFillStart, 0, | 
|  | Seg.getZeroFillSize()); | 
|  |  | 
|  | // Record the block for this segment. | 
|  | Blocks[KV.first] = std::move(SegMem); | 
|  | } | 
|  | return std::unique_ptr<InProcessMemoryManager::Allocation>( | 
|  | new IPMMAlloc(std::move(Blocks))); | 
|  | } | 
|  |  | 
|  | } // end namespace jitlink | 
|  | } // end namespace llvm |