1 //===-------- MemoryFlags.h - Memory allocation flags -----------*- 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 // Defines types and operations related to memory protection and allocation 10 // lifetimes. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_EXECUTIONENGINE_JITLINK_MEMORYFLAGS_H 15 #define LLVM_EXECUTIONENGINE_JITLINK_MEMORYFLAGS_H 16 17 #include "llvm/ADT/BitmaskEnum.h" 18 #include "llvm/ADT/DenseMapInfo.h" 19 #include "llvm/ADT/STLExtras.h" 20 #include "llvm/Support/Memory.h" 21 #include "llvm/Support/raw_ostream.h" 22 23 namespace llvm { 24 namespace jitlink { 25 26 /// Describes Read/Write/Exec permissions for memory. 27 enum class MemProt { 28 None = 0, 29 Read = 1U << 0, 30 Write = 1U << 1, 31 Exec = 1U << 2, 32 LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ Exec) 33 }; 34 35 /// Print a MemProt as an RWX triple. 36 raw_ostream &operator<<(raw_ostream &OS, MemProt MP); 37 38 /// Convert a MemProt value to a corresponding sys::Memory::ProtectionFlags 39 /// value. 40 inline sys::Memory::ProtectionFlags toSysMemoryProtectionFlags(MemProt MP) { 41 std::underlying_type_t<sys::Memory::ProtectionFlags> PF = 0; 42 if ((MP & MemProt::Read) != MemProt::None) 43 PF |= sys::Memory::MF_READ; 44 if ((MP & MemProt::Write) != MemProt::None) 45 PF |= sys::Memory::MF_WRITE; 46 if ((MP & MemProt::Exec) != MemProt::None) 47 PF |= sys::Memory::MF_EXEC; 48 return static_cast<sys::Memory::ProtectionFlags>(PF); 49 } 50 51 /// Convert a sys::Memory::ProtectionFlags value to a corresponding MemProt 52 /// value. 53 inline MemProt fromSysMemoryProtectionFlags(sys::Memory::ProtectionFlags PF) { 54 MemProt MP = MemProt::None; 55 if (PF & sys::Memory::MF_READ) 56 MP |= MemProt::Read; 57 if (PF & sys::Memory::MF_WRITE) 58 MP |= MemProt::Write; 59 if (PF & sys::Memory::MF_EXEC) 60 MP |= MemProt::None; 61 return MP; 62 } 63 64 /// Describes a memory deallocation policy for memory to be allocated by a 65 /// JITLinkMemoryManager. 66 /// 67 /// All memory allocated by a call to JITLinkMemoryManager::allocate should be 68 /// deallocated if a call is made to 69 /// JITLinkMemoryManager::InFlightAllocation::abandon. The policies below apply 70 /// to finalized allocations. 71 enum class MemDeallocPolicy { 72 /// Standard memory should be deallocated when the deallocate method is called 73 /// for the finalized allocation. 74 Standard, 75 76 /// Finalize memory should be overwritten and then deallocated after all 77 /// finalization functions have been run. 78 Finalize 79 }; 80 81 /// Print a MemDeallocPolicy. 82 raw_ostream &operator<<(raw_ostream &OS, MemDeallocPolicy MDP); 83 84 /// A pair of memory protections and allocation policies. 85 /// 86 /// Optimized for use as a small map key. 87 class AllocGroup { 88 friend struct llvm::DenseMapInfo<AllocGroup>; 89 90 using underlying_type = uint8_t; 91 static constexpr unsigned BitsForProt = 3; 92 static constexpr unsigned BitsForDeallocPolicy = 1; 93 static constexpr unsigned MaxIdentifiers = 94 1U << (BitsForProt + BitsForDeallocPolicy); 95 96 public: 97 static constexpr unsigned NumGroups = MaxIdentifiers; 98 99 /// Create a default AllocGroup. No memory protections, standard 100 /// deallocation policy. 101 AllocGroup() = default; 102 103 /// Create an AllocGroup from a MemProt only -- uses 104 /// MemoryDeallocationPolicy::Standard. 105 AllocGroup(MemProt MP) : Id(static_cast<underlying_type>(MP)) {} 106 107 /// Create an AllocGroup from a MemProt and a MemoryDeallocationPolicy. 108 AllocGroup(MemProt MP, MemDeallocPolicy MDP) 109 : Id(static_cast<underlying_type>(MP) | 110 (static_cast<underlying_type>(MDP) << BitsForProt)) {} 111 112 /// Returns the MemProt for this group. 113 MemProt getMemProt() const { 114 return static_cast<MemProt>(Id & ((1U << BitsForProt) - 1)); 115 } 116 117 /// Returns the MemoryDeallocationPolicy for this group. 118 MemDeallocPolicy getMemDeallocPolicy() const { 119 return static_cast<MemDeallocPolicy>(Id >> BitsForProt); 120 } 121 122 friend bool operator==(const AllocGroup &LHS, const AllocGroup &RHS) { 123 return LHS.Id == RHS.Id; 124 } 125 126 friend bool operator!=(const AllocGroup &LHS, const AllocGroup &RHS) { 127 return !(LHS == RHS); 128 } 129 130 friend bool operator<(const AllocGroup &LHS, const AllocGroup &RHS) { 131 return LHS.Id < RHS.Id; 132 } 133 134 private: 135 AllocGroup(underlying_type RawId) : Id(RawId) {} 136 underlying_type Id = 0; 137 }; 138 139 /// A specialized small-map for AllocGroups. 140 /// 141 /// Iteration order is guaranteed to match key ordering. 142 template <typename T> class AllocGroupSmallMap { 143 private: 144 using ElemT = std::pair<AllocGroup, T>; 145 using VectorTy = SmallVector<ElemT, 4>; 146 147 static bool compareKey(const ElemT &E, const AllocGroup &G) { 148 return E.first < G; 149 } 150 151 public: 152 using iterator = typename VectorTy::iterator; 153 154 AllocGroupSmallMap() = default; 155 AllocGroupSmallMap(std::initializer_list<std::pair<AllocGroup, T>> Inits) 156 : Elems(Inits) { 157 llvm::sort(Elems, llvm::less_first()); 158 } 159 160 iterator begin() { return Elems.begin(); } 161 iterator end() { return Elems.end(); } 162 iterator find(AllocGroup G) { 163 auto I = lower_bound(Elems, G, compareKey); 164 return (I->first == G) ? I : end(); 165 } 166 167 bool empty() const { return Elems.empty(); } 168 size_t size() const { return Elems.size(); } 169 170 T &operator[](AllocGroup G) { 171 auto I = lower_bound(Elems, G, compareKey); 172 if (I == Elems.end() || I->first != G) 173 I = Elems.insert(I, std::make_pair(G, T())); 174 return I->second; 175 } 176 177 private: 178 VectorTy Elems; 179 }; 180 181 /// Print an AllocGroup. 182 raw_ostream &operator<<(raw_ostream &OS, AllocGroup AG); 183 184 } // end namespace jitlink 185 186 template <> struct DenseMapInfo<jitlink::MemProt> { 187 static inline jitlink::MemProt getEmptyKey() { 188 return jitlink::MemProt(~uint8_t(0)); 189 } 190 static inline jitlink::MemProt getTombstoneKey() { 191 return jitlink::MemProt(~uint8_t(0) - 1); 192 } 193 static unsigned getHashValue(const jitlink::MemProt &Val) { 194 using UT = std::underlying_type_t<jitlink::MemProt>; 195 return DenseMapInfo<UT>::getHashValue(static_cast<UT>(Val)); 196 } 197 static bool isEqual(const jitlink::MemProt &LHS, 198 const jitlink::MemProt &RHS) { 199 return LHS == RHS; 200 } 201 }; 202 203 template <> struct DenseMapInfo<jitlink::AllocGroup> { 204 static inline jitlink::AllocGroup getEmptyKey() { 205 return jitlink::AllocGroup(~uint8_t(0)); 206 } 207 static inline jitlink::AllocGroup getTombstoneKey() { 208 return jitlink::AllocGroup(~uint8_t(0) - 1); 209 } 210 static unsigned getHashValue(const jitlink::AllocGroup &Val) { 211 return DenseMapInfo<jitlink::AllocGroup::underlying_type>::getHashValue( 212 Val.Id); 213 } 214 static bool isEqual(const jitlink::AllocGroup &LHS, 215 const jitlink::AllocGroup &RHS) { 216 return LHS == RHS; 217 } 218 }; 219 220 } // end namespace llvm 221 222 #endif // LLVM_EXECUTIONENGINE_JITLINK_MEMORYFLAGS_H 223