blob: 18b972ed8291b8b269a387d3f37e2a73cdfbcda4 [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
Andrew Scull0372a572018-11-16 15:47:06 +000026#include "llvm/ADT/BitmaskEnum.h"
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010027#include "llvm/ADT/StringRef.h"
28#include "llvm/Support/Error.h"
29
30namespace llvm {
31
32class GlobalValue;
33
34namespace object {
35
Andrew Scullcdfcccc2018-10-05 20:58:37 +010036class SymbolRef;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010037
38} // end namespace object
39
Andrew Scullcdfcccc2018-10-05 20:58:37 +010040/// Represents an address in the target process's address space.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010041using JITTargetAddress = uint64_t;
42
Andrew Scullcdfcccc2018-10-05 20:58:37 +010043/// Flags for symbols in the JIT.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010044class JITSymbolFlags {
45public:
46 using UnderlyingType = uint8_t;
47 using TargetFlagsType = uint64_t;
48
49 enum FlagNames : UnderlyingType {
50 None = 0,
51 HasError = 1U << 0,
52 Weak = 1U << 1,
53 Common = 1U << 2,
54 Absolute = 1U << 3,
55 Exported = 1U << 4,
Andrew Scullcdfcccc2018-10-05 20:58:37 +010056 Callable = 1U << 5,
57 Lazy = 1U << 6,
Andrew Scull0372a572018-11-16 15:47:06 +000058 Materializing = 1U << 7,
59 LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ Materializing)
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010060 };
61
62 static JITSymbolFlags stripTransientFlags(JITSymbolFlags Orig) {
Andrew Scullcdfcccc2018-10-05 20:58:37 +010063 return static_cast<FlagNames>(Orig.Flags & ~Lazy & ~Materializing);
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010064 }
65
Andrew Scullcdfcccc2018-10-05 20:58:37 +010066 /// Default-construct a JITSymbolFlags instance.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010067 JITSymbolFlags() = default;
68
Andrew Scullcdfcccc2018-10-05 20:58:37 +010069 /// Construct a JITSymbolFlags instance from the given flags.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010070 JITSymbolFlags(FlagNames Flags) : Flags(Flags) {}
71
Andrew Scullcdfcccc2018-10-05 20:58:37 +010072 /// Construct a JITSymbolFlags instance from the given flags and target
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010073 /// flags.
74 JITSymbolFlags(FlagNames Flags, TargetFlagsType TargetFlags)
75 : Flags(Flags), TargetFlags(TargetFlags) {}
76
Andrew Scull0372a572018-11-16 15:47:06 +000077 /// Implicitly convert to bool. Returs true if any flag is set.
78 explicit operator bool() const { return Flags != None || TargetFlags != 0; }
79
80 /// Compare for equality.
81 bool operator==(const JITSymbolFlags &RHS) const {
82 return Flags == RHS.Flags && TargetFlags == RHS.TargetFlags;
83 }
84
85 /// Bitwise AND-assignment for FlagNames.
86 JITSymbolFlags &operator&=(const FlagNames &RHS) {
87 Flags &= RHS;
88 return *this;
89 }
90
91 /// Bitwise OR-assignment for FlagNames.
92 JITSymbolFlags &operator|=(const FlagNames &RHS) {
93 Flags |= RHS;
94 return *this;
95 }
96
Andrew Scullcdfcccc2018-10-05 20:58:37 +010097 /// Return true if there was an error retrieving this symbol.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010098 bool hasError() const {
99 return (Flags & HasError) == HasError;
100 }
101
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100102 /// Returns true if this is a lazy symbol.
103 /// This flag is used internally by the JIT APIs to track
104 /// materialization states.
105 bool isLazy() const { return Flags & Lazy; }
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100106
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100107 /// Returns true if this symbol is in the process of being
108 /// materialized.
109 bool isMaterializing() const { return Flags & Materializing; }
110
111 /// Returns true if this symbol is fully materialized.
112 /// (i.e. neither lazy, nor materializing).
113 bool isMaterialized() const { return !(Flags & (Lazy | Materializing)); }
114
115 /// Returns true if the Weak flag is set.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100116 bool isWeak() const {
117 return (Flags & Weak) == Weak;
118 }
119
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100120 /// Returns true if the Common flag is set.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100121 bool isCommon() const {
122 return (Flags & Common) == Common;
123 }
124
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100125 /// Returns true if the symbol isn't weak or common.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100126 bool isStrong() const {
127 return !isWeak() && !isCommon();
128 }
129
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100130 /// Returns true if the Exported flag is set.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100131 bool isExported() const {
132 return (Flags & Exported) == Exported;
133 }
134
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100135 /// Returns true if the given symbol is known to be callable.
136 bool isCallable() const { return (Flags & Callable) == Callable; }
137
Andrew Scull0372a572018-11-16 15:47:06 +0000138 /// Get the underlying flags value as an integer.
139 UnderlyingType getRawFlagsValue() const {
140 return static_cast<UnderlyingType>(Flags);
141 }
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100142
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100143 /// Return a reference to the target-specific flags.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100144 TargetFlagsType& getTargetFlags() { return TargetFlags; }
145
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100146 /// Return a reference to the target-specific flags.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100147 const TargetFlagsType& getTargetFlags() const { return TargetFlags; }
148
149 /// Construct a JITSymbolFlags value based on the flags of the given global
150 /// value.
151 static JITSymbolFlags fromGlobalValue(const GlobalValue &GV);
152
153 /// Construct a JITSymbolFlags value based on the flags of the given libobject
154 /// symbol.
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100155 static Expected<JITSymbolFlags>
156 fromObjectSymbol(const object::SymbolRef &Symbol);
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100157
158private:
Andrew Scull0372a572018-11-16 15:47:06 +0000159 FlagNames Flags = None;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100160 TargetFlagsType TargetFlags = 0;
161};
162
Andrew Scull0372a572018-11-16 15:47:06 +0000163inline JITSymbolFlags operator&(const JITSymbolFlags &LHS,
164 const JITSymbolFlags::FlagNames &RHS) {
165 JITSymbolFlags Tmp = LHS;
166 Tmp &= RHS;
167 return Tmp;
168}
169
170inline JITSymbolFlags operator|(const JITSymbolFlags &LHS,
171 const JITSymbolFlags::FlagNames &RHS) {
172 JITSymbolFlags Tmp = LHS;
173 Tmp |= RHS;
174 return Tmp;
175}
176
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100177/// ARM-specific JIT symbol flags.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100178/// FIXME: This should be moved into a target-specific header.
179class ARMJITSymbolFlags {
180public:
181 ARMJITSymbolFlags() = default;
182
183 enum FlagNames {
184 None = 0,
185 Thumb = 1 << 0
186 };
187
188 operator JITSymbolFlags::TargetFlagsType&() { return Flags; }
189
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100190 static ARMJITSymbolFlags fromObjectSymbol(const object::SymbolRef &Symbol);
191
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100192private:
193 JITSymbolFlags::TargetFlagsType Flags = 0;
194};
195
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100196/// Represents a symbol that has been evaluated to an address already.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100197class JITEvaluatedSymbol {
198public:
199 JITEvaluatedSymbol() = default;
200
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100201 /// Create a 'null' symbol.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100202 JITEvaluatedSymbol(std::nullptr_t) {}
203
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100204 /// Create a symbol for the given address and flags.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100205 JITEvaluatedSymbol(JITTargetAddress Address, JITSymbolFlags Flags)
206 : Address(Address), Flags(Flags) {}
207
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100208 /// An evaluated symbol converts to 'true' if its address is non-zero.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100209 explicit operator bool() const { return Address != 0; }
210
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100211 /// Return the address of this symbol.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100212 JITTargetAddress getAddress() const { return Address; }
213
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100214 /// Return the flags for this symbol.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100215 JITSymbolFlags getFlags() const { return Flags; }
216
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100217 /// Set the flags for this symbol.
218 void setFlags(JITSymbolFlags Flags) { this->Flags = std::move(Flags); }
219
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100220private:
221 JITTargetAddress Address = 0;
222 JITSymbolFlags Flags;
223};
224
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100225/// Represents a symbol in the JIT.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100226class JITSymbol {
227public:
228 using GetAddressFtor = std::function<Expected<JITTargetAddress>()>;
229
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100230 /// Create a 'null' symbol, used to represent a "symbol not found"
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100231 /// result from a successful (non-erroneous) lookup.
232 JITSymbol(std::nullptr_t)
233 : CachedAddr(0) {}
234
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100235 /// Create a JITSymbol representing an error in the symbol lookup
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100236 /// process (e.g. a network failure during a remote lookup).
237 JITSymbol(Error Err)
238 : Err(std::move(Err)), Flags(JITSymbolFlags::HasError) {}
239
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100240 /// Create a symbol for a definition with a known address.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100241 JITSymbol(JITTargetAddress Addr, JITSymbolFlags Flags)
242 : CachedAddr(Addr), Flags(Flags) {}
243
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100244 /// Construct a JITSymbol from a JITEvaluatedSymbol.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100245 JITSymbol(JITEvaluatedSymbol Sym)
246 : CachedAddr(Sym.getAddress()), Flags(Sym.getFlags()) {}
247
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100248 /// Create a symbol for a definition that doesn't have a known address
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100249 /// yet.
250 /// @param GetAddress A functor to materialize a definition (fixing the
251 /// address) on demand.
252 ///
253 /// This constructor allows a JIT layer to provide a reference to a symbol
254 /// definition without actually materializing the definition up front. The
255 /// user can materialize the definition at any time by calling the getAddress
256 /// method.
257 JITSymbol(GetAddressFtor GetAddress, JITSymbolFlags Flags)
258 : GetAddress(std::move(GetAddress)), CachedAddr(0), Flags(Flags) {}
259
260 JITSymbol(const JITSymbol&) = delete;
261 JITSymbol& operator=(const JITSymbol&) = delete;
262
263 JITSymbol(JITSymbol &&Other)
264 : GetAddress(std::move(Other.GetAddress)), Flags(std::move(Other.Flags)) {
265 if (Flags.hasError())
266 Err = std::move(Other.Err);
267 else
268 CachedAddr = std::move(Other.CachedAddr);
269 }
270
271 JITSymbol& operator=(JITSymbol &&Other) {
272 GetAddress = std::move(Other.GetAddress);
273 Flags = std::move(Other.Flags);
274 if (Flags.hasError())
275 Err = std::move(Other.Err);
276 else
277 CachedAddr = std::move(Other.CachedAddr);
278 return *this;
279 }
280
281 ~JITSymbol() {
282 if (Flags.hasError())
283 Err.~Error();
284 else
285 CachedAddr.~JITTargetAddress();
286 }
287
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100288 /// Returns true if the symbol exists, false otherwise.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100289 explicit operator bool() const {
290 return !Flags.hasError() && (CachedAddr || GetAddress);
291 }
292
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100293 /// Move the error field value out of this JITSymbol.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100294 Error takeError() {
295 if (Flags.hasError())
296 return std::move(Err);
297 return Error::success();
298 }
299
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100300 /// Get the address of the symbol in the target address space. Returns
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100301 /// '0' if the symbol does not exist.
302 Expected<JITTargetAddress> getAddress() {
303 assert(!Flags.hasError() && "getAddress called on error value");
304 if (GetAddress) {
305 if (auto CachedAddrOrErr = GetAddress()) {
306 GetAddress = nullptr;
307 CachedAddr = *CachedAddrOrErr;
308 assert(CachedAddr && "Symbol could not be materialized.");
309 } else
310 return CachedAddrOrErr.takeError();
311 }
312 return CachedAddr;
313 }
314
315 JITSymbolFlags getFlags() const { return Flags; }
316
317private:
318 GetAddressFtor GetAddress;
319 union {
320 JITTargetAddress CachedAddr;
321 Error Err;
322 };
323 JITSymbolFlags Flags;
324};
325
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100326/// Symbol resolution interface.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100327///
328/// Allows symbol flags and addresses to be looked up by name.
329/// Symbol queries are done in bulk (i.e. you request resolution of a set of
330/// symbols, rather than a single one) to reduce IPC overhead in the case of
331/// remote JITing, and expose opportunities for parallel compilation.
332class JITSymbolResolver {
333public:
334 using LookupSet = std::set<StringRef>;
335 using LookupResult = std::map<StringRef, JITEvaluatedSymbol>;
Andrew Scull0372a572018-11-16 15:47:06 +0000336 using OnResolvedFunction = std::function<void(Expected<LookupResult>)>;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100337
338 virtual ~JITSymbolResolver() = default;
339
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100340 /// Returns the fully resolved address and flags for each of the given
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100341 /// symbols.
342 ///
343 /// This method will return an error if any of the given symbols can not be
344 /// resolved, or if the resolution process itself triggers an error.
Andrew Scull0372a572018-11-16 15:47:06 +0000345 virtual void lookup(const LookupSet &Symbols,
346 OnResolvedFunction OnResolved) = 0;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100347
Andrew Scull0372a572018-11-16 15:47:06 +0000348 /// Returns the subset of the given symbols that should be materialized by
349 /// the caller. Only weak/common symbols should be looked up, as strong
350 /// definitions are implicitly always part of the caller's responsibility.
351 virtual Expected<LookupSet>
352 getResponsibilitySet(const LookupSet &Symbols) = 0;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100353
354private:
355 virtual void anchor();
356};
357
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100358/// Legacy symbol resolution interface.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100359class LegacyJITSymbolResolver : public JITSymbolResolver {
360public:
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100361 /// Performs lookup by, for each symbol, first calling
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100362 /// findSymbolInLogicalDylib and if that fails calling
363 /// findSymbol.
Andrew Scull0372a572018-11-16 15:47:06 +0000364 void lookup(const LookupSet &Symbols, OnResolvedFunction OnResolved) final;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100365
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100366 /// Performs flags lookup by calling findSymbolInLogicalDylib and
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100367 /// returning the flags value for that symbol.
Andrew Scull0372a572018-11-16 15:47:06 +0000368 Expected<LookupSet> getResponsibilitySet(const LookupSet &Symbols) final;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100369
370 /// This method returns the address of the specified symbol if it exists
371 /// within the logical dynamic library represented by this JITSymbolResolver.
372 /// Unlike findSymbol, queries through this interface should return addresses
373 /// for hidden symbols.
374 ///
375 /// This is of particular importance for the Orc JIT APIs, which support lazy
376 /// compilation by breaking up modules: Each of those broken out modules
377 /// must be able to resolve hidden symbols provided by the others. Clients
378 /// writing memory managers for MCJIT can usually ignore this method.
379 ///
380 /// This method will be queried by RuntimeDyld when checking for previous
381 /// definitions of common symbols.
382 virtual JITSymbol findSymbolInLogicalDylib(const std::string &Name) = 0;
383
384 /// This method returns the address of the specified function or variable.
385 /// It is used to resolve symbols during module linking.
386 ///
387 /// If the returned symbol's address is equal to ~0ULL then RuntimeDyld will
388 /// skip all relocations for that symbol, and the client will be responsible
389 /// for handling them manually.
390 virtual JITSymbol findSymbol(const std::string &Name) = 0;
391
392private:
393 virtual void anchor();
394};
395
396} // end namespace llvm
397
398#endif // LLVM_EXECUTIONENGINE_JITSYMBOL_H