147
|
1 //===--- JITLinkMemoryManager.cpp - JITLinkMemoryManager implementation ---===//
|
|
2 //
|
|
3 // The LLVM Compiler Infrastructure
|
|
4 //
|
|
5 // This file is distributed under the University of Illinois Open Source
|
|
6 // License. See LICENSE.TXT for details.
|
|
7 //
|
|
8 //===----------------------------------------------------------------------===//
|
|
9
|
|
10 #include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
|
|
11 #include "llvm/Support/Process.h"
|
|
12
|
|
13 namespace llvm {
|
|
14 namespace jitlink {
|
|
15
|
|
16 JITLinkMemoryManager::~JITLinkMemoryManager() = default;
|
|
17 JITLinkMemoryManager::Allocation::~Allocation() = default;
|
|
18
|
|
19 Expected<std::unique_ptr<JITLinkMemoryManager::Allocation>>
|
|
20 InProcessMemoryManager::allocate(const SegmentsRequestMap &Request) {
|
|
21
|
|
22 using AllocationMap = DenseMap<unsigned, sys::MemoryBlock>;
|
|
23
|
|
24 // Local class for allocation.
|
|
25 class IPMMAlloc : public Allocation {
|
|
26 public:
|
|
27 IPMMAlloc(AllocationMap SegBlocks) : SegBlocks(std::move(SegBlocks)) {}
|
|
28 MutableArrayRef<char> getWorkingMemory(ProtectionFlags Seg) override {
|
|
29 assert(SegBlocks.count(Seg) && "No allocation for segment");
|
|
30 return {static_cast<char *>(SegBlocks[Seg].base()),
|
|
31 SegBlocks[Seg].allocatedSize()};
|
|
32 }
|
|
33 JITTargetAddress getTargetMemory(ProtectionFlags Seg) override {
|
|
34 assert(SegBlocks.count(Seg) && "No allocation for segment");
|
|
35 return reinterpret_cast<JITTargetAddress>(SegBlocks[Seg].base());
|
|
36 }
|
|
37 void finalizeAsync(FinalizeContinuation OnFinalize) override {
|
|
38 OnFinalize(applyProtections());
|
|
39 }
|
|
40 Error deallocate() override {
|
|
41 for (auto &KV : SegBlocks)
|
|
42 if (auto EC = sys::Memory::releaseMappedMemory(KV.second))
|
|
43 return errorCodeToError(EC);
|
|
44 return Error::success();
|
|
45 }
|
|
46
|
|
47 private:
|
|
48 Error applyProtections() {
|
|
49 for (auto &KV : SegBlocks) {
|
|
50 auto &Prot = KV.first;
|
|
51 auto &Block = KV.second;
|
|
52 if (auto EC = sys::Memory::protectMappedMemory(Block, Prot))
|
|
53 return errorCodeToError(EC);
|
|
54 if (Prot & sys::Memory::MF_EXEC)
|
|
55 sys::Memory::InvalidateInstructionCache(Block.base(),
|
|
56 Block.allocatedSize());
|
|
57 }
|
|
58 return Error::success();
|
|
59 }
|
|
60
|
|
61 AllocationMap SegBlocks;
|
|
62 };
|
|
63
|
|
64 AllocationMap Blocks;
|
|
65 const sys::Memory::ProtectionFlags ReadWrite =
|
|
66 static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
|
|
67 sys::Memory::MF_WRITE);
|
|
68
|
|
69 for (auto &KV : Request) {
|
|
70 auto &Seg = KV.second;
|
|
71
|
|
72 if (Seg.getContentAlignment() > sys::Process::getPageSizeEstimate())
|
|
73 return make_error<StringError>("Cannot request higher than page "
|
|
74 "alignment",
|
|
75 inconvertibleErrorCode());
|
|
76
|
|
77 if (sys::Process::getPageSizeEstimate() % Seg.getContentAlignment() != 0)
|
|
78 return make_error<StringError>("Page size is not a multiple of "
|
|
79 "alignment",
|
|
80 inconvertibleErrorCode());
|
|
81
|
|
82 uint64_t ZeroFillStart =
|
|
83 alignTo(Seg.getContentSize(), Seg.getZeroFillAlignment());
|
|
84 uint64_t SegmentSize = ZeroFillStart + Seg.getZeroFillSize();
|
|
85
|
|
86 std::error_code EC;
|
|
87 auto SegMem =
|
|
88 sys::Memory::allocateMappedMemory(SegmentSize, nullptr, ReadWrite, EC);
|
|
89
|
|
90 if (EC)
|
|
91 return errorCodeToError(EC);
|
|
92
|
|
93 // Zero out the zero-fill memory.
|
|
94 memset(static_cast<char *>(SegMem.base()) + ZeroFillStart, 0,
|
|
95 Seg.getZeroFillSize());
|
|
96
|
|
97 // Record the block for this segment.
|
|
98 Blocks[KV.first] = std::move(SegMem);
|
|
99 }
|
|
100 return std::unique_ptr<InProcessMemoryManager::Allocation>(
|
|
101 new IPMMAlloc(std::move(Blocks)));
|
|
102 }
|
|
103
|
|
104 } // end namespace jitlink
|
|
105 } // end namespace llvm
|