[llvm] r317770 - [SectionMemoryManager] Abstract out mmap, munmap, mprotect even more ; NFC

Sanjoy Das via llvm-commits llvm-commits at lists.llvm.org
Wed Nov 8 22:31:33 PST 2017


Author: sanjoy
Date: Wed Nov  8 22:31:33 2017
New Revision: 317770

URL: http://llvm.org/viewvc/llvm-project?rev=317770&view=rev
Log:
[SectionMemoryManager] Abstract out mmap, munmap, mprotect even more ; NFC

Summary:
This will let ORC JIT clients plug in custom logic for the mmap, munmap and
mprotect paths.

Reviewers: loladiro, dblaikie

Subscribers: mcrosier, llvm-commits

Differential Revision: https://reviews.llvm.org/D39300

Modified:
    llvm/trunk/include/llvm/ExecutionEngine/SectionMemoryManager.h
    llvm/trunk/lib/ExecutionEngine/SectionMemoryManager.cpp

Modified: llvm/trunk/include/llvm/ExecutionEngine/SectionMemoryManager.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/SectionMemoryManager.h?rev=317770&r1=317769&r2=317770&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ExecutionEngine/SectionMemoryManager.h (original)
+++ llvm/trunk/include/llvm/ExecutionEngine/SectionMemoryManager.h Wed Nov  8 22:31:33 2017
@@ -40,9 +40,75 @@ namespace llvm {
 /// directly.  Clients of MCJIT should call MCJIT::finalizeObject.
 class SectionMemoryManager : public RTDyldMemoryManager {
 public:
-  SectionMemoryManager() = default;
-  SectionMemoryManager(const SectionMemoryManager&) = delete;
-  void operator=(const SectionMemoryManager&) = delete;
+  /// This enum describes the various reasons to allocate pages from
+  /// allocateMappedMemory.
+  enum class AllocationPurpose {
+    Code,
+    ROData,
+    RWData,
+  };
+
+  /// Implementations of this interface are used by SectionMemoryManager to
+  /// request pages from the operating system.
+  class MemoryMapper {
+  public:
+    /// This method attempts to allocate \p NumBytes bytes of virtual memory for
+    /// \p Purpose.  \p NearBlock may point to an existing allocation, in which
+    /// case an attempt is made to allocate more memory near the existing block.
+    /// The actual allocated address is not guaranteed to be near the requested
+    /// address.  \p Flags is used to set the initial protection flags for the
+    /// block of the memory.  \p EC [out] returns an object describing any error
+    /// that occurs.
+    ///
+    /// This method may allocate more than the number of bytes requested.  The
+    /// actual number of bytes allocated is indicated in the returned
+    /// MemoryBlock.
+    ///
+    /// The start of the allocated block must be aligned with the system
+    /// allocation granularity (64K on Windows, page size on Linux).  If the
+    /// address following \p NearBlock is not so aligned, it will be rounded up
+    /// to the next allocation granularity boundary.
+    ///
+    /// \r a non-null MemoryBlock if the function was successful, otherwise a
+    /// null MemoryBlock with \p EC describing the error.
+    virtual sys::MemoryBlock
+    allocateMappedMemory(AllocationPurpose Purpose, size_t NumBytes,
+                         const sys::MemoryBlock *const NearBlock,
+                         unsigned Flags, std::error_code &EC) = 0;
+
+    /// This method sets the protection flags for a block of memory to the state
+    /// specified by \p Flags.  The behavior is not specified if the memory was
+    /// not allocated using the allocateMappedMemory method.
+    /// \p Block describes the memory block to be protected.
+    /// \p Flags specifies the new protection state to be assigned to the block.
+    ///
+    /// If \p Flags is MF_WRITE, the actual behavior varies with the operating
+    /// system (i.e. MF_READ | MF_WRITE on Windows) and the target architecture
+    /// (i.e. MF_WRITE -> MF_READ | MF_WRITE on i386).
+    ///
+    /// \r error_success if the function was successful, or an error_code
+    /// describing the failure if an error occurred.
+    virtual std::error_code protectMappedMemory(const sys::MemoryBlock &Block,
+                                                unsigned Flags) = 0;
+
+    /// This method releases a block of memory that was allocated with the
+    /// allocateMappedMemory method. It should not be used to release any memory
+    /// block allocated any other way.
+    /// \p Block describes the memory to be released.
+    ///
+    /// \r error_success if the function was successful, or an error_code
+    /// describing the failure if an error occurred.
+    virtual std::error_code releaseMappedMemory(sys::MemoryBlock &M) = 0;
+
+    virtual ~MemoryMapper();
+  };
+
+  /// Creates a SectionMemoryManager instance with \p MM as the associated
+  /// memory mapper.  If \p MM is nullptr then a default memory mapper is used
+  /// that directly calls into the operating system.
+  SectionMemoryManager(MemoryMapper *MM = nullptr);
+  SectionMemoryManager(const SectionMemoryManager &) = delete;
+  void operator=(const SectionMemoryManager &) = delete;
   ~SectionMemoryManager() override;
 
   /// \brief Allocates a memory block of (at least) the given size suitable for
@@ -110,7 +176,7 @@ private:
     sys::MemoryBlock Near;
   };
 
-  uint8_t *allocateSection(MemoryGroup &MemGroup, uintptr_t Size,
+  uint8_t *allocateSection(AllocationPurpose Purpose, uintptr_t Size,
                            unsigned Alignment);
 
   std::error_code applyMemoryGroupPermissions(MemoryGroup &MemGroup,
@@ -119,6 +185,7 @@ private:
   MemoryGroup CodeMem;
   MemoryGroup RWDataMem;
   MemoryGroup RODataMem;
+  MemoryMapper &MMapper;
 };
 
 } // end namespace llvm

Modified: llvm/trunk/lib/ExecutionEngine/SectionMemoryManager.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/SectionMemoryManager.cpp?rev=317770&r1=317769&r2=317770&view=diff
==============================================================================
--- llvm/trunk/lib/ExecutionEngine/SectionMemoryManager.cpp (original)
+++ llvm/trunk/lib/ExecutionEngine/SectionMemoryManager.cpp Wed Nov  8 22:31:33 2017
@@ -25,28 +25,42 @@ uint8_t *SectionMemoryManager::allocateD
                                                    StringRef SectionName,
                                                    bool IsReadOnly) {
   if (IsReadOnly)
-    return allocateSection(RODataMem, Size, Alignment);
-  return allocateSection(RWDataMem, Size, Alignment);
+    return allocateSection(SectionMemoryManager::AllocationPurpose::ROData,
+                           Size, Alignment);
+  return allocateSection(SectionMemoryManager::AllocationPurpose::RWData, Size,
+                         Alignment);
 }
 
 uint8_t *SectionMemoryManager::allocateCodeSection(uintptr_t Size,
                                                    unsigned Alignment,
                                                    unsigned SectionID,
                                                    StringRef SectionName) {
-  return allocateSection(CodeMem, Size, Alignment);
+  return allocateSection(SectionMemoryManager::AllocationPurpose::Code, Size,
+                         Alignment);
 }
 
