LCOV - code coverage report
Current view: top level - lib/ExecutionEngine - SectionMemoryManager.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 77 83 92.8 %
Date: 2017-09-14 15:23:50 Functions: 9 9 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //===- SectionMemoryManager.cpp - Memory manager for MCJIT/RtDyld *- C++ -*-==//
       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             : // This file implements the section-based memory manager used by the MCJIT
      11             : // execution engine and RuntimeDyld
      12             : //
      13             : //===----------------------------------------------------------------------===//
      14             : 
      15             : #include "llvm/ExecutionEngine/SectionMemoryManager.h"
      16             : #include "llvm/Config/config.h"
      17             : #include "llvm/Support/MathExtras.h"
      18             : #include "llvm/Support/Process.h"
      19             : 
      20             : namespace llvm {
      21             : 
      22       20401 : uint8_t *SectionMemoryManager::allocateDataSection(uintptr_t Size,
      23             :                                                    unsigned Alignment,
      24             :                                                    unsigned SectionID,
      25             :                                                    StringRef SectionName,
      26             :                                                    bool IsReadOnly) {
      27       20401 :   if (IsReadOnly)
      28        8651 :     return allocateSection(RODataMem, Size, Alignment);
      29       11750 :   return allocateSection(RWDataMem, Size, Alignment);
      30             : }
      31             : 
      32       20249 : uint8_t *SectionMemoryManager::allocateCodeSection(uintptr_t Size,
      33             :                                                    unsigned Alignment,
      34             :                                                    unsigned SectionID,
      35             :                                                    StringRef SectionName) {
      36       20249 :   return allocateSection(CodeMem, Size, Alignment);
      37             : }
      38             : 
      39       40650 : uint8_t *SectionMemoryManager::allocateSection(MemoryGroup &MemGroup,
      40             :                                                uintptr_t Size,
      41             :                                                unsigned Alignment) {
      42       40650 :   if (!Alignment)
      43       20008 :     Alignment = 16;
      44             : 
      45             :   assert(!(Alignment & (Alignment - 1)) && "Alignment must be a power of two.");
      46             : 
      47       40650 :   uintptr_t RequiredSize = Alignment * ((Size + Alignment - 1)/Alignment + 1);
      48       40650 :   uintptr_t Addr = 0;
      49             : 
      50             :   // Look in the list of free memory regions and use a block there if one
      51             :   // is available.
      52     1133987 :   for (FreeMemBlock &FreeMB : MemGroup.FreeMem) {
      53     1051932 :     if (FreeMB.Free.size() >= RequiredSize) {
      54       39895 :       Addr = (uintptr_t)FreeMB.Free.base();
      55       39895 :       uintptr_t EndOfBlock = Addr + FreeMB.Free.size();
      56             :       // Align the address.
      57       39895 :       Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1);
      58             : 
      59       39895 :       if (FreeMB.PendingPrefixIndex == (unsigned)-1) {
      60             :         // The part of the block we're giving out to the user is now pending
      61         724 :         MemGroup.PendingMem.push_back(sys::MemoryBlock((void *)Addr, Size));
      62             : 
      63             :         // Remember this pending block, such that future allocations can just
      64             :         // modify it rather than creating a new one
      65         724 :         FreeMB.PendingPrefixIndex = MemGroup.PendingMem.size() - 1;
      66             :       } else {
      67       79066 :         sys::MemoryBlock &PendingMB = MemGroup.PendingMem[FreeMB.PendingPrefixIndex];
      68       39533 :         PendingMB = sys::MemoryBlock(PendingMB.base(), Addr + Size - (uintptr_t)PendingMB.base());
      69             :       }
      70             : 
      71             :       // Remember how much free space is now left in this block
      72       39895 :       FreeMB.Free = sys::MemoryBlock((void *)(Addr + Size), EndOfBlock - Addr - Size);
      73       39895 :       return (uint8_t*)Addr;
      74             :     }
      75             :   }
      76             : 
      77             :   // No pre-allocated free block was large enough. Allocate a new memory region.
      78             :   // Note that all sections get allocated as read-write.  The permissions will
      79             :   // be updated later based on memory group.
      80             :   //
      81             :   // FIXME: It would be useful to define a default allocation size (or add
      82             :   // it as a constructor parameter) to minimize the number of allocations.
      83             :   //
      84             :   // FIXME: Initialize the Near member for each memory group to avoid
      85             :   // interleaving.
      86         755 :   std::error_code ec;
      87             :   sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(RequiredSize,
      88         755 :                                                           &MemGroup.Near,
      89             :                                                           sys::Memory::MF_READ |
      90             :                                                             sys::Memory::MF_WRITE,
      91         755 :                                                           ec);
      92         755 :   if (ec) {
      93             :     // FIXME: Add error propagation to the interface.
      94             :     return nullptr;
      95             :   }
      96             : 
      97             :   // Save this address as the basis for our next request
      98         755 :   MemGroup.Near = MB;
      99             : 
     100             :   // Remember that we allocated this memory
     101         755 :   MemGroup.AllocatedMem.push_back(MB);
     102         755 :   Addr = (uintptr_t)MB.base();
     103         755 :   uintptr_t EndOfBlock = Addr + MB.size();
     104             : 
     105             :   // Align the address.
     106         755 :   Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1);
     107             : 
     108             :   // The part of the block we're giving out to the user is now pending
     109        1510 :   MemGroup.PendingMem.push_back(sys::MemoryBlock((void *)Addr, Size));
     110             : 
     111             :   // The allocateMappedMemory may allocate much more memory than we need. In
     112             :   // this case, we store the unused memory as a free memory block.
     113         755 :   unsigned FreeSize = EndOfBlock-Addr-Size;
     114         755 :   if (FreeSize > 16) {
     115         755 :     FreeMemBlock FreeMB;
     116         755 :     FreeMB.Free = sys::MemoryBlock((void*)(Addr + Size), FreeSize);
     117         755 :     FreeMB.PendingPrefixIndex = (unsigned)-1;
     118         755 :     MemGroup.FreeMem.push_back(FreeMB);
     119             :   }
     120             : 
     121             :   // Return aligned address
     122             :   return (uint8_t*)Addr;
     123             : }
     124             : 
     125         362 : bool SectionMemoryManager::finalizeMemory(std::string *ErrMsg)
     126             : {
     127             :   // FIXME: Should in-progress permissions be reverted if an error occurs?
     128         362 :   std::error_code ec;
     129             : 
     130             :   // Make code memory executable.
     131         362 :   ec = applyMemoryGroupPermissions(CodeMem,
     132         362 :                                    sys::Memory::MF_READ | sys::Memory::MF_EXEC);
     133         362 :   if (ec) {
     134           0 :     if (ErrMsg) {
     135           0 :       *ErrMsg = ec.message();
     136             :     }
     137             :     return true;
     138             :   }
     139             : 
     140             :   // Make read-only data memory read-only.
     141         362 :   ec = applyMemoryGroupPermissions(RODataMem,
     142         362 :                                    sys::Memory::MF_READ | sys::Memory::MF_EXEC);
     143         362 :   if (ec) {
     144           0 :     if (ErrMsg) {
     145           0 :       *ErrMsg = ec.message();
     146             :     }
     147             :     return true;
     148             :   }
     149             : 
     150             :   // Read-write data memory already has the correct permissions
     151             : 
     152             :   // Some platforms with separate data cache and instruction cache require
     153             :   // explicit cache flush, otherwise JIT code manipulations (like resolved
     154             :   // relocations) will get to the data cache but not to the instruction cache.
     155         362 :   invalidateInstructionCache();
     156             : 
     157         362 :   return false;
     158             : }
     159             : 
     160         515 : static sys::MemoryBlock trimBlockToPageSize(sys::MemoryBlock M) {
     161         515 :   static const size_t PageSize = sys::Process::getPageSize();
     162             : 
     163             :   size_t StartOverlap =
     164         515 :       (PageSize - ((uintptr_t)M.base() % PageSize)) % PageSize;
     165             : 
     166         515 :   size_t TrimmedSize = M.size();
     167         515 :   TrimmedSize -= StartOverlap;
     168         515 :   TrimmedSize -= TrimmedSize % PageSize;
     169             : 
     170        1030 :   sys::MemoryBlock Trimmed((void *)((uintptr_t)M.base() + StartOverlap), TrimmedSize);
     171             : 
     172             :   assert(((uintptr_t)Trimmed.base() % PageSize) == 0);
     173             :   assert((Trimmed.size() % PageSize) == 0);
     174             :   assert(M.base() <= Trimmed.base() && Trimmed.size() <= M.size());
     175             : 
     176         515 :   return Trimmed;
     177             : }
     178             : 
     179             : 
     180             : std::error_code
     181         724 : SectionMemoryManager::applyMemoryGroupPermissions(MemoryGroup &MemGroup,
     182             :                                                   unsigned Permissions) {
     183        2875 :   for (sys::MemoryBlock &MB : MemGroup.PendingMem)
     184         703 :     if (std::error_code EC = sys::Memory::protectMappedMemory(MB, Permissions))
     185           0 :       return EC;
     186             : 
     187        1448 :   MemGroup.PendingMem.clear();
     188             : 
     189             :   // Now go through free blocks and trim any of them that don't span the entire
     190             :   // page because one of the pending blocks may have overlapped it.
     191        2687 :   for (FreeMemBlock &FreeMB : MemGroup.FreeMem) {
     192         515 :     FreeMB.Free = trimBlockToPageSize(FreeMB.Free);
     193             :     // We cleared the PendingMem list, so all these pointers are now invalid
     194         515 :     FreeMB.PendingPrefixIndex = (unsigned)-1;
     195             :   }
     196             : 
     197             :   // Remove all blocks which are now empty
     198        1448 :   MemGroup.FreeMem.erase(
     199        1448 :       remove_if(MemGroup.FreeMem,
     200         515 :                 [](FreeMemBlock &FreeMB) { return FreeMB.Free.size() == 0; }),
     201        1448 :       MemGroup.FreeMem.end());
     202             : 
     203         724 :   return std::error_code();
     204             : }
     205             : 
     206         498 : void SectionMemoryManager::invalidateInstructionCache() {
     207        1494 :   for (sys::MemoryBlock &Block : CodeMem.PendingMem)
     208           0 :     sys::Memory::InvalidateInstructionCache(Block.base(), Block.size());
     209         498 : }
     210             : 
     211         253 : SectionMemoryManager::~SectionMemoryManager() {
     212         510 :   for (MemoryGroup *Group : {&CodeMem, &RWDataMem, &RODataMem}) {
     213        1356 :     for (sys::MemoryBlock &Block : Group->AllocatedMem)
     214         438 :       sys::Memory::releaseMappedMemory(Block);
     215             :   }
     216         151 : }
     217             : 
     218             : } // namespace llvm

Generated by: LCOV version 1.13