blob: 0e33f014c7f62baa764d7d389a667d0e98c448aa [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
Andrew Scullcdfcccc2018-10-05 20:58:37 +010035class SymbolRef;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010036
37} // end namespace object
38
Andrew Scullcdfcccc2018-10-05 20:58:37 +010039/// Represents an address in the target process's address space.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010040using JITTargetAddress = uint64_t;
41
Andrew Scullcdfcccc2018-10-05 20:58:37 +010042/// Flags for symbols in the JIT.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010043class 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,
Andrew Scullcdfcccc2018-10-05 20:58:37 +010055 Callable = 1U << 5,
56 Lazy = 1U << 6,
57 Materializing = 1U << 7
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010058 };
59
60 static JITSymbolFlags stripTransientFlags(JITSymbolFlags Orig) {
Andrew Scullcdfcccc2018-10-05 20:58:37 +010061 return static_cast<FlagNames>(Orig.Flags & ~Lazy & ~Materializing);
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010062 }
63
Andrew Scullcdfcccc2018-10-05 20:58:37 +010064 /// Default-construct a JITSymbolFlags instance.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010065 JITSymbolFlags() = default;
66
Andrew Scullcdfcccc2018-10-05 20:58:37 +010067 /// Construct a JITSymbolFlags instance from the given flags.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010068 JITSymbolFlags(FlagNames Flags) : Flags(Flags) {}
69
Andrew Scullcdfcccc2018-10-05 20:58:37 +010070 /// Construct a JITSymbolFlags instance from the given flags and target
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010071 /// flags.
72 JITSymbolFlags(FlagNames Flags, TargetFlagsType TargetFlags)
73 : Flags(Flags), TargetFlags(TargetFlags) {}
74
Andrew Scullcdfcccc2018-10-05 20:58:37 +010075 /// Return true if there was an error retrieving this symbol.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010076 bool hasError() const {
77 return (Flags & HasError) == HasError;
78 }
79
Andrew Scullcdfcccc2018-10-05 20:58:37 +010080 /// Returns true if this is a lazy symbol.
81 /// This flag is used internally by the JIT APIs to track
82 /// materialization states.
83 bool isLazy() const { return Flags & Lazy; }
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010084
Andrew Scullcdfcccc2018-10-05 20:58:37 +010085 /// Returns true if this symbol is in the process of being
86 /// materialized.
87 bool isMaterializing() const { return Flags & Materializing; }
88
89 /// Returns true if this symbol is fully materialized.
90 /// (i.e. neither lazy, nor materializing).
91 bool isMaterialized() const { return !(Flags & (Lazy | Materializing)); }
92
93 /// Returns true if the Weak flag is set.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010094 bool isWeak() const {
95 return (Flags & Weak) == Weak;
96 }
97
Andrew Scullcdfcccc2018-10-05 20:58:37 +010098 /// Returns true if the Common flag is set.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010099 bool isCommon() const {
100 return (Flags & Common) == Common;
101 }
102
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100103 /// Returns true if the symbol isn't weak or common.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100104 bool isStrong() const {
105 return !isWeak() && !isCommon();
106 }
107
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100108 /// Returns true if the Exported flag is set.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100109 bool isExported() const {
110 return (Flags & Exported) == Exported;
111 }
112
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100113 /// Returns true if the given symbol is known to be callable.
114 bool isCallable() const { return (Flags & Callable) == Callable; }
115
116 /// Implicitly convert to the underlying flags type.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100117 operator UnderlyingType&() { return Flags; }
118
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100119 /// Implicitly convert to the underlying flags type.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100120 operator const UnderlyingType&() const { return Flags; }
121
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100122 /// Return a reference to the target-specific flags.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100123 TargetFlagsType& getTargetFlags() { return TargetFlags; }
124
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100125 /// Return a reference to the target-specific flags.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100126 const TargetFlagsType& getTargetFlags() const { return TargetFlags; }
127
128 /// Construct a JITSymbolFlags value based on the flags of the given global
129 /// value.
130 static JITSymbolFlags fromGlobalValue(const GlobalValue &GV);
131
132 /// Construct a JITSymbolFlags value based on the flags of the given libobject
133 /// symbol.
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100134 static Expected<JITSymbolFlags>
135 fromObjectSymbol(const object::SymbolRef &Symbol);
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100136
137private:
138 UnderlyingType Flags = None;
139 TargetFlagsType TargetFlags = 0;
140};
141
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100142/// ARM-specific JIT symbol flags.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100143/// FIXME: This should be moved into a target-specific header.
144class ARMJITSymbolFlags {
145public:
146 ARMJITSymbolFlags() = default;
147
148 enum FlagNames {
149 None = 0,
150 Thumb = 1 << 0
151 };
152
153 operator JITSymbolFlags::TargetFlagsType&() { return Flags; }
154
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100155 static ARMJITSymbolFlags fromObjectSymbol(const object::SymbolRef &Symbol);
156
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100157private:
158 JITSymbolFlags::TargetFlagsType Flags = 0;
159};
160
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100161/// Represents a symbol that has been evaluated to an address already.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100162class JITEvaluatedSymbol {
163public:
164 JITEvaluatedSymbol() = default;
165
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100166 /// Create a 'null' symbol.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100167 JITEvaluatedSymbol(std::nullptr_t) {}
168
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100169 /// Create a symbol for the given address and flags.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100170 JITEvaluatedSymbol(JITTargetAddress Address, JITSymbolFlags Flags)
171 : Address(Address), Flags(Flags) {}
172
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100173 /// An evaluated symbol converts to 'true' if its address is non-zero.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100174 explicit operator bool() const { return Address != 0; }
175
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100176 /// Return the address of this symbol.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100177 JITTargetAddress getAddress() const { return Address; }
178
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100179 /// Return the flags for this symbol.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100180 JITSymbolFlags getFlags() const { return Flags; }
181
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100182 /// Set the flags for this symbol.
183 void setFlags(JITSymbolFlags Flags) { this->Flags = std::move(Flags); }
184
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100185private:
186 JITTargetAddress Address = 0;
187 JITSymbolFlags Flags;
188};
189
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100190/// Represents a symbol in the JIT.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100191class JITSymbol {
192public:
193 using GetAddressFtor = std::function<Expected<JITTargetAddress>()>;
194
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100195 /// Create a 'null' symbol, used to represent a "symbol not found"
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100196 /// result from a successful (non-erroneous) lookup.
197 JITSymbol(std::nullptr_t)
198 : CachedAddr(0) {}
199
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100200 /// Create a JITSymbol representing an error in the symbol lookup
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100201 /// process (e.g. a network failure during a remote lookup).
202 JITSymbol(Error Err)
203 : Err(std::move(Err)), Flags(JITSymbolFlags::HasError) {}
204
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100205 /// Create a symbol for a definition with a known address.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100206 JITSymbol(JITTargetAddress Addr, JITSymbolFlags Flags)
207 : CachedAddr(Addr), Flags(Flags) {}
208
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100209 /// Construct a JITSymbol from a JITEvaluatedSymbol.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100210 JITSymbol(JITEvaluatedSymbol Sym)
211 : CachedAddr(Sym.getAddress()), Flags(Sym.getFlags()) {}
212
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100213 /// Create a symbol for a definition that doesn't have a known address
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100214 /// yet.
215 /// @param GetAddress A functor to materialize a definition (fixing the
216 /// address) on demand.
217 ///
218 /// This constructor allows a JIT layer to provide a reference to a symbol
219 /// definition without actually materializing the definition up front. The
220 /// user can materialize the definition at any time by calling the getAddress
221 /// method.
222 JITSymbol(GetAddressFtor GetAddress, JITSymbolFlags Flags)
223 : GetAddress(std::move(GetAddress)), CachedAddr(0), Flags(Flags) {}
224
225 JITSymbol(const JITSymbol&) = delete;
226 JITSymbol& operator=(const JITSymbol&) = delete;
227
228 JITSymbol(JITSymbol &&Other)
229 : GetAddress(std::move(Other.GetAddress)), Flags(std::move(Other.Flags)) {
230 if (Flags.hasError())
231 Err = std::move(Other.Err);
232 else
233 CachedAddr = std::move(Other.CachedAddr);
234 }
235
236 JITSymbol& operator=(JITSymbol &&Other) {
237 GetAddress = std::move(Other.GetAddress);
238 Flags = std::move(Other.Flags);
239 if (Flags.hasError())
240 Err = std::move(Other.Err);
241 else
242 CachedAddr = std::move(Other.CachedAddr);
243 return *this;
244 }
245
246 ~JITSymbol() {
247 if (Flags.hasError())
248 Err.~Error();
249 else
250 CachedAddr.~JITTargetAddress();
251 }
252
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100253 /// Returns true if the symbol exists, false otherwise.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100254 explicit operator bool() const {
255 return !Flags.hasError() && (CachedAddr || GetAddress);
256 }
257
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100258 /// Move the error field value out of this JITSymbol.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100259 Error takeError() {
260 if (Flags.hasError())
261 return std::move(Err);
262 return Error::success();
263 }
264
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100265 /// Get the address of the symbol in the target address space. Returns
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100266 /// '0' if the symbol does not exist.
267 Expected<JITTargetAddress> getAddress() {
268 assert(!Flags.hasError() && "getAddress called on error value");
269 if (GetAddress) {
270 if (auto CachedAddrOrErr = GetAddress()) {
271 GetAddress = nullptr;
272 CachedAddr = *CachedAddrOrErr;
273 assert(CachedAddr && "Symbol could not be materialized.");
274 } else
275 return CachedAddrOrErr.takeError();
276 }
277 return CachedAddr;
278 }
279
280 JITSymbolFlags getFlags() const { return Flags; }
281
282private:
283 GetAddressFtor GetAddress;
284 union {
285 JITTargetAddress CachedAddr;
286 Error Err;
287 };
288 JITSymbolFlags Flags;
289};
290
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100291/// Symbol resolution interface.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100292///
293/// Allows symbol flags and addresses to be looked up by name.
294/// Symbol queries are done in bulk (i.e. you request resolution of a set of
295/// symbols, rather than a single one) to reduce IPC overhead in the case of
296/// remote JITing, and expose opportunities for parallel compilation.
297class JITSymbolResolver {
298public:
299 using LookupSet = std::set<StringRef>;
300 using LookupResult = std::map<StringRef, JITEvaluatedSymbol>;
301 using LookupFlagsResult = std::map<StringRef, JITSymbolFlags>;
302
303 virtual ~JITSymbolResolver() = default;
304
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100305 /// Returns the fully resolved address and flags for each of the given
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100306 /// symbols.
307 ///
308 /// This method will return an error if any of the given symbols can not be
309 /// resolved, or if the resolution process itself triggers an error.
310 virtual Expected<LookupResult> lookup(const LookupSet &Symbols) = 0;
311
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100312 /// Returns the symbol flags for each of the given symbols.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100313 ///
314 /// This method does NOT return an error if any of the given symbols is
315 /// missing. Instead, that symbol will be left out of the result map.
316 virtual Expected<LookupFlagsResult> lookupFlags(const LookupSet &Symbols) = 0;
317
318private:
319 virtual void anchor();
320};
321
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100322/// Legacy symbol resolution interface.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100323class LegacyJITSymbolResolver : public JITSymbolResolver {
324public:
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100325 /// Performs lookup by, for each symbol, first calling
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100326 /// findSymbolInLogicalDylib and if that fails calling
327 /// findSymbol.
328 Expected<LookupResult> lookup(const LookupSet &Symbols) final;
329
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100330 /// Performs flags lookup by calling findSymbolInLogicalDylib and
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100331 /// returning the flags value for that symbol.
332 Expected<LookupFlagsResult> lookupFlags(const LookupSet &Symbols) final;
333
334 /// This method returns the address of the specified symbol if it exists
335 /// within the logical dynamic library represented by this JITSymbolResolver.
336 /// Unlike findSymbol, queries through this interface should return addresses
337 /// for hidden symbols.
338 ///
339 /// This is of particular importance for the Orc JIT APIs, which support lazy
340 /// compilation by breaking up modules: Each of those broken out modules
341 /// must be able to resolve hidden symbols provided by the others. Clients
342 /// writing memory managers for MCJIT can usually ignore this method.
343 ///
344 /// This method will be queried by RuntimeDyld when checking for previous
345 /// definitions of common symbols.
346 virtual JITSymbol findSymbolInLogicalDylib(const std::string &Name) = 0;
347
348 /// This method returns the address of the specified function or variable.
349 /// It is used to resolve symbols during module linking.
350 ///
351 /// If the returned symbol's address is equal to ~0ULL then RuntimeDyld will
352 /// skip all relocations for that symbol, and the client will be responsible
353 /// for handling them manually.
354 virtual JITSymbol findSymbol(const std::string &Name) = 0;
355
356private:
357 virtual void anchor();
358};
359
360} // end namespace llvm
361
362#endif // LLVM_EXECUTIONENGINE_JITSYMBOL_H