134 lines
4.8 KiB
C++
134 lines
4.8 KiB
C++
//===--- 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 JITLinkDylib *JD,
|
|
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 pointerToJITTargetAddress(SegBlocks[Seg].base());
|
|
}
|
|
void finalizeAsync(FinalizeContinuation OnFinalize) override {
|
|
OnFinalize(applyProtections());
|
|
}
|
|
Error deallocate() override {
|
|
if (SegBlocks.empty())
|
|
return Error::success();
|
|
void *SlabStart = SegBlocks.begin()->second.base();
|
|
char *SlabEnd = (char *)SlabStart;
|
|
for (auto &KV : SegBlocks) {
|
|
SlabStart = std::min(SlabStart, KV.second.base());
|
|
SlabEnd = std::max(SlabEnd, (char *)(KV.second.base()) +
|
|
KV.second.allocatedSize());
|
|
}
|
|
size_t SlabSize = SlabEnd - (char *)SlabStart;
|
|
assert((SlabSize % sys::Process::getPageSizeEstimate()) == 0 &&
|
|
"Slab size is not a multiple of page size");
|
|
sys::MemoryBlock Slab(SlabStart, SlabSize);
|
|
if (auto EC = sys::Memory::releaseMappedMemory(Slab))
|
|
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;
|
|
};
|
|
|
|
if (!isPowerOf2_64((uint64_t)sys::Process::getPageSizeEstimate()))
|
|
return make_error<StringError>("Page size is not a power of 2",
|
|
inconvertibleErrorCode());
|
|
|
|
AllocationMap Blocks;
|
|
const sys::Memory::ProtectionFlags ReadWrite =
|
|
static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
|
|
sys::Memory::MF_WRITE);
|
|
|
|
// Compute the total number of pages to allocate.
|
|
size_t TotalSize = 0;
|
|
for (auto &KV : Request) {
|
|
const auto &Seg = KV.second;
|
|
|
|
if (Seg.getAlignment() > sys::Process::getPageSizeEstimate())
|
|
return make_error<StringError>("Cannot request higher than page "
|
|
"alignment",
|
|
inconvertibleErrorCode());
|
|
|
|
TotalSize = alignTo(TotalSize, sys::Process::getPageSizeEstimate());
|
|
TotalSize += Seg.getContentSize();
|
|
TotalSize += Seg.getZeroFillSize();
|
|
}
|
|
|
|
// Allocate one slab to cover all the segments.
|
|
std::error_code EC;
|
|
auto SlabRemaining =
|
|
sys::Memory::allocateMappedMemory(TotalSize, nullptr, ReadWrite, EC);
|
|
|
|
if (EC)
|
|
return errorCodeToError(EC);
|
|
|
|
// Allocate segment memory from the slab.
|
|
for (auto &KV : Request) {
|
|
|
|
const auto &Seg = KV.second;
|
|
|
|
uint64_t SegmentSize = alignTo(Seg.getContentSize() + Seg.getZeroFillSize(),
|
|
sys::Process::getPageSizeEstimate());
|
|
|
|
sys::MemoryBlock SegMem(SlabRemaining.base(), SegmentSize);
|
|
SlabRemaining = sys::MemoryBlock((char *)SlabRemaining.base() + SegmentSize,
|
|
SegmentSize);
|
|
|
|
// Zero out the zero-fill memory.
|
|
memset(static_cast<char *>(SegMem.base()) + Seg.getContentSize(), 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
|