mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 11:13:28 +01:00
[JITLink] Move JITLinkMemoryManager into its own header.
llvm-svn: 363444
This commit is contained in:
parent
0d0cbbbdf4
commit
1644fea7a8
@ -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>;
|
||||
|
||||
|
99
include/llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h
Normal file
99
include/llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h
Normal 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
|
@ -1,6 +1,7 @@
|
||||
add_llvm_library(LLVMJITLink
|
||||
JITLink.cpp
|
||||
JITLinkGeneric.cpp
|
||||
JITLinkMemoryManager.cpp
|
||||
EHFrameSupport.cpp
|
||||
MachO.cpp
|
||||
MachO_x86_64.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 {
|
||||
|
105
lib/ExecutionEngine/JITLink/JITLinkMemoryManager.cpp
Normal file
105
lib/ExecutionEngine/JITLink/JITLinkMemoryManager.cpp
Normal 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
|
Loading…
Reference in New Issue
Block a user