1bdd1243dSDimitry Andric //===-------- MemoryFlags.h - Memory allocation flags -----------*- C++ -*-===//
2bdd1243dSDimitry Andric //
3bdd1243dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4bdd1243dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5bdd1243dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6bdd1243dSDimitry Andric //
7bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
8bdd1243dSDimitry Andric //
9bdd1243dSDimitry Andric // Defines types and operations related to memory protection and allocation
10bdd1243dSDimitry Andric // lifetimes.
11bdd1243dSDimitry Andric //
12bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
13bdd1243dSDimitry Andric 
14bdd1243dSDimitry Andric #ifndef LLVM_EXECUTIONENGINE_ORC_SHARED_MEMORYFLAGS_H
15bdd1243dSDimitry Andric #define LLVM_EXECUTIONENGINE_ORC_SHARED_MEMORYFLAGS_H
16bdd1243dSDimitry Andric 
17bdd1243dSDimitry Andric #include "llvm/ADT/BitmaskEnum.h"
18bdd1243dSDimitry Andric #include "llvm/ADT/DenseMapInfo.h"
19bdd1243dSDimitry Andric #include "llvm/ADT/STLExtras.h"
20bdd1243dSDimitry Andric #include "llvm/Support/Memory.h"
21bdd1243dSDimitry Andric #include "llvm/Support/raw_ostream.h"
22bdd1243dSDimitry Andric 
23bdd1243dSDimitry Andric namespace llvm {
24bdd1243dSDimitry Andric namespace orc {
25bdd1243dSDimitry Andric 
26bdd1243dSDimitry Andric /// Describes Read/Write/Exec permissions for memory.
27bdd1243dSDimitry Andric enum class MemProt {
28bdd1243dSDimitry Andric   None = 0,
29bdd1243dSDimitry Andric   Read = 1U << 0,
30bdd1243dSDimitry Andric   Write = 1U << 1,
31bdd1243dSDimitry Andric   Exec = 1U << 2,
32bdd1243dSDimitry Andric   LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ Exec)
33bdd1243dSDimitry Andric };
34bdd1243dSDimitry Andric 
35bdd1243dSDimitry Andric /// Print a MemProt as an RWX triple.
36bdd1243dSDimitry Andric inline raw_ostream &operator<<(raw_ostream &OS, MemProt MP) {
37bdd1243dSDimitry Andric   return OS << (((MP & MemProt::Read) != MemProt::None) ? 'R' : '-')
38bdd1243dSDimitry Andric             << (((MP & MemProt::Write) != MemProt::None) ? 'W' : '-')
39bdd1243dSDimitry Andric             << (((MP & MemProt::Exec) != MemProt::None) ? 'X' : '-');
40bdd1243dSDimitry Andric }
41bdd1243dSDimitry Andric 
42bdd1243dSDimitry Andric /// Convert a MemProt value to a corresponding sys::Memory::ProtectionFlags
43bdd1243dSDimitry Andric /// value.
toSysMemoryProtectionFlags(MemProt MP)44bdd1243dSDimitry Andric inline sys::Memory::ProtectionFlags toSysMemoryProtectionFlags(MemProt MP) {
45bdd1243dSDimitry Andric   std::underlying_type_t<sys::Memory::ProtectionFlags> PF = 0;
46bdd1243dSDimitry Andric   if ((MP & MemProt::Read) != MemProt::None)
47bdd1243dSDimitry Andric     PF |= sys::Memory::MF_READ;
48bdd1243dSDimitry Andric   if ((MP & MemProt::Write) != MemProt::None)
49bdd1243dSDimitry Andric     PF |= sys::Memory::MF_WRITE;
50bdd1243dSDimitry Andric   if ((MP & MemProt::Exec) != MemProt::None)
51bdd1243dSDimitry Andric     PF |= sys::Memory::MF_EXEC;
52bdd1243dSDimitry Andric   return static_cast<sys::Memory::ProtectionFlags>(PF);
53bdd1243dSDimitry Andric }
54bdd1243dSDimitry Andric 
55bdd1243dSDimitry Andric /// Convert a sys::Memory::ProtectionFlags value to a corresponding MemProt
56bdd1243dSDimitry Andric /// value.
fromSysMemoryProtectionFlags(sys::Memory::ProtectionFlags PF)57bdd1243dSDimitry Andric inline MemProt fromSysMemoryProtectionFlags(sys::Memory::ProtectionFlags PF) {
58bdd1243dSDimitry Andric   MemProt MP = MemProt::None;
59bdd1243dSDimitry Andric   if (PF & sys::Memory::MF_READ)
60bdd1243dSDimitry Andric     MP |= MemProt::Read;
61bdd1243dSDimitry Andric   if (PF & sys::Memory::MF_WRITE)
62bdd1243dSDimitry Andric     MP |= MemProt::Write;
63bdd1243dSDimitry Andric   if (PF & sys::Memory::MF_EXEC)
64bdd1243dSDimitry Andric     MP |= MemProt::None;
65bdd1243dSDimitry Andric   return MP;
66bdd1243dSDimitry Andric }
67bdd1243dSDimitry Andric 
6806c3fb27SDimitry Andric /// Describes a memory lifetime policy for memory to be allocated by a
69bdd1243dSDimitry Andric /// JITLinkMemoryManager.
70bdd1243dSDimitry Andric ///
71bdd1243dSDimitry Andric /// All memory allocated by a call to JITLinkMemoryManager::allocate should be
72bdd1243dSDimitry Andric /// deallocated if a call is made to
73bdd1243dSDimitry Andric /// JITLinkMemoryManager::InFlightAllocation::abandon. The policies below apply
74bdd1243dSDimitry Andric /// to finalized allocations.
75*5f757f3fSDimitry Andric enum class MemLifetime {
7606c3fb27SDimitry Andric   /// Standard memory should be allocated by the allocator and then deallocated
7706c3fb27SDimitry Andric   /// when the deallocate method is called for the finalized allocation.
78bdd1243dSDimitry Andric   Standard,
79bdd1243dSDimitry Andric 
8006c3fb27SDimitry Andric   /// Finalize memory should be allocated by the allocator, and then be
8106c3fb27SDimitry Andric   /// overwritten and deallocated after all finalization functions have been
8206c3fb27SDimitry Andric   /// run.
8306c3fb27SDimitry Andric   Finalize,
8406c3fb27SDimitry Andric 
8506c3fb27SDimitry Andric   /// NoAlloc memory should not be allocated by the JITLinkMemoryManager at
8606c3fb27SDimitry Andric   /// all. It is used for sections that don't need to be transferred to the
8706c3fb27SDimitry Andric   /// executor process, typically metadata sections.
8806c3fb27SDimitry Andric   NoAlloc
89bdd1243dSDimitry Andric };
90bdd1243dSDimitry Andric 
91bdd1243dSDimitry Andric /// Print a MemDeallocPolicy.
92*5f757f3fSDimitry Andric inline raw_ostream &operator<<(raw_ostream &OS, MemLifetime MLP) {
9306c3fb27SDimitry Andric   switch (MLP) {
94*5f757f3fSDimitry Andric   case MemLifetime::Standard:
9506c3fb27SDimitry Andric     OS << "standard";
9606c3fb27SDimitry Andric     break;
97*5f757f3fSDimitry Andric   case MemLifetime::Finalize:
9806c3fb27SDimitry Andric     OS << "finalize";
9906c3fb27SDimitry Andric     break;
100*5f757f3fSDimitry Andric   case MemLifetime::NoAlloc:
10106c3fb27SDimitry Andric     OS << "noalloc";
10206c3fb27SDimitry Andric     break;
10306c3fb27SDimitry Andric   }
10406c3fb27SDimitry Andric   return OS;
105bdd1243dSDimitry Andric }
106bdd1243dSDimitry Andric 
107bdd1243dSDimitry Andric /// A pair of memory protections and allocation policies.
108bdd1243dSDimitry Andric ///
109bdd1243dSDimitry Andric /// Optimized for use as a small map key.
110bdd1243dSDimitry Andric class AllocGroup {
111bdd1243dSDimitry Andric   friend struct llvm::DenseMapInfo<AllocGroup>;
112bdd1243dSDimitry Andric 
113bdd1243dSDimitry Andric   using underlying_type = uint8_t;
114bdd1243dSDimitry Andric   static constexpr unsigned BitsForProt = 3;
11506c3fb27SDimitry Andric   static constexpr unsigned BitsForLifetimePolicy = 2;
116bdd1243dSDimitry Andric   static constexpr unsigned MaxIdentifiers =
11706c3fb27SDimitry Andric       1U << (BitsForProt + BitsForLifetimePolicy);
118bdd1243dSDimitry Andric 
119bdd1243dSDimitry Andric public:
120bdd1243dSDimitry Andric   static constexpr unsigned NumGroups = MaxIdentifiers;
121bdd1243dSDimitry Andric 
122bdd1243dSDimitry Andric   /// Create a default AllocGroup. No memory protections, standard
12306c3fb27SDimitry Andric   /// lifetime policy.
124bdd1243dSDimitry Andric   AllocGroup() = default;
125bdd1243dSDimitry Andric 
126bdd1243dSDimitry Andric   /// Create an AllocGroup from a MemProt only -- uses
127*5f757f3fSDimitry Andric   /// MemLifetime::Standard.
128bdd1243dSDimitry Andric   AllocGroup(MemProt MP) : Id(static_cast<underlying_type>(MP)) {}
129bdd1243dSDimitry Andric 
130*5f757f3fSDimitry Andric   /// Create an AllocGroup from a MemProt and a MemLifetime.
131*5f757f3fSDimitry Andric   AllocGroup(MemProt MP, MemLifetime MLP)
132bdd1243dSDimitry Andric       : Id(static_cast<underlying_type>(MP) |
13306c3fb27SDimitry Andric            (static_cast<underlying_type>(MLP) << BitsForProt)) {}
134bdd1243dSDimitry Andric 
135bdd1243dSDimitry Andric   /// Returns the MemProt for this group.
136bdd1243dSDimitry Andric   MemProt getMemProt() const {
137bdd1243dSDimitry Andric     return static_cast<MemProt>(Id & ((1U << BitsForProt) - 1));
138bdd1243dSDimitry Andric   }
139bdd1243dSDimitry Andric 
140*5f757f3fSDimitry Andric   /// Returns the MemLifetime for this group.
141*5f757f3fSDimitry Andric   MemLifetime getMemLifetime() const {
142*5f757f3fSDimitry Andric     return static_cast<MemLifetime>(Id >> BitsForProt);
143bdd1243dSDimitry Andric   }
144bdd1243dSDimitry Andric 
145bdd1243dSDimitry Andric   friend bool operator==(const AllocGroup &LHS, const AllocGroup &RHS) {
146bdd1243dSDimitry Andric     return LHS.Id == RHS.Id;
147bdd1243dSDimitry Andric   }
148bdd1243dSDimitry Andric 
149bdd1243dSDimitry Andric   friend bool operator!=(const AllocGroup &LHS, const AllocGroup &RHS) {
150bdd1243dSDimitry Andric     return !(LHS == RHS);
151bdd1243dSDimitry Andric   }
152bdd1243dSDimitry Andric 
153bdd1243dSDimitry Andric   friend bool operator<(const AllocGroup &LHS, const AllocGroup &RHS) {
154bdd1243dSDimitry Andric     return LHS.Id < RHS.Id;
155bdd1243dSDimitry Andric   }
156bdd1243dSDimitry Andric 
157bdd1243dSDimitry Andric private:
158bdd1243dSDimitry Andric   AllocGroup(underlying_type RawId) : Id(RawId) {}
159bdd1243dSDimitry Andric   underlying_type Id = 0;
160bdd1243dSDimitry Andric };
161bdd1243dSDimitry Andric 
162bdd1243dSDimitry Andric /// A specialized small-map for AllocGroups.
163bdd1243dSDimitry Andric ///
164bdd1243dSDimitry Andric /// Iteration order is guaranteed to match key ordering.
165bdd1243dSDimitry Andric template <typename T> class AllocGroupSmallMap {
166bdd1243dSDimitry Andric private:
167bdd1243dSDimitry Andric   using ElemT = std::pair<AllocGroup, T>;
168bdd1243dSDimitry Andric   using VectorTy = SmallVector<ElemT, 4>;
169bdd1243dSDimitry Andric 
170bdd1243dSDimitry Andric   static bool compareKey(const ElemT &E, const AllocGroup &G) {
171bdd1243dSDimitry Andric     return E.first < G;
172bdd1243dSDimitry Andric   }
173bdd1243dSDimitry Andric 
174bdd1243dSDimitry Andric public:
175bdd1243dSDimitry Andric   using iterator = typename VectorTy::iterator;
176bdd1243dSDimitry Andric 
177bdd1243dSDimitry Andric   AllocGroupSmallMap() = default;
178bdd1243dSDimitry Andric   AllocGroupSmallMap(std::initializer_list<std::pair<AllocGroup, T>> Inits)
179bdd1243dSDimitry Andric       : Elems(Inits) {
180bdd1243dSDimitry Andric     llvm::sort(Elems, llvm::less_first());
181bdd1243dSDimitry Andric   }
182bdd1243dSDimitry Andric 
183bdd1243dSDimitry Andric   iterator begin() { return Elems.begin(); }
184bdd1243dSDimitry Andric   iterator end() { return Elems.end(); }
185bdd1243dSDimitry Andric   iterator find(AllocGroup G) {
186bdd1243dSDimitry Andric     auto I = lower_bound(Elems, G, compareKey);
187bdd1243dSDimitry Andric     return (I->first == G) ? I : end();
188bdd1243dSDimitry Andric   }
189bdd1243dSDimitry Andric 
190bdd1243dSDimitry Andric   bool empty() const { return Elems.empty(); }
191bdd1243dSDimitry Andric   size_t size() const { return Elems.size(); }
192bdd1243dSDimitry Andric 
193bdd1243dSDimitry Andric   T &operator[](AllocGroup G) {
194bdd1243dSDimitry Andric     auto I = lower_bound(Elems, G, compareKey);
195bdd1243dSDimitry Andric     if (I == Elems.end() || I->first != G)
196bdd1243dSDimitry Andric       I = Elems.insert(I, std::make_pair(G, T()));
197bdd1243dSDimitry Andric     return I->second;
198bdd1243dSDimitry Andric   }
199bdd1243dSDimitry Andric 
200bdd1243dSDimitry Andric private:
201bdd1243dSDimitry Andric   VectorTy Elems;
202bdd1243dSDimitry Andric };
203bdd1243dSDimitry Andric 
204bdd1243dSDimitry Andric /// Print an AllocGroup.
205bdd1243dSDimitry Andric inline raw_ostream &operator<<(raw_ostream &OS, AllocGroup AG) {
206*5f757f3fSDimitry Andric   return OS << '(' << AG.getMemProt() << ", " << AG.getMemLifetime() << ')';
207bdd1243dSDimitry Andric }
208bdd1243dSDimitry Andric 
209bdd1243dSDimitry Andric } // end namespace orc
210bdd1243dSDimitry Andric 
211bdd1243dSDimitry Andric template <> struct DenseMapInfo<orc::MemProt> {
212bdd1243dSDimitry Andric   static inline orc::MemProt getEmptyKey() { return orc::MemProt(~uint8_t(0)); }
213bdd1243dSDimitry Andric   static inline orc::MemProt getTombstoneKey() {
214bdd1243dSDimitry Andric     return orc::MemProt(~uint8_t(0) - 1);
215bdd1243dSDimitry Andric   }
216bdd1243dSDimitry Andric   static unsigned getHashValue(const orc::MemProt &Val) {
217bdd1243dSDimitry Andric     using UT = std::underlying_type_t<orc::MemProt>;
218bdd1243dSDimitry Andric     return DenseMapInfo<UT>::getHashValue(static_cast<UT>(Val));
219bdd1243dSDimitry Andric   }
220bdd1243dSDimitry Andric   static bool isEqual(const orc::MemProt &LHS, const orc::MemProt &RHS) {
221bdd1243dSDimitry Andric     return LHS == RHS;
222bdd1243dSDimitry Andric   }
223bdd1243dSDimitry Andric };
224bdd1243dSDimitry Andric 
225bdd1243dSDimitry Andric template <> struct DenseMapInfo<orc::AllocGroup> {
226bdd1243dSDimitry Andric   static inline orc::AllocGroup getEmptyKey() {
227bdd1243dSDimitry Andric     return orc::AllocGroup(~uint8_t(0));
228bdd1243dSDimitry Andric   }
229bdd1243dSDimitry Andric   static inline orc::AllocGroup getTombstoneKey() {
230bdd1243dSDimitry Andric     return orc::AllocGroup(~uint8_t(0) - 1);
231bdd1243dSDimitry Andric   }
232bdd1243dSDimitry Andric   static unsigned getHashValue(const orc::AllocGroup &Val) {
233bdd1243dSDimitry Andric     return DenseMapInfo<orc::AllocGroup::underlying_type>::getHashValue(Val.Id);
234bdd1243dSDimitry Andric   }
235bdd1243dSDimitry Andric   static bool isEqual(const orc::AllocGroup &LHS, const orc::AllocGroup &RHS) {
236bdd1243dSDimitry Andric     return LHS == RHS;
237bdd1243dSDimitry Andric   }
238bdd1243dSDimitry Andric };
239bdd1243dSDimitry Andric 
240bdd1243dSDimitry Andric } // end namespace llvm
241bdd1243dSDimitry Andric 
242bdd1243dSDimitry Andric #endif // LLVM_EXECUTIONENGINE_ORC_SHARED_MEMORYFLAGS_H
243