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:
Tag(uintptr_t TagValue,uintptr_t TagOffset)46     constexpr Tag(uintptr_t TagValue, uintptr_t TagOffset)
47         : TagMask(TagValue << TagOffset) {}
48 
operator()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:
Untag(uintptr_t TagLen,uintptr_t TagOffset)61     constexpr Untag(uintptr_t TagLen, uintptr_t TagOffset)
62         : UntagMask(~(((uintptr_t(1) << TagLen) - 1) << TagOffset)) {}
63 
operator()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.
ExecutorAddr(uint64_t Addr)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 
getValue()105   uint64_t getValue() const { return Addr; }
setValue(uint64_t Addr)106   void setValue(uint64_t Addr) { this->Addr = Addr; }
isNull()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;
ExecutorAddrRangeExecutorAddrRange193   ExecutorAddrRange(ExecutorAddr Start, ExecutorAddr End)
194       : Start(Start), End(End) {}
ExecutorAddrRangeExecutorAddrRange195   ExecutorAddrRange(ExecutorAddr Start, ExecutorAddrDiff Size)
196       : Start(Start), End(Start + Size) {}
197 
emptyExecutorAddrRange198   bool empty() const { return Start == End; }
sizeExecutorAddrRange199   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   }
containsExecutorAddrRange209   bool contains(ExecutorAddr Addr) const { return Start <= Addr && Addr < End; }
overlapsExecutorAddrRange210   bool overlaps(const ExecutorAddrRange &Other) {
211     return !(Other.End <= Start || End <= Other.Start);
212   }
213 
214   ExecutorAddr Start;
215   ExecutorAddr End;
216 };
217 
218 inline raw_ostream &operator<<(raw_ostream &OS, const ExecutorAddr &A) {
219   return OS << formatv("{0:x}", A.getValue());
220 }
221 
222 inline raw_ostream &operator<<(raw_ostream &OS, const ExecutorAddrRange &R) {
223   return OS << formatv("{0:x} -- {1:x}", R.Start.getValue(), R.End.getValue());
224 }
225 
226 namespace shared {
227 
228 class SPSExecutorAddr {};
229 
230 /// SPS serializatior for ExecutorAddr.
231 template <> class SPSSerializationTraits<SPSExecutorAddr, ExecutorAddr> {
232 public:
size(const ExecutorAddr & EA)233   static size_t size(const ExecutorAddr &EA) {
234     return SPSArgList<uint64_t>::size(EA.getValue());
235   }
236 
serialize(SPSOutputBuffer & BOB,const ExecutorAddr & EA)237   static bool serialize(SPSOutputBuffer &BOB, const ExecutorAddr &EA) {
238     return SPSArgList<uint64_t>::serialize(BOB, EA.getValue());
239   }
240 
deserialize(SPSInputBuffer & BIB,ExecutorAddr & EA)241   static bool deserialize(SPSInputBuffer &BIB, ExecutorAddr &EA) {
242     uint64_t Tmp;
243     if (!SPSArgList<uint64_t>::deserialize(BIB, Tmp))
244       return false;
245     EA = ExecutorAddr(Tmp);
246     return true;
247   }
248 };
249 
250 using SPSExecutorAddrRange = SPSTuple<SPSExecutorAddr, SPSExecutorAddr>;
251 
252 /// Serialization traits for address ranges.
253 template <>
254 class SPSSerializationTraits<SPSExecutorAddrRange, ExecutorAddrRange> {
255 public:
size(const ExecutorAddrRange & Value)256   static size_t size(const ExecutorAddrRange &Value) {
257     return SPSArgList<SPSExecutorAddr, SPSExecutorAddr>::size(Value.Start,
258                                                               Value.End);
259   }
260 
serialize(SPSOutputBuffer & BOB,const ExecutorAddrRange & Value)261   static bool serialize(SPSOutputBuffer &BOB, const ExecutorAddrRange &Value) {
262     return SPSArgList<SPSExecutorAddr, SPSExecutorAddr>::serialize(
263         BOB, Value.Start, Value.End);
264   }
265 
deserialize(SPSInputBuffer & BIB,ExecutorAddrRange & Value)266   static bool deserialize(SPSInputBuffer &BIB, ExecutorAddrRange &Value) {
267     return SPSArgList<SPSExecutorAddr, SPSExecutorAddr>::deserialize(
268         BIB, Value.Start, Value.End);
269   }
270 };
271 
272 using SPSExecutorAddrRangeSequence = SPSSequence<SPSExecutorAddrRange>;
273 
274 } // End namespace shared.
275 } // End namespace orc.
276 
277 // Provide DenseMapInfo for ExecutorAddrs.
278 template <> struct DenseMapInfo<orc::ExecutorAddr> {
279   static inline orc::ExecutorAddr getEmptyKey() {
280     return orc::ExecutorAddr(DenseMapInfo<uint64_t>::getEmptyKey());
281   }
282   static inline orc::ExecutorAddr getTombstoneKey() {
283     return orc::ExecutorAddr(DenseMapInfo<uint64_t>::getTombstoneKey());
284   }
285 
286   static unsigned getHashValue(const orc::ExecutorAddr &Addr) {
287     return DenseMapInfo<uint64_t>::getHashValue(Addr.getValue());
288   }
289 
290   static bool isEqual(const orc::ExecutorAddr &LHS,
291                       const orc::ExecutorAddr &RHS) {
292     return DenseMapInfo<uint64_t>::isEqual(LHS.getValue(), RHS.getValue());
293   }
294 };
295 
296 } // End namespace llvm.
297 
298 #endif // LLVM_EXECUTIONENGINE_ORC_SHARED_EXECUTORADDRESS_H
299