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