18a6f3554SLang Hames //===- SectionMemoryManager.cpp - Memory manager for MCJIT/RtDyld *- C++ -*-==//
28a6f3554SLang Hames //
38a6f3554SLang Hames //                     The LLVM Compiler Infrastructure
48a6f3554SLang Hames //
58a6f3554SLang Hames // This file is distributed under the University of Illinois Open Source
68a6f3554SLang Hames // License. See LICENSE.TXT for details.
78a6f3554SLang Hames //
88a6f3554SLang Hames //===----------------------------------------------------------------------===//
98a6f3554SLang Hames //
108a6f3554SLang Hames // This file implements the section-based memory manager used by the MCJIT
118a6f3554SLang Hames // execution engine and RuntimeDyld
128a6f3554SLang Hames //
138a6f3554SLang Hames //===----------------------------------------------------------------------===//
148a6f3554SLang Hames 
158a6f3554SLang Hames #include "llvm/Config/config.h"
168a6f3554SLang Hames #include "llvm/ExecutionEngine/SectionMemoryManager.h"
178a6f3554SLang Hames #include "llvm/Support/MathExtras.h"
18*94f181a4SKeno Fischer #include "llvm/Support/Process.h"
198a6f3554SLang Hames 
208a6f3554SLang Hames namespace llvm {
218a6f3554SLang Hames 
228a6f3554SLang Hames uint8_t *SectionMemoryManager::allocateDataSection(uintptr_t Size,
238a6f3554SLang Hames                                                    unsigned Alignment,
248a6f3554SLang Hames                                                    unsigned SectionID,
258a6f3554SLang Hames                                                    StringRef SectionName,
268a6f3554SLang Hames                                                    bool IsReadOnly) {
278a6f3554SLang Hames   if (IsReadOnly)
288a6f3554SLang Hames     return allocateSection(RODataMem, Size, Alignment);
298a6f3554SLang Hames   return allocateSection(RWDataMem, Size, Alignment);
308a6f3554SLang Hames }
318a6f3554SLang Hames 
328a6f3554SLang Hames uint8_t *SectionMemoryManager::allocateCodeSection(uintptr_t Size,
338a6f3554SLang Hames                                                    unsigned Alignment,
348a6f3554SLang Hames                                                    unsigned SectionID,
358a6f3554SLang Hames                                                    StringRef SectionName) {
368a6f3554SLang Hames   return allocateSection(CodeMem, Size, Alignment);
378a6f3554SLang Hames }
388a6f3554SLang Hames 
398a6f3554SLang Hames uint8_t *SectionMemoryManager::allocateSection(MemoryGroup &MemGroup,
408a6f3554SLang Hames                                                uintptr_t Size,
418a6f3554SLang Hames                                                unsigned Alignment) {
428a6f3554SLang Hames   if (!Alignment)
438a6f3554SLang Hames     Alignment = 16;
448a6f3554SLang Hames 
458a6f3554SLang Hames   assert(!(Alignment & (Alignment - 1)) && "Alignment must be a power of two.");
468a6f3554SLang Hames 
478a6f3554SLang Hames   uintptr_t RequiredSize = Alignment * ((Size + Alignment - 1)/Alignment + 1);
488a6f3554SLang Hames   uintptr_t Addr = 0;
498a6f3554SLang Hames 
508a6f3554SLang Hames   // Look in the list of free memory regions and use a block there if one
518a6f3554SLang Hames   // is available.
52*94f181a4SKeno Fischer   for (FreeMemBlock &FreeMB : MemGroup.FreeMem) {
53*94f181a4SKeno Fischer     if (FreeMB.Free.size() >= RequiredSize) {
54*94f181a4SKeno Fischer       Addr = (uintptr_t)FreeMB.Free.base();
55*94f181a4SKeno Fischer       uintptr_t EndOfBlock = Addr + FreeMB.Free.size();
568a6f3554SLang Hames       // Align the address.
578a6f3554SLang Hames       Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1);
58*94f181a4SKeno Fischer 
59*94f181a4SKeno Fischer       if (FreeMB.PendingPrefixIndex == (unsigned)-1) {
60*94f181a4SKeno Fischer         // The part of the block we're giving out to the user is now pending
61*94f181a4SKeno Fischer         MemGroup.PendingMem.push_back(sys::MemoryBlock((void *)Addr, Size));
62*94f181a4SKeno Fischer 
63*94f181a4SKeno Fischer         // Remember this pending block, such that future allocations can just
64*94f181a4SKeno Fischer         // modify it rather than creating a new one
65*94f181a4SKeno Fischer         FreeMB.PendingPrefixIndex = MemGroup.PendingMem.size() - 1;
66*94f181a4SKeno Fischer       } else {
67*94f181a4SKeno Fischer         sys::MemoryBlock &PendingMB = MemGroup.PendingMem[FreeMB.PendingPrefixIndex];
68*94f181a4SKeno Fischer         PendingMB = sys::MemoryBlock(PendingMB.base(), Addr + Size - (uintptr_t)PendingMB.base());
69*94f181a4SKeno Fischer       }
70*94f181a4SKeno Fischer 
71*94f181a4SKeno Fischer       // Remember how much free space is now left in this block
72*94f181a4SKeno Fischer       FreeMB.Free = sys::MemoryBlock((void *)(Addr + Size), EndOfBlock - Addr - Size);
738a6f3554SLang Hames       return (uint8_t*)Addr;
748a6f3554SLang Hames     }
758a6f3554SLang Hames   }
768a6f3554SLang Hames 
778a6f3554SLang Hames   // No pre-allocated free block was large enough. Allocate a new memory region.
788a6f3554SLang Hames   // Note that all sections get allocated as read-write.  The permissions will
798a6f3554SLang Hames   // be updated later based on memory group.
808a6f3554SLang Hames   //
818a6f3554SLang Hames   // FIXME: It would be useful to define a default allocation size (or add
828a6f3554SLang Hames   // it as a constructor parameter) to minimize the number of allocations.
838a6f3554SLang Hames   //
848a6f3554SLang Hames   // FIXME: Initialize the Near member for each memory group to avoid
858a6f3554SLang Hames   // interleaving.
868a6f3554SLang Hames   std::error_code ec;
878a6f3554SLang Hames   sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(RequiredSize,
888a6f3554SLang Hames                                                           &MemGroup.Near,
898a6f3554SLang Hames                                                           sys::Memory::MF_READ |
908a6f3554SLang Hames                                                             sys::Memory::MF_WRITE,
918a6f3554SLang Hames                                                           ec);
928a6f3554SLang Hames   if (ec) {
938a6f3554SLang Hames     // FIXME: Add error propagation to the interface.
948a6f3554SLang Hames     return nullptr;
958a6f3554SLang Hames   }
968a6f3554SLang Hames 
978a6f3554SLang Hames   // Save this address as the basis for our next request
988a6f3554SLang Hames   MemGroup.Near = MB;
998a6f3554SLang Hames 
100*94f181a4SKeno Fischer   // Remember that we allocated this memory
101*94f181a4SKeno Fischer   MemGroup.AllocatedMem.push_back(MB);
1028a6f3554SLang Hames   Addr = (uintptr_t)MB.base();
1038a6f3554SLang Hames   uintptr_t EndOfBlock = Addr + MB.size();
1048a6f3554SLang Hames 
1058a6f3554SLang Hames   // Align the address.
1068a6f3554SLang Hames   Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1);
1078a6f3554SLang Hames 
108*94f181a4SKeno Fischer   // The part of the block we're giving out to the user is now pending
109*94f181a4SKeno Fischer   MemGroup.PendingMem.push_back(sys::MemoryBlock((void *)Addr, Size));
110*94f181a4SKeno Fischer 
1118a6f3554SLang Hames   // The allocateMappedMemory may allocate much more memory than we need. In
1128a6f3554SLang Hames   // this case, we store the unused memory as a free memory block.
1138a6f3554SLang Hames   unsigned FreeSize = EndOfBlock-Addr-Size;
114*94f181a4SKeno Fischer   if (FreeSize > 16) {
115*94f181a4SKeno Fischer     FreeMemBlock FreeMB;
116*94f181a4SKeno Fischer     FreeMB.Free = sys::MemoryBlock((void*)(Addr + Size), FreeSize);
117*94f181a4SKeno Fischer     FreeMB.PendingPrefixIndex = (unsigned)-1;
118*94f181a4SKeno Fischer     MemGroup.FreeMem.push_back(FreeMB);
119*94f181a4SKeno Fischer   }
1208a6f3554SLang Hames 
1218a6f3554SLang Hames   // Return aligned address
1228a6f3554SLang Hames   return (uint8_t*)Addr;
1238a6f3554SLang Hames }
1248a6f3554SLang Hames 
1258a6f3554SLang Hames bool SectionMemoryManager::finalizeMemory(std::string *ErrMsg)
1268a6f3554SLang Hames {
1278a6f3554SLang Hames   // FIXME: Should in-progress permissions be reverted if an error occurs?
1288a6f3554SLang Hames   std::error_code ec;
1298a6f3554SLang Hames 
1308a6f3554SLang Hames   // Make code memory executable.
1318a6f3554SLang Hames   ec = applyMemoryGroupPermissions(CodeMem,
1328a6f3554SLang Hames                                    sys::Memory::MF_READ | sys::Memory::MF_EXEC);
1338a6f3554SLang Hames   if (ec) {
1348a6f3554SLang Hames     if (ErrMsg) {
1358a6f3554SLang Hames       *ErrMsg = ec.message();
1368a6f3554SLang Hames     }
1378a6f3554SLang Hames     return true;
1388a6f3554SLang Hames   }
1398a6f3554SLang Hames 
1408a6f3554SLang Hames   // Don't allow free memory blocks to be used after setting protection flags.
1418a6f3554SLang Hames   RODataMem.FreeMem.clear();
1428a6f3554SLang Hames 
1438a6f3554SLang Hames   // Make read-only data memory read-only.
1448a6f3554SLang Hames   ec = applyMemoryGroupPermissions(RODataMem,
1458a6f3554SLang Hames                                    sys::Memory::MF_READ | sys::Memory::MF_EXEC);
1468a6f3554SLang Hames   if (ec) {
1478a6f3554SLang Hames     if (ErrMsg) {
1488a6f3554SLang Hames       *ErrMsg = ec.message();
1498a6f3554SLang Hames     }
1508a6f3554SLang Hames     return true;
1518a6f3554SLang Hames   }
1528a6f3554SLang Hames 
1538a6f3554SLang Hames   // Read-write data memory already has the correct permissions
1548a6f3554SLang Hames 
1558a6f3554SLang Hames   // Some platforms with separate data cache and instruction cache require
1568a6f3554SLang Hames   // explicit cache flush, otherwise JIT code manipulations (like resolved
1578a6f3554SLang Hames   // relocations) will get to the data cache but not to the instruction cache.
1588a6f3554SLang Hames   invalidateInstructionCache();
1598a6f3554SLang Hames 
1608a6f3554SLang Hames   return false;
1618a6f3554SLang Hames }
1628a6f3554SLang Hames 
163*94f181a4SKeno Fischer static sys::MemoryBlock trimBlockToPageSize(sys::MemoryBlock M) {
164*94f181a4SKeno Fischer   static const size_t PageSize = sys::Process::getPageSize();
165*94f181a4SKeno Fischer 
166*94f181a4SKeno Fischer   size_t StartOverlap =
167*94f181a4SKeno Fischer       (PageSize - ((uintptr_t)M.base() % PageSize)) % PageSize;
168*94f181a4SKeno Fischer 
169*94f181a4SKeno Fischer   size_t TrimmedSize = M.size();
170*94f181a4SKeno Fischer   TrimmedSize -= StartOverlap;
171*94f181a4SKeno Fischer   TrimmedSize -= TrimmedSize % PageSize;
172*94f181a4SKeno Fischer 
173*94f181a4SKeno Fischer   sys::MemoryBlock Trimmed((void *)((uintptr_t)M.base() + StartOverlap), TrimmedSize);
174*94f181a4SKeno Fischer 
175*94f181a4SKeno Fischer   assert(((uintptr_t)Trimmed.base() % PageSize) == 0);
176*94f181a4SKeno Fischer   assert((Trimmed.size() % PageSize) == 0);
177*94f181a4SKeno Fischer   assert(M.base() <= Trimmed.base() && Trimmed.size() <= M.size());
178*94f181a4SKeno Fischer 
179*94f181a4SKeno Fischer   return Trimmed;
180*94f181a4SKeno Fischer }
181*94f181a4SKeno Fischer 
182*94f181a4SKeno Fischer 
1838a6f3554SLang Hames std::error_code
1848a6f3554SLang Hames SectionMemoryManager::applyMemoryGroupPermissions(MemoryGroup &MemGroup,
1858a6f3554SLang Hames                                                   unsigned Permissions) {
18617433bd1SKeno Fischer   for (sys::MemoryBlock &MB : MemGroup.PendingMem)
187efeddcc5SBenjamin Kramer     if (std::error_code EC = sys::Memory::protectMappedMemory(MB, Permissions))
188efeddcc5SBenjamin Kramer       return EC;
1898a6f3554SLang Hames 
190*94f181a4SKeno Fischer   MemGroup.PendingMem.clear();
191*94f181a4SKeno Fischer 
192*94f181a4SKeno Fischer   // Now go through free blocks and trim any of them that don't span the entire
193*94f181a4SKeno Fischer   // page because one of the pending blocks may have overlapped it.
194*94f181a4SKeno Fischer   for (FreeMemBlock &FreeMB : MemGroup.FreeMem) {
195*94f181a4SKeno Fischer     FreeMB.Free = trimBlockToPageSize(FreeMB.Free);
196*94f181a4SKeno Fischer     // We cleared the PendingMem list, so all these pointers are now invalid
197*94f181a4SKeno Fischer     FreeMB.PendingPrefixIndex = (unsigned)-1;
198*94f181a4SKeno Fischer   }
199*94f181a4SKeno Fischer 
200*94f181a4SKeno Fischer   // Remove all blocks which are now empty
201*94f181a4SKeno Fischer   MemGroup.FreeMem.erase(
202*94f181a4SKeno Fischer       std::remove_if(MemGroup.FreeMem.begin(), MemGroup.FreeMem.end(),
203*94f181a4SKeno Fischer                      [](FreeMemBlock &FreeMB) { return FreeMB.Free.size() == 0; }),
204*94f181a4SKeno Fischer       MemGroup.FreeMem.end());
205*94f181a4SKeno Fischer 
2068a6f3554SLang Hames   return std::error_code();
2078a6f3554SLang Hames }
2088a6f3554SLang Hames 
2098a6f3554SLang Hames void SectionMemoryManager::invalidateInstructionCache() {
21017433bd1SKeno Fischer   for (sys::MemoryBlock &Block : CodeMem.PendingMem)
211efeddcc5SBenjamin Kramer     sys::Memory::InvalidateInstructionCache(Block.base(), Block.size());
2128a6f3554SLang Hames }
2138a6f3554SLang Hames 
2148a6f3554SLang Hames SectionMemoryManager::~SectionMemoryManager() {
21517433bd1SKeno Fischer   for (MemoryGroup *Group : {&CodeMem, &RWDataMem, &RODataMem}) {
216efeddcc5SBenjamin Kramer     for (sys::MemoryBlock &Block : Group->AllocatedMem)
217efeddcc5SBenjamin Kramer       sys::Memory::releaseMappedMemory(Block);
21817433bd1SKeno Fischer   }
2198a6f3554SLang Hames }
2208a6f3554SLang Hames 
2218a6f3554SLang Hames } // namespace llvm
222