LLVM API Documentation

SectionMemoryManager.cpp
Go to the documentation of this file.
00001 //===- SectionMemoryManager.cpp - Memory manager for MCJIT/RtDyld *- C++ -*-==//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // This file implements the section-based memory manager used by the MCJIT
00011 // execution engine and RuntimeDyld
00012 //
00013 //===----------------------------------------------------------------------===//
00014 
00015 #include "llvm/Config/config.h"
00016 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
00017 #include "llvm/Support/MathExtras.h"
00018 
00019 namespace llvm {
00020 
00021 uint8_t *SectionMemoryManager::allocateDataSection(uintptr_t Size,
00022                                                    unsigned Alignment,
00023                                                    unsigned SectionID,
00024                                                    StringRef SectionName,
00025                                                    bool IsReadOnly) {
00026   if (IsReadOnly)
00027     return allocateSection(RODataMem, Size, Alignment);
00028   return allocateSection(RWDataMem, Size, Alignment);
00029 }
00030 
00031 uint8_t *SectionMemoryManager::allocateCodeSection(uintptr_t Size,
00032                                                    unsigned Alignment,
00033                                                    unsigned SectionID,
00034                                                    StringRef SectionName) {
00035   return allocateSection(CodeMem, Size, Alignment);
00036 }
00037 
00038 uint8_t *SectionMemoryManager::allocateSection(MemoryGroup &MemGroup,
00039                                                uintptr_t Size,
00040                                                unsigned Alignment) {
00041   if (!Alignment)
00042     Alignment = 16;
00043 
00044   assert(!(Alignment & (Alignment - 1)) && "Alignment must be a power of two.");
00045 
00046   uintptr_t RequiredSize = Alignment * ((Size + Alignment - 1)/Alignment + 1);
00047   uintptr_t Addr = 0;
00048 
00049   // Look in the list of free memory regions and use a block there if one
00050   // is available.
00051   for (int i = 0, e = MemGroup.FreeMem.size(); i != e; ++i) {
00052     sys::MemoryBlock &MB = MemGroup.FreeMem[i];
00053     if (MB.size() >= RequiredSize) {
00054       Addr = (uintptr_t)MB.base();
00055       uintptr_t EndOfBlock = Addr + MB.size();
00056       // Align the address.
00057       Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1);
00058       // Store cutted free memory block.
00059       MemGroup.FreeMem[i] = sys::MemoryBlock((void*)(Addr + Size),
00060                                              EndOfBlock - Addr - Size);
00061       return (uint8_t*)Addr;
00062     }
00063   }
00064 
00065   // No pre-allocated free block was large enough. Allocate a new memory region.
00066   // Note that all sections get allocated as read-write.  The permissions will
00067   // be updated later based on memory group.
00068   //
00069   // FIXME: It would be useful to define a default allocation size (or add
00070   // it as a constructor parameter) to minimize the number of allocations.
00071   //
00072   // FIXME: Initialize the Near member for each memory group to avoid
00073   // interleaving.
00074   std::error_code ec;
00075   sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(RequiredSize,
00076                                                           &MemGroup.Near,
00077                                                           sys::Memory::MF_READ |
00078                                                             sys::Memory::MF_WRITE,
00079                                                           ec);
00080   if (ec) {
00081     // FIXME: Add error propagation to the interface.
00082     return nullptr;
00083   }
00084 
00085   // Save this address as the basis for our next request
00086   MemGroup.Near = MB;
00087 
00088   MemGroup.AllocatedMem.push_back(MB);
00089   Addr = (uintptr_t)MB.base();
00090   uintptr_t EndOfBlock = Addr + MB.size();
00091 
00092   // Align the address.
00093   Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1);
00094 
00095   // The allocateMappedMemory may allocate much more memory than we need. In
00096   // this case, we store the unused memory as a free memory block.
00097   unsigned FreeSize = EndOfBlock-Addr-Size;
00098   if (FreeSize > 16)
00099     MemGroup.FreeMem.push_back(sys::MemoryBlock((void*)(Addr + Size), FreeSize));
00100 
00101   // Return aligned address
00102   return (uint8_t*)Addr;
00103 }
00104 
00105 bool SectionMemoryManager::finalizeMemory(std::string *ErrMsg)
00106 {
00107   // FIXME: Should in-progress permissions be reverted if an error occurs?
00108   std::error_code ec;
00109 
00110   // Don't allow free memory blocks to be used after setting protection flags.
00111   CodeMem.FreeMem.clear();
00112 
00113   // Make code memory executable.
00114   ec = applyMemoryGroupPermissions(CodeMem,
00115                                    sys::Memory::MF_READ | sys::Memory::MF_EXEC);
00116   if (ec) {
00117     if (ErrMsg) {
00118       *ErrMsg = ec.message();
00119     }
00120     return true;
00121   }
00122 
00123   // Don't allow free memory blocks to be used after setting protection flags.
00124   RODataMem.FreeMem.clear();
00125 
00126   // Make read-only data memory read-only.
00127   ec = applyMemoryGroupPermissions(RODataMem,
00128                                    sys::Memory::MF_READ | sys::Memory::MF_EXEC);
00129   if (ec) {
00130     if (ErrMsg) {
00131       *ErrMsg = ec.message();
00132     }
00133     return true;
00134   }
00135 
00136   // Read-write data memory already has the correct permissions
00137 
00138   // Some platforms with separate data cache and instruction cache require
00139   // explicit cache flush, otherwise JIT code manipulations (like resolved
00140   // relocations) will get to the data cache but not to the instruction cache.
00141   invalidateInstructionCache();
00142 
00143   return false;
00144 }
00145 
00146 std::error_code
00147 SectionMemoryManager::applyMemoryGroupPermissions(MemoryGroup &MemGroup,
00148                                                   unsigned Permissions) {
00149 
00150   for (int i = 0, e = MemGroup.AllocatedMem.size(); i != e; ++i) {
00151     std::error_code ec;
00152     ec =
00153         sys::Memory::protectMappedMemory(MemGroup.AllocatedMem[i], Permissions);
00154     if (ec) {
00155       return ec;
00156     }
00157   }
00158 
00159   return std::error_code();
00160 }
00161 
00162 void SectionMemoryManager::invalidateInstructionCache() {
00163   for (int i = 0, e = CodeMem.AllocatedMem.size(); i != e; ++i)
00164     sys::Memory::InvalidateInstructionCache(CodeMem.AllocatedMem[i].base(),
00165                                             CodeMem.AllocatedMem[i].size());
00166 }
00167 
00168 SectionMemoryManager::~SectionMemoryManager() {
00169   for (unsigned i = 0, e = CodeMem.AllocatedMem.size(); i != e; ++i)
00170     sys::Memory::releaseMappedMemory(CodeMem.AllocatedMem[i]);
00171   for (unsigned i = 0, e = RWDataMem.AllocatedMem.size(); i != e; ++i)
00172     sys::Memory::releaseMappedMemory(RWDataMem.AllocatedMem[i]);
00173   for (unsigned i = 0, e = RODataMem.AllocatedMem.size(); i != e; ++i)
00174     sys::Memory::releaseMappedMemory(RODataMem.AllocatedMem[i]);
00175 }
00176 
00177 } // namespace llvm
00178