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