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