diff options
5 files changed, 206 insertions, 162 deletions
diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h b/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h index 01e26a90217..be80d44ccf5 100644 --- a/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h +++ b/llvm/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<unsigned, SegmentRequest>; - - /// 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<void(Error)>; - - virtual ~Allocation(); - - /// Should return the address of linker working memory for the segment with - /// the given protection flags. - virtual MutableArrayRef<char> 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<std::unique_ptr<Allocation>> - 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<std::unique_ptr<Allocation>> - allocate(const SegmentsRequestMap &Request) override; -}; - /// A map of symbol names to resolved addresses. using AsyncLookupResult = DenseMap<StringRef, JITEvaluatedSymbol>; diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h b/llvm/include/llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h new file mode 100644 index 00000000000..9d0b37fe4a4 --- /dev/null +++ b/llvm/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 <cstdint> + +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<unsigned, SegmentRequest>; + + /// 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<void(Error)>; + + virtual ~Allocation(); + + /// Should return the address of linker working memory for the segment with + /// the given protection flags. + virtual MutableArrayRef<char> 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<std::unique_ptr<Allocation>> + allocate(const SegmentsRequestMap &Request) = 0; +}; + +/// A JITLinkMemoryManager that allocates in-process memory. +class InProcessMemoryManager : public JITLinkMemoryManager { +public: + Expected<std::unique_ptr<Allocation>> + allocate(const SegmentsRequestMap &Request) override; +}; + +} // end namespace jitlink +} // end namespace llvm + +#endif // LLVM_EXECUTIONENGINE_JITLINK_JITLINK_H diff --git a/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt b/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt index 00fe8b07122..e81648311cf 100644 --- a/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt +++ b/llvm/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/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp b/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp index 16ef4c603ce..9d0a7459dc0 100644 --- a/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp +++ b/llvm/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<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))); -} - JITLinkContext::~JITLinkContext() {} bool JITLinkContext::shouldAddDefaultTargetPasses(const Triple &TT) const { diff --git a/llvm/lib/ExecutionEngine/JITLink/JITLinkMemoryManager.cpp b/llvm/lib/ExecutionEngine/JITLink/JITLinkMemoryManager.cpp new file mode 100644 index 00000000000..267307cfde0 --- /dev/null +++ b/llvm/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<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 |

