xref: /freebsd/contrib/llvm-project/llvm/include/llvm/Support/Memory.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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/Compiler.h"
17 #include "llvm/Support/DataTypes.h"
18 #include <system_error>
19 #include <utility>
20 
21 namespace llvm {
22 
23 // Forward declare raw_ostream: it is used for debug dumping below.
24 class raw_ostream;
25 
26 namespace sys {
27 
28   /// This class encapsulates the notion of a memory block which has an address
29   /// and a size. It is used by the Memory class (a friend) as the result of
30   /// various memory allocation operations.
31   /// @see Memory
32   /// Memory block abstraction.
33   class MemoryBlock {
34   public:
MemoryBlock()35     MemoryBlock() : Address(nullptr), AllocatedSize(0) {}
MemoryBlock(void * addr,size_t allocatedSize)36     MemoryBlock(void *addr, size_t allocatedSize)
37         : Address(addr), AllocatedSize(allocatedSize) {}
base()38     void *base() const { return Address; }
39     /// The size as it was allocated. This is always greater or equal to the
40     /// size that was originally requested.
allocatedSize()41     size_t allocatedSize() const { return AllocatedSize; }
42 
43   private:
44     void *Address;    ///< Address of first byte of memory area
45     size_t AllocatedSize; ///< Size, in bytes of the memory area
46     unsigned Flags = 0;
47     friend class Memory;
48   };
49 
50   /// This class provides various memory handling functions that manipulate
51   /// MemoryBlock instances.
52   /// @since 1.4
53   /// An abstraction for memory operations.
54   class Memory {
55   public:
56     enum ProtectionFlags {
57       MF_READ = 0x1000000,
58       MF_WRITE = 0x2000000,
59       MF_EXEC = 0x4000000,
60       MF_RWE_MASK = 0x7000000,
61 
62       /// The \p MF_HUGE_HINT flag is used to indicate that the request for
63       /// a memory block should be satisfied with large pages if possible.
64       /// This is only a hint and small pages will be used as fallback.
65       ///
66       /// The presence or absence of this flag in the returned memory block
67       /// is (at least currently) *not* a reliable indicator that the memory
68       /// block will use or will not use large pages. On some systems a request
69       /// without this flag can be backed by large pages without this flag being
70       /// set, and on some other systems a request with this flag can fallback
71       /// to small pages without this flag being cleared.
72       MF_HUGE_HINT = 0x0000001
73     };
74 
75     /// This method allocates a block of memory that is suitable for loading
76     /// dynamically generated code (e.g. JIT). An attempt to allocate
77     /// \p NumBytes bytes of virtual memory is made.
78     /// \p NearBlock may point to an existing allocation in which case
79     /// an attempt is made to allocate more memory near the existing block.
80     /// The actual allocated address is not guaranteed to be near the requested
81     /// address.
82     /// \p Flags is used to set the initial protection flags for the block
83     /// of the memory.
84     /// \p EC [out] returns an object describing any error that occurs.
85     ///
86     /// This method may allocate more than the number of bytes requested.  The
87     /// actual number of bytes allocated is indicated in the returned
88     /// MemoryBlock.
89     ///
90     /// The start of the allocated block must be aligned with the
91     /// system allocation granularity (64K on Windows, page size on Linux).
92     /// If the address following \p NearBlock is not so aligned, it will be
93     /// rounded up to the next allocation granularity boundary.
94     ///
95     /// \r a non-null MemoryBlock if the function was successful,
96     /// otherwise a null MemoryBlock is with \p EC describing the error.
97     ///
98     /// Allocate mapped memory.
99     LLVM_ABI static MemoryBlock
100     allocateMappedMemory(size_t NumBytes, const MemoryBlock *const NearBlock,
101                          unsigned Flags, 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     LLVM_ABI 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     ///
120     /// If \p Flags is MF_WRITE, the actual behavior varies
121     /// with the operating system (i.e. MF_READ | MF_WRITE on Windows) and the
122     /// target architecture (i.e. MF_WRITE -> MF_READ | MF_WRITE on i386).
123     ///
124     /// \r error_success if the function was successful, or an error_code
125     /// describing the failure if an error occurred.
126     ///
127     /// Set memory protection state.
128     LLVM_ABI static std::error_code
129     protectMappedMemory(const MemoryBlock &Block, unsigned Flags);
130 
131     /// InvalidateInstructionCache - Before the JIT can run a block of code
132     /// that has been emitted it must invalidate the instruction cache on some
133     /// platforms.
134     LLVM_ABI static void InvalidateInstructionCache(const void *Addr,
135                                                     size_t Len);
136   };
137 
138   /// Owning version of MemoryBlock.
139   class OwningMemoryBlock {
140   public:
141     OwningMemoryBlock() = default;
OwningMemoryBlock(MemoryBlock M)142     explicit OwningMemoryBlock(MemoryBlock M) : M(std::move(M)) {}
OwningMemoryBlock(OwningMemoryBlock && Other)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     }
~OwningMemoryBlock()152     ~OwningMemoryBlock() {
153       if (M.base())
154         Memory::releaseMappedMemory(M);
155     }
base()156     void *base() const { return M.base(); }
157     /// The size as it was allocated. This is always greater or equal to the
158     /// size that was originally requested.
allocatedSize()159     size_t allocatedSize() const { return M.allocatedSize(); }
getMemoryBlock()160     MemoryBlock getMemoryBlock() const { return M; }
release()161     std::error_code release() {
162       std::error_code EC;
163       if (M.base()) {
164         EC = Memory::releaseMappedMemory(M);
165         M = MemoryBlock();
166       }
167       return EC;
168     }
169   private:
170     MemoryBlock M;
171   };
172 
173 #ifndef NDEBUG
174   /// Debugging output for Memory::ProtectionFlags.
175   raw_ostream &operator<<(raw_ostream &OS, const Memory::ProtectionFlags &PF);
176 
177   /// Debugging output for MemoryBlock.
178   raw_ostream &operator<<(raw_ostream &OS, const MemoryBlock &MB);
179 #endif // ifndef NDEBUG
180   }    // end namespace sys
181   }    // end namespace llvm
182 
183 #endif
184