1249259Sdim//===- SectionMemoryManager.h - Memory manager for MCJIT/RtDyld -*- C++ -*-===//
2249259Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6249259Sdim//
7249259Sdim//===----------------------------------------------------------------------===//
8249259Sdim//
9249259Sdim// This file contains the declaration of a section-based memory manager used by
10249259Sdim// the MCJIT execution engine and RuntimeDyld.
11249259Sdim//
12249259Sdim//===----------------------------------------------------------------------===//
13249259Sdim
14249259Sdim#ifndef LLVM_EXECUTIONENGINE_SECTIONMEMORYMANAGER_H
15249259Sdim#define LLVM_EXECUTIONENGINE_SECTIONMEMORYMANAGER_H
16249259Sdim
17249259Sdim#include "llvm/ADT/SmallVector.h"
18314564Sdim#include "llvm/ADT/StringRef.h"
19288943Sdim#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
20249259Sdim#include "llvm/Support/Memory.h"
21314564Sdim#include <cstdint>
22314564Sdim#include <string>
23314564Sdim#include <system_error>
24249259Sdim
25249259Sdimnamespace llvm {
26314564Sdim
27249259Sdim/// This is a simple memory manager which implements the methods called by
28249259Sdim/// the RuntimeDyld class to allocate memory for section-based loading of
29249259Sdim/// objects, usually those generated by the MCJIT execution engine.
30249259Sdim///
31249259Sdim/// This memory manager allocates all section memory as read-write.  The
32249259Sdim/// RuntimeDyld will copy JITed section memory into these allocated blocks
33249259Sdim/// and perform any necessary linking and relocations.
34249259Sdim///
35249259Sdim/// Any client using this memory manager MUST ensure that section-specific
36249259Sdim/// page permissions have been applied before attempting to execute functions
37249259Sdim/// in the JITed object.  Permissions can be applied either by calling
38261991Sdim/// MCJIT::finalizeObject or by calling SectionMemoryManager::finalizeMemory
39249259Sdim/// directly.  Clients of MCJIT should call MCJIT::finalizeObject.
40261991Sdimclass SectionMemoryManager : public RTDyldMemoryManager {
41314564Sdimpublic:
42327952Sdim  /// This enum describes the various reasons to allocate pages from
43327952Sdim  /// allocateMappedMemory.
44327952Sdim  enum class AllocationPurpose {
45327952Sdim    Code,
46327952Sdim    ROData,
47327952Sdim    RWData,
48327952Sdim  };
49327952Sdim
50327952Sdim  /// Implementations of this interface are used by SectionMemoryManager to
51327952Sdim  /// request pages from the operating system.
52327952Sdim  class MemoryMapper {
53327952Sdim  public:
54327952Sdim    /// This method attempts to allocate \p NumBytes bytes of virtual memory for
55327952Sdim    /// \p Purpose.  \p NearBlock may point to an existing allocation, in which
56327952Sdim    /// case an attempt is made to allocate more memory near the existing block.
57327952Sdim    /// The actual allocated address is not guaranteed to be near the requested
58327952Sdim    /// address.  \p Flags is used to set the initial protection flags for the
59327952Sdim    /// block of the memory.  \p EC [out] returns an object describing any error
60327952Sdim    /// that occurs.
61327952Sdim    ///
62327952Sdim    /// This method may allocate more than the number of bytes requested.  The
63327952Sdim    /// actual number of bytes allocated is indicated in the returned
64327952Sdim    /// MemoryBlock.
65327952Sdim    ///
66327952Sdim    /// The start of the allocated block must be aligned with the system
67327952Sdim    /// allocation granularity (64K on Windows, page size on Linux).  If the
68327952Sdim    /// address following \p NearBlock is not so aligned, it will be rounded up
69327952Sdim    /// to the next allocation granularity boundary.
70327952Sdim    ///
71327952Sdim    /// \r a non-null MemoryBlock if the function was successful, otherwise a
72327952Sdim    /// null MemoryBlock with \p EC describing the error.
73327952Sdim    virtual sys::MemoryBlock
74327952Sdim    allocateMappedMemory(AllocationPurpose Purpose, size_t NumBytes,
75327952Sdim                         const sys::MemoryBlock *const NearBlock,
76327952Sdim                         unsigned Flags, std::error_code &EC) = 0;
77327952Sdim
78327952Sdim    /// This method sets the protection flags for a block of memory to the state
79327952Sdim    /// specified by \p Flags.  The behavior is not specified if the memory was
80327952Sdim    /// not allocated using the allocateMappedMemory method.
81327952Sdim    /// \p Block describes the memory block to be protected.
82327952Sdim    /// \p Flags specifies the new protection state to be assigned to the block.
83327952Sdim    ///
84327952Sdim    /// If \p Flags is MF_WRITE, the actual behavior varies with the operating
85327952Sdim    /// system (i.e. MF_READ | MF_WRITE on Windows) and the target architecture
86327952Sdim    /// (i.e. MF_WRITE -> MF_READ | MF_WRITE on i386).
87327952Sdim    ///
88327952Sdim    /// \r error_success if the function was successful, or an error_code
89327952Sdim    /// describing the failure if an error occurred.
90327952Sdim    virtual std::error_code protectMappedMemory(const sys::MemoryBlock &Block,
91327952Sdim                                                unsigned Flags) = 0;
92327952Sdim
93327952Sdim    /// This method releases a block of memory that was allocated with the
94327952Sdim    /// allocateMappedMemory method. It should not be used to release any memory
95327952Sdim    /// block allocated any other way.
96327952Sdim    /// \p Block describes the memory to be released.
97327952Sdim    ///
98327952Sdim    /// \r error_success if the function was successful, or an error_code
99327952Sdim    /// describing the failure if an error occurred.
100327952Sdim    virtual std::error_code releaseMappedMemory(sys::MemoryBlock &M) = 0;
101327952Sdim
102327952Sdim    virtual ~MemoryMapper();
103327952Sdim  };
104327952Sdim
105327952Sdim  /// Creates a SectionMemoryManager instance with \p MM as the associated
106327952Sdim  /// memory mapper.  If \p MM is nullptr then a default memory mapper is used
107327952Sdim  /// that directly calls into the operating system.
108327952Sdim  SectionMemoryManager(MemoryMapper *MM = nullptr);
109327952Sdim  SectionMemoryManager(const SectionMemoryManager &) = delete;
110327952Sdim  void operator=(const SectionMemoryManager &) = delete;
111288943Sdim  ~SectionMemoryManager() override;
112249259Sdim
113341825Sdim  /// Allocates a memory block of (at least) the given size suitable for
114249259Sdim  /// executable code.
115249259Sdim  ///
116249259Sdim  /// The value of \p Alignment must be a power of two.  If \p Alignment is zero
117249259Sdim  /// a default alignment of 16 will be used.
118276479Sdim  uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
119276479Sdim                               unsigned SectionID,
120276479Sdim                               StringRef SectionName) override;
121249259Sdim
122341825Sdim  /// Allocates a memory block of (at least) the given size suitable for
123249259Sdim  /// executable code.
124249259Sdim  ///
125249259Sdim  /// The value of \p Alignment must be a power of two.  If \p Alignment is zero
126249259Sdim  /// a default alignment of 16 will be used.
127276479Sdim  uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
128276479Sdim                               unsigned SectionID, StringRef SectionName,
129276479Sdim                               bool isReadOnly) override;
130249259Sdim
131341825Sdim  /// Update section-specific memory permissions and other attributes.
132249259Sdim  ///
133249259Sdim  /// This method is called when object loading is complete and section page
134249259Sdim  /// permissions can be applied.  It is up to the memory manager implementation
135249259Sdim  /// to decide whether or not to act on this method.  The memory manager will
136249259Sdim  /// typically allocate all sections as read-write and then apply specific
137249259Sdim  /// permissions when this method is called.  Code sections cannot be executed
138261991Sdim  /// until this function has been called.  In addition, any cache coherency
139261991Sdim  /// operations needed to reliably use the memory are also performed.
140249259Sdim  ///
141249259Sdim  /// \returns true if an error occurred, false otherwise.
142276479Sdim  bool finalizeMemory(std::string *ErrMsg = nullptr) override;
143249259Sdim
144341825Sdim  /// Invalidate instruction cache for code sections.
145249259Sdim  ///
146249259Sdim  /// Some platforms with separate data cache and instruction cache require
147249259Sdim  /// explicit cache flush, otherwise JIT code manipulations (like resolved
148249259Sdim  /// relocations) will get to the data cache but not to the instruction cache.
149249259Sdim  ///
150261991Sdim  /// This method is called from finalizeMemory.
151249259Sdim  virtual void invalidateInstructionCache();
152249259Sdim
153249259Sdimprivate:
154296417Sdim  struct FreeMemBlock {
155296417Sdim    // The actual block of free memory
156296417Sdim    sys::MemoryBlock Free;
157296417Sdim    // If there is a pending allocation from the same reservation right before
158296417Sdim    // this block, store it's index in PendingMem, to be able to update the
159296417Sdim    // pending region if part of this block is allocated, rather than having to
160296417Sdim    // create a new one
161296417Sdim    unsigned PendingPrefixIndex;
162296417Sdim  };
163296417Sdim
164249259Sdim  struct MemoryGroup {
165296417Sdim    // PendingMem contains all blocks of memory (subblocks of AllocatedMem)
166296417Sdim    // which have not yet had their permissions applied, but have been given
167296417Sdim    // out to the user. FreeMem contains all block of memory, which have
168296417Sdim    // neither had their permissions applied, nor been given out to the user.
169296417Sdim    SmallVector<sys::MemoryBlock, 16> PendingMem;
170296417Sdim    SmallVector<FreeMemBlock, 16> FreeMem;
171296417Sdim
172296417Sdim    // All memory blocks that have been requested from the system
173296417Sdim    SmallVector<sys::MemoryBlock, 16> AllocatedMem;
174296417Sdim
175296417Sdim    sys::MemoryBlock Near;
176249259Sdim  };
177249259Sdim
178327952Sdim  uint8_t *allocateSection(AllocationPurpose Purpose, uintptr_t Size,
179249259Sdim                           unsigned Alignment);
180249259Sdim
181276479Sdim  std::error_code applyMemoryGroupPermissions(MemoryGroup &MemGroup,
182276479Sdim                                              unsigned Permissions);
183249259Sdim
184341825Sdim  void anchor() override;
185341825Sdim
186249259Sdim  MemoryGroup CodeMem;
187249259Sdim  MemoryGroup RWDataMem;
188249259Sdim  MemoryGroup RODataMem;
189327952Sdim  MemoryMapper &MMapper;
190249259Sdim};
191249259Sdim
192314564Sdim} // end namespace llvm
193249259Sdim
194249259Sdim#endif // LLVM_EXECUTION_ENGINE_SECTION_MEMORY_MANAGER_H
195