xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/JITLinkMemoryManager.cpp (revision cd0d51baaa4509a1db83251a601d34404d20c990)
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
106