1 //===------ Core.h -- Core ORC APIs (Layer, JITDylib, etc.) -----*- 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 // Contains core ORC APIs.
12 //===----------------------------------------------------------------------===//
14 #ifndef LLVM_EXECUTIONENGINE_ORC_CORE_H
15 #define LLVM_EXECUTIONENGINE_ORC_CORE_H
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"
26 #define DEBUG_TYPE "orc"
31 // Forward declare some classes.
32 class AsynchronousSymbolQuery;
33 class ExecutionSession;
34 class MaterializationUnit;
35 class MaterializationResponsibility;
38 /// VModuleKey provides a unique identifier (allocated and managed by
39 /// ExecutionSessions) for a module added to the JIT.
40 using VModuleKey = uint64_t;
42 /// A set of symbol names (represented by SymbolStringPtrs for
44 using SymbolNameSet = DenseSet<SymbolStringPtr>;
46 /// A map from symbol names (as SymbolStringPtrs) to JITSymbols
47 /// (address/flags pairs).
48 using SymbolMap = DenseMap<SymbolStringPtr, JITEvaluatedSymbol>;
50 /// A map from symbol names (as SymbolStringPtrs) to JITSymbolFlags.
51 using SymbolFlagsMap = DenseMap<SymbolStringPtr, JITSymbolFlags>;
53 /// A base class for materialization failures that allows the failing
54 /// symbols to be obtained for logging.
55 using SymbolDependenceMap = DenseMap<JITDylib *, SymbolNameSet>;
57 /// A list of (JITDylib*, bool) pairs.
58 using JITDylibSearchList = std::vector<std::pair<JITDylib *, bool>>;
60 /// Render a SymbolStringPtr.
61 raw_ostream &operator<<(raw_ostream &OS, const SymbolStringPtr &Sym);
63 /// Render a SymbolNameSet.
64 raw_ostream &operator<<(raw_ostream &OS, const SymbolNameSet &Symbols);
66 /// Render a SymbolFlagsMap entry.
67 raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap::value_type &KV);
69 /// Render a SymbolMap entry.
70 raw_ostream &operator<<(raw_ostream &OS, const SymbolMap::value_type &KV);
72 /// Render a SymbolFlagsMap.
73 raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap &SymbolFlags);
75 /// Render a SymbolMap.
76 raw_ostream &operator<<(raw_ostream &OS, const SymbolMap &Symbols);
78 /// Render a SymbolDependenceMap entry.
79 raw_ostream &operator<<(raw_ostream &OS,
80 const SymbolDependenceMap::value_type &KV);
82 /// Render a SymbolDependendeMap.
83 raw_ostream &operator<<(raw_ostream &OS, const SymbolDependenceMap &Deps);
85 /// Render a MaterializationUnit.
86 raw_ostream &operator<<(raw_ostream &OS, const MaterializationUnit &MU);
88 /// Render a JITDylibSearchList.
89 raw_ostream &operator<<(raw_ostream &OS, const JITDylibSearchList &JDs);
91 /// Callback to notify client that symbols have been resolved.
92 using SymbolsResolvedCallback = std::function<void(Expected<SymbolMap>)>;
94 /// Callback to notify client that symbols are ready for execution.
95 using SymbolsReadyCallback = std::function<void(Error)>;
97 /// Callback to register the dependencies for a given query.
98 using RegisterDependenciesFunction =
99 std::function<void(const SymbolDependenceMap &)>;
101 /// This can be used as the value for a RegisterDependenciesFunction if there
102 /// are no dependants to register with.
103 extern RegisterDependenciesFunction NoDependenciesToRegister;
105 /// Used to notify a JITDylib that the given set of symbols failed to
107 class FailedToMaterialize : public ErrorInfo<FailedToMaterialize> {
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; }
117 SymbolNameSet Symbols;
120 /// Used to notify clients when symbols can not be found during a lookup.
121 class SymbolsNotFound : public ErrorInfo<SymbolsNotFound> {
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; }
131 SymbolNameSet Symbols;
134 /// Used to notify clients that a set of symbols could not be removed.
135 class SymbolsCouldNotBeRemoved : public ErrorInfo<SymbolsCouldNotBeRemoved> {
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; }
145 SymbolNameSet Symbols;
148 /// Tracks responsibility for materialization, and mediates interactions between
149 /// MaterializationUnits and JDs.
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;
158 MaterializationResponsibility(MaterializationResponsibility &&) = default;
159 MaterializationResponsibility &
160 operator=(MaterializationResponsibility &&) = delete;
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();
167 /// Returns the target JITDylib that these symbols are being materialized
169 JITDylib &getTargetJITDylib() const { return JD; }
171 /// Returns the VModuleKey for this instance.
172 VModuleKey getVModuleKey() const { return K; }
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
178 const SymbolFlagsMap &getSymbols() { return SymbolFlags; }
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;
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);
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.
199 /// Adds new symbols to the JITDylib and this responsibility instance.
200 /// JITDylib entries start out in the materializing state.
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);
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
212 void failMaterialization();
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);
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());
227 void addDependencies(const SymbolStringPtr &Name,
228 const SymbolDependenceMap &Dependencies);
230 /// Add dependencies that apply to all symbols covered by this instance.
231 void addDependenciesForAll(const SymbolDependenceMap &Dependencies);
234 /// Create a MaterializationResponsibility for the given JITDylib and
236 MaterializationResponsibility(JITDylib &JD, SymbolFlagsMap SymbolFlags,
240 SymbolFlagsMap SymbolFlags;
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).
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 {
254 MaterializationUnit(SymbolFlagsMap InitalSymbolFlags, VModuleKey K)
255 : SymbolFlags(std::move(InitalSymbolFlags)), K(std::move(K)) {}
257 virtual ~MaterializationUnit() {}
259 /// Return the name of this materialization unit. Useful for debugging
261 virtual StringRef getName() const = 0;
263 /// Return the set of symbols that this source provides.
264 const SymbolFlagsMap &getSymbols() const { return SymbolFlags; }
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),
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));
282 SymbolFlagsMap SymbolFlags;
286 virtual void anchor();
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;
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
297 virtual void discard(const JITDylib &JD, const SymbolStringPtr &Name) = 0;
300 using MaterializationUnitList =
301 std::vector<std::unique_ptr<MaterializationUnit>>;
303 /// A MaterializationUnit implementation for pre-existing absolute symbols.
305 /// All symbols will be resolved and marked ready as soon as the unit is
307 class AbsoluteSymbolsMaterializationUnit : public MaterializationUnit {
309 AbsoluteSymbolsMaterializationUnit(SymbolMap Symbols, VModuleKey K);
311 StringRef getName() const override;
314 void materialize(MaterializationResponsibility R) override;
315 void discard(const JITDylib &JD, const SymbolStringPtr &Name) override;
316 static SymbolFlagsMap extractFlags(const SymbolMap &Symbols);
321 /// Create an AbsoluteSymbolsMaterializationUnit with the given symbols.
322 /// Useful for inserting absolute symbols into a JITDylib. E.g.:
324 /// JITDylib &JD = ...;
325 /// SymbolStringPtr Foo = ...;
326 /// JITEvaluatedSymbol FooSym = ...;
327 /// if (auto Err = JD.define(absoluteSymbols({{Foo, FooSym}})))
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));
337 struct SymbolAliasMapEntry {
338 SymbolAliasMapEntry() = default;
339 SymbolAliasMapEntry(SymbolStringPtr Aliasee, JITSymbolFlags AliasFlags)
340 : Aliasee(std::move(Aliasee)), AliasFlags(AliasFlags) {}
342 SymbolStringPtr Aliasee;
343 JITSymbolFlags AliasFlags;
346 /// A map of Symbols to (Symbol, Flags) pairs.
347 using SymbolAliasMap = DenseMap<SymbolStringPtr, SymbolAliasMapEntry>;
349 /// A materialization unit for symbol aliases. Allows existing symbols to be
350 /// aliased with alternate flags.
351 class ReExportsMaterializationUnit : public MaterializationUnit {
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.
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
361 ReExportsMaterializationUnit(JITDylib *SourceJD, bool MatchNonExported,
362 SymbolAliasMap Aliases, VModuleKey K);
364 StringRef getName() const override;
367 void materialize(MaterializationResponsibility R) override;
368 void discard(const JITDylib &JD, const SymbolStringPtr &Name) override;
369 static SymbolFlagsMap extractFlags(const SymbolAliasMap &Aliases);
371 JITDylib *SourceJD = nullptr;
372 bool MatchNonExported = false;
373 SymbolAliasMap Aliases;
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 }}}))
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));
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));
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);
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 {
414 using SymbolPredicate = std::function<bool(SymbolStringPtr)>;
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());
422 SymbolNameSet operator()(JITDylib &JD, const SymbolNameSet &Names);
426 bool MatchNonExported = false;
427 SymbolPredicate Allow;
430 /// A symbol query that returns results via a callback when results are
433 /// makes a callback when all symbols are available.
434 class AsynchronousSymbolQuery {
435 friend class ExecutionSession;
436 friend class JITDylib;
437 friend class JITSymbolResolverAdapter;
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);
447 /// Set the resolved symbol information for the given symbol name.
448 void resolve(const SymbolStringPtr &Name, JITEvaluatedSymbol Sym);
450 /// Returns true if all symbols covered by this query have been
452 bool isFullyResolved() const { return NotYetResolvedCount == 0; }
454 /// Call the NotifySymbolsResolved callback.
456 /// This should only be called if all symbols covered by the query have been
458 void handleFullyResolved();
460 /// Notify the query that a requested symbol is ready for execution.
461 void notifySymbolReady();
463 /// Returns true if all symbols covered by this query are ready.
464 bool isFullyReady() const { return NotYetReadyCount == 0; }
466 /// Calls the NotifySymbolsReady callback.
468 /// This should only be called if all symbols covered by this query are ready.
469 void handleFullyReady();
472 void addQueryDependence(JITDylib &JD, SymbolStringPtr Name);
474 void removeQueryDependence(JITDylib &JD, const SymbolStringPtr &Name);
478 void handleFailed(Error Err);
482 SymbolsResolvedCallback NotifySymbolsResolved;
483 SymbolsReadyCallback NotifySymbolsReady;
484 SymbolDependenceMap QueryRegistrations;
485 SymbolMap ResolvedSymbols;
486 size_t NotYetResolvedCount;
487 size_t NotYetReadyCount;
490 /// A symbol table that supports asynchoronous symbol queries.
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.
497 friend class AsynchronousSymbolQuery;
498 friend class ExecutionSession;
499 friend class MaterializationResponsibility;
501 using GeneratorFunction = std::function<SymbolNameSet(
502 JITDylib &Parent, const SymbolNameSet &Names)>;
504 using AsynchronousSymbolQuerySet =
505 std::set<std::shared_ptr<AsynchronousSymbolQuery>>;
507 JITDylib(const JITDylib &) = delete;
508 JITDylib &operator=(const JITDylib &) = delete;
509 JITDylib(JITDylib &&) = delete;
510 JITDylib &operator=(JITDylib &&) = delete;
512 /// Get the name for this JITDylib.
513 const std::string &getName() const { return JITDylibName; }
515 /// Get a reference to the ExecutionSession for this JITDylib.
516 ExecutionSession &getExecutionSession() const { return ES; }
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);
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
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).
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);
549 /// Add the given JITDylib to the search order for definitions in this
551 void addToSearchOrder(JITDylib &JD, bool MatcNonExported = false);
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);
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);
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 &>()));
567 /// Define all symbols provided by the materialization unit to be part of this
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);
575 /// Define all symbols provided by the materialization unit to be part of this
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);
585 /// Tries to remove the given symbols.
587 /// If any symbols are not defined in this JITDylib this method will return
588 /// a SymbolsNotFound error covering the missing symbols.
590 /// If all symbols are found but some symbols are in the process of being
591 /// materialized this method will return a SymbolsCouldNotBeRemoved error.
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);
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);
601 /// Dump current JITDylib state to OS.
602 void dump(raw_ostream &OS);
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.
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
612 SymbolNameSet legacyLookup(std::shared_ptr<AsynchronousSymbolQuery> Q,
613 SymbolNameSet Names);
616 using AsynchronousSymbolQueryList =
617 std::vector<std::shared_ptr<AsynchronousSymbolQuery>>;
619 struct UnmaterializedInfo {
620 UnmaterializedInfo(std::unique_ptr<MaterializationUnit> MU)
621 : MU(std::move(MU)) {}
623 std::unique_ptr<MaterializationUnit> MU;
626 using UnmaterializedInfosMap =
627 DenseMap<SymbolStringPtr, std::shared_ptr<UnmaterializedInfo>>;
629 struct MaterializingInfo {
630 AsynchronousSymbolQueryList PendingQueries;
631 SymbolDependenceMap Dependants;
632 SymbolDependenceMap UnemittedDependencies;
633 bool IsEmitted = false;
636 using MaterializingInfosMap = DenseMap<SymbolStringPtr, MaterializingInfo>;
638 using LookupImplActionFlags = enum {
640 NotifyFullyResolved = 1 << 0U,
641 NotifyFullyReady = 1 << 1U,
642 LLVM_MARK_AS_BITMASK_ENUM(NotifyFullyReady)
645 JITDylib(ExecutionSession &ES, std::string Name);
647 Error defineImpl(MaterializationUnit &MU);
649 SymbolNameSet lookupFlagsImpl(SymbolFlagsMap &Flags,
650 const SymbolNameSet &Names);
652 void lodgeQuery(std::shared_ptr<AsynchronousSymbolQuery> &Q,
653 SymbolNameSet &Unresolved, bool MatchNonExported,
654 MaterializationUnitList &MUs);
656 void lodgeQueryImpl(std::shared_ptr<AsynchronousSymbolQuery> &Q,
657 SymbolNameSet &Unresolved, bool MatchNonExported,
658 MaterializationUnitList &MUs);
660 LookupImplActionFlags
661 lookupImpl(std::shared_ptr<AsynchronousSymbolQuery> &Q,
662 std::vector<std::unique_ptr<MaterializationUnit>> &MUs,
663 SymbolNameSet &Unresolved);
665 void detachQueryHelper(AsynchronousSymbolQuery &Q,
666 const SymbolNameSet &QuerySymbols);
668 void transferEmittedNodeDependencies(MaterializingInfo &DependantMI,
669 const SymbolStringPtr &DependantName,
670 MaterializingInfo &EmittedMI);
672 Error defineMaterializing(const SymbolFlagsMap &SymbolFlags);
674 void replace(std::unique_ptr<MaterializationUnit> MU);
676 SymbolNameSet getRequestedSymbols(const SymbolFlagsMap &SymbolFlags) const;
678 void addDependencies(const SymbolStringPtr &Name,
679 const SymbolDependenceMap &Dependants);
681 void resolve(const SymbolMap &Resolved);
683 void emit(const SymbolFlagsMap &Emitted);
685 void notifyFailed(const SymbolNameSet &FailedSymbols);
687 ExecutionSession &ES;
688 std::string JITDylibName;
690 UnmaterializedInfosMap UnmaterializedInfos;
691 MaterializingInfosMap MaterializingInfos;
692 GeneratorFunction DefGenerator;
693 JITDylibSearchList SearchOrder;
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;
702 /// For reporting errors.
703 using ErrorReporter = std::function<void(Error)>;
705 /// For dispatching MaterializationUnit::materialize calls.
706 using DispatchMaterializationFunction = std::function<void(
707 JITDylib &JD, std::unique_ptr<MaterializationUnit> MU)>;
709 /// Construct an ExecutionSession.
711 /// SymbolStringPools may be shared between ExecutionSessions.
712 ExecutionSession(std::shared_ptr<SymbolStringPool> SSP = nullptr);
714 /// Add a symbol name to the SymbolStringPool and return a pointer to it.
715 SymbolStringPtr intern(StringRef SymName) { return SSP->intern(SymName); }
717 /// Returns a shared_ptr to the SymbolStringPool for this ExecutionSession.
718 std::shared_ptr<SymbolStringPool> getSymbolStringPool() const { return SSP; }
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);
726 /// Get the "main" JITDylib, which is created automatically on construction of
727 /// the ExecutionSession.
728 JITDylib &getMainJITDylib();
730 /// Add a new JITDylib to this ExecutionSession.
731 JITDylib &createJITDylib(std::string Name,
732 bool AddToMainDylibSearchOrder = true);
734 /// Allocate a module key for a new module to add to the JIT.
735 VModuleKey allocateVModule() {
736 return runSessionLocked([this]() { return ++LastKey; });
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 */
745 /// Set the error reporter function.
746 ExecutionSession &setErrorReporter(ErrorReporter ReportError) {
747 this->ReportError = std::move(ReportError);
751 /// Report a error for this execution session.
753 /// Unhandled errors can be sent here to log them.
754 void reportError(Error Err) { ReportError(std::move(Err)); }
756 /// Set the materialization dispatch function.
757 ExecutionSession &setDispatchMaterialization(
758 DispatchMaterializationFunction DispatchMaterialization) {
759 this->DispatchMaterialization = std::move(DispatchMaterialization);
763 void legacyFailQuery(AsynchronousSymbolQuery &Q, Error Err);
765 using LegacyAsyncLookupFunction = std::function<SymbolNameSet(
766 std::shared_ptr<AsynchronousSymbolQuery> Q, SymbolNameSet Names)>;
768 /// A legacy lookup function for JITSymbolResolverAdapter.
769 /// Do not use -- this will be removed soon.
771 legacyLookup(LegacyAsyncLookupFunction AsyncLookup, SymbolNameSet Names,
773 RegisterDependenciesFunction RegisterDependencies);
775 /// Search the given JITDylib list for the given symbols.
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).
782 /// The OnResolve callback will be called once all requested symbols are
783 /// resolved, or if an error occurs prior to resolution.
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.
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
797 void lookup(const JITDylibSearchList &SearchOrder, SymbolNameSet Symbols,
798 SymbolsResolvedCallback OnResolve, SymbolsReadyCallback OnReady,
799 RegisterDependenciesFunction RegisterDependencies);
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);
814 /// Convenience version of blocking lookup.
815 /// Searches each of the JITDylibs in the search order in turn for the given
817 Expected<JITEvaluatedSymbol> lookup(const JITDylibSearchList &SearchOrder,
818 SymbolStringPtr Symbol);
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);
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,
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
839 DispatchMaterialization(JD, std::move(MU));
842 /// Dump the state of all the JITDylibs in this session.
843 void dump(raw_ostream &OS);
846 static void logErrorsToStdErr(Error Err) {
847 logAllUnhandledErrors(std::move(Err), errs(), "JIT session error: ");
851 materializeOnCurrentThread(JITDylib &JD,
852 std::unique_ptr<MaterializationUnit> MU) {
853 MU->doMaterialize(JD);
856 void runOutstandingMUs();
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;
865 std::vector<std::unique_ptr<JITDylib>> JDs;
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>>>
874 template <typename Func>
875 auto JITDylib::withSearchOrderDo(Func &&F)
876 -> decltype(F(std::declval<const JITDylibSearchList &>())) {
877 return ES.runSessionLocked([&]() { return F(SearchOrder); });
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))
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;
892 return Error::success();
896 template <typename MaterializationUnitType>
897 Error JITDylib::define(std::unique_ptr<MaterializationUnitType> &MU) {
898 assert(MU && "Can not define with a null MU");
900 return ES.runSessionLocked([&, this]() -> Error {
901 if (auto Err = defineImpl(*MU))
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;
909 return Error::success();
913 /// Mangles symbol names then uniques them in the context of an
914 /// ExecutionSession.
915 class MangleAndInterner {
917 MangleAndInterner(ExecutionSession &ES, const DataLayout &DL);
918 SymbolStringPtr operator()(StringRef Name);
921 ExecutionSession &ES;
922 const DataLayout &DL;
925 } // End namespace orc
926 } // End namespace llvm
928 #undef DEBUG_TYPE // "orc"
930 #endif // LLVM_EXECUTIONENGINE_ORC_CORE_H