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/ExecutionEngine/Orc/Shared/SimplePackedSerialization.h"
18 #include "llvm/Support/FormatVariadic.h"
19 #include "llvm/Support/raw_ostream.h"
20 
21 #include <cassert>
22 #include <type_traits>
23 
24 namespace llvm {
25 namespace orc {
26 
27 using ExecutorAddrDiff = uint64_t;
28 
29 /// Represents an address in the executor process.
30 class ExecutorAddr {
31 public:
32   ExecutorAddr() = default;
33 
34   /// Create an ExecutorAddr from the given value.
35   explicit constexpr ExecutorAddr(uint64_t Addr) : Addr(Addr) {}
36 
37   /// Create an ExecutorAddr from the given pointer.
38   /// Warning: This should only be used when JITing in-process.
39   template <typename T> static ExecutorAddr fromPtr(T *Value) {
40     return ExecutorAddr(
41         static_cast<uint64_t>(reinterpret_cast<uintptr_t>(Value)));
42   }
43 
44   /// Cast this ExecutorAddr to a pointer of the given type.
45   /// Warning: This should only be used when JITing in-process.
46   template <typename T>
47   std::enable_if_t<std::is_pointer<T>::value, T> toPtr() const {
48     uintptr_t IntPtr = static_cast<uintptr_t>(Addr);
49     assert(IntPtr == Addr && "ExecutorAddr value out of range for uintptr_t");
50     return reinterpret_cast<T>(IntPtr);
51   }
52 
53   /// Cast this ExecutorAddr to a pointer of the given function type.
54   /// Warning: This should only be used when JITing in-process.
55   template <typename T>
56   std::enable_if_t<std::is_function<T>::value, T *> toPtr() const {
57     uintptr_t IntPtr = static_cast<uintptr_t>(Addr);
58     assert(IntPtr == Addr && "ExecutorAddr value out of range for uintptr_t");
59     return reinterpret_cast<T *>(IntPtr);
60   }
61 
62   uint64_t getValue() const { return Addr; }
63   void setValue(uint64_t Addr) { this->Addr = Addr; }
64   bool isNull() const { return Addr == 0; }
65 
66   explicit operator bool() const { return Addr != 0; }
67 
68   friend bool operator==(const ExecutorAddr &LHS, const ExecutorAddr &RHS) {
69     return LHS.Addr == RHS.Addr;
70   }
71 
72   friend bool operator!=(const ExecutorAddr &LHS, const ExecutorAddr &RHS) {
73     return LHS.Addr != RHS.Addr;
74   }
75 
76   friend bool operator<(const ExecutorAddr &LHS, const ExecutorAddr &RHS) {
77     return LHS.Addr < RHS.Addr;
78   }
79 
80   friend bool operator<=(const ExecutorAddr &LHS, const ExecutorAddr &RHS) {
81     return LHS.Addr <= RHS.Addr;
82   }
83 
84   friend bool operator>(const ExecutorAddr &LHS, const ExecutorAddr &RHS) {
85     return LHS.Addr > RHS.Addr;
86   }
87 
88   friend bool operator>=(const ExecutorAddr &LHS, const ExecutorAddr &RHS) {
89     return LHS.Addr >= RHS.Addr;
90   }
91 
92   ExecutorAddr &operator++() {
93     ++Addr;
94     return *this;
95   }
96   ExecutorAddr &operator--() {
97     --Addr;
98     return *this;
99   }
100   ExecutorAddr operator++(int) { return ExecutorAddr(Addr++); }
101   ExecutorAddr operator--(int) { return ExecutorAddr(Addr--); }
102 
103   ExecutorAddr &operator+=(const ExecutorAddrDiff &Delta) {
104     Addr += Delta;
105     return *this;
106   }
107 
108   ExecutorAddr &operator-=(const ExecutorAddrDiff &Delta) {
109     Addr -= Delta;
110     return *this;
111   }
112 
113 private:
114   uint64_t Addr = 0;
115 };
116 
117 /// Subtracting two addresses yields an offset.
118 inline ExecutorAddrDiff operator-(const ExecutorAddr &LHS,
119                                   const ExecutorAddr &RHS) {
120   return ExecutorAddrDiff(LHS.getValue() - RHS.getValue());
121 }
122 
123 /// Adding an offset and an address yields an address.
124 inline ExecutorAddr operator+(const ExecutorAddr &LHS,
125                               const ExecutorAddrDiff &RHS) {
126   return ExecutorAddr(LHS.getValue() + RHS);
127 }
128 
129 /// Adding an address and an offset yields an address.
130 inline ExecutorAddr operator+(const ExecutorAddrDiff &LHS,
131                               const ExecutorAddr &RHS) {
132   return ExecutorAddr(LHS + RHS.getValue());
133 }
134 
135 /// Subtracting an offset from an address yields an address.
136 inline ExecutorAddr operator-(const ExecutorAddr &LHS,
137                               const ExecutorAddrDiff &RHS) {
138   return ExecutorAddr(LHS.getValue() - RHS);
139 }
140 
141 /// Taking the modulus of an address and a diff yields a diff.
142 inline ExecutorAddrDiff operator%(const ExecutorAddr &LHS,
143                                   const ExecutorAddrDiff &RHS) {
144   return ExecutorAddrDiff(LHS.getValue() % RHS);
145 }
146 
147 /// Represents an address range in the exceutor process.
148 struct ExecutorAddrRange {
149   ExecutorAddrRange() = default;
150   ExecutorAddrRange(ExecutorAddr Start, ExecutorAddr End)
151       : Start(Start), End(End) {}
152   ExecutorAddrRange(ExecutorAddr Start, ExecutorAddrDiff Size)
153       : Start(Start), End(Start + Size) {}
154 
155   bool empty() const { return Start == End; }
156   ExecutorAddrDiff size() const { return End - Start; }
157 
158   friend bool operator==(const ExecutorAddrRange &LHS,
159                          const ExecutorAddrRange &RHS) {
160     return LHS.Start == RHS.Start && LHS.End == RHS.End;
161   }
162   friend bool operator!=(const ExecutorAddrRange &LHS,
163                          const ExecutorAddrRange &RHS) {
164     return !(LHS == RHS);
165   }
166   bool contains(ExecutorAddr Addr) const { return Start <= Addr && Addr < End; }
167   bool overlaps(const ExecutorAddrRange &Other) {
168     return !(Other.End <= Start || End <= Other.Start);
169   }
170 
171   ExecutorAddr Start;
172   ExecutorAddr End;
173 };
174 
175 inline raw_ostream &operator<<(raw_ostream &OS, const ExecutorAddr &A) {
176   return OS << formatv("{0:x}", A.getValue());
177 }
178 
179 inline raw_ostream &operator<<(raw_ostream &OS, const ExecutorAddrRange &R) {
180   return OS << formatv("{0:x} -- {1:x}", R.Start.getValue(), R.End.getValue());
181 }
182 
183 namespace shared {
184 
185 class SPSExecutorAddr {};
186 
187 /// SPS serializatior for ExecutorAddr.
188 template <> class SPSSerializationTraits<SPSExecutorAddr, ExecutorAddr> {
189 public:
190   static size_t size(const ExecutorAddr &EA) {
191     return SPSArgList<uint64_t>::size(EA.getValue());
192   }
193 
194   static bool serialize(SPSOutputBuffer &BOB, const ExecutorAddr &EA) {
195     return SPSArgList<uint64_t>::serialize(BOB, EA.getValue());
196   }
197 
198   static bool deserialize(SPSInputBuffer &BIB, ExecutorAddr &EA) {
199     uint64_t Tmp;
200     if (!SPSArgList<uint64_t>::deserialize(BIB, Tmp))
201       return false;
202     EA = ExecutorAddr(Tmp);
203     return true;
204   }
205 };
206 
207 using SPSExecutorAddrRange = SPSTuple<SPSExecutorAddr, SPSExecutorAddr>;
208 
209 /// Serialization traits for address ranges.
210 template <>
211 class SPSSerializationTraits<SPSExecutorAddrRange, ExecutorAddrRange> {
212 public:
213   static size_t size(const ExecutorAddrRange &Value) {
214     return SPSArgList<SPSExecutorAddr, SPSExecutorAddr>::size(Value.Start,
215                                                               Value.End);
216   }
217 
218   static bool serialize(SPSOutputBuffer &BOB, const ExecutorAddrRange &Value) {
219     return SPSArgList<SPSExecutorAddr, SPSExecutorAddr>::serialize(
220         BOB, Value.Start, Value.End);
221   }
222 
223   static bool deserialize(SPSInputBuffer &BIB, ExecutorAddrRange &Value) {
224     return SPSArgList<SPSExecutorAddr, SPSExecutorAddr>::deserialize(
225         BIB, Value.Start, Value.End);
226   }
227 };
228 
229 using SPSExecutorAddrRangeSequence = SPSSequence<SPSExecutorAddrRange>;
230 
231 } // End namespace shared.
232 } // End namespace orc.
233 
234 // Provide DenseMapInfo for ExecutorAddrs.
235 template <> struct DenseMapInfo<orc::ExecutorAddr> {
236   static inline orc::ExecutorAddr getEmptyKey() {
237     return orc::ExecutorAddr(DenseMapInfo<uint64_t>::getEmptyKey());
238   }
239   static inline orc::ExecutorAddr getTombstoneKey() {
240     return orc::ExecutorAddr(DenseMapInfo<uint64_t>::getTombstoneKey());
241   }
242 
243   static unsigned getHashValue(const orc::ExecutorAddr &Addr) {
244     return DenseMapInfo<uint64_t>::getHashValue(Addr.getValue());
245   }
246 
247   static bool isEqual(const orc::ExecutorAddr &LHS,
248                       const orc::ExecutorAddr &RHS) {
249     return DenseMapInfo<uint64_t>::isEqual(LHS.getValue(), RHS.getValue());
250   }
251 };
252 
253 } // End namespace llvm.
254 
255 #endif // LLVM_EXECUTIONENGINE_ORC_SHARED_EXECUTORADDRESS_H
256