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 // This file was derived from
12 // llvm/include/llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h.
13 //
14 //===----------------------------------------------------------------------===//
15 
16 #ifndef ORC_RT_EXECUTOR_ADDRESS_H
17 #define ORC_RT_EXECUTOR_ADDRESS_H
18 
19 #include "adt.h"
20 #include "simple_packed_serialization.h"
21 
22 #include <cassert>
23 #include <type_traits>
24 
25 namespace __orc_rt {
26 
27 using ExecutorAddrDiff = uint64_t;
28 
29 /// Represents an address in the executor process.
30 class ExecutorAddr {
31 public:
32   /// A wrap/unwrap function that leaves pointers unmodified.
33   template <typename T> using rawPtr = __orc_rt::identity<T *>;
34 
35   /// Default wrap function to use on this host.
36   template <typename T> using defaultWrap = rawPtr<T>;
37 
38   /// Default unwrap function to use on this host.
39   template <typename T> using defaultUnwrap = rawPtr<T>;
40 
41   /// Merges a tag into the raw address value:
42   ///   P' = P | (TagValue << TagOffset).
43   class Tag {
44   public:
Tag(uintptr_t TagValue,uintptr_t TagOffset)45     constexpr Tag(uintptr_t TagValue, uintptr_t TagOffset)
46         : TagMask(TagValue << TagOffset) {}
47 
operator()48     template <typename T> constexpr T *operator()(T *P) {
49       return reinterpret_cast<T *>(reinterpret_cast<uintptr_t>(P) | TagMask);
50     }
51 
52   private:
53     uintptr_t TagMask;
54   };
55 
56   /// Strips a tag of the given length from the given offset within the pointer:
57   /// P' = P & ~(((1 << TagLen) -1) << TagOffset)
58   class Untag {
59   public:
Untag(uintptr_t TagLen,uintptr_t TagOffset)60     constexpr Untag(uintptr_t TagLen, uintptr_t TagOffset)
61         : UntagMask(~(((uintptr_t(1) << TagLen) - 1) << TagOffset)) {}
62 
operator()63     template <typename T> constexpr T *operator()(T *P) {
64       return reinterpret_cast<T *>(reinterpret_cast<uintptr_t>(P) & UntagMask);
65     }
66 
67   private:
68     uintptr_t UntagMask;
69   };
70 
71   ExecutorAddr() = default;
ExecutorAddr(uint64_t Addr)72   explicit ExecutorAddr(uint64_t Addr) : Addr(Addr) {}
73 
74   /// Create an ExecutorAddr from the given pointer.
75   template <typename T, typename UnwrapFn = defaultUnwrap<T>>
76   static ExecutorAddr fromPtr(T *Ptr, UnwrapFn &&Unwrap = UnwrapFn()) {
77     return ExecutorAddr(
78         static_cast<uint64_t>(reinterpret_cast<uintptr_t>(Unwrap(Ptr))));
79   }
80 
81   /// Cast this ExecutorAddr to a pointer of the given type.
82   template <typename T, typename WrapFn = defaultWrap<std::remove_pointer_t<T>>>
83   std::enable_if_t<std::is_pointer<T>::value, T>
84   toPtr(WrapFn &&Wrap = WrapFn()) const {
85     uintptr_t IntPtr = static_cast<uintptr_t>(Addr);
86     assert(IntPtr == Addr && "ExecutorAddr value out of range for uintptr_t");
87     return Wrap(reinterpret_cast<T>(IntPtr));
88   }
89 
90   /// Cast this ExecutorAddr to a pointer of the given function type.
91   template <typename T, typename WrapFn = defaultWrap<T>>
92   std::enable_if_t<std::is_function<T>::value, T *>
93   toPtr(WrapFn &&Wrap = WrapFn()) const {
94     uintptr_t IntPtr = static_cast<uintptr_t>(Addr);
95     assert(IntPtr == Addr && "ExecutorAddr value out of range for uintptr_t");
96     return Wrap(reinterpret_cast<T *>(IntPtr));
97   }
98 
getValue()99   uint64_t getValue() const { return Addr; }
setValue(uint64_t Addr)100   void setValue(uint64_t Addr) { this->Addr = Addr; }
isNull()101   bool isNull() const { return Addr == 0; }
102 
103   explicit operator bool() const { return Addr != 0; }
104 
105   friend bool operator==(const ExecutorAddr &LHS, const ExecutorAddr &RHS) {
106     return LHS.Addr == RHS.Addr;
107   }
108 
109   friend bool operator!=(const ExecutorAddr &LHS, const ExecutorAddr &RHS) {
110     return LHS.Addr != RHS.Addr;
111   }
112 
113   friend bool operator<(const ExecutorAddr &LHS, const ExecutorAddr &RHS) {
114     return LHS.Addr < RHS.Addr;
115   }
116 
117   friend bool operator<=(const ExecutorAddr &LHS, const ExecutorAddr &RHS) {
118     return LHS.Addr <= RHS.Addr;
119   }
120 
121   friend bool operator>(const ExecutorAddr &LHS, const ExecutorAddr &RHS) {
122     return LHS.Addr > RHS.Addr;
123   }
124 
125   friend bool operator>=(const ExecutorAddr &LHS, const ExecutorAddr &RHS) {
126     return LHS.Addr >= RHS.Addr;
127   }
128 
129   ExecutorAddr &operator++() {
130     ++Addr;
131     return *this;
132   }
133   ExecutorAddr &operator--() {
134     --Addr;
135     return *this;
136   }
137   ExecutorAddr operator++(int) { return ExecutorAddr(Addr++); }
138   ExecutorAddr operator--(int) { return ExecutorAddr(Addr++); }
139 
140   ExecutorAddr &operator+=(const ExecutorAddrDiff Delta) {
141     Addr += Delta;
142     return *this;
143   }
144 
145   ExecutorAddr &operator-=(const ExecutorAddrDiff Delta) {
146     Addr -= Delta;
147     return *this;
148   }
149 
150 private:
151   uint64_t Addr = 0;
152 };
153 
154 /// Subtracting two addresses yields an offset.
155 inline ExecutorAddrDiff operator-(const ExecutorAddr &LHS,
156                                   const ExecutorAddr &RHS) {
157   return ExecutorAddrDiff(LHS.getValue() - RHS.getValue());
158 }
159 
160 /// Adding an offset and an address yields an address.
161 inline ExecutorAddr operator+(const ExecutorAddr &LHS,
162                               const ExecutorAddrDiff &RHS) {
163   return ExecutorAddr(LHS.getValue() + RHS);
164 }
165 
166 /// Adding an address and an offset yields an address.
167 inline ExecutorAddr operator+(const ExecutorAddrDiff &LHS,
168                               const ExecutorAddr &RHS) {
169   return ExecutorAddr(LHS + RHS.getValue());
170 }
171 
172 /// Represents an address range in the exceutor process.
173 struct ExecutorAddrRange {
174   ExecutorAddrRange() = default;
ExecutorAddrRangeExecutorAddrRange175   ExecutorAddrRange(ExecutorAddr Start, ExecutorAddr End)
176       : Start(Start), End(End) {}
ExecutorAddrRangeExecutorAddrRange177   ExecutorAddrRange(ExecutorAddr Start, ExecutorAddrDiff Size)
178       : Start(Start), End(Start + Size) {}
179 
emptyExecutorAddrRange180   bool empty() const { return Start == End; }
sizeExecutorAddrRange181   ExecutorAddrDiff size() const { return End - Start; }
182 
183   friend bool operator==(const ExecutorAddrRange &LHS,
184                          const ExecutorAddrRange &RHS) {
185     return LHS.Start == RHS.Start && LHS.End == RHS.End;
186   }
187   friend bool operator!=(const ExecutorAddrRange &LHS,
188                          const ExecutorAddrRange &RHS) {
189     return !(LHS == RHS);
190   }
containsExecutorAddrRange191   bool contains(ExecutorAddr Addr) const { return Start <= Addr && Addr < End; }
overlapsExecutorAddrRange192   bool overlaps(const ExecutorAddrRange &Other) {
193     return !(Other.End <= Start || End <= Other.Start);
194   }
195 
toSpanExecutorAddrRange196   template <typename T> span<T> toSpan() const {
197     assert(size() % sizeof(T) == 0 &&
198            "AddressRange is not a multiple of sizeof(T)");
199     return span<T>(Start.toPtr<T *>(), size() / sizeof(T));
200   }
201 
202   ExecutorAddr Start;
203   ExecutorAddr End;
204 };
205 
206 /// SPS serializatior for ExecutorAddr.
207 template <> class SPSSerializationTraits<SPSExecutorAddr, ExecutorAddr> {
208 public:
size(const ExecutorAddr & EA)209   static size_t size(const ExecutorAddr &EA) {
210     return SPSArgList<uint64_t>::size(EA.getValue());
211   }
212 
serialize(SPSOutputBuffer & BOB,const ExecutorAddr & EA)213   static bool serialize(SPSOutputBuffer &BOB, const ExecutorAddr &EA) {
214     return SPSArgList<uint64_t>::serialize(BOB, EA.getValue());
215   }
216 
deserialize(SPSInputBuffer & BIB,ExecutorAddr & EA)217   static bool deserialize(SPSInputBuffer &BIB, ExecutorAddr &EA) {
218     uint64_t Tmp;
219     if (!SPSArgList<uint64_t>::deserialize(BIB, Tmp))
220       return false;
221     EA = ExecutorAddr(Tmp);
222     return true;
223   }
224 };
225 
226 using SPSExecutorAddrRange = SPSTuple<SPSExecutorAddr, SPSExecutorAddr>;
227 
228 /// Serialization traits for address ranges.
229 template <>
230 class SPSSerializationTraits<SPSExecutorAddrRange, ExecutorAddrRange> {
231 public:
size(const ExecutorAddrRange & Value)232   static size_t size(const ExecutorAddrRange &Value) {
233     return SPSArgList<SPSExecutorAddr, SPSExecutorAddr>::size(Value.Start,
234                                                               Value.End);
235   }
236 
serialize(SPSOutputBuffer & BOB,const ExecutorAddrRange & Value)237   static bool serialize(SPSOutputBuffer &BOB, const ExecutorAddrRange &Value) {
238     return SPSArgList<SPSExecutorAddr, SPSExecutorAddr>::serialize(
239         BOB, Value.Start, Value.End);
240   }
241 
deserialize(SPSInputBuffer & BIB,ExecutorAddrRange & Value)242   static bool deserialize(SPSInputBuffer &BIB, ExecutorAddrRange &Value) {
243     return SPSArgList<SPSExecutorAddr, SPSExecutorAddr>::deserialize(
244         BIB, Value.Start, Value.End);
245   }
246 };
247 
248 using SPSExecutorAddrRangeSequence = SPSSequence<SPSExecutorAddrRange>;
249 
250 } // End namespace __orc_rt
251 
252 namespace std {
253 
254 // Make ExecutorAddr hashable.
255 template <> struct hash<__orc_rt::ExecutorAddr> {
256   size_t operator()(const __orc_rt::ExecutorAddr &A) const {
257     return hash<uint64_t>()(A.getValue());
258   }
259 };
260 
261 } // namespace std
262 
263 #endif // ORC_RT_EXECUTOR_ADDRESS_H
264