LLVM  9.0.0svn
JITSymbol.h
Go to the documentation of this file.
1 //===- JITSymbol.h - JIT symbol abstraction ---------------------*- 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 // Abstraction for target process addresses.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_EXECUTIONENGINE_JITSYMBOL_H
14 #define LLVM_EXECUTIONENGINE_JITSYMBOL_H
15 
16 #include <algorithm>
17 #include <cassert>
18 #include <cstddef>
19 #include <cstdint>
20 #include <functional>
21 #include <map>
22 #include <set>
23 #include <string>
24 
25 #include "llvm/ADT/BitmaskEnum.h"
26 #include "llvm/ADT/StringRef.h"
27 #include "llvm/Support/Error.h"
28 
29 namespace llvm {
30 
31 class GlobalValue;
32 
33 namespace object {
34 
35 class SymbolRef;
36 
37 } // end namespace object
38 
39 /// Represents an address in the target process's address space.
40 using JITTargetAddress = uint64_t;
41 
42 /// Convert a JITTargetAddress to a pointer.
43 template <typename T> T jitTargetAddressToPointer(JITTargetAddress Addr) {
44  static_assert(std::is_pointer<T>::value, "T must be a pointer type");
45  uintptr_t IntPtr = static_cast<uintptr_t>(Addr);
46  assert(IntPtr == Addr && "JITTargetAddress value out of range for uintptr_t");
47  return reinterpret_cast<T>(IntPtr);
48 }
49 
50 template <typename T> JITTargetAddress pointerToJITTargetAddress(T *Ptr) {
51  return static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(Ptr));
52 }
53 
54 /// Flags for symbols in the JIT.
56 public:
57  using UnderlyingType = uint8_t;
58  using TargetFlagsType = uint64_t;
59 
61  None = 0,
62  HasError = 1U << 0,
63  Weak = 1U << 1,
64  Common = 1U << 2,
65  Absolute = 1U << 3,
66  Exported = 1U << 4,
67  Callable = 1U << 5,
68  Lazy = 1U << 6,
69  Materializing = 1U << 7,
70  LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ Materializing)
71  };
72 
74  return static_cast<FlagNames>(Orig.Flags & ~Lazy & ~Materializing);
75  }
76 
77  /// Default-construct a JITSymbolFlags instance.
78  JITSymbolFlags() = default;
79 
80  /// Construct a JITSymbolFlags instance from the given flags.
81  JITSymbolFlags(FlagNames Flags) : Flags(Flags) {}
82 
83  /// Construct a JITSymbolFlags instance from the given flags and target
84  /// flags.
86  : Flags(Flags), TargetFlags(TargetFlags) {}
87 
88  /// Implicitly convert to bool. Returs true if any flag is set.
89  explicit operator bool() const { return Flags != None || TargetFlags != 0; }
90 
91  /// Compare for equality.
92  bool operator==(const JITSymbolFlags &RHS) const {
93  return Flags == RHS.Flags && TargetFlags == RHS.TargetFlags;
94  }
95 
96  /// Bitwise AND-assignment for FlagNames.
98  Flags &= RHS;
99  return *this;
100  }
101 
102  /// Bitwise OR-assignment for FlagNames.
104  Flags |= RHS;
105  return *this;
106  }
107 
108  /// Return true if there was an error retrieving this symbol.
109  bool hasError() const {
110  return (Flags & HasError) == HasError;
111  }
112 
113  /// Returns true if this is a lazy symbol.
114  /// This flag is used internally by the JIT APIs to track
115  /// materialization states.
116  bool isLazy() const { return Flags & Lazy; }
117 
118  /// Returns true if this symbol is in the process of being
119  /// materialized.
120  bool isMaterializing() const { return Flags & Materializing; }
121 
122  /// Returns true if this symbol is fully materialized.
123  /// (i.e. neither lazy, nor materializing).
124  bool isMaterialized() const { return !(Flags & (Lazy | Materializing)); }
125 
126  /// Returns true if the Weak flag is set.
127  bool isWeak() const {
128  return (Flags & Weak) == Weak;
129  }
130 
131  /// Returns true if the Common flag is set.
132  bool isCommon() const {
133  return (Flags & Common) == Common;
134  }
135 
136  /// Returns true if the symbol isn't weak or common.
137  bool isStrong() const {
138  return !isWeak() && !isCommon();
139  }
140 
141  /// Returns true if the Exported flag is set.
142  bool isExported() const {
143  return (Flags & Exported) == Exported;
144  }
145 
146  /// Returns true if the given symbol is known to be callable.
147  bool isCallable() const { return (Flags & Callable) == Callable; }
148 
149  /// Get the underlying flags value as an integer.
151  return static_cast<UnderlyingType>(Flags);
152  }
153 
154  /// Return a reference to the target-specific flags.
156 
157  /// Return a reference to the target-specific flags.
158  const TargetFlagsType& getTargetFlags() const { return TargetFlags; }
159 
160  /// Construct a JITSymbolFlags value based on the flags of the given global
161  /// value.
162  static JITSymbolFlags fromGlobalValue(const GlobalValue &GV);
163 
164  /// Construct a JITSymbolFlags value based on the flags of the given libobject
165  /// symbol.
167  fromObjectSymbol(const object::SymbolRef &Symbol);
168 
169 private:
170  FlagNames Flags = None;
172 };
173 
175  const JITSymbolFlags::FlagNames &RHS) {
176  JITSymbolFlags Tmp = LHS;
177  Tmp &= RHS;
178  return Tmp;
179 }
180 
182  const JITSymbolFlags::FlagNames &RHS) {
183  JITSymbolFlags Tmp = LHS;
184  Tmp |= RHS;
185  return Tmp;
186 }
187 
188 /// ARM-specific JIT symbol flags.
189 /// FIXME: This should be moved into a target-specific header.
191 public:
192  ARMJITSymbolFlags() = default;
193 
194  enum FlagNames {
195  None = 0,
196  Thumb = 1 << 0
197  };
198 
199  operator JITSymbolFlags::TargetFlagsType&() { return Flags; }
200 
201  static ARMJITSymbolFlags fromObjectSymbol(const object::SymbolRef &Symbol);
202 
203 private:
205 };
206 
207 /// Represents a symbol that has been evaluated to an address already.
209 public:
210  JITEvaluatedSymbol() = default;
211 
212  /// Create a 'null' symbol.
213  JITEvaluatedSymbol(std::nullptr_t) {}
214 
215  /// Create a symbol for the given address and flags.
217  : Address(Address), Flags(Flags) {}
218 
219  /// An evaluated symbol converts to 'true' if its address is non-zero.
220  explicit operator bool() const { return Address != 0; }
221 
222  /// Return the address of this symbol.
223  JITTargetAddress getAddress() const { return Address; }
224 
225  /// Return the flags for this symbol.
226  JITSymbolFlags getFlags() const { return Flags; }
227 
228  /// Set the flags for this symbol.
229  void setFlags(JITSymbolFlags Flags) { this->Flags = std::move(Flags); }
230 
231 private:
233  JITSymbolFlags Flags;
234 };
235 
236 /// Represents a symbol in the JIT.
237 class JITSymbol {
238 public:
239  using GetAddressFtor = std::function<Expected<JITTargetAddress>()>;
240 
241  /// Create a 'null' symbol, used to represent a "symbol not found"
242  /// result from a successful (non-erroneous) lookup.
243  JITSymbol(std::nullptr_t)
244  : CachedAddr(0) {}
245 
246  /// Create a JITSymbol representing an error in the symbol lookup
247  /// process (e.g. a network failure during a remote lookup).
249  : Err(std::move(Err)), Flags(JITSymbolFlags::HasError) {}
250 
251  /// Create a symbol for a definition with a known address.
253  : CachedAddr(Addr), Flags(Flags) {}
254 
255  /// Construct a JITSymbol from a JITEvaluatedSymbol.
257  : CachedAddr(Sym.getAddress()), Flags(Sym.getFlags()) {}
258 
259  /// Create a symbol for a definition that doesn't have a known address
260  /// yet.
261  /// @param GetAddress A functor to materialize a definition (fixing the
262  /// address) on demand.
263  ///
264  /// This constructor allows a JIT layer to provide a reference to a symbol
265  /// definition without actually materializing the definition up front. The
266  /// user can materialize the definition at any time by calling the getAddress
267  /// method.
269  : GetAddress(std::move(GetAddress)), CachedAddr(0), Flags(Flags) {}
270 
271  JITSymbol(const JITSymbol&) = delete;
272  JITSymbol& operator=(const JITSymbol&) = delete;
273 
275  : GetAddress(std::move(Other.GetAddress)), Flags(std::move(Other.Flags)) {
276  if (Flags.hasError())
277  Err = std::move(Other.Err);
278  else
279  CachedAddr = std::move(Other.CachedAddr);
280  }
281 
283  GetAddress = std::move(Other.GetAddress);
284  Flags = std::move(Other.Flags);
285  if (Flags.hasError())
286  Err = std::move(Other.Err);
287  else
288  CachedAddr = std::move(Other.CachedAddr);
289  return *this;
290  }
291 
293  if (Flags.hasError())
294  Err.~Error();
295  else
296  CachedAddr.~JITTargetAddress();
297  }
298 
299  /// Returns true if the symbol exists, false otherwise.
300  explicit operator bool() const {
301  return !Flags.hasError() && (CachedAddr || GetAddress);
302  }
303 
304  /// Move the error field value out of this JITSymbol.
306  if (Flags.hasError())
307  return std::move(Err);
308  return Error::success();
309  }
310 
311  /// Get the address of the symbol in the target address space. Returns
312  /// '0' if the symbol does not exist.
314  assert(!Flags.hasError() && "getAddress called on error value");
315  if (GetAddress) {
316  if (auto CachedAddrOrErr = GetAddress()) {
317  GetAddress = nullptr;
318  CachedAddr = *CachedAddrOrErr;
319  assert(CachedAddr && "Symbol could not be materialized.");
320  } else
321  return CachedAddrOrErr.takeError();
322  }
323  return CachedAddr;
324  }
325 
326  JITSymbolFlags getFlags() const { return Flags; }
327 
328 private:
329  GetAddressFtor GetAddress;
330  union {
333  };
334  JITSymbolFlags Flags;
335 };
336 
337 /// Symbol resolution interface.
338 ///
339 /// Allows symbol flags and addresses to be looked up by name.
340 /// Symbol queries are done in bulk (i.e. you request resolution of a set of
341 /// symbols, rather than a single one) to reduce IPC overhead in the case of
342 /// remote JITing, and expose opportunities for parallel compilation.
344 public:
345  using LookupSet = std::set<StringRef>;
346  using LookupResult = std::map<StringRef, JITEvaluatedSymbol>;
347  using OnResolvedFunction = std::function<void(Expected<LookupResult>)>;
348 
349  virtual ~JITSymbolResolver() = default;
350 
351  /// Returns the fully resolved address and flags for each of the given
352  /// symbols.
353  ///
354  /// This method will return an error if any of the given symbols can not be
355  /// resolved, or if the resolution process itself triggers an error.
356  virtual void lookup(const LookupSet &Symbols,
357  OnResolvedFunction OnResolved) = 0;
358 
359  /// Returns the subset of the given symbols that should be materialized by
360  /// the caller. Only weak/common symbols should be looked up, as strong
361  /// definitions are implicitly always part of the caller's responsibility.
362  virtual Expected<LookupSet>
363  getResponsibilitySet(const LookupSet &Symbols) = 0;
364 
365 private:
366  virtual void anchor();
367 };
368 
369 /// Legacy symbol resolution interface.
371 public:
372  /// Performs lookup by, for each symbol, first calling
373  /// findSymbolInLogicalDylib and if that fails calling
374  /// findSymbol.
375  void lookup(const LookupSet &Symbols, OnResolvedFunction OnResolved) final;
376 
377  /// Performs flags lookup by calling findSymbolInLogicalDylib and
378  /// returning the flags value for that symbol.
379  Expected<LookupSet> getResponsibilitySet(const LookupSet &Symbols) final;
380 
381  /// This method returns the address of the specified symbol if it exists
382  /// within the logical dynamic library represented by this JITSymbolResolver.
383  /// Unlike findSymbol, queries through this interface should return addresses
384  /// for hidden symbols.
385  ///
386  /// This is of particular importance for the Orc JIT APIs, which support lazy
387  /// compilation by breaking up modules: Each of those broken out modules
388  /// must be able to resolve hidden symbols provided by the others. Clients
389  /// writing memory managers for MCJIT can usually ignore this method.
390  ///
391  /// This method will be queried by RuntimeDyld when checking for previous
392  /// definitions of common symbols.
393  virtual JITSymbol findSymbolInLogicalDylib(const std::string &Name) = 0;
394 
395  /// This method returns the address of the specified function or variable.
396  /// It is used to resolve symbols during module linking.
397  ///
398  /// If the returned symbol's address is equal to ~0ULL then RuntimeDyld will
399  /// skip all relocations for that symbol, and the client will be responsible
400  /// for handling them manually.
401  virtual JITSymbol findSymbol(const std::string &Name) = 0;
402 
403 private:
404  virtual void anchor();
405 };
406 
407 } // end namespace llvm
408 
409 #endif // LLVM_EXECUTIONENGINE_JITSYMBOL_H
bool isLazy() const
Returns true if this is a lazy symbol.
Definition: JITSymbol.h:116
const NoneType None
Definition: None.h:23
std::function< void(Expected< LookupResult >)> OnResolvedFunction
Definition: JITSymbol.h:347
#define LLVM_MARK_AS_BITMASK_ENUM(LargestValue)
LLVM_MARK_AS_BITMASK_ENUM lets you opt in an individual enum type so you can perform bitwise operatio...
Definition: BitmaskEnum.h:41
Represents a symbol in the JIT.
Definition: JITSymbol.h:237
bool isCommon() const
Returns true if the Common flag is set.
Definition: JITSymbol.h:132
This class represents lattice values for constants.
Definition: AllocatorList.h:23
amdgpu Simplify well known AMD library false FunctionCallee Value const Twine & Name
JITSymbolFlags getFlags() const
Return the flags for this symbol.
Definition: JITSymbol.h:226
Legacy symbol resolution interface.
Definition: JITSymbol.h:370
bool isStrong() const
Returns true if the symbol isn&#39;t weak or common.
Definition: JITSymbol.h:137
APInt operator &(APInt a, const APInt &b)
Definition: APInt.h:1978
bool operator==(const JITSymbolFlags &RHS) const
Compare for equality.
Definition: JITSymbol.h:92
std::set< StringRef > LookupSet
Definition: JITSymbol.h:345
T jitTargetAddressToPointer(JITTargetAddress Addr)
Convert a JITTargetAddress to a pointer.
Definition: JITSymbol.h:43
JITSymbol & operator=(JITSymbol &&Other)
Definition: JITSymbol.h:282
bool isWeak() const
Returns true if the Weak flag is set.
Definition: JITSymbol.h:127
JITSymbolFlags getFlags() const
Definition: JITSymbol.h:326
bool isMaterializing() const
Returns true if this symbol is in the process of being materialized.
Definition: JITSymbol.h:120
void setFlags(JITSymbolFlags Flags)
Set the flags for this symbol.
Definition: JITSymbol.h:229
Definition: BitVector.h:937
Tagged union holding either a T or a Error.
Definition: CachePruning.h:22
static const uint16_t * lookup(unsigned opcode, unsigned domain, ArrayRef< uint16_t[3]> Table)
ELFYAML::ELF_STO Other
Definition: ELFYAML.cpp:810
const TargetFlagsType & getTargetFlags() const
Return a reference to the target-specific flags.
Definition: JITSymbol.h:158
JITSymbolFlags(FlagNames Flags, TargetFlagsType TargetFlags)
Construct a JITSymbolFlags instance from the given flags and target flags.
Definition: JITSymbol.h:85
uint64_t TargetFlagsType
Definition: JITSymbol.h:58
uint64_t JITTargetAddress
Represents an address in the target process&#39;s address space.
Definition: JITSymbol.h:40
JITSymbol(Error Err)
Create a JITSymbol representing an error in the symbol lookup process (e.g.
Definition: JITSymbol.h:248
bool isCallable() const
Returns true if the given symbol is known to be callable.
Definition: JITSymbol.h:147
JITTargetAddress pointerToJITTargetAddress(T *Ptr)
Definition: JITSymbol.h:50
JITEvaluatedSymbol(std::nullptr_t)
Create a &#39;null&#39; symbol.
Definition: JITSymbol.h:213
JITSymbolFlags(FlagNames Flags)
Construct a JITSymbolFlags instance from the given flags.
Definition: JITSymbol.h:81
Flags for symbols in the JIT.
Definition: JITSymbol.h:55
Symbol resolution interface.
Definition: JITSymbol.h:343
JITSymbol(JITEvaluatedSymbol Sym)
Construct a JITSymbol from a JITEvaluatedSymbol.
Definition: JITSymbol.h:256
JITEvaluatedSymbol(JITTargetAddress Address, JITSymbolFlags Flags)
Create a symbol for the given address and flags.
Definition: JITSymbol.h:216
static ErrorSuccess success()
Create a success value.
Definition: Error.h:326
bool isMaterialized() const
Returns true if this symbol is fully materialized.
Definition: JITSymbol.h:124
JITSymbol(JITSymbol &&Other)
Definition: JITSymbol.h:274
Expected< JITTargetAddress > getAddress()
Get the address of the symbol in the target address space.
Definition: JITSymbol.h:313
bool hasError() const
Return true if there was an error retrieving this symbol.
Definition: JITSymbol.h:109
UnderlyingType getRawFlagsValue() const
Get the underlying flags value as an integer.
Definition: JITSymbol.h:150
uint8_t UnderlyingType
Definition: JITSymbol.h:57
static bool isWeak(const MCSymbolELF &Sym)
JITSymbol(std::nullptr_t)
Create a &#39;null&#39; symbol, used to represent a "symbol not found" result from a successful (non-erroneou...
Definition: JITSymbol.h:243
Represents a symbol that has been evaluated to an address already.
Definition: JITSymbol.h:208
This is a value type class that represents a single symbol in the list of symbols in the object file...
Definition: ObjectFile.h:140
std::function< Expected< JITTargetAddress >()> GetAddressFtor
Definition: JITSymbol.h:239
bool isExported() const
Returns true if the Exported flag is set.
Definition: JITSymbol.h:142
JITSymbol(JITTargetAddress Addr, JITSymbolFlags Flags)
Create a symbol for a definition with a known address.
Definition: JITSymbol.h:252
TargetFlagsType & getTargetFlags()
Return a reference to the target-specific flags.
Definition: JITSymbol.h:155
JITSymbolFlags & operator|=(const FlagNames &RHS)
Bitwise OR-assignment for FlagNames.
Definition: JITSymbol.h:103
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
E & operator &=(E &LHS, E RHS)
Definition: BitmaskEnum.h:133
std::map< StringRef, JITEvaluatedSymbol > LookupResult
Definition: JITSymbol.h:346
ARM-specific JIT symbol flags.
Definition: JITSymbol.h:190
Lightweight error class with error context and mandatory checking.
Definition: Error.h:157
static JITSymbolFlags stripTransientFlags(JITSymbolFlags Orig)
Definition: JITSymbol.h:73
JITSymbol(GetAddressFtor GetAddress, JITSymbolFlags Flags)
Create a symbol for a definition that doesn&#39;t have a known address yet.
Definition: JITSymbol.h:268
Error takeError()
Move the error field value out of this JITSymbol.
Definition: JITSymbol.h:305
JITTargetAddress getAddress() const
Return the address of this symbol.
Definition: JITSymbol.h:223
APInt operator|(APInt a, const APInt &b)
Definition: APInt.h:1998
JITTargetAddress CachedAddr
Definition: JITSymbol.h:331