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 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 
117     sys::MemoryBlock SegMem(SlabRemaining.base(), SegmentSize);
118     SlabRemaining = sys::MemoryBlock((char *)SlabRemaining.base() + SegmentSize,
119                                      SegmentSize);
120 
121     // Zero out the zero-fill memory.
122     memset(static_cast<char *>(SegMem.base()) + Seg.getContentSize(), 0,
123            Seg.getZeroFillSize());
124 
125     // Record the block for this segment.
126     Blocks[KV.first] = std::move(SegMem);
127   }
128   return std::unique_ptr<InProcessMemoryManager::Allocation>(
129       new IPMMAlloc(std::move(Blocks)));
130 }
131 
132 } // end namespace jitlink
133 } // end namespace llvm
134