[JITLink] Move JITLinkMemoryManager into its own header.

llvm-svn: 363444
This commit is contained in:
Lang Hames 2019-06-14 19:41:21 +00:00
parent 0784e01a98
commit 1b091540d2
5 changed files with 206 additions and 162 deletions

View File

@ -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>;

View File

@ -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

View File

@ -1,6 +1,7 @@
add_llvm_library(LLVMJITLink
JITLink.cpp
JITLinkGeneric.cpp
JITLinkMemoryManager.cpp
EHFrameSupport.cpp
MachO.cpp
MachO_x86_64.cpp

View File

@ -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 {

View File

@ -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