-uint8_t *SectionMemoryManager::allocateSection(MemoryGroup &MemGroup,
-                                               uintptr_t Size,
-                                               unsigned Alignment) {
+uint8_t *SectionMemoryManager::allocateSection(
+    SectionMemoryManager::AllocationPurpose Purpose, uintptr_t Size,
+    unsigned Alignment) {
   if (!Alignment)
     Alignment = 16;
 
   assert(!(Alignment & (Alignment - 1)) && "Alignment must be a power of two.");
 
-  uintptr_t RequiredSize = Alignment * ((Size + Alignment - 1)/Alignment + 1);
+  uintptr_t RequiredSize = Alignment * ((Size + Alignment - 1) / Alignment + 1);
   uintptr_t Addr = 0;
 
+  MemoryGroup &MemGroup = [&]() -> MemoryGroup & {
+    switch (Purpose) {
+    case AllocationPurpose::Code:
+      return CodeMem;
+    case AllocationPurpose::ROData:
+      return RODataMem;
+    case AllocationPurpose::RWData:
+      return RWDataMem;
+    }
+  }();
+
   // Look in the list of free memory regions and use a block there if one
   // is available.
   for (FreeMemBlock &FreeMB : MemGroup.FreeMem) {
@@ -64,13 +78,16 @@ uint8_t *SectionMemoryManager::allocateS
         // modify it rather than creating a new one
         FreeMB.PendingPrefixIndex = MemGroup.PendingMem.size() - 1;
       } else {
-        sys::MemoryBlock &PendingMB = MemGroup.PendingMem[FreeMB.PendingPrefixIndex];
-        PendingMB = sys::MemoryBlock(PendingMB.base(), Addr + Size - (uintptr_t)PendingMB.base());
+        sys::MemoryBlock &PendingMB =
+            MemGroup.PendingMem[FreeMB.PendingPrefixIndex];
+        PendingMB = sys::MemoryBlock(PendingMB.base(),
+                                     Addr + Size - (uintptr_t)PendingMB.base());
       }
 
       // Remember how much free space is now left in this block
-      FreeMB.Free = sys::MemoryBlock((void *)(Addr + Size), EndOfBlock - Addr - Size);
-      return (uint8_t*)Addr;
+      FreeMB.Free =
+          sys::MemoryBlock((void *)(Addr + Size), EndOfBlock - Addr - Size);
+      return (uint8_t *)Addr;
     }
   }
 
