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