1ff0cc061SDimitry Andric //===- SectionMemoryManager.cpp - Memory manager for MCJIT/RtDyld *- C++ -*-==//
2ff0cc061SDimitry Andric //
3ff0cc061SDimitry Andric //                     The LLVM Compiler Infrastructure
4ff0cc061SDimitry Andric //
5ff0cc061SDimitry Andric // This file is distributed under the University of Illinois Open Source
6ff0cc061SDimitry Andric // License. See LICENSE.TXT for details.
7ff0cc061SDimitry Andric //
8ff0cc061SDimitry Andric //===----------------------------------------------------------------------===//
9ff0cc061SDimitry Andric //
10ff0cc061SDimitry Andric // This file implements the section-based memory manager used by the MCJIT
11ff0cc061SDimitry Andric // execution engine and RuntimeDyld
12ff0cc061SDimitry Andric //
13ff0cc061SDimitry Andric //===----------------------------------------------------------------------===//
14ff0cc061SDimitry Andric 
15ff0cc061SDimitry Andric #include "llvm/ExecutionEngine/SectionMemoryManager.h"
16db17bf38SDimitry Andric #include "llvm/Config/config.h"
17ff0cc061SDimitry Andric #include "llvm/Support/MathExtras.h"
187d523365SDimitry Andric #include "llvm/Support/Process.h"
19ff0cc061SDimitry Andric 
20ff0cc061SDimitry Andric namespace llvm {
21ff0cc061SDimitry Andric 
allocateDataSection(uintptr_t Size,unsigned Alignment,unsigned SectionID,StringRef SectionName,bool IsReadOnly)22ff0cc061SDimitry Andric uint8_t *SectionMemoryManager::allocateDataSection(uintptr_t Size,
23ff0cc061SDimitry Andric                                                    unsigned Alignment,
24ff0cc061SDimitry Andric                                                    unsigned SectionID,
25ff0cc061SDimitry Andric                                                    StringRef SectionName,
26ff0cc061SDimitry Andric                                                    bool IsReadOnly) {
27ff0cc061SDimitry Andric   if (IsReadOnly)
282cab237bSDimitry Andric     return allocateSection(SectionMemoryManager::AllocationPurpose::ROData,
292cab237bSDimitry Andric                            Size, Alignment);
302cab237bSDimitry Andric   return allocateSection(SectionMemoryManager::AllocationPurpose::RWData, Size,
312cab237bSDimitry Andric                          Alignment);
32ff0cc061SDimitry Andric }
33ff0cc061SDimitry Andric 
allocateCodeSection(uintptr_t Size,unsigned Alignment,unsigned SectionID,StringRef SectionName)34ff0cc061SDimitry Andric uint8_t *SectionMemoryManager::allocateCodeSection(uintptr_t Size,
35ff0cc061SDimitry Andric                                                    unsigned Alignment,
36ff0cc061SDimitry Andric                                                    unsigned SectionID,
37ff0cc061SDimitry Andric                                                    StringRef SectionName) {
382cab237bSDimitry Andric   return allocateSection(SectionMemoryManager::AllocationPurpose::Code, Size,
392cab237bSDimitry Andric                          Alignment);
40ff0cc061SDimitry Andric }
41ff0cc061SDimitry Andric 
allocateSection(SectionMemoryManager::AllocationPurpose Purpose,uintptr_t Size,unsigned Alignment)422cab237bSDimitry Andric uint8_t *SectionMemoryManager::allocateSection(
432cab237bSDimitry Andric     SectionMemoryManager::AllocationPurpose Purpose, uintptr_t Size,
44ff0cc061SDimitry Andric     unsigned Alignment) {
45ff0cc061SDimitry Andric   if (!Alignment)
46ff0cc061SDimitry Andric     Alignment = 16;
47ff0cc061SDimitry Andric 
48ff0cc061SDimitry Andric   assert(!(Alignment & (Alignment - 1)) && "Alignment must be a power of two.");
49ff0cc061SDimitry Andric 
50ff0cc061SDimitry Andric   uintptr_t RequiredSize = Alignment * ((Size + Alignment - 1) / Alignment + 1);
51ff0cc061SDimitry Andric   uintptr_t Addr = 0;
52ff0cc061SDimitry Andric 
532cab237bSDimitry Andric   MemoryGroup &MemGroup = [&]() -> MemoryGroup & {
542cab237bSDimitry Andric     switch (Purpose) {
552cab237bSDimitry Andric     case AllocationPurpose::Code:
562cab237bSDimitry Andric       return CodeMem;
572cab237bSDimitry Andric     case AllocationPurpose::ROData:
582cab237bSDimitry Andric       return RODataMem;
592cab237bSDimitry Andric     case AllocationPurpose::RWData:
602cab237bSDimitry Andric       return RWDataMem;
612cab237bSDimitry Andric     }
622cab237bSDimitry Andric     llvm_unreachable("Unknown SectionMemoryManager::AllocationPurpose");
632cab237bSDimitry Andric   }();
642cab237bSDimitry Andric 
65ff0cc061SDimitry Andric   // Look in the list of free memory regions and use a block there if one
66ff0cc061SDimitry Andric   // is available.
677d523365SDimitry Andric   for (FreeMemBlock &FreeMB : MemGroup.FreeMem) {
687d523365SDimitry Andric     if (FreeMB.Free.size() >= RequiredSize) {
697d523365SDimitry Andric       Addr = (uintptr_t)FreeMB.Free.base();
707d523365SDimitry Andric       uintptr_t EndOfBlock = Addr + FreeMB.Free.size();
71ff0cc061SDimitry Andric       // Align the address.
72ff0cc061SDimitry Andric       Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1);
737d523365SDimitry Andric 
747d523365SDimitry Andric       if (FreeMB.PendingPrefixIndex == (unsigned)-1) {
757d523365SDimitry Andric         // The part of the block we're giving out to the user is now pending
767d523365SDimitry Andric         MemGroup.PendingMem.push_back(sys::MemoryBlock((void *)Addr, Size));
777d523365SDimitry Andric 
787d523365SDimitry Andric         // Remember this pending block, such that future allocations can just
797d523365SDimitry Andric         // modify it rather than creating a new one
807d523365SDimitry Andric         FreeMB.PendingPrefixIndex = MemGroup.PendingMem.size() - 1;
817d523365SDimitry Andric       } else {
822cab237bSDimitry Andric         sys::MemoryBlock &PendingMB =
832cab237bSDimitry Andric             MemGroup.PendingMem[FreeMB.PendingPrefixIndex];
842cab237bSDimitry Andric         PendingMB = sys::MemoryBlock(PendingMB.base(),
852cab237bSDimitry Andric                                      Addr + Size - (uintptr_t)PendingMB.base());
867d523365SDimitry Andric       }
877d523365SDimitry Andric 
887d523365SDimitry Andric       // Remember how much free space is now left in this block
892cab237bSDimitry Andric       FreeMB.Free =
902cab237bSDimitry Andric           sys::MemoryBlock((void *)(Addr + Size), EndOfBlock - Addr - Size);
91ff0cc061SDimitry Andric       return (uint8_t *)Addr;
92ff0cc061SDimitry Andric     }
93ff0cc061SDimitry Andric   }
94ff0cc061SDimitry Andric 
95ff0cc061SDimitry Andric   // No pre-allocated free block was large enough. Allocate a new memory region.
96ff0cc061SDimitry Andric   // Note that all sections get allocated as read-write.  The permissions will
97ff0cc061SDimitry Andric   // be updated later based on memory group.
98ff0cc061SDimitry Andric   //
99ff0cc061SDimitry Andric   // FIXME: It would be useful to define a default allocation size (or add
100ff0cc061SDimitry Andric   // it as a constructor parameter) to minimize the number of allocations.
101ff0cc061SDimitry Andric   //
102ff0cc061SDimitry Andric   // FIXME: Initialize the Near member for each memory group to avoid
103ff0cc061SDimitry Andric   // interleaving.
104ff0cc061SDimitry Andric   std::error_code ec;
1052cab237bSDimitry Andric   sys::MemoryBlock MB = MMapper.allocateMappedMemory(
1062cab237bSDimitry Andric       Purpose, RequiredSize, &MemGroup.Near,
1072cab237bSDimitry Andric       sys::Memory::MF_READ | sys::Memory::MF_WRITE, ec);
108ff0cc061SDimitry Andric   if (ec) {
109ff0cc061SDimitry Andric     // FIXME: Add error propagation to the interface.
110ff0cc061SDimitry Andric     return nullptr;
111ff0cc061SDimitry Andric   }
112ff0cc061SDimitry Andric 
113ff0cc061SDimitry Andric   // Save this address as the basis for our next request
114ff0cc061SDimitry Andric   MemGroup.Near = MB;
115ff0cc061SDimitry Andric 
1167d523365SDimitry Andric   // Remember that we allocated this memory
117ff0cc061SDimitry Andric   MemGroup.AllocatedMem.push_back(MB);
118ff0cc061SDimitry Andric   Addr = (uintptr_t)MB.base();
119ff0cc061SDimitry Andric   uintptr_t EndOfBlock = Addr + MB.size();
120ff0cc061SDimitry Andric 
121ff0cc061SDimitry Andric   // Align the address.
122ff0cc061SDimitry Andric   Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1);
123ff0cc061SDimitry Andric 
1247d523365SDimitry Andric   // The part of the block we're giving out to the user is now pending
1257d523365SDimitry Andric   MemGroup.PendingMem.push_back(sys::MemoryBlock((void *)Addr, Size));
1267d523365SDimitry Andric 
127ff0cc061SDimitry Andric   // The allocateMappedMemory may allocate much more memory than we need. In
128ff0cc061SDimitry Andric   // this case, we store the unused memory as a free memory block.
129ff0cc061SDimitry Andric   unsigned FreeSize = EndOfBlock - Addr - Size;
1307d523365SDimitry Andric   if (FreeSize > 16) {
1317d523365SDimitry Andric     FreeMemBlock FreeMB;
1327d523365SDimitry Andric     FreeMB.Free = sys::MemoryBlock((void *)(Addr + Size), FreeSize);
1337d523365SDimitry Andric     FreeMB.PendingPrefixIndex = (unsigned)-1;
1347d523365SDimitry Andric     MemGroup.FreeMem.push_back(FreeMB);
1357d523365SDimitry Andric   }
136ff0cc061SDimitry Andric 
137ff0cc061SDimitry Andric   // Return aligned address
138ff0cc061SDimitry Andric   return (uint8_t *)Addr;
139ff0cc061SDimitry Andric }
140ff0cc061SDimitry Andric 
finalizeMemory(std::string * ErrMsg)1412cab237bSDimitry Andric bool SectionMemoryManager::finalizeMemory(std::string *ErrMsg) {
142ff0cc061SDimitry Andric   // FIXME: Should in-progress permissions be reverted if an error occurs?
143ff0cc061SDimitry Andric   std::error_code ec;
144ff0cc061SDimitry Andric 
145ff0cc061SDimitry Andric   // Make code memory executable.
146ff0cc061SDimitry Andric   ec = applyMemoryGroupPermissions(CodeMem,
147ff0cc061SDimitry Andric                                    sys::Memory::MF_READ | sys::Memory::MF_EXEC);
148ff0cc061SDimitry Andric   if (ec) {
149ff0cc061SDimitry Andric     if (ErrMsg) {
150ff0cc061SDimitry Andric       *ErrMsg = ec.message();
151ff0cc061SDimitry Andric     }
152ff0cc061SDimitry Andric     return true;
153ff0cc061SDimitry Andric   }
154ff0cc061SDimitry Andric 
155ff0cc061SDimitry Andric   // Make read-only data memory read-only.
156ff0cc061SDimitry Andric   ec = applyMemoryGroupPermissions(RODataMem,
157ff0cc061SDimitry Andric                                    sys::Memory::MF_READ | sys::Memory::MF_EXEC);
158ff0cc061SDimitry Andric   if (ec) {
159ff0cc061SDimitry Andric     if (ErrMsg) {
160ff0cc061SDimitry Andric       *ErrMsg = ec.message();
161ff0cc061SDimitry Andric     }
162ff0cc061SDimitry Andric     return true;
163ff0cc061SDimitry Andric   }
164ff0cc061SDimitry Andric 
165ff0cc061SDimitry Andric   // Read-write data memory already has the correct permissions
166ff0cc061SDimitry Andric 
167ff0cc061SDimitry Andric   // Some platforms with separate data cache and instruction cache require
168ff0cc061SDimitry Andric   // explicit cache flush, otherwise JIT code manipulations (like resolved
169ff0cc061SDimitry Andric   // relocations) will get to the data cache but not to the instruction cache.
170ff0cc061SDimitry Andric   invalidateInstructionCache();
171ff0cc061SDimitry Andric 
172ff0cc061SDimitry Andric   return false;
173ff0cc061SDimitry Andric }
174ff0cc061SDimitry Andric 
trimBlockToPageSize(sys::MemoryBlock M)1757d523365SDimitry Andric static sys::MemoryBlock trimBlockToPageSize(sys::MemoryBlock M) {
1767d523365SDimitry Andric   static const size_t PageSize = sys::Process::getPageSize();
1777d523365SDimitry Andric 
1787d523365SDimitry Andric   size_t StartOverlap =
1797d523365SDimitry Andric       (PageSize - ((uintptr_t)M.base() % PageSize)) % PageSize;
1807d523365SDimitry Andric 
1817d523365SDimitry Andric   size_t TrimmedSize = M.size();
1827d523365SDimitry Andric   TrimmedSize -= StartOverlap;
1837d523365SDimitry Andric   TrimmedSize -= TrimmedSize % PageSize;
1847d523365SDimitry Andric 
1852cab237bSDimitry Andric   sys::MemoryBlock Trimmed((void *)((uintptr_t)M.base() + StartOverlap),
1862cab237bSDimitry Andric                            TrimmedSize);
1877d523365SDimitry Andric 
1887d523365SDimitry Andric   assert(((uintptr_t)Trimmed.base() % PageSize) == 0);
1897d523365SDimitry Andric   assert((Trimmed.size() % PageSize) == 0);
1907d523365SDimitry Andric   assert(M.base() <= Trimmed.base() && Trimmed.size() <= M.size());
1917d523365SDimitry Andric 
1927d523365SDimitry Andric   return Trimmed;
1937d523365SDimitry Andric }
1947d523365SDimitry Andric 
195ff0cc061SDimitry Andric std::error_code
applyMemoryGroupPermissions(MemoryGroup & MemGroup,unsigned Permissions)196ff0cc061SDimitry Andric SectionMemoryManager::applyMemoryGroupPermissions(MemoryGroup &MemGroup,
197ff0cc061SDimitry Andric                                                   unsigned Permissions) {
1987d523365SDimitry Andric   for (sys::MemoryBlock &MB : MemGroup.PendingMem)
1992cab237bSDimitry Andric     if (std::error_code EC = MMapper.protectMappedMemory(MB, Permissions))
2007d523365SDimitry Andric       return EC;
201ff0cc061SDimitry Andric 
2027d523365SDimitry Andric   MemGroup.PendingMem.clear();
2037d523365SDimitry Andric 
2047d523365SDimitry Andric   // Now go through free blocks and trim any of them that don't span the entire
2057d523365SDimitry Andric   // page because one of the pending blocks may have overlapped it.
2067d523365SDimitry Andric   for (FreeMemBlock &FreeMB : MemGroup.FreeMem) {
2077d523365SDimitry Andric     FreeMB.Free = trimBlockToPageSize(FreeMB.Free);
2087d523365SDimitry Andric     // We cleared the PendingMem list, so all these pointers are now invalid
2097d523365SDimitry Andric     FreeMB.PendingPrefixIndex = (unsigned)-1;
210ff0cc061SDimitry Andric   }
2117d523365SDimitry Andric 
2127d523365SDimitry Andric   // Remove all blocks which are now empty
2137d523365SDimitry Andric   MemGroup.FreeMem.erase(
214d88c1a5aSDimitry Andric       remove_if(MemGroup.FreeMem,
2157d523365SDimitry Andric                 [](FreeMemBlock &FreeMB) { return FreeMB.Free.size() == 0; }),
2167d523365SDimitry Andric       MemGroup.FreeMem.end());
217ff0cc061SDimitry Andric 
218ff0cc061SDimitry Andric   return std::error_code();
219ff0cc061SDimitry Andric }
220ff0cc061SDimitry Andric 
invalidateInstructionCache()221ff0cc061SDimitry Andric void SectionMemoryManager::invalidateInstructionCache() {
2227d523365SDimitry Andric   for (sys::MemoryBlock &Block : CodeMem.PendingMem)
2237d523365SDimitry Andric     sys::Memory::InvalidateInstructionCache(Block.base(), Block.size());
224ff0cc061SDimitry Andric }
225ff0cc061SDimitry Andric 
~SectionMemoryManager()226ff0cc061SDimitry Andric SectionMemoryManager::~SectionMemoryManager() {
2277d523365SDimitry Andric   for (MemoryGroup *Group : {&CodeMem, &RWDataMem, &RODataMem}) {
2287d523365SDimitry Andric     for (sys::MemoryBlock &Block : Group->AllocatedMem)
2292cab237bSDimitry Andric       MMapper.releaseMappedMemory(Block);
2307d523365SDimitry Andric   }
231ff0cc061SDimitry Andric }
232ff0cc061SDimitry Andric 
~MemoryMapper()2332cab237bSDimitry Andric SectionMemoryManager::MemoryMapper::~MemoryMapper() {}
2342cab237bSDimitry Andric 
anchor()235*4ba319b5SDimitry Andric void SectionMemoryManager::anchor() {}
236*4ba319b5SDimitry Andric 
2372cab237bSDimitry Andric namespace {
2382cab237bSDimitry Andric // Trivial implementation of SectionMemoryManager::MemoryMapper that just calls
2392cab237bSDimitry Andric // into sys::Memory.
2402cab237bSDimitry Andric class DefaultMMapper final : public SectionMemoryManager::MemoryMapper {
2412cab237bSDimitry Andric public:
2422cab237bSDimitry Andric   sys::MemoryBlock
allocateMappedMemory(SectionMemoryManager::AllocationPurpose Purpose,size_t NumBytes,const sys::MemoryBlock * const NearBlock,unsigned Flags,std::error_code & EC)2432cab237bSDimitry Andric   allocateMappedMemory(SectionMemoryManager::AllocationPurpose Purpose,
2442cab237bSDimitry Andric                        size_t NumBytes, const sys::MemoryBlock *const NearBlock,
2452cab237bSDimitry Andric                        unsigned Flags, std::error_code &EC) override {
2462cab237bSDimitry Andric     return sys::Memory::allocateMappedMemory(NumBytes, NearBlock, Flags, EC);
2472cab237bSDimitry Andric   }
2482cab237bSDimitry Andric 
protectMappedMemory(const sys::MemoryBlock & Block,unsigned Flags)2492cab237bSDimitry Andric   std::error_code protectMappedMemory(const sys::MemoryBlock &Block,
2502cab237bSDimitry Andric                                       unsigned Flags) override {
2512cab237bSDimitry Andric     return sys::Memory::protectMappedMemory(Block, Flags);
2522cab237bSDimitry Andric   }
2532cab237bSDimitry Andric 
releaseMappedMemory(sys::MemoryBlock & M)2542cab237bSDimitry Andric   std::error_code releaseMappedMemory(sys::MemoryBlock &M) override {
2552cab237bSDimitry Andric     return sys::Memory::releaseMappedMemory(M);
2562cab237bSDimitry Andric   }
2572cab237bSDimitry Andric };
2582cab237bSDimitry Andric 
2592cab237bSDimitry Andric DefaultMMapper DefaultMMapperInstance;
2602cab237bSDimitry Andric } // namespace
2612cab237bSDimitry Andric 
SectionMemoryManager(MemoryMapper * MM)2622cab237bSDimitry Andric SectionMemoryManager::SectionMemoryManager(MemoryMapper *MM)
2632cab237bSDimitry Andric     : MMapper(MM ? *MM : DefaultMMapperInstance) {}
2642cab237bSDimitry Andric 
265ff0cc061SDimitry Andric } // namespace llvm
266