@@ -84,11 +101,9 @@ uint8_t *SectionMemoryManager::allocateS
   // FIXME: Initialize the Near member for each memory group to avoid
   // interleaving.
   std::error_code ec;
-  sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(RequiredSize,
-                                                          &MemGroup.Near,
-                                                          sys::Memory::MF_READ |
-                                                            sys::Memory::MF_WRITE,
-                                                          ec);
+  sys::MemoryBlock MB = MMapper.allocateMappedMemory(
+      Purpose, RequiredSize, &MemGroup.Near,
+      sys::Memory::MF_READ | sys::Memory::MF_WRITE, ec);
   if (ec) {
     // FIXME: Add error propagation to the interface.
     return nullptr;
@@ -110,20 +125,19 @@ uint8_t *SectionMemoryManager::allocateS
 
   // The allocateMappedMemory may allocate much more memory than we need. In
   // this case, we store the unused memory as a free memory block.
-  unsigned FreeSize = EndOfBlock-Addr-Size;
+  unsigned FreeSize = EndOfBlock - Addr - Size;
   if (FreeSize > 16) {
     FreeMemBlock FreeMB;
-    FreeMB.Free = sys::MemoryBlock((void*)(Addr + Size), FreeSize);
+    FreeMB.Free = sys::MemoryBlock((void *)(Addr + Size), FreeSize);
     FreeMB.PendingPrefixIndex = (unsigned)-1;
     MemGroup.FreeMem.push_back(FreeMB);
   }
 
   // Return aligned address
-  return (uint8_t*)Addr;
+  return (uint8_t *)Addr;
 }
 
-bool SectionMemoryManager::finalizeMemory(std::string *ErrMsg)
-{
+bool SectionMemoryManager::finalizeMemory(std::string *ErrMsg) {
   // FIXME: Should in-progress permissions be reverted if an error occurs?
   std::error_code ec;
 
@@ -167,7 +181,8 @@ static sys::MemoryBlock trimBlockToPageS
   TrimmedSize -= StartOverlap;
   TrimmedSize -= TrimmedSize % PageSize;
 
-  sys::MemoryBlock Trimmed((void *)((uintptr_t)M.base() + StartOverlap), TrimmedSize);
+  sys::MemoryBlock Trimmed((void *)((uintptr_t)M.base() + StartOverlap),
+                           TrimmedSize);
 
   assert(((uintptr_t)Trimmed.base() % PageSize) == 0);
   assert((Trimmed.size() % PageSize) == 0);
@@ -176,12 +191,11 @@ static sys::MemoryBlock trimBlockToPageS
   return Trimmed;
 }
 
-
 std::error_code
 SectionMemoryManager::applyMemoryGroupPermissions(MemoryGroup &MemGroup,
                                                   unsigned Permissions) {
   for (sys::MemoryBlock &MB : MemGroup.PendingMem)
-    if (std::error_code EC = sys::Memory::protectMappedMemory(MB, Permissions))
+    if (std::error_code EC = MMapper.protectMappedMemory(MB, Permissions))
       return EC;
 
   MemGroup.PendingMem.clear();
@@ -211,8 +225,38 @@ void SectionMemoryManager::invalidateIns
 SectionMemoryManager::~SectionMemoryManager() {
   for (MemoryGroup *Group : {&CodeMem, &RWDataMem, &RODataMem}) {
     for (sys::MemoryBlock &Block : Group->AllocatedMem)
-      sys::Memory::releaseMappedMemory(Block);
+      MMapper.releaseMappedMemory(Block);
   }
 }
 
+SectionMemoryManager::MemoryMapper::~MemoryMapper() {}
+
+namespace {
+// Trivial implementation of SectionMemoryManager::MemoryMapper that just calls
+// into sys::Memory.
+class DefaultMMapper final : public SectionMemoryManager::MemoryMapper {
+public:
+  sys::MemoryBlock
+  allocateMappedMemory(SectionMemoryManager::AllocationPurpose Purpose,
+                       size_t NumBytes, const sys::MemoryBlock *const NearBlock,
+                       unsigned Flags, std::error_code &EC) override {
+    return sys::Memory::allocateMappedMemory(NumBytes, NearBlock, Flags, EC);
+  }
+
+  std::error_code protectMappedMemory(const sys::MemoryBlock &Block,
+                                      unsigned Flags) override {
+    return sys::Memory::protectMappedMemory(Block, Flags);
+  }
+
+  std::error_code releaseMappedMemory(sys::MemoryBlock &M) override {
+    return sys::Memory::releaseMappedMemory(M);
+  }
+};
+
+DefaultMMapper DefaultMMapperInstance;
+} // namespace
+
+SectionMemoryManager::SectionMemoryManager(MemoryMapper *MM)
+    : MMapper(MM ? *MM : DefaultMMapperInstance) {}
+
 } // namespace llvm




More information about the llvm-commits mailing list