blob: 86ab17363e19dfbb81ffdc8ce75e41b00d92a26a [file] [log] [blame]
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01001//===- JITSymbol.h - JIT symbol abstraction ---------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// Abstraction for target process addresses.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_EXECUTIONENGINE_JITSYMBOL_H
15#define LLVM_EXECUTIONENGINE_JITSYMBOL_H
16
17#include <algorithm>
18#include <cassert>
19#include <cstddef>
20#include <cstdint>
21#include <functional>
22#include <map>
23#include <set>
24#include <string>
25
26#include "llvm/ADT/StringRef.h"
27#include "llvm/Support/Error.h"
28
29namespace llvm {
30
31class GlobalValue;
32
33namespace object {
34
35class BasicSymbolRef;
36
37} // end namespace object
38
39/// @brief Represents an address in the target process's address space.
40using JITTargetAddress = uint64_t;
41
42/// @brief Flags for symbols in the JIT.
43class JITSymbolFlags {
44public:
45 using UnderlyingType = uint8_t;
46 using TargetFlagsType = uint64_t;
47
48 enum FlagNames : UnderlyingType {
49 None = 0,
50 HasError = 1U << 0,
51 Weak = 1U << 1,
52 Common = 1U << 2,
53 Absolute = 1U << 3,
54 Exported = 1U << 4,
55 NotMaterialized = 1U << 5
56 };
57
58 static JITSymbolFlags stripTransientFlags(JITSymbolFlags Orig) {
59 return static_cast<FlagNames>(Orig.Flags & ~NotMaterialized);
60 }
61
62 /// @brief Default-construct a JITSymbolFlags instance.
63 JITSymbolFlags() = default;
64
65 /// @brief Construct a JITSymbolFlags instance from the given flags.
66 JITSymbolFlags(FlagNames Flags) : Flags(Flags) {}
67
68 /// @brief Construct a JITSymbolFlags instance from the given flags and target
69 /// flags.
70 JITSymbolFlags(FlagNames Flags, TargetFlagsType TargetFlags)
71 : Flags(Flags), TargetFlags(TargetFlags) {}
72
73 /// @brief Return true if there was an error retrieving this symbol.
74 bool hasError() const {
75 return (Flags & HasError) == HasError;
76 }
77
78 /// @brief Returns true if this symbol has been fully materialized (i.e. is
79 /// callable).
80 bool isMaterialized() const { return !(Flags & NotMaterialized); }
81
82 /// @brief Returns true if the Weak flag is set.
83 bool isWeak() const {
84 return (Flags & Weak) == Weak;
85 }
86
87 /// @brief Returns true if the Common flag is set.
88 bool isCommon() const {
89 return (Flags & Common) == Common;
90 }
91
92 /// @brief Returns true if the symbol isn't weak or common.
93 bool isStrong() const {
94 return !isWeak() && !isCommon();
95 }
96
97 /// @brief Returns true if the Exported flag is set.
98 bool isExported() const {
99 return (Flags & Exported) == Exported;
100 }
101
102 /// @brief Implicitly convert to the underlying flags type.
103 operator UnderlyingType&() { return Flags; }
104
105 /// @brief Implicitly convert to the underlying flags type.
106 operator const UnderlyingType&() const { return Flags; }
107
108 /// @brief Return a reference to the target-specific flags.
109 TargetFlagsType& getTargetFlags() { return TargetFlags; }
110
111 /// @brief Return a reference to the target-specific flags.
112 const TargetFlagsType& getTargetFlags() const { return TargetFlags; }
113
114 /// Construct a JITSymbolFlags value based on the flags of the given global
115 /// value.
116 static JITSymbolFlags fromGlobalValue(const GlobalValue &GV);
117
118 /// Construct a JITSymbolFlags value based on the flags of the given libobject
119 /// symbol.
120 static JITSymbolFlags fromObjectSymbol(const object::BasicSymbolRef &Symbol);
121
122private:
123 UnderlyingType Flags = None;
124 TargetFlagsType TargetFlags = 0;
125};
126
127/// @brief ARM-specific JIT symbol flags.
128/// FIXME: This should be moved into a target-specific header.
129class ARMJITSymbolFlags {
130public:
131 ARMJITSymbolFlags() = default;
132
133 enum FlagNames {
134 None = 0,
135 Thumb = 1 << 0
136 };
137
138 operator JITSymbolFlags::TargetFlagsType&() { return Flags; }
139
140 static ARMJITSymbolFlags fromObjectSymbol(
141 const object::BasicSymbolRef &Symbol);
142private:
143 JITSymbolFlags::TargetFlagsType Flags = 0;
144};
145
146/// @brief Represents a symbol that has been evaluated to an address already.
147class JITEvaluatedSymbol {
148public:
149 JITEvaluatedSymbol() = default;
150
151 /// @brief Create a 'null' symbol.
152 JITEvaluatedSymbol(std::nullptr_t) {}
153
154 /// @brief Create a symbol for the given address and flags.
155 JITEvaluatedSymbol(JITTargetAddress Address, JITSymbolFlags Flags)
156 : Address(Address), Flags(Flags) {}
157
158 /// @brief An evaluated symbol converts to 'true' if its address is non-zero.
159 explicit operator bool() const { return Address != 0; }
160
161 /// @brief Return the address of this symbol.
162 JITTargetAddress getAddress() const { return Address; }
163
164 /// @brief Return the flags for this symbol.
165 JITSymbolFlags getFlags() const { return Flags; }
166
167private:
168 JITTargetAddress Address = 0;
169 JITSymbolFlags Flags;
170};
171
172/// @brief Represents a symbol in the JIT.
173class JITSymbol {
174public:
175 using GetAddressFtor = std::function<Expected<JITTargetAddress>()>;
176
177 /// @brief Create a 'null' symbol, used to represent a "symbol not found"
178 /// result from a successful (non-erroneous) lookup.
179 JITSymbol(std::nullptr_t)
180 : CachedAddr(0) {}
181
182 /// @brief Create a JITSymbol representing an error in the symbol lookup
183 /// process (e.g. a network failure during a remote lookup).
184 JITSymbol(Error Err)
185 : Err(std::move(Err)), Flags(JITSymbolFlags::HasError) {}
186
187 /// @brief Create a symbol for a definition with a known address.
188 JITSymbol(JITTargetAddress Addr, JITSymbolFlags Flags)
189 : CachedAddr(Addr), Flags(Flags) {}
190
191 /// @brief Construct a JITSymbol from a JITEvaluatedSymbol.
192 JITSymbol(JITEvaluatedSymbol Sym)
193 : CachedAddr(Sym.getAddress()), Flags(Sym.getFlags()) {}
194
195 /// @brief Create a symbol for a definition that doesn't have a known address
196 /// yet.
197 /// @param GetAddress A functor to materialize a definition (fixing the
198 /// address) on demand.
199 ///
200 /// This constructor allows a JIT layer to provide a reference to a symbol
201 /// definition without actually materializing the definition up front. The
202 /// user can materialize the definition at any time by calling the getAddress
203 /// method.
204 JITSymbol(GetAddressFtor GetAddress, JITSymbolFlags Flags)
205 : GetAddress(std::move(GetAddress)), CachedAddr(0), Flags(Flags) {}
206
207 JITSymbol(const JITSymbol&) = delete;
208 JITSymbol& operator=(const JITSymbol&) = delete;
209
210 JITSymbol(JITSymbol &&Other)
211 : GetAddress(std::move(Other.GetAddress)), Flags(std::move(Other.Flags)) {
212 if (Flags.hasError())
213 Err = std::move(Other.Err);
214 else
215 CachedAddr = std::move(Other.CachedAddr);
216 }
217
218 JITSymbol& operator=(JITSymbol &&Other) {
219 GetAddress = std::move(Other.GetAddress);
220 Flags = std::move(Other.Flags);
221 if (Flags.hasError())
222 Err = std::move(Other.Err);
223 else
224 CachedAddr = std::move(Other.CachedAddr);
225 return *this;
226 }
227
228 ~JITSymbol() {
229 if (Flags.hasError())
230 Err.~Error();
231 else
232 CachedAddr.~JITTargetAddress();
233 }
234
235 /// @brief Returns true if the symbol exists, false otherwise.
236 explicit operator bool() const {
237 return !Flags.hasError() && (CachedAddr || GetAddress);
238 }
239
240 /// @brief Move the error field value out of this JITSymbol.
241 Error takeError() {
242 if (Flags.hasError())
243 return std::move(Err);
244 return Error::success();
245 }
246
247 /// @brief Get the address of the symbol in the target address space. Returns
248 /// '0' if the symbol does not exist.
249 Expected<JITTargetAddress> getAddress() {
250 assert(!Flags.hasError() && "getAddress called on error value");
251 if (GetAddress) {
252 if (auto CachedAddrOrErr = GetAddress()) {
253 GetAddress = nullptr;
254 CachedAddr = *CachedAddrOrErr;
255 assert(CachedAddr && "Symbol could not be materialized.");
256 } else
257 return CachedAddrOrErr.takeError();
258 }
259 return CachedAddr;
260 }
261
262 JITSymbolFlags getFlags() const { return Flags; }
263
264private:
265 GetAddressFtor GetAddress;
266 union {
267 JITTargetAddress CachedAddr;
268 Error Err;
269 };
270 JITSymbolFlags Flags;
271};
272
273/// @brief Symbol resolution interface.
274///
275/// Allows symbol flags and addresses to be looked up by name.
276/// Symbol queries are done in bulk (i.e. you request resolution of a set of
277/// symbols, rather than a single one) to reduce IPC overhead in the case of
278/// remote JITing, and expose opportunities for parallel compilation.
279class JITSymbolResolver {
280public:
281 using LookupSet = std::set<StringRef>;
282 using LookupResult = std::map<StringRef, JITEvaluatedSymbol>;
283 using LookupFlagsResult = std::map<StringRef, JITSymbolFlags>;
284
285 virtual ~JITSymbolResolver() = default;
286
287 /// @brief Returns the fully resolved address and flags for each of the given
288 /// symbols.
289 ///
290 /// This method will return an error if any of the given symbols can not be
291 /// resolved, or if the resolution process itself triggers an error.
292 virtual Expected<LookupResult> lookup(const LookupSet &Symbols) = 0;
293
294 /// @brief Returns the symbol flags for each of the given symbols.
295 ///
296 /// This method does NOT return an error if any of the given symbols is
297 /// missing. Instead, that symbol will be left out of the result map.
298 virtual Expected<LookupFlagsResult> lookupFlags(const LookupSet &Symbols) = 0;
299
300private:
301 virtual void anchor();
302};
303
304/// \brief Legacy symbol resolution interface.
305class LegacyJITSymbolResolver : public JITSymbolResolver {
306public:
307 /// @brief Performs lookup by, for each symbol, first calling
308 /// findSymbolInLogicalDylib and if that fails calling
309 /// findSymbol.
310 Expected<LookupResult> lookup(const LookupSet &Symbols) final;
311
312 /// @brief Performs flags lookup by calling findSymbolInLogicalDylib and
313 /// returning the flags value for that symbol.
314 Expected<LookupFlagsResult> lookupFlags(const LookupSet &Symbols) final;
315
316 /// This method returns the address of the specified symbol if it exists
317 /// within the logical dynamic library represented by this JITSymbolResolver.
318 /// Unlike findSymbol, queries through this interface should return addresses
319 /// for hidden symbols.
320 ///
321 /// This is of particular importance for the Orc JIT APIs, which support lazy
322 /// compilation by breaking up modules: Each of those broken out modules
323 /// must be able to resolve hidden symbols provided by the others. Clients
324 /// writing memory managers for MCJIT can usually ignore this method.
325 ///
326 /// This method will be queried by RuntimeDyld when checking for previous
327 /// definitions of common symbols.
328 virtual JITSymbol findSymbolInLogicalDylib(const std::string &Name) = 0;
329
330 /// This method returns the address of the specified function or variable.
331 /// It is used to resolve symbols during module linking.
332 ///
333 /// If the returned symbol's address is equal to ~0ULL then RuntimeDyld will
334 /// skip all relocations for that symbol, and the client will be responsible
335 /// for handling them manually.
336 virtual JITSymbol findSymbol(const std::string &Name) = 0;
337
338private:
339 virtual void anchor();
340};
341
342} // end namespace llvm
343
344#endif // LLVM_EXECUTIONENGINE_JITSYMBOL_H