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 
20 namespace llvm {
21 
22 // Forward declare raw_ostream: it is used for debug dumping below.
23 class raw_ostream;
24 
25 namespace 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