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"
1894f181a4SKeno 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.
5294f181a4SKeno Fischer   for (FreeMemBlock &FreeMB : MemGroup.FreeMem) {
5394f181a4SKeno Fischer     if (FreeMB.Free.size() >= RequiredSize) {
5494f181a4SKeno Fischer       Addr = (uintptr_t)FreeMB.Free.base();
5594f181a4SKeno Fischer       uintptr_t EndOfBlock = Addr + FreeMB.Free.size();
568a6f3554SLang Hames       // Align the address.
578a6f3554SLang Hames       Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1);
5894f181a4SKeno Fischer 
5994f181a4SKeno Fischer       if (FreeMB.PendingPrefixIndex == (unsigned)-1) {
6094f181a4SKeno Fischer         // The part of the block we're giving out to the user is now pending
6194f181a4SKeno Fischer         MemGroup.PendingMem.push_back(sys::MemoryBlock((void *)Addr, Size));
6294f181a4SKeno Fischer 
6394f181a4SKeno Fischer         // Remember this pending block, such that future allocations can just
6494f181a4SKeno Fischer         // modify it rather than creating a new one
6594f181a4SKeno Fischer         FreeMB.PendingPrefixIndex = MemGroup.PendingMem.size() - 1;
6694f181a4SKeno Fischer       } else {
6794f181a4SKeno Fischer         sys::MemoryBlock &PendingMB = MemGroup.PendingMem[FreeMB.PendingPrefixIndex];
6894f181a4SKeno Fischer         PendingMB = sys::MemoryBlock(PendingMB.base(), Addr + Size - (uintptr_t)PendingMB.base());
6994f181a4SKeno Fischer       }
7094f181a4SKeno Fischer 
7194f181a4SKeno Fischer       // Remember how much free space is now left in this block
7294f181a4SKeno 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 
10094f181a4SKeno Fischer   // Remember that we allocated this memory
10194f181a4SKeno 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 
10894f181a4SKeno Fischer   // The part of the block we're giving out to the user is now pending
10994f181a4SKeno Fischer   MemGroup.PendingMem.push_back(sys::MemoryBlock((void *)Addr, Size));
11094f181a4SKeno 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;
11494f181a4SKeno Fischer   if (FreeSize > 16) {
11594f181a4SKeno Fischer     FreeMemBlock FreeMB;
11694f181a4SKeno Fischer     FreeMB.Free = sys::MemoryBlock((void*)(Addr + Size), FreeSize);
11794f181a4SKeno Fischer     FreeMB.PendingPrefixIndex = (unsigned)-1;
11894f181a4SKeno Fischer     MemGroup.FreeMem.push_back(FreeMB);
11994f181a4SKeno 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   // Make read-only data memory read-only.
1418a6f3554SLang Hames   ec = applyMemoryGroupPermissions(RODataMem,
1428a6f3554SLang Hames                                    sys::Memory::MF_READ | sys::Memory::MF_EXEC);
1438a6f3554SLang Hames   if (ec) {
1448a6f3554SLang Hames     if (ErrMsg) {
1458a6f3554SLang Hames       *ErrMsg = ec.message();
1468a6f3554SLang Hames     }
1478a6f3554SLang Hames     return true;
1488a6f3554SLang Hames   }
1498a6f3554SLang Hames 
1508a6f3554SLang Hames   // Read-write data memory already has the correct permissions
1518a6f3554SLang Hames 
1528a6f3554SLang Hames   // Some platforms with separate data cache and instruction cache require
1538a6f3554SLang Hames   // explicit cache flush, otherwise JIT code manipulations (like resolved
1548a6f3554SLang Hames   // relocations) will get to the data cache but not to the instruction cache.
1558a6f3554SLang Hames   invalidateInstructionCache();
1568a6f3554SLang Hames 
1578a6f3554SLang Hames   return false;
1588a6f3554SLang Hames }
1598a6f3554SLang Hames 
16094f181a4SKeno Fischer static sys::MemoryBlock trimBlockToPageSize(sys::MemoryBlock M) {
16194f181a4SKeno Fischer   static const size_t PageSize = sys::Process::getPageSize();
16294f181a4SKeno Fischer 
16394f181a4SKeno Fischer   size_t StartOverlap =
16494f181a4SKeno Fischer       (PageSize - ((uintptr_t)M.base() % PageSize)) % PageSize;
16594f181a4SKeno Fischer 
16694f181a4SKeno Fischer   size_t TrimmedSize = M.size();
16794f181a4SKeno Fischer   TrimmedSize -= StartOverlap;
16894f181a4SKeno Fischer   TrimmedSize -= TrimmedSize % PageSize;
16994f181a4SKeno Fischer 
17094f181a4SKeno Fischer   sys::MemoryBlock Trimmed((void *)((uintptr_t)M.base() + StartOverlap), TrimmedSize);
17194f181a4SKeno Fischer 
17294f181a4SKeno Fischer   assert(((uintptr_t)Trimmed.base() % PageSize) == 0);
17394f181a4SKeno Fischer   assert((Trimmed.size() % PageSize) == 0);
17494f181a4SKeno Fischer   assert(M.base() <= Trimmed.base() && Trimmed.size() <= M.size());
17594f181a4SKeno Fischer 
17694f181a4SKeno Fischer   return Trimmed;
17794f181a4SKeno Fischer }
17894f181a4SKeno Fischer 
17994f181a4SKeno Fischer 
1808a6f3554SLang Hames std::error_code
1818a6f3554SLang Hames SectionMemoryManager::applyMemoryGroupPermissions(MemoryGroup &MemGroup,
1828a6f3554SLang Hames                                                   unsigned Permissions) {
18317433bd1SKeno Fischer   for (sys::MemoryBlock &MB : MemGroup.PendingMem)
184efeddcc5SBenjamin Kramer     if (std::error_code EC = sys::Memory::protectMappedMemory(MB, Permissions))
185efeddcc5SBenjamin Kramer       return EC;
1868a6f3554SLang Hames 
18794f181a4SKeno Fischer   MemGroup.PendingMem.clear();
18894f181a4SKeno Fischer 
18994f181a4SKeno Fischer   // Now go through free blocks and trim any of them that don't span the entire
19094f181a4SKeno Fischer   // page because one of the pending blocks may have overlapped it.
19194f181a4SKeno Fischer   for (FreeMemBlock &FreeMB : MemGroup.FreeMem) {
19294f181a4SKeno Fischer     FreeMB.Free = trimBlockToPageSize(FreeMB.Free);
19394f181a4SKeno Fischer     // We cleared the PendingMem list, so all these pointers are now invalid
19494f181a4SKeno Fischer     FreeMB.PendingPrefixIndex = (unsigned)-1;
19594f181a4SKeno Fischer   }
19694f181a4SKeno Fischer 
19794f181a4SKeno Fischer   // Remove all blocks which are now empty
19894f181a4SKeno Fischer   MemGroup.FreeMem.erase(
199*c700490fSDavid Majnemer       remove_if(MemGroup.FreeMem,
20094f181a4SKeno Fischer                 [](FreeMemBlock &FreeMB) { return FreeMB.Free.size() == 0; }),
20194f181a4SKeno Fischer       MemGroup.FreeMem.end());
20294f181a4SKeno Fischer 
2038a6f3554SLang Hames   return std::error_code();
2048a6f3554SLang Hames }
2058a6f3554SLang Hames 
2068a6f3554SLang Hames void SectionMemoryManager::invalidateInstructionCache() {
20717433bd1SKeno Fischer   for (sys::MemoryBlock &Block : CodeMem.PendingMem)
208efeddcc5SBenjamin Kramer     sys::Memory::InvalidateInstructionCache(Block.base(), Block.size());
2098a6f3554SLang Hames }
2108a6f3554SLang Hames 
2118a6f3554SLang Hames SectionMemoryManager::~SectionMemoryManager() {
21217433bd1SKeno Fischer   for (MemoryGroup *Group : {&CodeMem, &RWDataMem, &RODataMem}) {
213efeddcc5SBenjamin Kramer     for (sys::MemoryBlock &Block : Group->AllocatedMem)
214efeddcc5SBenjamin Kramer       sys::Memory::releaseMappedMemory(Block);
21517433bd1SKeno Fischer   }
2168a6f3554SLang Hames }
2178a6f3554SLang Hames 
2188a6f3554SLang Hames } // namespace llvm
219