1 //===------ ExecutorAddress.h - Executing process address -------*- 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 // Represents an address in the executing program.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_EXECUTIONENGINE_ORC_SHARED_EXECUTORADDRESS_H
14 #define LLVM_EXECUTIONENGINE_ORC_SHARED_EXECUTORADDRESS_H
15 
16 #include "llvm/ADT/DenseMapInfo.h"
17 #include "llvm/ADT/identity.h"
18 #include "llvm/ExecutionEngine/Orc/Shared/SimplePackedSerialization.h"
19 #include "llvm/Support/FormatVariadic.h"
20 #include "llvm/Support/raw_ostream.h"
21 
22 #include <cassert>
23 #include <type_traits>
24 
25 namespace llvm {
26 namespace orc {
27 
28 using ExecutorAddrDiff = uint64_t;
29 
30 /// Represents an address in the executor process.
31 class ExecutorAddr {
32 public:
33   /// A wrap/unwrap function that leaves pointers unmodified.
34   template <typename T> using rawPtr = llvm::identity<T *>;
35 
36   /// Default wrap function to use on this host.
37   template <typename T> using defaultWrap = rawPtr<T>;
38 
39   /// Default unwrap function to use on this host.
40   template <typename T> using defaultUnwrap = rawPtr<T>;
41 
42   /// Merges a tag into the raw address value:
43   ///   P' = P | (TagValue << TagOffset).
44   class Tag {
45   public:
46     constexpr Tag(uintptr_t TagValue, uintptr_t TagOffset)
47         : TagMask(TagValue << TagOffset) {}
48 
49     template <typename T> constexpr T *operator()(T *P) {
50       return reinterpret_cast<T *>(reinterpret_cast<uintptr_t>(P) | TagMask);
51     }
52 
53   private:
54     uintptr_t TagMask;
55   };
56 
57   /// Strips a tag of the given length from the given offset within the pointer:
58   /// P' = P & ~(((1 << TagLen) -1) << TagOffset)
59   class Untag {
60   public:
61     constexpr Untag(uintptr_t TagLen, uintptr_t TagOffset)
62         : UntagMask(~(((uintptr_t(1) << TagLen) - 1) << TagOffset)) {}
63 
64     template <typename T> constexpr T *operator()(T *P) {
65       return reinterpret_cast<T *>(reinterpret_cast<uintptr_t>(P) & UntagMask);
66     }
67 
68   private:
69     uintptr_t UntagMask;
70   };
71 
72   ExecutorAddr() = default;
73 
74   /// Create an ExecutorAddr from the given value.
75   explicit constexpr ExecutorAddr(uint64_t Addr) : Addr(Addr) {}
76 
77   /// Create an ExecutorAddr from the given pointer.
78   /// Warning: This should only be used when JITing in-process.
79   template <typename T, typename UnwrapFn = defaultUnwrap<T>>
80   static ExecutorAddr fromPtr(T *Ptr, UnwrapFn &&Unwrap = UnwrapFn()) {
81     return ExecutorAddr(
82         static_cast<uint64_t>(reinterpret_cast<uintptr_t>(Unwrap(Ptr))));
83   }
84 
85   /// Cast this ExecutorAddr to a pointer of the given type.
86   /// Warning: This should only be used when JITing in-process.
87   template <typename T, typename WrapFn = defaultWrap<std::remove_pointer_t<T>>>
88   std::enable_if_t<std::is_pointer<T>::value, T>
89   toPtr(WrapFn &&Wrap = WrapFn()) const {
90     uintptr_t IntPtr = static_cast<uintptr_t>(Addr);
91     assert(IntPtr == Addr && "ExecutorAddr value out of range for uintptr_t");
92     return Wrap(reinterpret_cast<T>(IntPtr));
93   }
94 
95   /// Cast this ExecutorAddr to a pointer of the given function type.
96   /// Warning: This should only be used when JITing in-process.
97   template <typename T, typename WrapFn = defaultWrap<T>>
98   std::enable_if_t<std::is_function<T>::value, T *>
99   toPtr(WrapFn &&Wrap = WrapFn()) const {
100     uintptr_t IntPtr = static_cast<uintptr_t>(Addr);
101     assert(IntPtr == Addr && "ExecutorAddr value out of range for uintptr_t");
102     return Wrap(reinterpret_cast<T *>(IntPtr));
103   }
104 
105   uint64_t getValue() const { return Addr; }
106   void setValue(uint64_t Addr) { this->Addr = Addr; }
107   bool isNull() const { return Addr == 0; }
108 
109   explicit operator bool() const { return Addr != 0; }
110 
111   friend bool operator==(const ExecutorAddr &LHS, const ExecutorAddr &RHS) {
112     return LHS.Addr == RHS.Addr;
113   }
114 
115   friend bool operator!=(const ExecutorAddr &LHS, const ExecutorAddr &RHS) {
116     return LHS.Addr != RHS.Addr;
117   }
118 
119   friend bool operator<(const ExecutorAddr &LHS, const ExecutorAddr &RHS) {
120     return LHS.Addr < RHS.Addr;
121   }
122 
123   friend bool operator<=(const ExecutorAddr &LHS, const ExecutorAddr &RHS) {
124     return LHS.Addr <= RHS.Addr;
125   }
126 
127   friend bool operator>(const ExecutorAddr &LHS, const ExecutorAddr &RHS) {
128     return LHS.Addr > RHS.Addr;
129   }
130 
131   friend bool operator>=(const ExecutorAddr &LHS, const ExecutorAddr &RHS) {
132     return LHS.Addr >= RHS.Addr;
133   }
134 
135   ExecutorAddr &operator++() {
136     ++Addr;
137     return *this;
138   }
139   ExecutorAddr &operator--() {
140     --Addr;
141     return *this;
142   }
143   ExecutorAddr operator++(int) { return ExecutorAddr(Addr++); }
144   ExecutorAddr operator--(int) { return ExecutorAddr(Addr--); }
145 
146   ExecutorAddr &operator+=(const ExecutorAddrDiff &Delta) {
147     Addr += Delta;
148     return *this;
149   }
150 
151   ExecutorAddr &operator-=(const ExecutorAddrDiff &Delta) {
152     Addr -= Delta;
153     return *this;
154   }
155 
156 private:
157   uint64_t Addr = 0;
158 };
159 
160 /// Subtracting two addresses yields an offset.
161 inline ExecutorAddrDiff operator-(const ExecutorAddr &LHS,
162                                   const ExecutorAddr &RHS) {
163   return ExecutorAddrDiff(LHS.getValue() - RHS.getValue());
164 }
165 
166 /// Adding an offset and an address yields an address.
167 inline ExecutorAddr operator+(const ExecutorAddr &LHS,
168                               const ExecutorAddrDiff &RHS) {
169   return ExecutorAddr(LHS.getValue() + RHS);
170 }
171 
172 /// Adding an address and an offset yields an address.
173 inline ExecutorAddr operator+(const ExecutorAddrDiff &LHS,
174                               const ExecutorAddr &RHS) {
175   return ExecutorAddr(LHS + RHS.getValue());
176 }
177 
178 /// Subtracting an offset from an address yields an address.
179 inline ExecutorAddr operator-(const ExecutorAddr &LHS,
180                               const ExecutorAddrDiff &RHS) {
181   return ExecutorAddr(LHS.getValue() - RHS);
182 }
183 
184 /// Taking the modulus of an address and a diff yields a diff.
185 inline ExecutorAddrDiff operator%(const ExecutorAddr &LHS,
186                                   const ExecutorAddrDiff &RHS) {
187   return ExecutorAddrDiff(LHS.getValue() % RHS);
188 }
189 
190 /// Represents an address range in the exceutor process.
191 struct ExecutorAddrRange {
192   ExecutorAddrRange() = default;
193   ExecutorAddrRange(ExecutorAddr Start, ExecutorAddr End)
194       : Start(Start), End(End) {}
195   ExecutorAddrRange(ExecutorAddr Start, ExecutorAddrDiff Size)
196       : Start(Start), End(Start + Size) {}
197 
198   bool empty() const { return Start == End; }
199   ExecutorAddrDiff size() const { return End - Start; }
200 
201   friend bool operator==(const ExecutorAddrRange &LHS,
202                          const ExecutorAddrRange &RHS) {
203     return LHS.Start == RHS.Start && LHS.End == RHS.End;
204   }
205   friend bool operator!=(const ExecutorAddrRange &LHS,
206                          const ExecutorAddrRange &RHS) {
207     return !(LHS == RHS);
208   }
209   friend bool operator<(const ExecutorAddrRange &LHS,
210                         const ExecutorAddrRange &RHS) {
211     return LHS.Start < RHS.Start ||
212            (LHS.Start == RHS.Start && LHS.End < RHS.End);
213   }
214   friend bool operator<=(const ExecutorAddrRange &LHS,
215                          const ExecutorAddrRange &RHS) {
216     return LHS.Start < RHS.Start ||
217            (LHS.Start == RHS.Start && LHS.End <= RHS.End);
218   }
219   friend bool operator>(const ExecutorAddrRange &LHS,
220                         const ExecutorAddrRange &RHS) {
221     return LHS.Start > RHS.Start ||
222            (LHS.Start == RHS.Start && LHS.End > RHS.End);
223   }
224   friend bool operator>=(const ExecutorAddrRange &LHS,
225                          const ExecutorAddrRange &RHS) {
226     return LHS.Start > RHS.Start ||
227            (LHS.Start == RHS.Start && LHS.End >= RHS.End);
228   }
229 
230   bool contains(ExecutorAddr Addr) const { return Start <= Addr && Addr < End; }
231   bool overlaps(const ExecutorAddrRange &Other) {
232     return !(Other.End <= Start || End <= Other.Start);
233   }
234 
235   ExecutorAddr Start;
236   ExecutorAddr End;
237 };
238 
239 inline raw_ostream &operator<<(raw_ostream &OS, const ExecutorAddr &A) {
240   return OS << formatv("{0:x}", A.getValue());
241 }
242 
243 inline raw_ostream &operator<<(raw_ostream &OS, const ExecutorAddrRange &R) {
244   return OS << formatv("{0:x} -- {1:x}", R.Start.getValue(), R.End.getValue());
245 }
246 
247 namespace shared {
248 
249 class SPSExecutorAddr {};
250 
251 /// SPS serializatior for ExecutorAddr.
252 template <> class SPSSerializationTraits<SPSExecutorAddr, ExecutorAddr> {
253 public:
254   static size_t size(const ExecutorAddr &EA) {
255     return SPSArgList<uint64_t>::size(EA.getValue());
256   }
257 
258   static bool serialize(SPSOutputBuffer &BOB, const ExecutorAddr &EA) {
259     return SPSArgList<uint64_t>::serialize(BOB, EA.getValue());
260   }
261 
262   static bool deserialize(SPSInputBuffer &BIB, ExecutorAddr &EA) {
263     uint64_t Tmp;
264     if (!SPSArgList<uint64_t>::deserialize(BIB, Tmp))
265       return false;
266     EA = ExecutorAddr(Tmp);
267     return true;
268   }
269 };
270 
271 using SPSExecutorAddrRange = SPSTuple<SPSExecutorAddr, SPSExecutorAddr>;
272 
273 /// Serialization traits for address ranges.
274 template <>
275 class SPSSerializationTraits<SPSExecutorAddrRange, ExecutorAddrRange> {
276 public:
277   static size_t size(const ExecutorAddrRange &Value) {
278     return SPSArgList<SPSExecutorAddr, SPSExecutorAddr>::size(Value.Start,
279                                                               Value.End);
280   }
281 
282   static bool serialize(SPSOutputBuffer &BOB, const ExecutorAddrRange &Value) {
283     return SPSArgList<SPSExecutorAddr, SPSExecutorAddr>::serialize(
284         BOB, Value.Start, Value.End);
285   }
286 
287   static bool deserialize(SPSInputBuffer &BIB, ExecutorAddrRange &Value) {
288     return SPSArgList<SPSExecutorAddr, SPSExecutorAddr>::deserialize(
289         BIB, Value.Start, Value.End);
290   }
291 };
292 
293 using SPSExecutorAddrRangeSequence = SPSSequence<SPSExecutorAddrRange>;
294 
295 } // End namespace shared.
296 } // End namespace orc.
297 
298 // Provide DenseMapInfo for ExecutorAddrs.
299 template <> struct DenseMapInfo<orc::ExecutorAddr> {
300   static inline orc::ExecutorAddr getEmptyKey() {
301     return orc::ExecutorAddr(DenseMapInfo<uint64_t>::getEmptyKey());
302   }
303   static inline orc::ExecutorAddr getTombstoneKey() {
304     return orc::ExecutorAddr(DenseMapInfo<uint64_t>::getTombstoneKey());
305   }
306 
307   static unsigned getHashValue(const orc::ExecutorAddr &Addr) {
308     return DenseMapInfo<uint64_t>::getHashValue(Addr.getValue());
309   }
310 
311   static bool isEqual(const orc::ExecutorAddr &LHS,
312                       const orc::ExecutorAddr &RHS) {
313     return DenseMapInfo<uint64_t>::isEqual(LHS.getValue(), RHS.getValue());
314   }
315 };
316 
317 } // End namespace llvm.
318 
319 #endif // LLVM_EXECUTIONENGINE_ORC_SHARED_EXECUTORADDRESS_H
320