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
19namespace llvm {
20
21// Forward declare raw_ostream: it is used for debug dumping below.
22class raw_ostream;
23
24namespace 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 Memory::releaseMappedMemory(M);
152 }
153 void *base() const { return M.base(); }
154 /// The size as it was allocated. This is always greater or equal to the
155 /// size that was originally requested.
156 size_t allocatedSize() const { return M.allocatedSize(); }
157 MemoryBlock getMemoryBlock() const { return M; }
158 private:
159 MemoryBlock M;
160 };
161
162#ifndef NDEBUG
163 /// Debugging output for Memory::ProtectionFlags.
164 raw_ostream &operator<<(raw_ostream &OS, const Memory::ProtectionFlags &PF);
165
166 /// Debugging output for MemoryBlock.
167 raw_ostream &operator<<(raw_ostream &OS, const MemoryBlock &MB);
168#endif // ifndef NDEBUG
169 } // end namespace sys
170 } // end namespace llvm
171
172#endif
173