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