1 //===- JITSymbol.h - JIT symbol abstraction ---------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // Abstraction for target process addresses.
12 //===----------------------------------------------------------------------===//
14 #ifndef LLVM_EXECUTIONENGINE_JITSYMBOL_H
15 #define LLVM_EXECUTIONENGINE_JITSYMBOL_H
26 #include "llvm/ADT/StringRef.h"
27 #include "llvm/Support/Error.h"
37 } // end namespace object
39 /// Represents an address in the target process's address space.
40 using JITTargetAddress = uint64_t;
42 /// Flags for symbols in the JIT.
43 class JITSymbolFlags {
45 using UnderlyingType = uint8_t;
46 using TargetFlagsType = uint64_t;
48 enum FlagNames : UnderlyingType {
56 Materializing = 1U << 6
59 static JITSymbolFlags stripTransientFlags(JITSymbolFlags Orig) {
60 return static_cast<FlagNames>(Orig.Flags & ~Lazy & ~Materializing);
63 /// Default-construct a JITSymbolFlags instance.
64 JITSymbolFlags() = default;
66 /// Construct a JITSymbolFlags instance from the given flags.
67 JITSymbolFlags(FlagNames Flags) : Flags(Flags) {}
69 /// Construct a JITSymbolFlags instance from the given flags and target
71 JITSymbolFlags(FlagNames Flags, TargetFlagsType TargetFlags)
72 : Flags(Flags), TargetFlags(TargetFlags) {}
74 /// Return true if there was an error retrieving this symbol.
75 bool hasError() const {
76 return (Flags & HasError) == HasError;
79 /// Returns true if this is a lazy symbol.
80 /// This flag is used internally by the JIT APIs to track
81 /// materialization states.
82 bool isLazy() const { return Flags & Lazy; }
84 /// Returns true if this symbol is in the process of being
86 bool isMaterializing() const { return Flags & Materializing; }
88 /// Returns true if this symbol is fully materialized.
89 /// (i.e. neither lazy, nor materializing).
90 bool isMaterialized() const { return !(Flags & (Lazy | Materializing)); }
92 /// Returns true if the Weak flag is set.
94 return (Flags & Weak) == Weak;
97 /// Returns true if the Common flag is set.
98 bool isCommon() const {
99 return (Flags & Common) == Common;
102 /// Returns true if the symbol isn't weak or common.
103 bool isStrong() const {
104 return !isWeak() && !isCommon();
107 /// Returns true if the Exported flag is set.
108 bool isExported() const {
109 return (Flags & Exported) == Exported;
112 /// Implicitly convert to the underlying flags type.
113 operator UnderlyingType&() { return Flags; }
115 /// Implicitly convert to the underlying flags type.
116 operator const UnderlyingType&() const { return Flags; }
118 /// Return a reference to the target-specific flags.
119 TargetFlagsType& getTargetFlags() { return TargetFlags; }
121 /// Return a reference to the target-specific flags.
122 const TargetFlagsType& getTargetFlags() const { return TargetFlags; }
124 /// Construct a JITSymbolFlags value based on the flags of the given global
126 static JITSymbolFlags fromGlobalValue(const GlobalValue &GV);
128 /// Construct a JITSymbolFlags value based on the flags of the given libobject
130 static JITSymbolFlags fromObjectSymbol(const object::BasicSymbolRef &Symbol);
133 UnderlyingType Flags = None;
134 TargetFlagsType TargetFlags = 0;
137 /// ARM-specific JIT symbol flags.
138 /// FIXME: This should be moved into a target-specific header.
139 class ARMJITSymbolFlags {
141 ARMJITSymbolFlags() = default;
148 operator JITSymbolFlags::TargetFlagsType&() { return Flags; }
150 static ARMJITSymbolFlags fromObjectSymbol(
151 const object::BasicSymbolRef &Symbol);
153 JITSymbolFlags::TargetFlagsType Flags = 0;
156 /// Represents a symbol that has been evaluated to an address already.
157 class JITEvaluatedSymbol {
159 JITEvaluatedSymbol() = default;
161 /// Create a 'null' symbol.
162 JITEvaluatedSymbol(std::nullptr_t) {}
164 /// Create a symbol for the given address and flags.
165 JITEvaluatedSymbol(JITTargetAddress Address, JITSymbolFlags Flags)
166 : Address(Address), Flags(Flags) {}
168 /// An evaluated symbol converts to 'true' if its address is non-zero.
169 explicit operator bool() const { return Address != 0; }
171 /// Return the address of this symbol.
172 JITTargetAddress getAddress() const { return Address; }
174 /// Return the flags for this symbol.
175 JITSymbolFlags getFlags() const { return Flags; }
177 /// Set the flags for this symbol.
178 void setFlags(JITSymbolFlags Flags) { this->Flags = std::move(Flags); }
181 JITTargetAddress Address = 0;
182 JITSymbolFlags Flags;
185 /// Represents a symbol in the JIT.
188 using GetAddressFtor = std::function<Expected<JITTargetAddress>()>;
190 /// Create a 'null' symbol, used to represent a "symbol not found"
191 /// result from a successful (non-erroneous) lookup.
192 JITSymbol(std::nullptr_t)
195 /// Create a JITSymbol representing an error in the symbol lookup
196 /// process (e.g. a network failure during a remote lookup).
198 : Err(std::move(Err)), Flags(JITSymbolFlags::HasError) {}
200 /// Create a symbol for a definition with a known address.
201 JITSymbol(JITTargetAddress Addr, JITSymbolFlags Flags)
202 : CachedAddr(Addr), Flags(Flags) {}
204 /// Construct a JITSymbol from a JITEvaluatedSymbol.
205 JITSymbol(JITEvaluatedSymbol Sym)
206 : CachedAddr(Sym.getAddress()), Flags(Sym.getFlags()) {}
208 /// Create a symbol for a definition that doesn't have a known address
210 /// @param GetAddress A functor to materialize a definition (fixing the
211 /// address) on demand.
213 /// This constructor allows a JIT layer to provide a reference to a symbol
214 /// definition without actually materializing the definition up front. The
215 /// user can materialize the definition at any time by calling the getAddress
217 JITSymbol(GetAddressFtor GetAddress, JITSymbolFlags Flags)
218 : GetAddress(std::move(GetAddress)), CachedAddr(0), Flags(Flags) {}
220 JITSymbol(const JITSymbol&) = delete;
221 JITSymbol& operator=(const JITSymbol&) = delete;
223 JITSymbol(JITSymbol &&Other)
224 : GetAddress(std::move(Other.GetAddress)), Flags(std::move(Other.Flags)) {
225 if (Flags.hasError())
226 Err = std::move(Other.Err);
228 CachedAddr = std::move(Other.CachedAddr);
231 JITSymbol& operator=(JITSymbol &&Other) {
232 GetAddress = std::move(Other.GetAddress);
233 Flags = std::move(Other.Flags);
234 if (Flags.hasError())
235 Err = std::move(Other.Err);
237 CachedAddr = std::move(Other.CachedAddr);
242 if (Flags.hasError())
245 CachedAddr.~JITTargetAddress();
248 /// Returns true if the symbol exists, false otherwise.
249 explicit operator bool() const {
250 return !Flags.hasError() && (CachedAddr || GetAddress);
253 /// Move the error field value out of this JITSymbol.
255 if (Flags.hasError())
256 return std::move(Err);
257 return Error::success();
260 /// Get the address of the symbol in the target address space. Returns
261 /// '0' if the symbol does not exist.
262 Expected<JITTargetAddress> getAddress() {
263 assert(!Flags.hasError() && "getAddress called on error value");
265 if (auto CachedAddrOrErr = GetAddress()) {
266 GetAddress = nullptr;
267 CachedAddr = *CachedAddrOrErr;
268 assert(CachedAddr && "Symbol could not be materialized.");
270 return CachedAddrOrErr.takeError();
275 JITSymbolFlags getFlags() const { return Flags; }
278 GetAddressFtor GetAddress;
280 JITTargetAddress CachedAddr;
283 JITSymbolFlags Flags;
286 /// Symbol resolution interface.
288 /// Allows symbol flags and addresses to be looked up by name.
289 /// Symbol queries are done in bulk (i.e. you request resolution of a set of
290 /// symbols, rather than a single one) to reduce IPC overhead in the case of
291 /// remote JITing, and expose opportunities for parallel compilation.
292 class JITSymbolResolver {
294 using LookupSet = std::set<StringRef>;
295 using LookupResult = std::map<StringRef, JITEvaluatedSymbol>;
296 using LookupFlagsResult = std::map<StringRef, JITSymbolFlags>;
298 virtual ~JITSymbolResolver() = default;
300 /// Returns the fully resolved address and flags for each of the given
303 /// This method will return an error if any of the given symbols can not be
304 /// resolved, or if the resolution process itself triggers an error.
305 virtual Expected<LookupResult> lookup(const LookupSet &Symbols) = 0;
307 /// Returns the symbol flags for each of the given symbols.
309 /// This method does NOT return an error if any of the given symbols is
310 /// missing. Instead, that symbol will be left out of the result map.
311 virtual Expected<LookupFlagsResult> lookupFlags(const LookupSet &Symbols) = 0;
314 virtual void anchor();
317 /// Legacy symbol resolution interface.
318 class LegacyJITSymbolResolver : public JITSymbolResolver {
320 /// Performs lookup by, for each symbol, first calling
321 /// findSymbolInLogicalDylib and if that fails calling
323 Expected<LookupResult> lookup(const LookupSet &Symbols) final;
325 /// Performs flags lookup by calling findSymbolInLogicalDylib and
326 /// returning the flags value for that symbol.
327 Expected<LookupFlagsResult> lookupFlags(const LookupSet &Symbols) final;
329 /// This method returns the address of the specified symbol if it exists
330 /// within the logical dynamic library represented by this JITSymbolResolver.
331 /// Unlike findSymbol, queries through this interface should return addresses
332 /// for hidden symbols.
334 /// This is of particular importance for the Orc JIT APIs, which support lazy
335 /// compilation by breaking up modules: Each of those broken out modules
336 /// must be able to resolve hidden symbols provided by the others. Clients
337 /// writing memory managers for MCJIT can usually ignore this method.
339 /// This method will be queried by RuntimeDyld when checking for previous
340 /// definitions of common symbols.
341 virtual JITSymbol findSymbolInLogicalDylib(const std::string &Name) = 0;
343 /// This method returns the address of the specified function or variable.
344 /// It is used to resolve symbols during module linking.
346 /// If the returned symbol's address is equal to ~0ULL then RuntimeDyld will
347 /// skip all relocations for that symbol, and the client will be responsible
348 /// for handling them manually.
349 virtual JITSymbol findSymbol(const std::string &Name) = 0;
352 virtual void anchor();
355 } // end namespace llvm
357 #endif // LLVM_EXECUTIONENGINE_JITSYMBOL_H