1 | //===------ Core.h -- Core ORC APIs (Layer, JITDylib, etc.) -----*- 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 | // Contains core ORC APIs. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #ifndef LLVM_EXECUTIONENGINE_ORC_CORE_H |
15 | #define LLVM_EXECUTIONENGINE_ORC_CORE_H |
16 | |
17 | #include "llvm/ADT/BitmaskEnum.h" |
18 | #include "llvm/ExecutionEngine/JITSymbol.h" |
19 | #include "llvm/ExecutionEngine/Orc/SymbolStringPool.h" |
20 | #include "llvm/IR/Module.h" |
21 | #include "llvm/Support/Debug.h" |
22 | |
23 | #include <memory> |
24 | #include <vector> |
25 | |
26 | #define DEBUG_TYPE "orc" |
27 | |
28 | namespace llvm { |
29 | namespace orc { |
30 | |
31 | // Forward declare some classes. |
32 | class AsynchronousSymbolQuery; |
33 | class ExecutionSession; |
34 | class MaterializationUnit; |
35 | class MaterializationResponsibility; |
36 | class JITDylib; |
37 | |
38 | /// VModuleKey provides a unique identifier (allocated and managed by |
39 | /// ExecutionSessions) for a module added to the JIT. |
40 | using VModuleKey = uint64_t; |
41 | |
42 | /// A set of symbol names (represented by SymbolStringPtrs for |
43 | // efficiency). |
44 | using SymbolNameSet = DenseSet<SymbolStringPtr>; |
45 | |
46 | /// A map from symbol names (as SymbolStringPtrs) to JITSymbols |
47 | /// (address/flags pairs). |
48 | using SymbolMap = DenseMap<SymbolStringPtr, JITEvaluatedSymbol>; |
49 | |
50 | /// A map from symbol names (as SymbolStringPtrs) to JITSymbolFlags. |
51 | using SymbolFlagsMap = DenseMap<SymbolStringPtr, JITSymbolFlags>; |
52 | |
53 | /// A base class for materialization failures that allows the failing |
54 | /// symbols to be obtained for logging. |
55 | using SymbolDependenceMap = DenseMap<JITDylib *, SymbolNameSet>; |
56 | |
57 | /// A list of (JITDylib*, bool) pairs. |
58 | using JITDylibSearchList = std::vector<std::pair<JITDylib *, bool>>; |
59 | |
60 | /// Render a SymbolStringPtr. |
61 | raw_ostream &operator<<(raw_ostream &OS, const SymbolStringPtr &Sym); |
62 | |
63 | /// Render a SymbolNameSet. |
64 | raw_ostream &operator<<(raw_ostream &OS, const SymbolNameSet &Symbols); |
65 | |
66 | /// Render a SymbolFlagsMap entry. |
67 | raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap::value_type &KV); |
68 | |
69 | /// Render a SymbolMap entry. |
70 | raw_ostream &operator<<(raw_ostream &OS, const SymbolMap::value_type &KV); |
71 | |
72 | /// Render a SymbolFlagsMap. |
73 | raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap &SymbolFlags); |
74 | |
75 | /// Render a SymbolMap. |
76 | raw_ostream &operator<<(raw_ostream &OS, const SymbolMap &Symbols); |
77 | |
78 | /// Render a SymbolDependenceMap entry. |
79 | raw_ostream &operator<<(raw_ostream &OS, |
80 | const SymbolDependenceMap::value_type &KV); |
81 | |
82 | /// Render a SymbolDependendeMap. |
83 | raw_ostream &operator<<(raw_ostream &OS, const SymbolDependenceMap &Deps); |
84 | |
85 | /// Render a MaterializationUnit. |
86 | raw_ostream &operator<<(raw_ostream &OS, const MaterializationUnit &MU); |
87 | |
88 | /// Render a JITDylibSearchList. |
89 | raw_ostream &operator<<(raw_ostream &OS, const JITDylibSearchList &JDs); |
90 | |
91 | /// Callback to notify client that symbols have been resolved. |
92 | using SymbolsResolvedCallback = std::function<void(Expected<SymbolMap>)>; |
93 | |
94 | /// Callback to notify client that symbols are ready for execution. |
95 | using SymbolsReadyCallback = std::function<void(Error)>; |
96 | |
97 | /// Callback to register the dependencies for a given query. |
98 | using RegisterDependenciesFunction = |
99 | std::function<void(const SymbolDependenceMap &)>; |
100 | |
101 | /// This can be used as the value for a RegisterDependenciesFunction if there |
102 | /// are no dependants to register with. |
103 | extern RegisterDependenciesFunction NoDependenciesToRegister; |
104 | |
105 | /// Used to notify a JITDylib that the given set of symbols failed to |
106 | /// materialize. |
107 | class FailedToMaterialize : public ErrorInfo<FailedToMaterialize> { |
108 | public: |
109 | static char ID; |
110 | |
111 | FailedToMaterialize(SymbolNameSet Symbols); |
112 | std::error_code convertToErrorCode() const override; |
113 | void log(raw_ostream &OS) const override; |
114 | const SymbolNameSet &getSymbols() const { return Symbols; } |
115 | |
116 | private: |
117 | SymbolNameSet Symbols; |
118 | }; |
119 | |
120 | /// Used to notify clients when symbols can not be found during a lookup. |
121 | class SymbolsNotFound : public ErrorInfo<SymbolsNotFound> { |
122 | public: |
123 | static char ID; |
124 | |
125 | SymbolsNotFound(SymbolNameSet Symbols); |
126 | std::error_code convertToErrorCode() const override; |
127 | void log(raw_ostream &OS) const override; |
128 | const SymbolNameSet &getSymbols() const { return Symbols; } |
129 | |
130 | private: |
131 | SymbolNameSet Symbols; |
132 | }; |
133 | |
134 | /// Used to notify clients that a set of symbols could not be removed. |
135 | class SymbolsCouldNotBeRemoved : public ErrorInfo<SymbolsCouldNotBeRemoved> { |
136 | public: |
137 | static char ID; |
138 | |
139 | SymbolsCouldNotBeRemoved(SymbolNameSet Symbols); |
140 | std::error_code convertToErrorCode() const override; |
141 | void log(raw_ostream &OS) const override; |
142 | const SymbolNameSet &getSymbols() const { return Symbols; } |
143 | |
144 | private: |
145 | SymbolNameSet Symbols; |
146 | }; |
147 | |
148 | /// Tracks responsibility for materialization, and mediates interactions between |
149 | /// MaterializationUnits and JDs. |
150 | /// |
151 | /// An instance of this class is passed to MaterializationUnits when their |
152 | /// materialize method is called. It allows MaterializationUnits to resolve and |
153 | /// emit symbols, or abandon materialization by notifying any unmaterialized |
154 | /// symbols of an error. |
155 | class MaterializationResponsibility { |
156 | friend class MaterializationUnit; |
157 | public: |
158 | MaterializationResponsibility(MaterializationResponsibility &&) = default; |
159 | MaterializationResponsibility & |
160 | operator=(MaterializationResponsibility &&) = delete; |
161 | |
162 | /// Destruct a MaterializationResponsibility instance. In debug mode |
163 | /// this asserts that all symbols being tracked have been either |
164 | /// emitted or notified of an error. |
165 | ~MaterializationResponsibility(); |
166 | |
167 | /// Returns the target JITDylib that these symbols are being materialized |
168 | /// into. |
169 | JITDylib &getTargetJITDylib() const { return JD; } |
170 | |
171 | /// Returns the VModuleKey for this instance. |
172 | VModuleKey getVModuleKey() const { return K; } |
173 | |
174 | /// Returns the symbol flags map for this responsibility instance. |
175 | /// Note: The returned flags may have transient flags (Lazy, Materializing) |
176 | /// set. These should be stripped with JITSymbolFlags::stripTransientFlags |
177 | /// before using. |
178 | const SymbolFlagsMap &getSymbols() { return SymbolFlags; } |
179 | |
180 | /// Returns the names of any symbols covered by this |
181 | /// MaterializationResponsibility object that have queries pending. This |
182 | /// information can be used to return responsibility for unrequested symbols |
183 | /// back to the JITDylib via the delegate method. |
184 | SymbolNameSet getRequestedSymbols() const; |
185 | |
186 | /// Notifies the target JITDylib that the given symbols have been resolved. |
187 | /// This will update the given symbols' addresses in the JITDylib, and notify |
188 | /// any pending queries on the given symbols of their resolution. The given |
189 | /// symbols must be ones covered by this MaterializationResponsibility |
190 | /// instance. Individual calls to this method may resolve a subset of the |
191 | /// symbols, but all symbols must have been resolved prior to calling emit. |
192 | void resolve(const SymbolMap &Symbols); |
193 | |
194 | /// Notifies the target JITDylib (and any pending queries on that JITDylib) |
195 | /// that all symbols covered by this MaterializationResponsibility instance |
196 | /// have been emitted. |
197 | void emit(); |
198 | |
199 | /// Adds new symbols to the JITDylib and this responsibility instance. |
200 | /// JITDylib entries start out in the materializing state. |
201 | /// |
202 | /// This method can be used by materialization units that want to add |
203 | /// additional symbols at materialization time (e.g. stubs, compile |
204 | /// callbacks, metadata). |
205 | Error defineMaterializing(const SymbolFlagsMap &SymbolFlags); |
206 | |
207 | /// Notify all not-yet-emitted covered by this MaterializationResponsibility |
208 | /// instance that an error has occurred. |
209 | /// This will remove all symbols covered by this MaterializationResponsibilty |
210 | /// from the target JITDylib, and send an error to any queries waiting on |
211 | /// these symbols. |
212 | void failMaterialization(); |
213 | |
214 | /// Transfers responsibility to the given MaterializationUnit for all |
215 | /// symbols defined by that MaterializationUnit. This allows |
216 | /// materializers to break up work based on run-time information (e.g. |
217 | /// by introspecting which symbols have actually been looked up and |
218 | /// materializing only those). |
219 | void replace(std::unique_ptr<MaterializationUnit> MU); |
220 | |
221 | /// Delegates responsibility for the given symbols to the returned |
222 | /// materialization responsibility. Useful for breaking up work between |
223 | /// threads, or different kinds of materialization processes. |
224 | MaterializationResponsibility delegate(const SymbolNameSet &Symbols, |
225 | VModuleKey NewKey = VModuleKey()); |
226 | |
227 | void addDependencies(const SymbolStringPtr &Name, |
228 | const SymbolDependenceMap &Dependencies); |
229 | |
230 | /// Add dependencies that apply to all symbols covered by this instance. |
231 | void addDependenciesForAll(const SymbolDependenceMap &Dependencies); |
232 | |
233 | private: |
234 | /// Create a MaterializationResponsibility for the given JITDylib and |
235 | /// initial symbols. |
236 | MaterializationResponsibility(JITDylib &JD, SymbolFlagsMap SymbolFlags, |
237 | VModuleKey K); |
238 | |
239 | JITDylib &JD; |
240 | SymbolFlagsMap SymbolFlags; |
241 | VModuleKey K; |
242 | }; |
243 | |
244 | /// A MaterializationUnit represents a set of symbol definitions that can |
245 | /// be materialized as a group, or individually discarded (when |
246 | /// overriding definitions are encountered). |
247 | /// |
248 | /// MaterializationUnits are used when providing lazy definitions of symbols to |
249 | /// JITDylibs. The JITDylib will call materialize when the address of a symbol |
250 | /// is requested via the lookup method. The JITDylib will call discard if a |
251 | /// stronger definition is added or already present. |
252 | class MaterializationUnit { |
253 | public: |
254 | MaterializationUnit(SymbolFlagsMap InitalSymbolFlags, VModuleKey K) |
255 | : SymbolFlags(std::move(InitalSymbolFlags)), K(std::move(K)) {} |
256 | |
257 | virtual ~MaterializationUnit() {} |
258 | |
259 | /// Return the name of this materialization unit. Useful for debugging |
260 | /// output. |
261 | virtual StringRef getName() const = 0; |
262 | |
263 | /// Return the set of symbols that this source provides. |
264 | const SymbolFlagsMap &getSymbols() const { return SymbolFlags; } |
265 | |
266 | /// Called by materialization dispatchers (see |
267 | /// ExecutionSession::DispatchMaterializationFunction) to trigger |
268 | /// materialization of this MaterializationUnit. |
269 | void doMaterialize(JITDylib &JD) { |
270 | materialize(MaterializationResponsibility(JD, std::move(SymbolFlags), |
271 | std::move(K))); |
272 | } |
273 | |
274 | /// Called by JITDylibs to notify MaterializationUnits that the given symbol |
275 | /// has been overridden. |
276 | void doDiscard(const JITDylib &JD, const SymbolStringPtr &Name) { |
277 | SymbolFlags.erase(Name); |
278 | discard(JD, std::move(Name)); |
279 | } |
280 | |
281 | protected: |
282 | SymbolFlagsMap SymbolFlags; |
283 | VModuleKey K; |
284 | |
285 | private: |
286 | virtual void anchor(); |
287 | |
288 | /// Implementations of this method should materialize all symbols |
289 | /// in the materialzation unit, except for those that have been |
290 | /// previously discarded. |
291 | virtual void materialize(MaterializationResponsibility R) = 0; |
292 | |
293 | /// Implementations of this method should discard the given symbol |
294 | /// from the source (e.g. if the source is an LLVM IR Module and the |
295 | /// symbol is a function, delete the function body or mark it available |
296 | /// externally). |
297 | virtual void discard(const JITDylib &JD, const SymbolStringPtr &Name) = 0; |
298 | }; |
299 | |
300 | using MaterializationUnitList = |
301 | std::vector<std::unique_ptr<MaterializationUnit>>; |
302 | |
303 | /// A MaterializationUnit implementation for pre-existing absolute symbols. |
304 | /// |
305 | /// All symbols will be resolved and marked ready as soon as the unit is |
306 | /// materialized. |
307 | class AbsoluteSymbolsMaterializationUnit : public MaterializationUnit { |
308 | public: |
309 | AbsoluteSymbolsMaterializationUnit(SymbolMap Symbols, VModuleKey K); |
310 | |
311 | StringRef getName() const override; |
312 | |
313 | private: |
314 | void materialize(MaterializationResponsibility R) override; |
315 | void discard(const JITDylib &JD, const SymbolStringPtr &Name) override; |
316 | static SymbolFlagsMap (const SymbolMap &Symbols); |
317 | |
318 | SymbolMap Symbols; |
319 | }; |
320 | |
321 | /// Create an AbsoluteSymbolsMaterializationUnit with the given symbols. |
322 | /// Useful for inserting absolute symbols into a JITDylib. E.g.: |
323 | /// \code{.cpp} |
324 | /// JITDylib &JD = ...; |
325 | /// SymbolStringPtr Foo = ...; |
326 | /// JITEvaluatedSymbol FooSym = ...; |
327 | /// if (auto Err = JD.define(absoluteSymbols({{Foo, FooSym}}))) |
328 | /// return Err; |
329 | /// \endcode |
330 | /// |
331 | inline std::unique_ptr<AbsoluteSymbolsMaterializationUnit> |
332 | absoluteSymbols(SymbolMap Symbols, VModuleKey K = VModuleKey()) { |
333 | return llvm::make_unique<AbsoluteSymbolsMaterializationUnit>( |
334 | std::move(Symbols), std::move(K)); |
335 | } |
336 | |
337 | struct SymbolAliasMapEntry { |
338 | SymbolAliasMapEntry() = default; |
339 | SymbolAliasMapEntry(SymbolStringPtr Aliasee, JITSymbolFlags AliasFlags) |
340 | : Aliasee(std::move(Aliasee)), AliasFlags(AliasFlags) {} |
341 | |
342 | SymbolStringPtr Aliasee; |
343 | JITSymbolFlags AliasFlags; |
344 | }; |
345 | |
346 | /// A map of Symbols to (Symbol, Flags) pairs. |
347 | using SymbolAliasMap = DenseMap<SymbolStringPtr, SymbolAliasMapEntry>; |
348 | |
349 | /// A materialization unit for symbol aliases. Allows existing symbols to be |
350 | /// aliased with alternate flags. |
351 | class ReExportsMaterializationUnit : public MaterializationUnit { |
352 | public: |
353 | /// SourceJD is allowed to be nullptr, in which case the source JITDylib is |
354 | /// taken to be whatever JITDylib these definitions are materialized in (and |
355 | /// MatchNonExported has no effect). This is useful for defining aliases |
356 | /// within a JITDylib. |
357 | /// |
358 | /// Note: Care must be taken that no sets of aliases form a cycle, as such |
359 | /// a cycle will result in a deadlock when any symbol in the cycle is |
360 | /// resolved. |
361 | ReExportsMaterializationUnit(JITDylib *SourceJD, bool MatchNonExported, |
362 | SymbolAliasMap Aliases, VModuleKey K); |
363 | |
364 | StringRef getName() const override; |
365 | |
366 | private: |
367 | void materialize(MaterializationResponsibility R) override; |
368 | void discard(const JITDylib &JD, const SymbolStringPtr &Name) override; |
369 | static SymbolFlagsMap (const SymbolAliasMap &Aliases); |
370 | |
371 | JITDylib *SourceJD = nullptr; |
372 | bool MatchNonExported = false; |
373 | SymbolAliasMap Aliases; |
374 | }; |
375 | |
376 | /// Create a ReExportsMaterializationUnit with the given aliases. |
377 | /// Useful for defining symbol aliases.: E.g., given a JITDylib JD containing |
378 | /// symbols "foo" and "bar", we can define aliases "baz" (for "foo") and "qux" |
379 | /// (for "bar") with: \code{.cpp} |
380 | /// SymbolStringPtr Baz = ...; |
381 | /// SymbolStringPtr Qux = ...; |
382 | /// if (auto Err = JD.define(symbolAliases({ |
383 | /// {Baz, { Foo, JITSymbolFlags::Exported }}, |
384 | /// {Qux, { Bar, JITSymbolFlags::Weak }}})) |
385 | /// return Err; |
386 | /// \endcode |
387 | inline std::unique_ptr<ReExportsMaterializationUnit> |
388 | symbolAliases(SymbolAliasMap Aliases, VModuleKey K = VModuleKey()) { |
389 | return llvm::make_unique<ReExportsMaterializationUnit>( |
390 | nullptr, true, std::move(Aliases), std::move(K)); |
391 | } |
392 | |
393 | /// Create a materialization unit for re-exporting symbols from another JITDylib |
394 | /// with alternative names/flags. |
395 | /// If MatchNonExported is true then non-exported symbols from SourceJD can be |
396 | /// re-exported. If it is false, attempts to re-export a non-exported symbol |
397 | /// will result in a "symbol not found" error. |
398 | inline std::unique_ptr<ReExportsMaterializationUnit> |
399 | reexports(JITDylib &SourceJD, SymbolAliasMap Aliases, |
400 | bool MatchNonExported = false, VModuleKey K = VModuleKey()) { |
401 | return llvm::make_unique<ReExportsMaterializationUnit>( |
402 | &SourceJD, MatchNonExported, std::move(Aliases), std::move(K)); |
403 | } |
404 | |
405 | /// Build a SymbolAliasMap for the common case where you want to re-export |
406 | /// symbols from another JITDylib with the same linkage/flags. |
407 | Expected<SymbolAliasMap> |
408 | buildSimpleReexportsAliasMap(JITDylib &SourceJD, const SymbolNameSet &Symbols); |
409 | |
410 | /// ReexportsGenerator can be used with JITDylib::setGenerator to automatically |
411 | /// re-export a subset of the source JITDylib's symbols in the target. |
412 | class ReexportsGenerator { |
413 | public: |
414 | using SymbolPredicate = std::function<bool(SymbolStringPtr)>; |
415 | |
416 | /// Create a reexports generator. If an Allow predicate is passed, only |
417 | /// symbols for which the predicate returns true will be reexported. If no |
418 | /// Allow predicate is passed, all symbols will be exported. |
419 | ReexportsGenerator(JITDylib &SourceJD, bool MatchNonExported = false, |
420 | SymbolPredicate Allow = SymbolPredicate()); |
421 | |
422 | SymbolNameSet operator()(JITDylib &JD, const SymbolNameSet &Names); |
423 | |
424 | private: |
425 | JITDylib &SourceJD; |
426 | bool MatchNonExported = false; |
427 | SymbolPredicate Allow; |
428 | }; |
429 | |
430 | /// A symbol query that returns results via a callback when results are |
431 | /// ready. |
432 | /// |
433 | /// makes a callback when all symbols are available. |
434 | class AsynchronousSymbolQuery { |
435 | friend class ExecutionSession; |
436 | friend class JITDylib; |
437 | friend class JITSymbolResolverAdapter; |
438 | |
439 | public: |
440 | |
441 | /// Create a query for the given symbols, notify-resolved and |
442 | /// notify-ready callbacks. |
443 | AsynchronousSymbolQuery(const SymbolNameSet &Symbols, |
444 | SymbolsResolvedCallback NotifySymbolsResolved, |
445 | SymbolsReadyCallback NotifySymbolsReady); |
446 | |
447 | /// Set the resolved symbol information for the given symbol name. |
448 | void resolve(const SymbolStringPtr &Name, JITEvaluatedSymbol Sym); |
449 | |
450 | /// Returns true if all symbols covered by this query have been |
451 | /// resolved. |
452 | bool isFullyResolved() const { return NotYetResolvedCount == 0; } |
453 | |
454 | /// Call the NotifySymbolsResolved callback. |
455 | /// |
456 | /// This should only be called if all symbols covered by the query have been |
457 | /// resolved. |
458 | void handleFullyResolved(); |
459 | |
460 | /// Notify the query that a requested symbol is ready for execution. |
461 | void notifySymbolReady(); |
462 | |
463 | /// Returns true if all symbols covered by this query are ready. |
464 | bool isFullyReady() const { return NotYetReadyCount == 0; } |
465 | |
466 | /// Calls the NotifySymbolsReady callback. |
467 | /// |
468 | /// This should only be called if all symbols covered by this query are ready. |
469 | void handleFullyReady(); |
470 | |
471 | private: |
472 | void addQueryDependence(JITDylib &JD, SymbolStringPtr Name); |
473 | |
474 | void removeQueryDependence(JITDylib &JD, const SymbolStringPtr &Name); |
475 | |
476 | bool canStillFail(); |
477 | |
478 | void handleFailed(Error Err); |
479 | |
480 | void detach(); |
481 | |
482 | SymbolsResolvedCallback NotifySymbolsResolved; |
483 | SymbolsReadyCallback NotifySymbolsReady; |
484 | SymbolDependenceMap QueryRegistrations; |
485 | SymbolMap ResolvedSymbols; |
486 | size_t NotYetResolvedCount; |
487 | size_t NotYetReadyCount; |
488 | }; |
489 | |
490 | /// A symbol table that supports asynchoronous symbol queries. |
491 | /// |
492 | /// Represents a virtual shared object. Instances can not be copied or moved, so |
493 | /// their addresses may be used as keys for resource management. |
494 | /// JITDylib state changes must be made via an ExecutionSession to guarantee |
495 | /// that they are synchronized with respect to other JITDylib operations. |
496 | class JITDylib { |
497 | friend class AsynchronousSymbolQuery; |
498 | friend class ExecutionSession; |
499 | friend class MaterializationResponsibility; |
500 | public: |
501 | using GeneratorFunction = std::function<SymbolNameSet( |
502 | JITDylib &Parent, const SymbolNameSet &Names)>; |
503 | |
504 | using AsynchronousSymbolQuerySet = |
505 | std::set<std::shared_ptr<AsynchronousSymbolQuery>>; |
506 | |
507 | JITDylib(const JITDylib &) = delete; |
508 | JITDylib &operator=(const JITDylib &) = delete; |
509 | JITDylib(JITDylib &&) = delete; |
510 | JITDylib &operator=(JITDylib &&) = delete; |
511 | |
512 | /// Get the name for this JITDylib. |
513 | const std::string &getName() const { return JITDylibName; } |
514 | |
515 | /// Get a reference to the ExecutionSession for this JITDylib. |
516 | ExecutionSession &getExecutionSession() const { return ES; } |
517 | |
518 | /// Set a definition generator. If set, whenever a symbol fails to resolve |
519 | /// within this JITDylib, lookup and lookupFlags will pass the unresolved |
520 | /// symbols set to the definition generator. The generator can optionally |
521 | /// add a definition for the unresolved symbols to the dylib. |
522 | void setGenerator(GeneratorFunction DefGenerator) { |
523 | this->DefGenerator = std::move(DefGenerator); |
524 | } |
525 | |
526 | /// Set the search order to be used when fixing up definitions in JITDylib. |
527 | /// This will replace the previous search order, and apply to any symbol |
528 | /// resolutions made for definitions in this JITDylib after the call to |
529 | /// setSearchOrder (even if the definition itself was added before the |
530 | /// call). |
531 | /// |
532 | /// If SearchThisJITDylibFirst is set, which by default it is, then this |
533 | /// JITDylib will add itself to the beginning of the SearchOrder (Clients |
534 | /// should *not* put this JITDylib in the list in this case, to avoid |
535 | /// redundant lookups). |
536 | /// |
537 | /// If SearchThisJITDylibFirst is false then the search order will be used as |
538 | /// given. The main motivation for this feature is to support deliberate |
539 | /// shadowing of symbols in this JITDylib by a facade JITDylib. For example, |
540 | /// the facade may resolve function names to stubs, and the stubs may compile |
541 | /// lazily by looking up symbols in this dylib. Adding the facade dylib |
542 | /// as the first in the search order (instead of this dylib) ensures that |
543 | /// definitions within this dylib resolve to the lazy-compiling stubs, |
544 | /// rather than immediately materializing the definitions in this dylib. |
545 | void setSearchOrder(JITDylibSearchList NewSearchOrder, |
546 | bool SearchThisJITDylibFirst = true, |
547 | bool MatchNonExportedInThisDylib = true); |
548 | |
549 | /// Add the given JITDylib to the search order for definitions in this |
550 | /// JITDylib. |
551 | void addToSearchOrder(JITDylib &JD, bool MatcNonExported = false); |
552 | |
553 | /// Replace OldJD with NewJD in the search order if OldJD is present. |
554 | /// Otherwise this operation is a no-op. |
555 | void replaceInSearchOrder(JITDylib &OldJD, JITDylib &NewJD, |
556 | bool MatchNonExported = false); |
557 | |
558 | /// Remove the given JITDylib from the search order for this JITDylib if it is |
559 | /// present. Otherwise this operation is a no-op. |
560 | void removeFromSearchOrder(JITDylib &JD); |
561 | |
562 | /// Do something with the search order (run under the session lock). |
563 | template <typename Func> |
564 | auto withSearchOrderDo(Func &&F) |
565 | -> decltype(F(std::declval<const JITDylibSearchList &>())); |
566 | |
567 | /// Define all symbols provided by the materialization unit to be part of this |
568 | /// JITDylib. |
569 | /// |
570 | /// This overload always takes ownership of the MaterializationUnit. If any |
571 | /// errors occur, the MaterializationUnit consumed. |
572 | template <typename MaterializationUnitType> |
573 | Error define(std::unique_ptr<MaterializationUnitType> &&MU); |
574 | |
575 | /// Define all symbols provided by the materialization unit to be part of this |
576 | /// JITDylib. |
577 | /// |
578 | /// This overload only takes ownership of the MaterializationUnit no error is |
579 | /// generated. If an error occurs, ownership remains with the caller. This |
580 | /// may allow the caller to modify the MaterializationUnit to correct the |
581 | /// issue, then re-call define. |
582 | template <typename MaterializationUnitType> |
583 | Error define(std::unique_ptr<MaterializationUnitType> &MU); |
584 | |
585 | /// Tries to remove the given symbols. |
586 | /// |
587 | /// If any symbols are not defined in this JITDylib this method will return |
588 | /// a SymbolsNotFound error covering the missing symbols. |
589 | /// |
590 | /// If all symbols are found but some symbols are in the process of being |
591 | /// materialized this method will return a SymbolsCouldNotBeRemoved error. |
592 | /// |
593 | /// On success, all symbols are removed. On failure, the JITDylib state is |
594 | /// left unmodified (no symbols are removed). |
595 | Error remove(const SymbolNameSet &Names); |
596 | |
597 | /// Search the given JITDylib for the symbols in Symbols. If found, store |
598 | /// the flags for each symbol in Flags. Returns any unresolved symbols. |
599 | SymbolFlagsMap lookupFlags(const SymbolNameSet &Names); |
600 | |
601 | /// Dump current JITDylib state to OS. |
602 | void dump(raw_ostream &OS); |
603 | |
604 | /// FIXME: Remove this when we remove the old ORC layers. |
605 | /// Search the given JITDylibs in order for the symbols in Symbols. Results |
606 | /// (once they become available) will be returned via the given Query. |
607 | /// |
608 | /// If any symbol is not found then the unresolved symbols will be returned, |
609 | /// and the query will not be applied. The Query is not failed and can be |
610 | /// re-used in a subsequent lookup once the symbols have been added, or |
611 | /// manually failed. |
612 | SymbolNameSet legacyLookup(std::shared_ptr<AsynchronousSymbolQuery> Q, |
613 | SymbolNameSet Names); |
614 | |
615 | private: |
616 | using AsynchronousSymbolQueryList = |
617 | std::vector<std::shared_ptr<AsynchronousSymbolQuery>>; |
618 | |
619 | struct UnmaterializedInfo { |
620 | UnmaterializedInfo(std::unique_ptr<MaterializationUnit> MU) |
621 | : MU(std::move(MU)) {} |
622 | |
623 | std::unique_ptr<MaterializationUnit> MU; |
624 | }; |
625 | |
626 | using UnmaterializedInfosMap = |
627 | DenseMap<SymbolStringPtr, std::shared_ptr<UnmaterializedInfo>>; |
628 | |
629 | struct MaterializingInfo { |
630 | AsynchronousSymbolQueryList PendingQueries; |
631 | SymbolDependenceMap Dependants; |
632 | SymbolDependenceMap UnemittedDependencies; |
633 | bool IsEmitted = false; |
634 | }; |
635 | |
636 | using MaterializingInfosMap = DenseMap<SymbolStringPtr, MaterializingInfo>; |
637 | |
638 | using LookupImplActionFlags = enum { |
639 | None = 0, |
640 | NotifyFullyResolved = 1 << 0U, |
641 | NotifyFullyReady = 1 << 1U, |
642 | LLVM_MARK_AS_BITMASK_ENUM(NotifyFullyReady) |
643 | }; |
644 | |
645 | JITDylib(ExecutionSession &ES, std::string Name); |
646 | |
647 | Error defineImpl(MaterializationUnit &MU); |
648 | |
649 | SymbolNameSet lookupFlagsImpl(SymbolFlagsMap &Flags, |
650 | const SymbolNameSet &Names); |
651 | |
652 | void lodgeQuery(std::shared_ptr<AsynchronousSymbolQuery> &Q, |
653 | SymbolNameSet &Unresolved, bool MatchNonExported, |
654 | MaterializationUnitList &MUs); |
655 | |
656 | void lodgeQueryImpl(std::shared_ptr<AsynchronousSymbolQuery> &Q, |
657 | SymbolNameSet &Unresolved, bool MatchNonExported, |
658 | MaterializationUnitList &MUs); |
659 | |
660 | LookupImplActionFlags |
661 | lookupImpl(std::shared_ptr<AsynchronousSymbolQuery> &Q, |
662 | std::vector<std::unique_ptr<MaterializationUnit>> &MUs, |
663 | SymbolNameSet &Unresolved); |
664 | |
665 | void detachQueryHelper(AsynchronousSymbolQuery &Q, |
666 | const SymbolNameSet &QuerySymbols); |
667 | |
668 | void transferEmittedNodeDependencies(MaterializingInfo &DependantMI, |
669 | const SymbolStringPtr &DependantName, |
670 | MaterializingInfo &EmittedMI); |
671 | |
672 | Error defineMaterializing(const SymbolFlagsMap &SymbolFlags); |
673 | |
674 | void replace(std::unique_ptr<MaterializationUnit> MU); |
675 | |
676 | SymbolNameSet getRequestedSymbols(const SymbolFlagsMap &SymbolFlags) const; |
677 | |
678 | void addDependencies(const SymbolStringPtr &Name, |
679 | const SymbolDependenceMap &Dependants); |
680 | |
681 | void resolve(const SymbolMap &Resolved); |
682 | |
683 | void emit(const SymbolFlagsMap &Emitted); |
684 | |
685 | void notifyFailed(const SymbolNameSet &FailedSymbols); |
686 | |
687 | ExecutionSession &ES; |
688 | std::string JITDylibName; |
689 | SymbolMap Symbols; |
690 | UnmaterializedInfosMap UnmaterializedInfos; |
691 | MaterializingInfosMap MaterializingInfos; |
692 | GeneratorFunction DefGenerator; |
693 | JITDylibSearchList SearchOrder; |
694 | }; |
695 | |
696 | /// An ExecutionSession represents a running JIT program. |
697 | class ExecutionSession { |
698 | // FIXME: Remove this when we remove the old ORC layers. |
699 | friend class JITDylib; |
700 | |
701 | public: |
702 | /// For reporting errors. |
703 | using ErrorReporter = std::function<void(Error)>; |
704 | |
705 | /// For dispatching MaterializationUnit::materialize calls. |
706 | using DispatchMaterializationFunction = std::function<void( |
707 | JITDylib &JD, std::unique_ptr<MaterializationUnit> MU)>; |
708 | |
709 | /// Construct an ExecutionSession. |
710 | /// |
711 | /// SymbolStringPools may be shared between ExecutionSessions. |
712 | ExecutionSession(std::shared_ptr<SymbolStringPool> SSP = nullptr); |
713 | |
714 | /// Add a symbol name to the SymbolStringPool and return a pointer to it. |
715 | SymbolStringPtr intern(StringRef SymName) { return SSP->intern(SymName); } |
716 | |
717 | /// Returns a shared_ptr to the SymbolStringPool for this ExecutionSession. |
718 | std::shared_ptr<SymbolStringPool> getSymbolStringPool() const { return SSP; } |
719 | |
720 | /// Run the given lambda with the session mutex locked. |
721 | template <typename Func> auto runSessionLocked(Func &&F) -> decltype(F()) { |
722 | std::lock_guard<std::recursive_mutex> Lock(SessionMutex); |
723 | return F(); |
724 | } |
725 | |
726 | /// Get the "main" JITDylib, which is created automatically on construction of |
727 | /// the ExecutionSession. |
728 | JITDylib &getMainJITDylib(); |
729 | |
730 | /// Add a new JITDylib to this ExecutionSession. |
731 | JITDylib &createJITDylib(std::string Name, |
732 | bool AddToMainDylibSearchOrder = true); |
733 | |
734 | /// Allocate a module key for a new module to add to the JIT. |
735 | VModuleKey allocateVModule() { |
736 | return runSessionLocked([this]() { return ++LastKey; }); |
737 | } |
738 | |
739 | /// Return a module key to the ExecutionSession so that it can be |
740 | /// re-used. This should only be done once all resources associated |
741 | /// with the original key have been released. |
742 | void releaseVModule(VModuleKey Key) { /* FIXME: Recycle keys */ |
743 | } |
744 | |
745 | /// Set the error reporter function. |
746 | ExecutionSession &setErrorReporter(ErrorReporter ReportError) { |
747 | this->ReportError = std::move(ReportError); |
748 | return *this; |
749 | } |
750 | |
751 | /// Report a error for this execution session. |
752 | /// |
753 | /// Unhandled errors can be sent here to log them. |
754 | void reportError(Error Err) { ReportError(std::move(Err)); } |
755 | |
756 | /// Set the materialization dispatch function. |
757 | ExecutionSession &setDispatchMaterialization( |
758 | DispatchMaterializationFunction DispatchMaterialization) { |
759 | this->DispatchMaterialization = std::move(DispatchMaterialization); |
760 | return *this; |
761 | } |
762 | |
763 | void legacyFailQuery(AsynchronousSymbolQuery &Q, Error Err); |
764 | |
765 | using LegacyAsyncLookupFunction = std::function<SymbolNameSet( |
766 | std::shared_ptr<AsynchronousSymbolQuery> Q, SymbolNameSet Names)>; |
767 | |
768 | /// A legacy lookup function for JITSymbolResolverAdapter. |
769 | /// Do not use -- this will be removed soon. |
770 | Expected<SymbolMap> |
771 | legacyLookup(LegacyAsyncLookupFunction AsyncLookup, SymbolNameSet Names, |
772 | bool WaiUntilReady, |
773 | RegisterDependenciesFunction RegisterDependencies); |
774 | |
775 | /// Search the given JITDylib list for the given symbols. |
776 | /// |
777 | /// SearchOrder lists the JITDylibs to search. For each dylib, the associated |
778 | /// boolean indicates whether the search should match against non-exported |
779 | /// (hidden visibility) symbols in that dylib (true means match against |
780 | /// non-exported symbols, false means do not match). |
781 | /// |
782 | /// The OnResolve callback will be called once all requested symbols are |
783 | /// resolved, or if an error occurs prior to resolution. |
784 | /// |
785 | /// The OnReady callback will be called once all requested symbols are ready, |
786 | /// or if an error occurs after resolution but before all symbols are ready. |
787 | /// |
788 | /// If all symbols are found, the RegisterDependencies function will be called |
789 | /// while the session lock is held. This gives clients a chance to register |
790 | /// dependencies for on the queried symbols for any symbols they are |
791 | /// materializing (if a MaterializationResponsibility instance is present, |
792 | /// this can be implemented by calling |
793 | /// MaterializationResponsibility::addDependencies). If there are no |
794 | /// dependenant symbols for this query (e.g. it is being made by a top level |
795 | /// client to get an address to call) then the value NoDependenciesToRegister |
796 | /// can be used. |
797 | void lookup(const JITDylibSearchList &SearchOrder, SymbolNameSet Symbols, |
798 | SymbolsResolvedCallback OnResolve, SymbolsReadyCallback OnReady, |
799 | RegisterDependenciesFunction RegisterDependencies); |
800 | |
801 | /// Blocking version of lookup above. Returns the resolved symbol map. |
802 | /// If WaitUntilReady is true (the default), will not return until all |
803 | /// requested symbols are ready (or an error occurs). If WaitUntilReady is |
804 | /// false, will return as soon as all requested symbols are resolved, |
805 | /// or an error occurs. If WaitUntilReady is false and an error occurs |
806 | /// after resolution, the function will return a success value, but the |
807 | /// error will be reported via reportErrors. |
808 | Expected<SymbolMap> lookup(const JITDylibSearchList &SearchOrder, |
809 | const SymbolNameSet &Symbols, |
810 | RegisterDependenciesFunction RegisterDependencies = |
811 | NoDependenciesToRegister, |
812 | bool WaitUntilReady = true); |
813 | |
814 | /// Convenience version of blocking lookup. |
815 | /// Searches each of the JITDylibs in the search order in turn for the given |
816 | /// symbol. |
817 | Expected<JITEvaluatedSymbol> lookup(const JITDylibSearchList &SearchOrder, |
818 | SymbolStringPtr Symbol); |
819 | |
820 | /// Convenience version of blocking lookup. |
821 | /// Searches each of the JITDylibs in the search order in turn for the given |
822 | /// symbol. The search will not find non-exported symbols. |
823 | Expected<JITEvaluatedSymbol> lookup(ArrayRef<JITDylib *> SearchOrder, |
824 | SymbolStringPtr Symbol); |
825 | |
826 | /// Convenience version of blocking lookup. |
827 | /// Searches each of the JITDylibs in the search order in turn for the given |
828 | /// symbol. The search will not find non-exported symbols. |
829 | Expected<JITEvaluatedSymbol> lookup(ArrayRef<JITDylib *> SearchOrder, |
830 | StringRef Symbol); |
831 | |
832 | /// Materialize the given unit. |
833 | void dispatchMaterialization(JITDylib &JD, |
834 | std::unique_ptr<MaterializationUnit> MU) { |
835 | LLVM_DEBUG(runSessionLocked([&]() { |
836 | dbgs() << "Compiling, for " << JD.getName() << ", " << *MU |
837 | << "\n" ; |
838 | });); |
839 | DispatchMaterialization(JD, std::move(MU)); |
840 | } |
841 | |
842 | /// Dump the state of all the JITDylibs in this session. |
843 | void dump(raw_ostream &OS); |
844 | |
845 | private: |
846 | static void logErrorsToStdErr(Error Err) { |
847 | logAllUnhandledErrors(std::move(Err), errs(), "JIT session error: " ); |
848 | } |
849 | |
850 | static void |
851 | materializeOnCurrentThread(JITDylib &JD, |
852 | std::unique_ptr<MaterializationUnit> MU) { |
853 | MU->doMaterialize(JD); |
854 | } |
855 | |
856 | void runOutstandingMUs(); |
857 | |
858 | mutable std::recursive_mutex SessionMutex; |
859 | std::shared_ptr<SymbolStringPool> SSP; |
860 | VModuleKey LastKey = 0; |
861 | ErrorReporter ReportError = logErrorsToStdErr; |
862 | DispatchMaterializationFunction DispatchMaterialization = |
863 | materializeOnCurrentThread; |
864 | |
865 | std::vector<std::unique_ptr<JITDylib>> JDs; |
866 | |
867 | // FIXME: Remove this (and runOutstandingMUs) once the linking layer works |
868 | // with callbacks from asynchronous queries. |
869 | mutable std::recursive_mutex OutstandingMUsMutex; |
870 | std::vector<std::pair<JITDylib *, std::unique_ptr<MaterializationUnit>>> |
871 | OutstandingMUs; |
872 | }; |
873 | |
874 | template <typename Func> |
875 | auto JITDylib::withSearchOrderDo(Func &&F) |
876 | -> decltype(F(std::declval<const JITDylibSearchList &>())) { |
877 | return ES.runSessionLocked([&]() { return F(SearchOrder); }); |
878 | } |
879 | |
880 | template <typename MaterializationUnitType> |
881 | Error JITDylib::define(std::unique_ptr<MaterializationUnitType> &&MU) { |
882 | assert(MU && "Can not define with a null MU" ); |
883 | return ES.runSessionLocked([&, this]() -> Error { |
884 | if (auto Err = defineImpl(*MU)) |
885 | return Err; |
886 | |
887 | /// defineImpl succeeded. |
888 | auto UMI = std::make_shared<UnmaterializedInfo>(std::move(MU)); |
889 | for (auto &KV : UMI->MU->getSymbols()) |
890 | UnmaterializedInfos[KV.first] = UMI; |
891 | |
892 | return Error::success(); |
893 | }); |
894 | } |
895 | |
896 | template <typename MaterializationUnitType> |
897 | Error JITDylib::define(std::unique_ptr<MaterializationUnitType> &MU) { |
898 | assert(MU && "Can not define with a null MU" ); |
899 | |
900 | return ES.runSessionLocked([&, this]() -> Error { |
901 | if (auto Err = defineImpl(*MU)) |
902 | return Err; |
903 | |
904 | /// defineImpl succeeded. |
905 | auto UMI = std::make_shared<UnmaterializedInfo>(std::move(MU)); |
906 | for (auto &KV : UMI->MU->getSymbols()) |
907 | UnmaterializedInfos[KV.first] = UMI; |
908 | |
909 | return Error::success(); |
910 | }); |
911 | } |
912 | |
913 | /// Mangles symbol names then uniques them in the context of an |
914 | /// ExecutionSession. |
915 | class MangleAndInterner { |
916 | public: |
917 | MangleAndInterner(ExecutionSession &ES, const DataLayout &DL); |
918 | SymbolStringPtr operator()(StringRef Name); |
919 | |
920 | private: |
921 | ExecutionSession &ES; |
922 | const DataLayout &DL; |
923 | }; |
924 | |
925 | } // End namespace orc |
926 | } // End namespace llvm |
927 | |
928 | #undef DEBUG_TYPE // "orc" |
929 | |
930 | #endif // LLVM_EXECUTIONENGINE_ORC_CORE_H |
931 | |