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"
188a6f3554SLang Hames 
198a6f3554SLang Hames namespace llvm {
208a6f3554SLang Hames 
218a6f3554SLang Hames uint8_t *SectionMemoryManager::allocateDataSection(uintptr_t Size,
228a6f3554SLang Hames                                                    unsigned Alignment,
238a6f3554SLang Hames                                                    unsigned SectionID,
248a6f3554SLang Hames                                                    StringRef SectionName,
258a6f3554SLang Hames                                                    bool IsReadOnly) {
268a6f3554SLang Hames   if (IsReadOnly)
278a6f3554SLang Hames     return allocateSection(RODataMem, Size, Alignment);
288a6f3554SLang Hames   return allocateSection(RWDataMem, Size, Alignment);
298a6f3554SLang Hames }
308a6f3554SLang Hames 
318a6f3554SLang Hames uint8_t *SectionMemoryManager::allocateCodeSection(uintptr_t Size,
328a6f3554SLang Hames                                                    unsigned Alignment,
338a6f3554SLang Hames                                                    unsigned SectionID,
348a6f3554SLang Hames                                                    StringRef SectionName) {
358a6f3554SLang Hames   return allocateSection(CodeMem, Size, Alignment);
368a6f3554SLang Hames }
378a6f3554SLang Hames 
388a6f3554SLang Hames uint8_t *SectionMemoryManager::allocateSection(MemoryGroup &MemGroup,
398a6f3554SLang Hames                                                uintptr_t Size,
408a6f3554SLang Hames                                                unsigned Alignment) {
418a6f3554SLang Hames   if (!Alignment)
428a6f3554SLang Hames     Alignment = 16;
438a6f3554SLang Hames 
448a6f3554SLang Hames   assert(!(Alignment & (Alignment - 1)) && "Alignment must be a power of two.");
458a6f3554SLang Hames 
468a6f3554SLang Hames   uintptr_t RequiredSize = Alignment * ((Size + Alignment - 1)/Alignment + 1);
478a6f3554SLang Hames   uintptr_t Addr = 0;
488a6f3554SLang Hames 
498a6f3554SLang Hames   // Look in the list of free memory regions and use a block there if one
508a6f3554SLang Hames   // is available.
51*efeddcc5SBenjamin Kramer   for (sys::MemoryBlock &MB : MemGroup.FreeMem) {
528a6f3554SLang Hames     if (MB.size() >= RequiredSize) {
538a6f3554SLang Hames       Addr = (uintptr_t)MB.base();
548a6f3554SLang Hames       uintptr_t EndOfBlock = Addr + MB.size();
558a6f3554SLang Hames       // Align the address.
568a6f3554SLang Hames       Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1);
578a6f3554SLang Hames       // Store cutted free memory block.
58*efeddcc5SBenjamin Kramer       MB = sys::MemoryBlock((void *)(Addr + Size), EndOfBlock - Addr - Size);
598a6f3554SLang Hames       return (uint8_t*)Addr;
608a6f3554SLang Hames     }
618a6f3554SLang Hames   }
628a6f3554SLang Hames 
638a6f3554SLang Hames   // No pre-allocated free block was large enough. Allocate a new memory region.
648a6f3554SLang Hames   // Note that all sections get allocated as read-write.  The permissions will
658a6f3554SLang Hames   // be updated later based on memory group.
668a6f3554SLang Hames   //
678a6f3554SLang Hames   // FIXME: It would be useful to define a default allocation size (or add
688a6f3554SLang Hames   // it as a constructor parameter) to minimize the number of allocations.
698a6f3554SLang Hames   //
708a6f3554SLang Hames   // FIXME: Initialize the Near member for each memory group to avoid
718a6f3554SLang Hames   // interleaving.
728a6f3554SLang Hames   std::error_code ec;
738a6f3554SLang Hames   sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(RequiredSize,
748a6f3554SLang Hames                                                           &MemGroup.Near,
758a6f3554SLang Hames                                                           sys::Memory::MF_READ |
768a6f3554SLang Hames                                                             sys::Memory::MF_WRITE,
778a6f3554SLang Hames                                                           ec);
788a6f3554SLang Hames   if (ec) {
798a6f3554SLang Hames     // FIXME: Add error propagation to the interface.
808a6f3554SLang Hames     return nullptr;
818a6f3554SLang Hames   }
828a6f3554SLang Hames 
838a6f3554SLang Hames   // Save this address as the basis for our next request
848a6f3554SLang Hames   MemGroup.Near = MB;
858a6f3554SLang Hames 
868a6f3554SLang Hames   MemGroup.AllocatedMem.push_back(MB);
878a6f3554SLang Hames   Addr = (uintptr_t)MB.base();
888a6f3554SLang Hames   uintptr_t EndOfBlock = Addr + MB.size();
898a6f3554SLang Hames 
908a6f3554SLang Hames   // Align the address.
918a6f3554SLang Hames   Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1);
928a6f3554SLang Hames 
938a6f3554SLang Hames   // The allocateMappedMemory may allocate much more memory than we need. In
948a6f3554SLang Hames   // this case, we store the unused memory as a free memory block.
958a6f3554SLang Hames   unsigned FreeSize = EndOfBlock-Addr-Size;
968a6f3554SLang Hames   if (FreeSize > 16)
978a6f3554SLang Hames     MemGroup.FreeMem.push_back(sys::MemoryBlock((void*)(Addr + Size), FreeSize));
988a6f3554SLang Hames 
998a6f3554SLang Hames   // Return aligned address
1008a6f3554SLang Hames   return (uint8_t*)Addr;
1018a6f3554SLang Hames }
1028a6f3554SLang Hames 
1038a6f3554SLang Hames bool SectionMemoryManager::finalizeMemory(std::string *ErrMsg)
1048a6f3554SLang Hames {
1058a6f3554SLang Hames   // FIXME: Should in-progress permissions be reverted if an error occurs?
1068a6f3554SLang Hames   std::error_code ec;
1078a6f3554SLang Hames 
1088a6f3554SLang Hames   // Don't allow free memory blocks to be used after setting protection flags.
1098a6f3554SLang Hames   CodeMem.FreeMem.clear();
1108a6f3554SLang Hames 
1118a6f3554SLang Hames   // Make code memory executable.
1128a6f3554SLang Hames   ec = applyMemoryGroupPermissions(CodeMem,
1138a6f3554SLang Hames                                    sys::Memory::MF_READ | sys::Memory::MF_EXEC);
1148a6f3554SLang Hames   if (ec) {
1158a6f3554SLang Hames     if (ErrMsg) {
1168a6f3554SLang Hames       *ErrMsg = ec.message();
1178a6f3554SLang Hames     }
1188a6f3554SLang Hames     return true;
1198a6f3554SLang Hames   }
1208a6f3554SLang Hames 
1218a6f3554SLang Hames   // Don't allow free memory blocks to be used after setting protection flags.
1228a6f3554SLang Hames   RODataMem.FreeMem.clear();
1238a6f3554SLang Hames 
1248a6f3554SLang Hames   // Make read-only data memory read-only.
1258a6f3554SLang Hames   ec = applyMemoryGroupPermissions(RODataMem,
1268a6f3554SLang Hames                                    sys::Memory::MF_READ | sys::Memory::MF_EXEC);
1278a6f3554SLang Hames   if (ec) {
1288a6f3554SLang Hames     if (ErrMsg) {
1298a6f3554SLang Hames       *ErrMsg = ec.message();
1308a6f3554SLang Hames     }
1318a6f3554SLang Hames     return true;
1328a6f3554SLang Hames   }
1338a6f3554SLang Hames 
1348a6f3554SLang Hames   // Read-write data memory already has the correct permissions
1358a6f3554SLang Hames 
1368a6f3554SLang Hames   // Some platforms with separate data cache and instruction cache require
1378a6f3554SLang Hames   // explicit cache flush, otherwise JIT code manipulations (like resolved
1388a6f3554SLang Hames   // relocations) will get to the data cache but not to the instruction cache.
1398a6f3554SLang Hames   invalidateInstructionCache();
1408a6f3554SLang Hames 
1418a6f3554SLang Hames   return false;
1428a6f3554SLang Hames }
1438a6f3554SLang Hames 
1448a6f3554SLang Hames std::error_code
1458a6f3554SLang Hames SectionMemoryManager::applyMemoryGroupPermissions(MemoryGroup &MemGroup,
1468a6f3554SLang Hames                                                   unsigned Permissions) {
1478a6f3554SLang Hames 
148*efeddcc5SBenjamin Kramer   for (sys::MemoryBlock &MB : MemGroup.AllocatedMem)
149*efeddcc5SBenjamin Kramer     if (std::error_code EC = sys::Memory::protectMappedMemory(MB, Permissions))
150*efeddcc5SBenjamin Kramer       return EC;
1518a6f3554SLang Hames 
1528a6f3554SLang Hames   return std::error_code();
1538a6f3554SLang Hames }
1548a6f3554SLang Hames 
1558a6f3554SLang Hames void SectionMemoryManager::invalidateInstructionCache() {
156*efeddcc5SBenjamin Kramer   for (sys::MemoryBlock &Block : CodeMem.AllocatedMem)
157*efeddcc5SBenjamin Kramer     sys::Memory::InvalidateInstructionCache(Block.base(), Block.size());
1588a6f3554SLang Hames }
1598a6f3554SLang Hames 
1608a6f3554SLang Hames SectionMemoryManager::~SectionMemoryManager() {
161*efeddcc5SBenjamin Kramer   for (MemoryGroup *Group : {&CodeMem, &RWDataMem, &RODataMem})
162*efeddcc5SBenjamin Kramer     for (sys::MemoryBlock &Block : Group->AllocatedMem)
163*efeddcc5SBenjamin Kramer       sys::Memory::releaseMappedMemory(Block);
1648a6f3554SLang Hames }
1658a6f3554SLang Hames 
1668a6f3554SLang Hames } // namespace llvm
1678a6f3554SLang Hames 
168