From 1644fea7a8f989aeda540a369eb8cda845306781 Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Fri, 14 Jun 2019 19:41:21 +0000 Subject: [PATCH] [JITLink] Move JITLinkMemoryManager into its own header. llvm-svn: 363444 --- .../llvm/ExecutionEngine/JITLink/JITLink.h | 73 +----------- .../JITLink/JITLinkMemoryManager.h | 99 +++++++++++++++++ lib/ExecutionEngine/JITLink/CMakeLists.txt | 1 + lib/ExecutionEngine/JITLink/JITLink.cpp | 90 --------------- .../JITLink/JITLinkMemoryManager.cpp | 105 ++++++++++++++++++ 5 files changed, 206 insertions(+), 162 deletions(-) create mode 100644 include/llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h create mode 100644 lib/ExecutionEngine/JITLink/JITLinkMemoryManager.cpp diff --git a/include/llvm/ExecutionEngine/JITLink/JITLink.h b/include/llvm/ExecutionEngine/JITLink/JITLink.h index 01e26a90217..be80d44ccf5 100644 --- a/include/llvm/ExecutionEngine/JITLink/JITLink.h +++ b/include/llvm/ExecutionEngine/JITLink/JITLink.h @@ -13,6 +13,7 @@ #ifndef LLVM_EXECUTIONENGINE_JITLINK_JITLINK_H #define LLVM_EXECUTIONENGINE_JITLINK_JITLINK_H +#include "JITLinkMemoryManager.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/Optional.h" @@ -49,71 +50,6 @@ private: std::string ErrMsg; }; -/// Manages allocations of JIT memory. -/// -/// Instances of this class may be accessed concurrently from multiple threads -/// and their implemetations should include any necessary synchronization. -class JITLinkMemoryManager { -public: - using ProtectionFlags = sys::Memory::ProtectionFlags; - - class SegmentRequest { - public: - SegmentRequest() = default; - SegmentRequest(size_t ContentSize, unsigned ContentAlign, - uint64_t ZeroFillSize, unsigned ZeroFillAlign) - : ContentSize(ContentSize), ZeroFillSize(ZeroFillSize), - ContentAlign(ContentAlign), ZeroFillAlign(ZeroFillAlign) {} - size_t getContentSize() const { return ContentSize; } - unsigned getContentAlignment() const { return ContentAlign; } - uint64_t getZeroFillSize() const { return ZeroFillSize; } - unsigned getZeroFillAlignment() const { return ZeroFillAlign; } - - private: - size_t ContentSize = 0; - uint64_t ZeroFillSize = 0; - unsigned ContentAlign = 0; - unsigned ZeroFillAlign = 0; - }; - - using SegmentsRequestMap = DenseMap; - - /// Represents an allocation created by the memory manager. - /// - /// An allocation object is responsible for allocating and owning jit-linker - /// working and target memory, and for transfering from working to target - /// memory. - /// - class Allocation { - public: - - using FinalizeContinuation = std::function; - - virtual ~Allocation(); - - /// Should return the address of linker working memory for the segment with - /// the given protection flags. - virtual MutableArrayRef getWorkingMemory(ProtectionFlags Seg) = 0; - - /// Should return the final address in the target process where the segment - /// will reside. - virtual JITTargetAddress getTargetMemory(ProtectionFlags Seg) = 0; - - /// Should transfer from working memory to target memory, and release - /// working memory. - virtual void finalizeAsync(FinalizeContinuation OnFinalize) = 0; - - /// Should deallocate target memory. - virtual Error deallocate() = 0; - }; - - virtual ~JITLinkMemoryManager(); - - /// Create an Allocation object. - virtual Expected> - allocate(const SegmentsRequestMap &Request) = 0; -}; - // Forward declare the Atom class. class Atom; @@ -909,13 +845,6 @@ struct PassConfiguration { AtomGraphPassList PostFixupPasses; }; -/// A JITLinkMemoryManager that allocates in-process memory. -class InProcessMemoryManager : public JITLinkMemoryManager { -public: - Expected> - allocate(const SegmentsRequestMap &Request) override; -}; - /// A map of symbol names to resolved addresses. using AsyncLookupResult = DenseMap; diff --git a/include/llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h b/include/llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h new file mode 100644 index 00000000000..9d0b37fe4a4 --- /dev/null +++ b/include/llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h @@ -0,0 +1,99 @@ +//===-- JITLinkMemoryManager.h - JITLink mem manager interface --*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Contains the JITLinkMemoryManager interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EXECUTIONENGINE_JITLINK_JITLINKMEMORYMANAGER_H +#define LLVM_EXECUTIONENGINE_JITLINK_JITLINKMEMORYMANAGER_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ExecutionEngine/JITSymbol.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/Memory.h" +#include + +namespace llvm { +namespace jitlink { + +/// Manages allocations of JIT memory. +/// +/// Instances of this class may be accessed concurrently from multiple threads +/// and their implemetations should include any necessary synchronization. +class JITLinkMemoryManager { +public: + using ProtectionFlags = sys::Memory::ProtectionFlags; + + class SegmentRequest { + public: + SegmentRequest() = default; + SegmentRequest(size_t ContentSize, unsigned ContentAlign, + uint64_t ZeroFillSize, unsigned ZeroFillAlign) + : ContentSize(ContentSize), ZeroFillSize(ZeroFillSize), + ContentAlign(ContentAlign), ZeroFillAlign(ZeroFillAlign) {} + size_t getContentSize() const { return ContentSize; } + unsigned getContentAlignment() const { return ContentAlign; } + uint64_t getZeroFillSize() const { return ZeroFillSize; } + unsigned getZeroFillAlignment() const { return ZeroFillAlign; } + + private: + size_t ContentSize = 0; + uint64_t ZeroFillSize = 0; + unsigned ContentAlign = 0; + unsigned ZeroFillAlign = 0; + }; + + using SegmentsRequestMap = DenseMap; + + /// Represents an allocation created by the memory manager. + /// + /// An allocation object is responsible for allocating and owning jit-linker + /// working and target memory, and for transfering from working to target + /// memory. + /// + class Allocation { + public: + using FinalizeContinuation = std::function; + + virtual ~Allocation(); + + /// Should return the address of linker working memory for the segment with + /// the given protection flags. + virtual MutableArrayRef getWorkingMemory(ProtectionFlags Seg) = 0; + + /// Should return the final address in the target process where the segment + /// will reside. + virtual JITTargetAddress getTargetMemory(ProtectionFlags Seg) = 0; + + /// Should transfer from working memory to target memory, and release + /// working memory. + virtual void finalizeAsync(FinalizeContinuation OnFinalize) = 0; + + /// Should deallocate target memory. + virtual Error deallocate() = 0; + }; + + virtual ~JITLinkMemoryManager(); + + /// Create an Allocation object. + virtual Expected> + allocate(const SegmentsRequestMap &Request) = 0; +}; + +/// A JITLinkMemoryManager that allocates in-process memory. +class InProcessMemoryManager : public JITLinkMemoryManager { +public: + Expected> + allocate(const SegmentsRequestMap &Request) override; +}; + +} // end namespace jitlink +} // end namespace llvm + +#endif // LLVM_EXECUTIONENGINE_JITLINK_JITLINK_H diff --git a/lib/ExecutionEngine/JITLink/CMakeLists.txt b/lib/ExecutionEngine/JITLink/CMakeLists.txt index 00fe8b07122..e81648311cf 100644 --- a/lib/ExecutionEngine/JITLink/CMakeLists.txt +++ b/lib/ExecutionEngine/JITLink/CMakeLists.txt @@ -1,6 +1,7 @@ add_llvm_library(LLVMJITLink JITLink.cpp JITLinkGeneric.cpp + JITLinkMemoryManager.cpp EHFrameSupport.cpp MachO.cpp MachO_x86_64.cpp diff --git a/lib/ExecutionEngine/JITLink/JITLink.cpp b/lib/ExecutionEngine/JITLink/JITLink.cpp index 16ef4c603ce..9d0a7459dc0 100644 --- a/lib/ExecutionEngine/JITLink/JITLink.cpp +++ b/lib/ExecutionEngine/JITLink/JITLink.cpp @@ -14,7 +14,6 @@ #include "llvm/Support/Format.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Process.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; @@ -57,10 +56,6 @@ std::error_code JITLinkError::convertToErrorCode() const { return std::error_code(GenericJITLinkError, *JITLinkerErrorCategory); } -JITLinkMemoryManager::~JITLinkMemoryManager() = default; - -JITLinkMemoryManager::Allocation::~Allocation() = default; - const StringRef getGenericEdgeKindName(Edge::Kind K) { switch (K) { case Edge::Invalid: @@ -142,91 +137,6 @@ void AtomGraph::dump(raw_ostream &OS, << "\n"; } -Expected> -InProcessMemoryManager::allocate(const SegmentsRequestMap &Request) { - - using AllocationMap = DenseMap; - - // Local class for allocation. - class IPMMAlloc : public Allocation { - public: - IPMMAlloc(AllocationMap SegBlocks) : SegBlocks(std::move(SegBlocks)) {} - MutableArrayRef getWorkingMemory(ProtectionFlags Seg) override { - assert(SegBlocks.count(Seg) && "No allocation for segment"); - return {static_cast(SegBlocks[Seg].base()), - SegBlocks[Seg].allocatedSize()}; - } - JITTargetAddress getTargetMemory(ProtectionFlags Seg) override { - assert(SegBlocks.count(Seg) && "No allocation for segment"); - return reinterpret_cast(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::MF_READ | - sys::Memory::MF_WRITE); - - for (auto &KV : Request) { - auto &Seg = KV.second; - - if (Seg.getContentAlignment() > sys::Process::getPageSizeEstimate()) - return make_error("Cannot request higher than page " - "alignment", - inconvertibleErrorCode()); - - if (sys::Process::getPageSizeEstimate() % Seg.getContentAlignment() != 0) - return make_error("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(SegMem.base()) + ZeroFillStart, 0, - Seg.getZeroFillSize()); - - // Record the block for this segment. - Blocks[KV.first] = std::move(SegMem); - } - return std::unique_ptr( - new IPMMAlloc(std::move(Blocks))); -} - JITLinkContext::~JITLinkContext() {} bool JITLinkContext::shouldAddDefaultTargetPasses(const Triple &TT) const { diff --git a/lib/ExecutionEngine/JITLink/JITLinkMemoryManager.cpp b/lib/ExecutionEngine/JITLink/JITLinkMemoryManager.cpp new file mode 100644 index 00000000000..267307cfde0 --- /dev/null +++ b/lib/ExecutionEngine/JITLink/JITLinkMemoryManager.cpp @@ -0,0 +1,105 @@ +//===--- 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> +InProcessMemoryManager::allocate(const SegmentsRequestMap &Request) { + + using AllocationMap = DenseMap; + + // Local class for allocation. + class IPMMAlloc : public Allocation { + public: + IPMMAlloc(AllocationMap SegBlocks) : SegBlocks(std::move(SegBlocks)) {} + MutableArrayRef getWorkingMemory(ProtectionFlags Seg) override { + assert(SegBlocks.count(Seg) && "No allocation for segment"); + return {static_cast(SegBlocks[Seg].base()), + SegBlocks[Seg].allocatedSize()}; + } + JITTargetAddress getTargetMemory(ProtectionFlags Seg) override { + assert(SegBlocks.count(Seg) && "No allocation for segment"); + return reinterpret_cast(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::MF_READ | + sys::Memory::MF_WRITE); + + for (auto &KV : Request) { + auto &Seg = KV.second; + + if (Seg.getContentAlignment() > sys::Process::getPageSizeEstimate()) + return make_error("Cannot request higher than page " + "alignment", + inconvertibleErrorCode()); + + if (sys::Process::getPageSizeEstimate() % Seg.getContentAlignment() != 0) + return make_error("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(SegMem.base()) + ZeroFillStart, 0, + Seg.getZeroFillSize()); + + // Record the block for this segment. + Blocks[KV.first] = std::move(SegMem); + } + return std::unique_ptr( + new IPMMAlloc(std::move(Blocks))); +} + +} // end namespace jitlink +} // end namespace llvm