Memory.h revision 360784
1//===- llvm/Support/Memory.h - Memory Support -------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file declares the llvm::sys::Memory class.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_SUPPORT_MEMORY_H
14#define LLVM_SUPPORT_MEMORY_H
15
16#include "llvm/Support/DataTypes.h"
17#include <string>
18#include <system_error>
19
20namespace llvm {
21
22// Forward declare raw_ostream: it is used for debug dumping below.
23class raw_ostream;
24
25namespace sys {
26
27  /// This class encapsulates the notion of a memory block which has an address
28  /// and a size. It is used by the Memory class (a friend) as the result of
29  /// various memory allocation operations.
30  /// @see Memory
31  /// Memory block abstraction.
32  class MemoryBlock {
33  public:
34    MemoryBlock() : Address(nullptr), AllocatedSize(0) {}
35    MemoryBlock(void *addr, size_t allocatedSize)
36        : Address(addr), AllocatedSize(allocatedSize) {}
37    void *base() const { return Address; }
38    /// The size as it was allocated. This is always greater or equal to the
39    /// size that was originally requested.
40    size_t allocatedSize() const { return AllocatedSize; }
41
42  private:
43    void *Address;    ///< Address of first byte of memory area
44    size_t AllocatedSize; ///< Size, in bytes of the memory area
45    unsigned Flags = 0;
46    friend class Memory;
47  };
48
49  /// This class provides various memory handling functions that manipulate
50  /// MemoryBlock instances.
51  /// @since 1.4
52  /// An abstraction for memory operations.
53  class Memory {
54  public:
55    enum ProtectionFlags {
56      MF_READ = 0x1000000,
57      MF_WRITE = 0x2000000,
58      MF_EXEC = 0x4000000,
59      MF_RWE_MASK = 0x7000000,
60
61      /// The \p MF_HUGE_HINT flag is used to indicate that the request for
62      /// a memory block should be satisfied with large pages if possible.
63      /// This is only a hint and small pages will be used as fallback.
64      ///
65      /// The presence or absence of this flag in the returned memory block
66      /// is (at least currently) *not* a reliable indicator that the memory
67      /// block will use or will not use large pages. On some systems a request
68      /// without this flag can be backed by large pages without this flag being
69      /// set, and on some other systems a request with this flag can fallback
70      /// to small pages without this flag being cleared.
71      MF_HUGE_HINT = 0x0000001
72    };
73
74    /// This method allocates a block of memory that is suitable for loading
75    /// dynamically generated code (e.g. JIT). An attempt to allocate
76    /// \p NumBytes bytes of virtual memory is made.
77    /// \p NearBlock may point to an existing allocation in which case
78    /// an attempt is made to allocate more memory near the existing block.
79    /// The actual allocated address is not guaranteed to be near the requested
80    /// address.
81    /// \p Flags is used to set the initial protection flags for the block
82    /// of the memory.
83    /// \p EC [out] returns an object describing any error that occurs.
84    ///
85    /// This method may allocate more than the number of bytes requested.  The
86    /// actual number of bytes allocated is indicated in the returned
87    /// MemoryBlock.
88    ///
89    /// The start of the allocated block must be aligned with the
90    /// system allocation granularity (64K on Windows, page size on Linux).
91    /// If the address following \p NearBlock is not so aligned, it will be
92    /// rounded up to the next allocation granularity boundary.
93    ///
94    /// \r a non-null MemoryBlock if the function was successful,
95    /// otherwise a null MemoryBlock is with \p EC describing the error.
96    ///
97    /// Allocate mapped memory.
98    static MemoryBlock allocateMappedMemory(size_t NumBytes,
99                                            const MemoryBlock *const NearBlock,
100                                            unsigned Flags,
101                                            std::error_code &EC);
102
103    /// This method releases a block of memory that was allocated with the
104    /// allocateMappedMemory method. It should not be used to release any
105    /// memory block allocated any other way.
106    /// \p Block describes the memory to be released.
107    ///
108    /// \r error_success if the function was successful, or an error_code
109    /// describing the failure if an error occurred.
110    ///
111    /// Release mapped memory.
112    static std::error_code releaseMappedMemory(MemoryBlock &Block);
113
114    /// This method sets the protection flags for a block of memory to the
115    /// state specified by /p Flags.  The behavior is not specified if the
116    /// memory was not allocated using the allocateMappedMemory method.
117    /// \p Block describes the memory block to be protected.
118    /// \p Flags specifies the new protection state to be assigned to the block.
119    /// \p ErrMsg [out] returns a string describing any error that occurred.
120    ///
121    /// If \p Flags is MF_WRITE, the actual behavior varies
122    /// with the operating system (i.e. MF_READ | MF_WRITE on Windows) and the
123    /// target architecture (i.e. MF_WRITE -> MF_READ | MF_WRITE on i386).
124    ///
125    /// \r error_success if the function was successful, or an error_code
126    /// describing the failure if an error occurred.
127    ///
128    /// Set memory protection state.
129    static std::error_code protectMappedMemory(const MemoryBlock &Block,
130                                               unsigned Flags);
131
132    /// InvalidateInstructionCache - Before the JIT can run a block of code
133    /// that has been emitted it must invalidate the instruction cache on some
134    /// platforms.
135    static void InvalidateInstructionCache(const void *Addr, size_t Len);
136  };
137
138  /// Owning version of MemoryBlock.
139  class OwningMemoryBlock {
140  public:
141    OwningMemoryBlock() = default;
142    explicit OwningMemoryBlock(MemoryBlock M) : M(M) {}
143    OwningMemoryBlock(OwningMemoryBlock &&Other) {
144      M = Other.M;
145      Other.M = MemoryBlock();
146    }
147    OwningMemoryBlock& operator=(OwningMemoryBlock &&Other) {
148      M = Other.M;
149      Other.M = MemoryBlock();
150      return *this;
151    }
152    ~OwningMemoryBlock() {
153      Memory::releaseMappedMemory(M);
154    }
155    void *base() const { return M.base(); }
156    /// The size as it was allocated. This is always greater or equal to the
157    /// size that was originally requested.
158    size_t allocatedSize() const { return M.allocatedSize(); }
159    MemoryBlock getMemoryBlock() const { return M; }
160  private:
161    MemoryBlock M;
162  };
163
164#ifndef NDEBUG
165  /// Debugging output for Memory::ProtectionFlags.
166  raw_ostream &operator<<(raw_ostream &OS, const Memory::ProtectionFlags &PF);
167
168  /// Debugging output for MemoryBlock.
169  raw_ostream &operator<<(raw_ostream &OS, const MemoryBlock &MB);
170#endif // ifndef NDEBUG
171  }    // end namespace sys
172  }    // end namespace llvm
173
174#endif
175