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>>
allocate(const SegmentsRequestMap & Request)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 if (SegBlocks.empty())
42 return Error::success();
43 void *SlabStart = SegBlocks.begin()->second.base();
44 char *SlabEnd = (char *)SlabStart;
45 for (auto &KV : SegBlocks) {
46 SlabStart = std::min(SlabStart, KV.second.base());
47 SlabEnd = std::max(SlabEnd, (char *)(KV.second.base()) +
48 KV.second.allocatedSize());
49 }
50 size_t SlabSize = SlabEnd - (char *)SlabStart;
51 assert((SlabSize % sys::Process::getPageSizeEstimate()) == 0 &&
52 "Slab size is not a multiple of page size");
53 sys::MemoryBlock Slab(SlabStart, SlabSize);
54 if (auto EC = sys::Memory::releaseMappedMemory(Slab))
55 return errorCodeToError(EC);
56 return Error::success();
57 }
58
59 private:
60 Error applyProtections() {
61 for (auto &KV : SegBlocks) {
62 auto &Prot = KV.first;
63 auto &Block = KV.second;
64 if (auto EC = sys::Memory::protectMappedMemory(Block, Prot))
65 return errorCodeToError(EC);
66 if (Prot & sys::Memory::MF_EXEC)
67 sys::Memory::InvalidateInstructionCache(Block.base(),
68 Block.allocatedSize());
69 }
70 return Error::success();
71 }
72
73 AllocationMap SegBlocks;
74 };
75
76 if (!isPowerOf2_64((uint64_t)sys::Process::getPageSizeEstimate()))
77 return make_error<StringError>("Page size is not a power of 2",
78 inconvertibleErrorCode());
79
80 AllocationMap Blocks;
81 const sys::Memory::ProtectionFlags ReadWrite =
82 static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
83 sys::Memory::MF_WRITE);
84
85 // Compute the total number of pages to allocate.
86 size_t TotalSize = 0;
87 for (auto &KV : Request) {
88 const auto &Seg = KV.second;
89
90 if (Seg.getAlignment() > sys::Process::getPageSizeEstimate())
91 return make_error<StringError>("Cannot request higher than page "
92 "alignment",
93 inconvertibleErrorCode());
94
95 TotalSize = alignTo(TotalSize, sys::Process::getPageSizeEstimate());
96 TotalSize += Seg.getContentSize();
97 TotalSize += Seg.getZeroFillSize();
98 }
99
100 // Allocate one slab to cover all the segments.
101 std::error_code EC;
102 auto SlabRemaining =
103 sys::Memory::allocateMappedMemory(TotalSize, nullptr, ReadWrite, EC);
104
105 if (EC)
106 return errorCodeToError(EC);
107
108 // Allocate segment memory from the slab.
109 for (auto &KV : Request) {
110
111 const auto &Seg = KV.second;
112
113 uint64_t SegmentSize = alignTo(Seg.getContentSize() + Seg.getZeroFillSize(),
114 sys::Process::getPageSizeEstimate());
115
116 sys::MemoryBlock SegMem(SlabRemaining.base(), SegmentSize);
117 SlabRemaining = sys::MemoryBlock((char *)SlabRemaining.base() + SegmentSize,
118 SegmentSize);
119
120 // Zero out the zero-fill memory.
121 memset(static_cast<char *>(SegMem.base()) + Seg.getContentSize(), 0,
122 Seg.getZeroFillSize());
123
124 // Record the block for this segment.
125 Blocks[KV.first] = std::move(SegMem);
126 }
127 return std::unique_ptr<InProcessMemoryManager::Allocation>(
128 new IPMMAlloc(std::move(Blocks)));
129 }
130
131 } // end namespace jitlink
132 } // end namespace llvm
133