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