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
22 #include <list>
23 #include <map>
24 #include <memory>
25 #include <set>
26 #include <vector>
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 VSO;
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 = std::set<SymbolStringPtr>;
45
46 /// Render a SymbolNameSet to an ostream.
47 raw_ostream &operator<<(raw_ostream &OS, const SymbolNameSet &Symbols);
48
49 /// A map from symbol names (as SymbolStringPtrs) to JITSymbols
50 /// (address/flags pairs).
51 using SymbolMap = std::map<SymbolStringPtr, JITEvaluatedSymbol>;
52
53 /// Render a SymbolMap to an ostream.
54 raw_ostream &operator<<(raw_ostream &OS, const SymbolMap &Symbols);
55
56 /// A map from symbol names (as SymbolStringPtrs) to JITSymbolFlags.
57 using SymbolFlagsMap = std::map<SymbolStringPtr, JITSymbolFlags>;
58
59 /// Render a SymbolMap to an ostream.
60 raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap &Symbols);
61
62 /// A base class for materialization failures that allows the failing
63 /// symbols to be obtained for logging.
64 using SymbolDependenceMap = std::map<VSO *, SymbolNameSet>;
65
66 /// Render a SymbolDependendeMap.
67 raw_ostream &operator<<(raw_ostream &OS, const SymbolDependenceMap &Deps);
68
69 /// A list of VSO pointers.
70 using VSOList = std::vector<VSO *>;
71
72 /// Render a VSOList.
73 raw_ostream &operator<<(raw_ostream &OS, const VSOList &VSOs);
74
75 /// Callback to notify client that symbols have been resolved.
76 using SymbolsResolvedCallback = std::function<void(Expected<SymbolMap>)>;
77
78 /// Callback to notify client that symbols are ready for execution.
79 using SymbolsReadyCallback = std::function<void(Error)>;
80
81 /// Callback to register the dependencies for a given query.
82 using RegisterDependenciesFunction =
83 std::function<void(const SymbolDependenceMap &)>;
84
85 /// This can be used as the value for a RegisterDependenciesFunction if there
86 /// are no dependants to register with.
87 extern RegisterDependenciesFunction NoDependenciesToRegister;
88
89 /// Used to notify a VSO that the given set of symbols failed to materialize.
90 class FailedToMaterialize : public ErrorInfo<FailedToMaterialize> {
91 public:
92 static char ID;
93
94 FailedToMaterialize(SymbolNameSet Symbols);
95 std::error_code convertToErrorCode() const override;
96 void log(raw_ostream &OS) const override;
getSymbols()97 const SymbolNameSet &getSymbols() const { return Symbols; }
98
99 private:
100 SymbolNameSet Symbols;
101 };
102
103 /// Used to notify clients when symbols can not be found during a lookup.
104 class SymbolsNotFound : public ErrorInfo<SymbolsNotFound> {
105 public:
106 static char ID;
107
108 SymbolsNotFound(SymbolNameSet Symbols);
109 std::error_code convertToErrorCode() const override;
110 void log(raw_ostream &OS) const override;
getSymbols()111 const SymbolNameSet &getSymbols() const { return Symbols; }
112
113 private:
114 SymbolNameSet Symbols;
115 };
116
117 /// Tracks responsibility for materialization, and mediates interactions between
118 /// MaterializationUnits and VSOs.
119 ///
120 /// An instance of this class is passed to MaterializationUnits when their
121 /// materialize method is called. It allows MaterializationUnits to resolve and
122 /// finalize symbols, or abandon materialization by notifying any unmaterialized
123 /// symbols of an error.
124 class MaterializationResponsibility {
125 friend class MaterializationUnit;
126 public:
127 MaterializationResponsibility(MaterializationResponsibility &&) = default;
128 MaterializationResponsibility &
129 operator=(MaterializationResponsibility &&) = delete;
130
131 /// Destruct a MaterializationResponsibility instance. In debug mode
132 /// this asserts that all symbols being tracked have been either
133 /// finalized or notified of an error.
134 ~MaterializationResponsibility();
135
136 /// Returns the target VSO that these symbols are being materialized
137 /// into.
getTargetVSO()138 VSO &getTargetVSO() const { return V; }
139
140 /// Returns the symbol flags map for this responsibility instance.
getSymbols()141 SymbolFlagsMap getSymbols() { return SymbolFlags; }
142
143 /// Returns the names of any symbols covered by this
144 /// MaterializationResponsibility object that have queries pending. This
145 /// information can be used to return responsibility for unrequested symbols
146 /// back to the VSO via the delegate method.
147 SymbolNameSet getRequestedSymbols();
148
149 /// Resolves the given symbols. Individual calls to this method may
150 /// resolve a subset of the symbols, but all symbols must have been
151 /// resolved prior to calling finalize.
152 void resolve(const SymbolMap &Symbols);
153
154 /// Finalizes all symbols tracked by this instance.
155 void finalize();
156
157 /// Adds new symbols to the VSO and this responsibility instance.
158 /// VSO entries start out in the materializing state.
159 ///
160 /// This method can be used by materialization units that want to add
161 /// additional symbols at materialization time (e.g. stubs, compile
162 /// callbacks, metadata).
163 Error defineMaterializing(const SymbolFlagsMap &SymbolFlags);
164
165 /// Notify all unfinalized symbols that an error has occurred.
166 /// This will remove all symbols covered by this MaterializationResponsibilty
167 /// from V, and send an error to any queries waiting on these symbols.
168 void failMaterialization();
169
170 /// Transfers responsibility to the given MaterializationUnit for all
171 /// symbols defined by that MaterializationUnit. This allows
172 /// materializers to break up work based on run-time information (e.g.
173 /// by introspecting which symbols have actually been looked up and
174 /// materializing only those).
175 void replace(std::unique_ptr<MaterializationUnit> MU);
176
177 /// Delegates responsibility for the given symbols to the returned
178 /// materialization responsibility. Useful for breaking up work between
179 /// threads, or different kinds of materialization processes.
180 MaterializationResponsibility delegate(const SymbolNameSet &Symbols);
181
182 void addDependencies(const SymbolStringPtr &Name,
183 const SymbolDependenceMap &Dependencies);
184
185 /// Add dependencies that apply to all symbols covered by this instance.
186 void addDependenciesForAll(const SymbolDependenceMap &Dependencies);
187
188 private:
189 /// Create a MaterializationResponsibility for the given VSO and
190 /// initial symbols.
191 MaterializationResponsibility(VSO &V, SymbolFlagsMap SymbolFlags);
192
193 VSO &V;
194 SymbolFlagsMap SymbolFlags;
195 };
196
197 /// A MaterializationUnit represents a set of symbol definitions that can
198 /// be materialized as a group, or individually discarded (when
199 /// overriding definitions are encountered).
200 ///
201 /// MaterializationUnits are used when providing lazy definitions of symbols to
202 /// VSOs. The VSO will call materialize when the address of a symbol is
203 /// requested via the lookup method. The VSO will call discard if a stronger
204 /// definition is added or already present.
205 class MaterializationUnit {
206 public:
MaterializationUnit(SymbolFlagsMap InitalSymbolFlags)207 MaterializationUnit(SymbolFlagsMap InitalSymbolFlags)
208 : SymbolFlags(std::move(InitalSymbolFlags)) {}
209
~MaterializationUnit()210 virtual ~MaterializationUnit() {}
211
212 /// Return the set of symbols that this source provides.
getSymbols()213 const SymbolFlagsMap &getSymbols() const { return SymbolFlags; }
214
215 /// Called by materialization dispatchers (see
216 /// ExecutionSession::DispatchMaterializationFunction) to trigger
217 /// materialization of this MaterializationUnit.
doMaterialize(VSO & V)218 void doMaterialize(VSO &V) {
219 materialize(MaterializationResponsibility(V, std::move(SymbolFlags)));
220 }
221
222 /// Called by VSOs to notify MaterializationUnits that the given symbol has
223 /// been overridden.
doDiscard(const VSO & V,SymbolStringPtr Name)224 void doDiscard(const VSO &V, SymbolStringPtr Name) {
225 SymbolFlags.erase(Name);
226 discard(V, std::move(Name));
227 }
228
229 protected:
230 SymbolFlagsMap SymbolFlags;
231
232 private:
233 virtual void anchor();
234
235 /// Implementations of this method should materialize all symbols
236 /// in the materialzation unit, except for those that have been
237 /// previously discarded.
238 virtual void materialize(MaterializationResponsibility R) = 0;
239
240 /// Implementations of this method should discard the given symbol
241 /// from the source (e.g. if the source is an LLVM IR Module and the
242 /// symbol is a function, delete the function body or mark it available
243 /// externally).
244 virtual void discard(const VSO &V, SymbolStringPtr Name) = 0;
245 };
246
247 using MaterializationUnitList =
248 std::vector<std::unique_ptr<MaterializationUnit>>;
249
250 /// A MaterializationUnit implementation for pre-existing absolute symbols.
251 ///
252 /// All symbols will be resolved and marked ready as soon as the unit is
253 /// materialized.
254 class AbsoluteSymbolsMaterializationUnit : public MaterializationUnit {
255 public:
256 AbsoluteSymbolsMaterializationUnit(SymbolMap Symbols);
257
258 private:
259 void materialize(MaterializationResponsibility R) override;
260 void discard(const VSO &V, SymbolStringPtr Name) override;
261 static SymbolFlagsMap extractFlags(const SymbolMap &Symbols);
262
263 SymbolMap Symbols;
264 };
265
266 /// Create an AbsoluteSymbolsMaterializationUnit with the given symbols.
267 /// Useful for inserting absolute symbols into a VSO. E.g.:
268 /// \code{.cpp}
269 /// VSO &V = ...;
270 /// SymbolStringPtr Foo = ...;
271 /// JITEvaluatedSymbol FooSym = ...;
272 /// if (auto Err = V.define(absoluteSymbols({{Foo, FooSym}})))
273 /// return Err;
274 /// \endcode
275 ///
276 inline std::unique_ptr<AbsoluteSymbolsMaterializationUnit>
absoluteSymbols(SymbolMap Symbols)277 absoluteSymbols(SymbolMap Symbols) {
278 return llvm::make_unique<AbsoluteSymbolsMaterializationUnit>(
279 std::move(Symbols));
280 }
281
282 struct SymbolAliasMapEntry {
283 SymbolAliasMapEntry() = default;
SymbolAliasMapEntrySymbolAliasMapEntry284 SymbolAliasMapEntry(SymbolStringPtr Aliasee, JITSymbolFlags AliasFlags)
285 : Aliasee(std::move(Aliasee)), AliasFlags(AliasFlags) {}
286
287 SymbolStringPtr Aliasee;
288 JITSymbolFlags AliasFlags;
289 };
290
291 /// A map of Symbols to (Symbol, Flags) pairs.
292 using SymbolAliasMap = std::map<SymbolStringPtr, SymbolAliasMapEntry>;
293
294 /// A materialization unit for symbol aliases. Allows existing symbols to be
295 /// aliased with alternate flags.
296 class ReExportsMaterializationUnit : public MaterializationUnit {
297 public:
298 /// SourceVSO is allowed to be nullptr, in which case the source VSO is
299 /// taken to be whatever VSO these definitions are materialized in. This
300 /// is useful for defining aliases within a VSO.
301 ///
302 /// Note: Care must be taken that no sets of aliases form a cycle, as such
303 /// a cycle will result in a deadlock when any symbol in the cycle is
304 /// resolved.
305 ReExportsMaterializationUnit(VSO *SourceVSO, SymbolAliasMap Aliases);
306
307 private:
308 void materialize(MaterializationResponsibility R) override;
309 void discard(const VSO &V, SymbolStringPtr Name) override;
310 static SymbolFlagsMap extractFlags(const SymbolAliasMap &Aliases);
311
312 VSO *SourceVSO = nullptr;
313 SymbolAliasMap Aliases;
314 };
315
316 /// Create a ReExportsMaterializationUnit with the given aliases.
317 /// Useful for defining symbol aliases.: E.g., given a VSO V containing symbols
318 /// "foo" and "bar", we can define aliases "baz" (for "foo") and "qux" (for
319 /// "bar") with:
320 /// \code{.cpp}
321 /// SymbolStringPtr Baz = ...;
322 /// SymbolStringPtr Qux = ...;
323 /// if (auto Err = V.define(symbolAliases({
324 /// {Baz, { Foo, JITSymbolFlags::Exported }},
325 /// {Qux, { Bar, JITSymbolFlags::Weak }}}))
326 /// return Err;
327 /// \endcode
328 inline std::unique_ptr<ReExportsMaterializationUnit>
symbolAliases(SymbolAliasMap Aliases)329 symbolAliases(SymbolAliasMap Aliases) {
330 return llvm::make_unique<ReExportsMaterializationUnit>(nullptr,
331 std::move(Aliases));
332 }
333
334 /// Create a materialization unit for re-exporting symbols from another VSO
335 /// with alternative names/flags.
336 inline std::unique_ptr<ReExportsMaterializationUnit>
reexports(VSO & SourceV,SymbolAliasMap Aliases)337 reexports(VSO &SourceV, SymbolAliasMap Aliases) {
338 return llvm::make_unique<ReExportsMaterializationUnit>(&SourceV,
339 std::move(Aliases));
340 }
341
342 /// Build a SymbolAliasMap for the common case where you want to re-export
343 /// symbols from another VSO with the same linkage/flags.
344 Expected<SymbolAliasMap>
345 buildSimpleReexportsAliasMap(VSO &SourceV, const SymbolNameSet &Symbols);
346
347 /// Base utilities for ExecutionSession.
348 class ExecutionSessionBase {
349 // FIXME: Remove this when we remove the old ORC layers.
350 friend class VSO;
351
352 public:
353 /// For reporting errors.
354 using ErrorReporter = std::function<void(Error)>;
355
356 /// For dispatching MaterializationUnit::materialize calls.
357 using DispatchMaterializationFunction =
358 std::function<void(VSO &V, std::unique_ptr<MaterializationUnit> MU)>;
359
360 /// Construct an ExecutionSessionBase.
361 ///
362 /// SymbolStringPools may be shared between ExecutionSessions.
363 ExecutionSessionBase(std::shared_ptr<SymbolStringPool> SSP = nullptr)
364 : SSP(SSP ? std::move(SSP) : std::make_shared<SymbolStringPool>()) {}
365
366 /// Returns the SymbolStringPool for this ExecutionSession.
getSymbolStringPool()367 SymbolStringPool &getSymbolStringPool() const { return *SSP; }
368
369 /// Run the given lambda with the session mutex locked.
370 template <typename Func> auto runSessionLocked(Func &&F) -> decltype(F()) {
371 std::lock_guard<std::recursive_mutex> Lock(SessionMutex);
372 return F();
373 }
374
375 /// Set the error reporter function.
setErrorReporter(ErrorReporter ReportError)376 ExecutionSessionBase &setErrorReporter(ErrorReporter ReportError) {
377 this->ReportError = std::move(ReportError);
378 return *this;
379 }
380
381 /// Set the materialization dispatch function.
setDispatchMaterialization(DispatchMaterializationFunction DispatchMaterialization)382 ExecutionSessionBase &setDispatchMaterialization(
383 DispatchMaterializationFunction DispatchMaterialization) {
384 this->DispatchMaterialization = std::move(DispatchMaterialization);
385 return *this;
386 }
387
388 /// Report a error for this execution session.
389 ///
390 /// Unhandled errors can be sent here to log them.
reportError(Error Err)391 void reportError(Error Err) { ReportError(std::move(Err)); }
392
393 /// Allocate a module key for a new module to add to the JIT.
allocateVModule()394 VModuleKey allocateVModule() { return ++LastKey; }
395
396 /// Return a module key to the ExecutionSession so that it can be
397 /// re-used. This should only be done once all resources associated
398 /// with the original key have been released.
releaseVModule(VModuleKey Key)399 void releaseVModule(VModuleKey Key) { /* FIXME: Recycle keys */
400 }
401
402 void legacyFailQuery(AsynchronousSymbolQuery &Q, Error Err);
403
404 using LegacyAsyncLookupFunction = std::function<SymbolNameSet(
405 std::shared_ptr<AsynchronousSymbolQuery> Q, SymbolNameSet Names)>;
406
407 /// A legacy lookup function for JITSymbolResolverAdapter.
408 /// Do not use -- this will be removed soon.
409 Expected<SymbolMap>
410 legacyLookup(ExecutionSessionBase &ES, LegacyAsyncLookupFunction AsyncLookup,
411 SymbolNameSet Names, bool WaiUntilReady,
412 RegisterDependenciesFunction RegisterDependencies);
413
414 /// Search the given VSO list for the given symbols.
415 ///
416 ///
417 /// The OnResolve callback will be called once all requested symbols are
418 /// resolved, or if an error occurs prior to resolution.
419 ///
420 /// The OnReady callback will be called once all requested symbols are ready,
421 /// or if an error occurs after resolution but before all symbols are ready.
422 ///
423 /// If all symbols are found, the RegisterDependencies function will be called
424 /// while the session lock is held. This gives clients a chance to register
425 /// dependencies for on the queried symbols for any symbols they are
426 /// materializing (if a MaterializationResponsibility instance is present,
427 /// this can be implemented by calling
428 /// MaterializationResponsibility::addDependencies). If there are no
429 /// dependenant symbols for this query (e.g. it is being made by a top level
430 /// client to get an address to call) then the value NoDependenciesToRegister
431 /// can be used.
432 void lookup(const VSOList &VSOs, const SymbolNameSet &Symbols,
433 SymbolsResolvedCallback OnResolve, SymbolsReadyCallback OnReady,
434 RegisterDependenciesFunction RegisterDependencies);
435
436 /// Blocking version of lookup above. Returns the resolved symbol map.
437 /// If WaitUntilReady is true (the default), will not return until all
438 /// requested symbols are ready (or an error occurs). If WaitUntilReady is
439 /// false, will return as soon as all requested symbols are resolved,
440 /// or an error occurs. If WaitUntilReady is false and an error occurs
441 /// after resolution, the function will return a success value, but the
442 /// error will be reported via reportErrors.
443 Expected<SymbolMap> lookup(const VSOList &VSOs, const SymbolNameSet &Symbols,
444 RegisterDependenciesFunction RegisterDependencies,
445 bool WaitUntilReady = true);
446
447 /// Materialize the given unit.
dispatchMaterialization(VSO & V,std::unique_ptr<MaterializationUnit> MU)448 void dispatchMaterialization(VSO &V,
449 std::unique_ptr<MaterializationUnit> MU) {
450 DispatchMaterialization(V, std::move(MU));
451 }
452
453 private:
logErrorsToStdErr(Error Err)454 static void logErrorsToStdErr(Error Err) {
455 logAllUnhandledErrors(std::move(Err), errs(), "JIT session error: ");
456 }
457
458 static void
materializeOnCurrentThread(VSO & V,std::unique_ptr<MaterializationUnit> MU)459 materializeOnCurrentThread(VSO &V, std::unique_ptr<MaterializationUnit> MU) {
460 MU->doMaterialize(V);
461 }
462
463 void runOutstandingMUs();
464
465 mutable std::recursive_mutex SessionMutex;
466 std::shared_ptr<SymbolStringPool> SSP;
467 VModuleKey LastKey = 0;
468 ErrorReporter ReportError = logErrorsToStdErr;
469 DispatchMaterializationFunction DispatchMaterialization =
470 materializeOnCurrentThread;
471
472 // FIXME: Remove this (and runOutstandingMUs) once the linking layer works
473 // with callbacks from asynchronous queries.
474 mutable std::recursive_mutex OutstandingMUsMutex;
475 std::vector<std::pair<VSO *, std::unique_ptr<MaterializationUnit>>>
476 OutstandingMUs;
477 };
478
479 /// A symbol query that returns results via a callback when results are
480 /// ready.
481 ///
482 /// makes a callback when all symbols are available.
483 class AsynchronousSymbolQuery {
484 friend class ExecutionSessionBase;
485 friend class VSO;
486
487 public:
488
489 /// Create a query for the given symbols, notify-resolved and
490 /// notify-ready callbacks.
491 AsynchronousSymbolQuery(const SymbolNameSet &Symbols,
492 SymbolsResolvedCallback NotifySymbolsResolved,
493 SymbolsReadyCallback NotifySymbolsReady);
494
495 /// Set the resolved symbol information for the given symbol name.
496 void resolve(const SymbolStringPtr &Name, JITEvaluatedSymbol Sym);
497
498 /// Returns true if all symbols covered by this query have been
499 /// resolved.
isFullyResolved()500 bool isFullyResolved() const { return NotYetResolvedCount == 0; }
501
502 /// Call the NotifySymbolsResolved callback.
503 ///
504 /// This should only be called if all symbols covered by the query have been
505 /// resolved.
506 void handleFullyResolved();
507
508 /// Notify the query that a requested symbol is ready for execution.
509 void notifySymbolReady();
510
511 /// Returns true if all symbols covered by this query are ready.
isFullyReady()512 bool isFullyReady() const { return NotYetReadyCount == 0; }
513
514 /// Calls the NotifySymbolsReady callback.
515 ///
516 /// This should only be called if all symbols covered by this query are ready.
517 void handleFullyReady();
518
519 private:
520 void addQueryDependence(VSO &V, SymbolStringPtr Name);
521
522 void removeQueryDependence(VSO &V, const SymbolStringPtr &Name);
523
524 bool canStillFail();
525
526 void handleFailed(Error Err);
527
528 void detach();
529
530 SymbolsResolvedCallback NotifySymbolsResolved;
531 SymbolsReadyCallback NotifySymbolsReady;
532 SymbolDependenceMap QueryRegistrations;
533 SymbolMap ResolvedSymbols;
534 size_t NotYetResolvedCount;
535 size_t NotYetReadyCount;
536 };
537
538 /// A symbol table that supports asynchoronous symbol queries.
539 ///
540 /// Represents a virtual shared object. Instances can not be copied or moved, so
541 /// their addresses may be used as keys for resource management.
542 /// VSO state changes must be made via an ExecutionSession to guarantee that
543 /// they are synchronized with respect to other VSO operations.
544 class VSO {
545 friend class AsynchronousSymbolQuery;
546 friend class ExecutionSession;
547 friend class ExecutionSessionBase;
548 friend class MaterializationResponsibility;
549 public:
550 using FallbackDefinitionGeneratorFunction =
551 std::function<SymbolNameSet(VSO &Parent, const SymbolNameSet &Names)>;
552
553 using AsynchronousSymbolQuerySet =
554 std::set<std::shared_ptr<AsynchronousSymbolQuery>>;
555
556 VSO(const VSO &) = delete;
557 VSO &operator=(const VSO &) = delete;
558 VSO(VSO &&) = delete;
559 VSO &operator=(VSO &&) = delete;
560
561 /// Get the name for this VSO.
getName()562 const std::string &getName() const { return VSOName; }
563
564 /// Get a reference to the ExecutionSession for this VSO.
getExecutionSession()565 ExecutionSessionBase &getExecutionSession() const { return ES; }
566
567 /// Set a fallback defenition generator. If set, lookup and lookupFlags will
568 /// pass the unresolved symbols set to the fallback definition generator,
569 /// allowing it to add a new definition to the VSO.
setFallbackDefinitionGenerator(FallbackDefinitionGeneratorFunction FallbackDefinitionGenerator)570 void setFallbackDefinitionGenerator(
571 FallbackDefinitionGeneratorFunction FallbackDefinitionGenerator) {
572 this->FallbackDefinitionGenerator = std::move(FallbackDefinitionGenerator);
573 }
574
575 /// Set the search order to be used when fixing up definitions in VSO.
576 /// This will replace the previous search order, and apply to any symbol
577 /// resolutions made for definitions in this VSO after the call to
578 /// setSearchOrder (even if the definition itself was added before the
579 /// call).
580 ///
581 /// If SearchThisVSOFirst is set, which by default it is, then this VSO will
582 /// add itself to the beginning of the SearchOrder (Clients should *not*
583 /// put this VSO in the list in this case, to avoid redundant lookups).
584 ///
585 /// If SearchThisVSOFirst is false then the search order will be used as
586 /// given. The main motivation for this feature is to support deliberate
587 /// shadowing of symbols in this VSO by a facade VSO. For example, the
588 /// facade may resolve function names to stubs, and the stubs may compile
589 /// lazily by looking up symbols in this dylib. Adding the facade dylib
590 /// as the first in the search order (instead of this dylib) ensures that
591 /// definitions within this dylib resolve to the lazy-compiling stubs,
592 /// rather than immediately materializing the definitions in this dylib.
593 void setSearchOrder(VSOList NewSearchOrder, bool SearchThisVSOFirst = true);
594
595 /// Add the given VSO to the search order for definitions in this VSO.
596 void addToSearchOrder(VSO &V);
597
598 /// Replace OldV with NewV in the search order if OldV is present. Otherwise
599 /// this operation is a no-op.
600 void replaceInSearchOrder(VSO &OldV, VSO &NewV);
601
602 /// Remove the given VSO from the search order for this VSO if it is
603 /// present. Otherwise this operation is a no-op.
604 void removeFromSearchOrder(VSO &V);
605
606 /// Do something with the search order (run under the session lock).
607 template <typename Func>
608 auto withSearchOrderDo(Func &&F)
609 -> decltype(F(std::declval<const VSOList &>())) {
610 return ES.runSessionLocked([&]() { return F(SearchOrder); });
611 }
612
613 /// Define all symbols provided by the materialization unit to be part
614 /// of the given VSO.
615 template <typename UniquePtrToMaterializationUnit>
616 typename std::enable_if<
617 std::is_convertible<
618 typename std::decay<UniquePtrToMaterializationUnit>::type,
619 std::unique_ptr<MaterializationUnit>>::value,
620 Error>::type
define(UniquePtrToMaterializationUnit && MU)621 define(UniquePtrToMaterializationUnit &&MU) {
622 return ES.runSessionLocked([&, this]() -> Error {
623 assert(MU && "Can't define with a null MU");
624
625 if (auto Err = defineImpl(*MU))
626 return Err;
627
628 /// defineImpl succeeded.
629 auto UMI = std::make_shared<UnmaterializedInfo>(std::move(MU));
630 for (auto &KV : UMI->MU->getSymbols())
631 UnmaterializedInfos[KV.first] = UMI;
632
633 return Error::success();
634 });
635 }
636
637 /// Search the given VSO for the symbols in Symbols. If found, store
638 /// the flags for each symbol in Flags. Returns any unresolved symbols.
639 SymbolFlagsMap lookupFlags(const SymbolNameSet &Names);
640
641 /// Dump current VSO state to OS.
642 void dump(raw_ostream &OS);
643
644 /// FIXME: Remove this when we remove the old ORC layers.
645 /// Search the given VSOs in order for the symbols in Symbols. Results
646 /// (once they become available) will be returned via the given Query.
647 ///
648 /// If any symbol is not found then the unresolved symbols will be returned,
649 /// and the query will not be applied. The Query is not failed and can be
650 /// re-used in a subsequent lookup once the symbols have been added, or
651 /// manually failed.
652 SymbolNameSet legacyLookup(std::shared_ptr<AsynchronousSymbolQuery> Q,
653 SymbolNameSet Names);
654
655 private:
656 using AsynchronousSymbolQueryList =
657 std::vector<std::shared_ptr<AsynchronousSymbolQuery>>;
658
659 struct UnmaterializedInfo {
UnmaterializedInfoUnmaterializedInfo660 UnmaterializedInfo(std::unique_ptr<MaterializationUnit> MU)
661 : MU(std::move(MU)) {}
662
663 std::unique_ptr<MaterializationUnit> MU;
664 };
665
666 using UnmaterializedInfosMap =
667 std::map<SymbolStringPtr, std::shared_ptr<UnmaterializedInfo>>;
668
669 struct MaterializingInfo {
670 AsynchronousSymbolQueryList PendingQueries;
671 SymbolDependenceMap Dependants;
672 SymbolDependenceMap UnfinalizedDependencies;
673 bool IsFinalized = false;
674 };
675
676 using MaterializingInfosMap = std::map<SymbolStringPtr, MaterializingInfo>;
677
678 using LookupImplActionFlags = enum {
679 None = 0,
680 NotifyFullyResolved = 1 << 0U,
681 NotifyFullyReady = 1 << 1U,
682 LLVM_MARK_AS_BITMASK_ENUM(NotifyFullyReady)
683 };
684
685 VSO(ExecutionSessionBase &ES, std::string Name);
686
687 Error defineImpl(MaterializationUnit &MU);
688
689 SymbolNameSet lookupFlagsImpl(SymbolFlagsMap &Flags,
690 const SymbolNameSet &Names);
691
692 void lodgeQuery(std::shared_ptr<AsynchronousSymbolQuery> &Q,
693 SymbolNameSet &Unresolved, MaterializationUnitList &MUs);
694
695 void lodgeQueryImpl(std::shared_ptr<AsynchronousSymbolQuery> &Q,
696 SymbolNameSet &Unresolved, MaterializationUnitList &MUs);
697
698 LookupImplActionFlags
699 lookupImpl(std::shared_ptr<AsynchronousSymbolQuery> &Q,
700 std::vector<std::unique_ptr<MaterializationUnit>> &MUs,
701 SymbolNameSet &Unresolved);
702
703 void detachQueryHelper(AsynchronousSymbolQuery &Q,
704 const SymbolNameSet &QuerySymbols);
705
706 void transferFinalizedNodeDependencies(MaterializingInfo &DependantMI,
707 const SymbolStringPtr &DependantName,
708 MaterializingInfo &FinalizedMI);
709
710 Error defineMaterializing(const SymbolFlagsMap &SymbolFlags);
711
712 void replace(std::unique_ptr<MaterializationUnit> MU);
713
714 SymbolNameSet getRequestedSymbols(const SymbolFlagsMap &SymbolFlags);
715
716 void addDependencies(const SymbolStringPtr &Name,
717 const SymbolDependenceMap &Dependants);
718
719 void resolve(const SymbolMap &Resolved);
720
721 void finalize(const SymbolFlagsMap &Finalized);
722
723 void notifyFailed(const SymbolNameSet &FailedSymbols);
724
725 ExecutionSessionBase &ES;
726 std::string VSOName;
727 SymbolMap Symbols;
728 UnmaterializedInfosMap UnmaterializedInfos;
729 MaterializingInfosMap MaterializingInfos;
730 FallbackDefinitionGeneratorFunction FallbackDefinitionGenerator;
731 VSOList SearchOrder;
732 };
733
734 /// An ExecutionSession represents a running JIT program.
735 class ExecutionSession : public ExecutionSessionBase {
736 public:
737 using ErrorReporter = std::function<void(Error)>;
738
739 using DispatchMaterializationFunction =
740 std::function<void(VSO &V, std::unique_ptr<MaterializationUnit> MU)>;
741
742 /// Construct an ExecutionEngine.
743 ///
744 /// SymbolStringPools may be shared between ExecutionSessions.
745 ExecutionSession(std::shared_ptr<SymbolStringPool> SSP = nullptr)
ExecutionSessionBase(std::move (SSP))746 : ExecutionSessionBase(std::move(SSP)) {}
747
748 /// Add a new VSO to this ExecutionSession.
749 VSO &createVSO(std::string Name);
750
751 private:
752 std::vector<std::unique_ptr<VSO>> VSOs;
753 };
754
755 /// Look up the given names in the given VSOs.
756 /// VSOs will be searched in order and no VSO pointer may be null.
757 /// All symbols must be found within the given VSOs or an error
758 /// will be returned.
759 Expected<SymbolMap> lookup(const VSOList &VSOs, SymbolNameSet Names);
760
761 /// Look up a symbol by searching a list of VSOs.
762 Expected<JITEvaluatedSymbol> lookup(const VSOList &VSOs, SymbolStringPtr Name);
763
764 /// Mangles symbol names then uniques them in the context of an
765 /// ExecutionSession.
766 class MangleAndInterner {
767 public:
768 MangleAndInterner(ExecutionSessionBase &ES, const DataLayout &DL);
769 SymbolStringPtr operator()(StringRef Name);
770
771 private:
772 ExecutionSessionBase &ES;
773 const DataLayout &DL;
774 };
775
776 } // End namespace orc
777 } // End namespace llvm
778
779 #endif // LLVM_EXECUTIONENGINE_ORC_CORE_H
780