xref: /llvm-project/llvm/lib/ExecutionEngine/JITLink/JITLinkMemoryManager.cpp (revision 4e920e58e6bc3bf4450b0aae6e225943957de195)
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   if (!isPowerOf2_64((uint64_t)sys::Process::getPageSizeEstimate()))
65     return make_error<StringError>("Page size is not a power of 2",
66                                    inconvertibleErrorCode());
67 
68   AllocationMap Blocks;
69   const sys::Memory::ProtectionFlags ReadWrite =
70       static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
71                                                 sys::Memory::MF_WRITE);
72 
73   for (auto &KV : Request) {
74     auto &Seg = KV.second;
75 
76     if (Seg.getAlignment() > sys::Process::getPageSizeEstimate())
77       return make_error<StringError>("Cannot request higher than page "
78                                      "alignment",
79                                      inconvertibleErrorCode());
80 
81     uint64_t SegmentSize = Seg.getContentSize() + Seg.getZeroFillSize();
82 
83     std::error_code EC;
84     auto SegMem =
85         sys::Memory::allocateMappedMemory(SegmentSize, nullptr, ReadWrite, EC);
86 
87     if (EC)
88       return errorCodeToError(EC);
89 
90     // Zero out the zero-fill memory.
91     memset(static_cast<char *>(SegMem.base()) + Seg.getContentSize(), 0,
92            Seg.getZeroFillSize());
93 
94     // Record the block for this segment.
95     Blocks[KV.first] = std::move(SegMem);
96   }
97   return std::unique_ptr<InProcessMemoryManager::Allocation>(
98       new IPMMAlloc(std::move(Blocks)));
99 }
100 
101 } // end namespace jitlink
102 } // end namespace llvm
103