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 /// Represents the difference between two addresses in the executor process.
28 class ExecutorAddrDiff {
29 public:
30   ExecutorAddrDiff() = default;
31   explicit ExecutorAddrDiff(uint64_t Value) : Value(Value) {}
32 
33   uint64_t getValue() const { return Value; }
34 
35 private:
36   int64_t Value = 0;
37 };
38 
39 /// Represents an address in the executor process.
40 class ExecutorAddr {
41 public:
42   ExecutorAddr() = default;
43   explicit ExecutorAddr(uint64_t Addr) : Addr(Addr) {}
44 
45   /// Create an ExecutorAddr from the given pointer.
46   /// Warning: This should only be used when JITing in-process.
47   template <typename T> static ExecutorAddr fromPtr(T *Value) {
48     return ExecutorAddr(
49         static_cast<uint64_t>(reinterpret_cast<uintptr_t>(Value)));
50   }
51 
52   /// Cast this ExecutorAddr to a pointer of the given type.
53   /// Warning: This should only be esude when JITing in-process.
54   template <typename T> T toPtr() const {
55     static_assert(std::is_pointer<T>::value, "T must be a pointer type");
56     uintptr_t IntPtr = static_cast<uintptr_t>(Addr);
57     assert(IntPtr == Addr &&
58            "JITTargetAddress 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.getValue();
105     return *this;
106   }
107 
108   ExecutorAddr &operator-=(const ExecutorAddrDiff Delta) {
109     Addr -= Delta.getValue();
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.getValue());
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.getValue() + RHS.getValue());
133 }
134 
135 /// Represents an address range in the exceutor process.
136 struct ExecutorAddrRange {
137   ExecutorAddrRange() = default;
138   ExecutorAddrRange(ExecutorAddr Start, ExecutorAddr End)
139       : Start(Start), End(End) {}
140   ExecutorAddrRange(ExecutorAddr Start, ExecutorAddrDiff Size)
141       : Start(Start), End(Start + Size) {}
142 
143   bool empty() const { return Start == End; }
144   ExecutorAddrDiff size() const { return End - Start; }
145 
146   friend bool operator==(const ExecutorAddrRange &LHS,
147                          const ExecutorAddrRange &RHS) {
148     return LHS.Start == RHS.Start && LHS.End == RHS.End;
149   }
150   friend bool operator!=(const ExecutorAddrRange &LHS,
151                          const ExecutorAddrRange &RHS) {
152     return !(LHS == RHS);
153   }
154   bool contains(ExecutorAddr Addr) const { return Start <= Addr && Addr < End; }
155   bool overlaps(const ExecutorAddrRange &Other) {
156     return !(Other.End <= Start || End <= Other.Start);
157   }
158 
159   template <typename T> span<T> toSpan() const {
160     assert(size().getValue() % sizeof(T) == 0 &&
161            "AddressRange is not a multiple of sizeof(T)");
162     return span<T>(Start.toPtr<T *>(), size().getValue() / sizeof(T));
163   }
164 
165   ExecutorAddr Start;
166   ExecutorAddr End;
167 };
168 
169 /// SPS serializatior for ExecutorAddr.
170 template <> class SPSSerializationTraits<SPSExecutorAddr, ExecutorAddr> {
171 public:
172   static size_t size(const ExecutorAddr &EA) {
173     return SPSArgList<uint64_t>::size(EA.getValue());
174   }
175 
176   static bool serialize(SPSOutputBuffer &BOB, const ExecutorAddr &EA) {
177     return SPSArgList<uint64_t>::serialize(BOB, EA.getValue());
178   }
179 
180   static bool deserialize(SPSInputBuffer &BIB, ExecutorAddr &EA) {
181     uint64_t Tmp;
182     if (!SPSArgList<uint64_t>::deserialize(BIB, Tmp))
183       return false;
184     EA = ExecutorAddr(Tmp);
185     return true;
186   }
187 };
188 
189 using SPSExecutorAddrRange = SPSTuple<SPSExecutorAddr, SPSExecutorAddr>;
190 
191 /// Serialization traits for address ranges.
192 template <>
193 class SPSSerializationTraits<SPSExecutorAddrRange, ExecutorAddrRange> {
194 public:
195   static size_t size(const ExecutorAddrRange &Value) {
196     return SPSArgList<SPSExecutorAddr, SPSExecutorAddr>::size(Value.Start,
197                                                               Value.End);
198   }
199 
200   static bool serialize(SPSOutputBuffer &BOB, const ExecutorAddrRange &Value) {
201     return SPSArgList<SPSExecutorAddr, SPSExecutorAddr>::serialize(
202         BOB, Value.Start, Value.End);
203   }
204 
205   static bool deserialize(SPSInputBuffer &BIB, ExecutorAddrRange &Value) {
206     return SPSArgList<SPSExecutorAddr, SPSExecutorAddr>::deserialize(
207         BIB, Value.Start, Value.End);
208   }
209 };
210 
211 using SPSExecutorAddrRangeSequence = SPSSequence<SPSExecutorAddrRange>;
212 
213 } // End namespace __orc_rt
214 
215 namespace std {
216 
217 // Make ExecutorAddr hashable.
218 template <> struct hash<__orc_rt::ExecutorAddr> {
219   size_t operator()(const __orc_rt::ExecutorAddr &A) const {
220     return hash<uint64_t>()(A.getValue());
221   }
222 };
223 
224 } // namespace std
225 
226 #endif // ORC_RT_EXECUTOR_ADDRESS_H
227