1 //===------ Core.h -- Core ORC APIs (Layer, JITDylib, etc.) -----*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // Contains core ORC APIs.
11 //===----------------------------------------------------------------------===//
13 #ifndef LLVM_EXECUTIONENGINE_ORC_CORE_H
14 #define LLVM_EXECUTIONENGINE_ORC_CORE_H
16 #include "llvm/ADT/BitmaskEnum.h"
17 #include "llvm/ExecutionEngine/JITSymbol.h"
18 #include "llvm/ExecutionEngine/Orc/SymbolStringPool.h"
19 #include "llvm/ExecutionEngine/OrcV1Deprecation.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;
37 enum class SymbolState : uint8_t;
39 /// VModuleKey provides a unique identifier (allocated and managed by
40 /// ExecutionSessions) for a module added to the JIT.
41 using VModuleKey = uint64_t;
43 /// A set of symbol names (represented by SymbolStringPtrs for
45 using SymbolNameSet = DenseSet<SymbolStringPtr>;
47 /// A map from symbol names (as SymbolStringPtrs) to JITSymbols
48 /// (address/flags pairs).
49 using SymbolMap = DenseMap<SymbolStringPtr, JITEvaluatedSymbol>;
51 /// A map from symbol names (as SymbolStringPtrs) to JITSymbolFlags.
52 using SymbolFlagsMap = DenseMap<SymbolStringPtr, JITSymbolFlags>;
54 /// A base class for materialization failures that allows the failing
55 /// symbols to be obtained for logging.
56 using SymbolDependenceMap = DenseMap<JITDylib *, SymbolNameSet>;
58 /// A list of (JITDylib*, bool) pairs.
59 using JITDylibSearchList = std::vector<std::pair<JITDylib *, bool>>;
61 struct SymbolAliasMapEntry {
62 SymbolAliasMapEntry() = default;
63 SymbolAliasMapEntry(SymbolStringPtr Aliasee, JITSymbolFlags AliasFlags)
64 : Aliasee(std::move(Aliasee)), AliasFlags(AliasFlags) {}
66 SymbolStringPtr Aliasee;
67 JITSymbolFlags AliasFlags;
70 /// A map of Symbols to (Symbol, Flags) pairs.
71 using SymbolAliasMap = DenseMap<SymbolStringPtr, SymbolAliasMapEntry>;
73 /// Render a SymbolStringPtr.
74 raw_ostream &operator<<(raw_ostream &OS, const SymbolStringPtr &Sym);
76 /// Render a SymbolNameSet.
77 raw_ostream &operator<<(raw_ostream &OS, const SymbolNameSet &Symbols);
79 /// Render a SymbolFlagsMap entry.
80 raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap::value_type &KV);
82 /// Render a SymbolMap entry.
83 raw_ostream &operator<<(raw_ostream &OS, const SymbolMap::value_type &KV);
85 /// Render a SymbolFlagsMap.
86 raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap &SymbolFlags);
88 /// Render a SymbolMap.
89 raw_ostream &operator<<(raw_ostream &OS, const SymbolMap &Symbols);
91 /// Render a SymbolDependenceMap entry.
92 raw_ostream &operator<<(raw_ostream &OS,
93 const SymbolDependenceMap::value_type &KV);
95 /// Render a SymbolDependendeMap.
96 raw_ostream &operator<<(raw_ostream &OS, const SymbolDependenceMap &Deps);
98 /// Render a MaterializationUnit.
99 raw_ostream &operator<<(raw_ostream &OS, const MaterializationUnit &MU);
101 /// Render a JITDylibSearchList.
102 raw_ostream &operator<<(raw_ostream &OS, const JITDylibSearchList &JDs);
104 /// Render a SymbolAliasMap.
105 raw_ostream &operator<<(raw_ostream &OS, const SymbolAliasMap &Aliases);
107 /// Render a SymbolState.
108 raw_ostream &operator<<(raw_ostream &OS, const SymbolState &S);
110 /// Callback to notify client that symbols have been resolved.
111 using SymbolsResolvedCallback = std::function<void(Expected<SymbolMap>)>;
113 /// Callback to register the dependencies for a given query.
114 using RegisterDependenciesFunction =
115 std::function<void(const SymbolDependenceMap &)>;
117 /// This can be used as the value for a RegisterDependenciesFunction if there
118 /// are no dependants to register with.
119 extern RegisterDependenciesFunction NoDependenciesToRegister;
121 /// Used to notify a JITDylib that the given set of symbols failed to
123 class FailedToMaterialize : public ErrorInfo<FailedToMaterialize> {
127 FailedToMaterialize(SymbolNameSet Symbols);
128 std::error_code convertToErrorCode() const override;
129 void log(raw_ostream &OS) const override;
130 const SymbolNameSet &getSymbols() const { return Symbols; }
133 SymbolNameSet Symbols;
136 /// Used to notify clients when symbols can not be found during a lookup.
137 class SymbolsNotFound : public ErrorInfo<SymbolsNotFound> {
141 SymbolsNotFound(SymbolNameSet Symbols);
142 std::error_code convertToErrorCode() const override;
143 void log(raw_ostream &OS) const override;
144 const SymbolNameSet &getSymbols() const { return Symbols; }
147 SymbolNameSet Symbols;
150 /// Used to notify clients that a set of symbols could not be removed.
151 class SymbolsCouldNotBeRemoved : public ErrorInfo<SymbolsCouldNotBeRemoved> {
155 SymbolsCouldNotBeRemoved(SymbolNameSet Symbols);
156 std::error_code convertToErrorCode() const override;
157 void log(raw_ostream &OS) const override;
158 const SymbolNameSet &getSymbols() const { return Symbols; }
161 SymbolNameSet Symbols;
164 /// Tracks responsibility for materialization, and mediates interactions between
165 /// MaterializationUnits and JDs.
167 /// An instance of this class is passed to MaterializationUnits when their
168 /// materialize method is called. It allows MaterializationUnits to resolve and
169 /// emit symbols, or abandon materialization by notifying any unmaterialized
170 /// symbols of an error.
171 class MaterializationResponsibility {
172 friend class MaterializationUnit;
174 MaterializationResponsibility(MaterializationResponsibility &&) = default;
175 MaterializationResponsibility &
176 operator=(MaterializationResponsibility &&) = delete;
178 /// Destruct a MaterializationResponsibility instance. In debug mode
179 /// this asserts that all symbols being tracked have been either
180 /// emitted or notified of an error.
181 ~MaterializationResponsibility();
183 /// Returns the target JITDylib that these symbols are being materialized
185 JITDylib &getTargetJITDylib() const { return JD; }
187 /// Returns the VModuleKey for this instance.
188 VModuleKey getVModuleKey() const { return K; }
190 /// Returns the symbol flags map for this responsibility instance.
191 /// Note: The returned flags may have transient flags (Lazy, Materializing)
192 /// set. These should be stripped with JITSymbolFlags::stripTransientFlags
194 const SymbolFlagsMap &getSymbols() const { return SymbolFlags; }
196 /// Returns the names of any symbols covered by this
197 /// MaterializationResponsibility object that have queries pending. This
198 /// information can be used to return responsibility for unrequested symbols
199 /// back to the JITDylib via the delegate method.
200 SymbolNameSet getRequestedSymbols() const;
202 /// Notifies the target JITDylib that the given symbols have been resolved.
203 /// This will update the given symbols' addresses in the JITDylib, and notify
204 /// any pending queries on the given symbols of their resolution. The given
205 /// symbols must be ones covered by this MaterializationResponsibility
206 /// instance. Individual calls to this method may resolve a subset of the
207 /// symbols, but all symbols must have been resolved prior to calling emit.
208 void notifyResolved(const SymbolMap &Symbols);
210 /// Notifies the target JITDylib (and any pending queries on that JITDylib)
211 /// that all symbols covered by this MaterializationResponsibility instance
212 /// have been emitted.
213 void notifyEmitted();
215 /// Adds new symbols to the JITDylib and this responsibility instance.
216 /// JITDylib entries start out in the materializing state.
218 /// This method can be used by materialization units that want to add
219 /// additional symbols at materialization time (e.g. stubs, compile
220 /// callbacks, metadata).
221 Error defineMaterializing(const SymbolFlagsMap &SymbolFlags);
223 /// Notify all not-yet-emitted covered by this MaterializationResponsibility
224 /// instance that an error has occurred.
225 /// This will remove all symbols covered by this MaterializationResponsibilty
226 /// from the target JITDylib, and send an error to any queries waiting on
228 void failMaterialization();
230 /// Transfers responsibility to the given MaterializationUnit for all
231 /// symbols defined by that MaterializationUnit. This allows
232 /// materializers to break up work based on run-time information (e.g.
233 /// by introspecting which symbols have actually been looked up and
234 /// materializing only those).
235 void replace(std::unique_ptr<MaterializationUnit> MU);
237 /// Delegates responsibility for the given symbols to the returned
238 /// materialization responsibility. Useful for breaking up work between
239 /// threads, or different kinds of materialization processes.
240 MaterializationResponsibility delegate(const SymbolNameSet &Symbols,
241 VModuleKey NewKey = VModuleKey());
243 void addDependencies(const SymbolStringPtr &Name,
244 const SymbolDependenceMap &Dependencies);
246 /// Add dependencies that apply to all symbols covered by this instance.
247 void addDependenciesForAll(const SymbolDependenceMap &Dependencies);
250 /// Create a MaterializationResponsibility for the given JITDylib and
252 MaterializationResponsibility(JITDylib &JD, SymbolFlagsMap SymbolFlags,
256 SymbolFlagsMap SymbolFlags;
260 /// A MaterializationUnit represents a set of symbol definitions that can
261 /// be materialized as a group, or individually discarded (when
262 /// overriding definitions are encountered).
264 /// MaterializationUnits are used when providing lazy definitions of symbols to
265 /// JITDylibs. The JITDylib will call materialize when the address of a symbol
266 /// is requested via the lookup method. The JITDylib will call discard if a
267 /// stronger definition is added or already present.
268 class MaterializationUnit {
270 MaterializationUnit(SymbolFlagsMap InitalSymbolFlags, VModuleKey K)
271 : SymbolFlags(std::move(InitalSymbolFlags)), K(std::move(K)) {}
273 virtual ~MaterializationUnit() {}
275 /// Return the name of this materialization unit. Useful for debugging
277 virtual StringRef getName() const = 0;
279 /// Return the set of symbols that this source provides.
280 const SymbolFlagsMap &getSymbols() const { return SymbolFlags; }
282 /// Called by materialization dispatchers (see
283 /// ExecutionSession::DispatchMaterializationFunction) to trigger
284 /// materialization of this MaterializationUnit.
285 void doMaterialize(JITDylib &JD) {
286 materialize(MaterializationResponsibility(JD, std::move(SymbolFlags),
290 /// Called by JITDylibs to notify MaterializationUnits that the given symbol
291 /// has been overridden.
292 void doDiscard(const JITDylib &JD, const SymbolStringPtr &Name) {
293 SymbolFlags.erase(Name);
294 discard(JD, std::move(Name));
298 SymbolFlagsMap SymbolFlags;
302 virtual void anchor();
304 /// Implementations of this method should materialize all symbols
305 /// in the materialzation unit, except for those that have been
306 /// previously discarded.
307 virtual void materialize(MaterializationResponsibility R) = 0;
309 /// Implementations of this method should discard the given symbol
310 /// from the source (e.g. if the source is an LLVM IR Module and the
311 /// symbol is a function, delete the function body or mark it available
313 virtual void discard(const JITDylib &JD, const SymbolStringPtr &Name) = 0;
316 using MaterializationUnitList =
317 std::vector<std::unique_ptr<MaterializationUnit>>;
319 /// A MaterializationUnit implementation for pre-existing absolute symbols.
321 /// All symbols will be resolved and marked ready as soon as the unit is
323 class AbsoluteSymbolsMaterializationUnit : public MaterializationUnit {
325 AbsoluteSymbolsMaterializationUnit(SymbolMap Symbols, VModuleKey K);
327 StringRef getName() const override;
330 void materialize(MaterializationResponsibility R) override;
331 void discard(const JITDylib &JD, const SymbolStringPtr &Name) override;
332 static SymbolFlagsMap extractFlags(const SymbolMap &Symbols);
337 /// Create an AbsoluteSymbolsMaterializationUnit with the given symbols.
338 /// Useful for inserting absolute symbols into a JITDylib. E.g.:
340 /// JITDylib &JD = ...;
341 /// SymbolStringPtr Foo = ...;
342 /// JITEvaluatedSymbol FooSym = ...;
343 /// if (auto Err = JD.define(absoluteSymbols({{Foo, FooSym}})))
347 inline std::unique_ptr<AbsoluteSymbolsMaterializationUnit>
348 absoluteSymbols(SymbolMap Symbols, VModuleKey K = VModuleKey()) {
349 return llvm::make_unique<AbsoluteSymbolsMaterializationUnit>(
350 std::move(Symbols), std::move(K));
353 /// A materialization unit for symbol aliases. Allows existing symbols to be
354 /// aliased with alternate flags.
355 class ReExportsMaterializationUnit : public MaterializationUnit {
357 /// SourceJD is allowed to be nullptr, in which case the source JITDylib is
358 /// taken to be whatever JITDylib these definitions are materialized in (and
359 /// MatchNonExported has no effect). This is useful for defining aliases
360 /// within a JITDylib.
362 /// Note: Care must be taken that no sets of aliases form a cycle, as such
363 /// a cycle will result in a deadlock when any symbol in the cycle is
365 ReExportsMaterializationUnit(JITDylib *SourceJD, bool MatchNonExported,
366 SymbolAliasMap Aliases, VModuleKey K);
368 StringRef getName() const override;
371 void materialize(MaterializationResponsibility R) override;
372 void discard(const JITDylib &JD, const SymbolStringPtr &Name) override;
373 static SymbolFlagsMap extractFlags(const SymbolAliasMap &Aliases);
375 JITDylib *SourceJD = nullptr;
376 bool MatchNonExported = false;
377 SymbolAliasMap Aliases;
380 /// Create a ReExportsMaterializationUnit with the given aliases.
381 /// Useful for defining symbol aliases.: E.g., given a JITDylib JD containing
382 /// symbols "foo" and "bar", we can define aliases "baz" (for "foo") and "qux"
383 /// (for "bar") with: \code{.cpp}
384 /// SymbolStringPtr Baz = ...;
385 /// SymbolStringPtr Qux = ...;
386 /// if (auto Err = JD.define(symbolAliases({
387 /// {Baz, { Foo, JITSymbolFlags::Exported }},
388 /// {Qux, { Bar, JITSymbolFlags::Weak }}}))
391 inline std::unique_ptr<ReExportsMaterializationUnit>
392 symbolAliases(SymbolAliasMap Aliases, VModuleKey K = VModuleKey()) {
393 return llvm::make_unique<ReExportsMaterializationUnit>(
394 nullptr, true, std::move(Aliases), std::move(K));
397 /// Create a materialization unit for re-exporting symbols from another JITDylib
398 /// with alternative names/flags.
399 /// If MatchNonExported is true then non-exported symbols from SourceJD can be
400 /// re-exported. If it is false, attempts to re-export a non-exported symbol
401 /// will result in a "symbol not found" error.
402 inline std::unique_ptr<ReExportsMaterializationUnit>
403 reexports(JITDylib &SourceJD, SymbolAliasMap Aliases,
404 bool MatchNonExported = false, VModuleKey K = VModuleKey()) {
405 return llvm::make_unique<ReExportsMaterializationUnit>(
406 &SourceJD, MatchNonExported, std::move(Aliases), std::move(K));
409 /// Build a SymbolAliasMap for the common case where you want to re-export
410 /// symbols from another JITDylib with the same linkage/flags.
411 Expected<SymbolAliasMap>
412 buildSimpleReexportsAliasMap(JITDylib &SourceJD, const SymbolNameSet &Symbols);
414 /// ReexportsGenerator can be used with JITDylib::setGenerator to automatically
415 /// re-export a subset of the source JITDylib's symbols in the target.
416 class ReexportsGenerator {
418 using SymbolPredicate = std::function<bool(SymbolStringPtr)>;
420 /// Create a reexports generator. If an Allow predicate is passed, only
421 /// symbols for which the predicate returns true will be reexported. If no
422 /// Allow predicate is passed, all symbols will be exported.
423 ReexportsGenerator(JITDylib &SourceJD, bool MatchNonExported = false,
424 SymbolPredicate Allow = SymbolPredicate());
426 Expected<SymbolNameSet> operator()(JITDylib &JD, const SymbolNameSet &Names);
430 bool MatchNonExported = false;
431 SymbolPredicate Allow;
434 /// Represents the state that a symbol has reached during materialization.
435 enum class SymbolState : uint8_t {
436 Invalid, /// No symbol should be in this state.
437 NeverSearched, /// Added to the symbol table, never queried.
438 Materializing, /// Queried, materialization begun.
439 Resolved, /// Assigned address, still materializing.
440 Ready = 0x3f /// Ready and safe for clients to access.
443 /// A symbol query that returns results via a callback when results are
446 /// makes a callback when all symbols are available.
447 class AsynchronousSymbolQuery {
448 friend class ExecutionSession;
449 friend class JITDylib;
450 friend class JITSymbolResolverAdapter;
453 /// Create a query for the given symbols. The NotifyComplete
454 /// callback will be called once all queried symbols reach the given
456 AsynchronousSymbolQuery(const SymbolNameSet &Symbols,
457 SymbolState RequiredState,
458 SymbolsResolvedCallback NotifyComplete);
460 /// Notify the query that a requested symbol has reached the required state.
461 void notifySymbolMetRequiredState(const SymbolStringPtr &Name,
462 JITEvaluatedSymbol Sym);
464 /// Returns true if all symbols covered by this query have been
466 bool isComplete() const { return OutstandingSymbolsCount == 0; }
468 /// Call the NotifyComplete callback.
470 /// This should only be called if all symbols covered by the query have
471 /// reached the specified state.
472 void handleComplete();
475 SymbolState getRequiredState() { return RequiredState; }
477 void addQueryDependence(JITDylib &JD, SymbolStringPtr Name);
479 void removeQueryDependence(JITDylib &JD, const SymbolStringPtr &Name);
483 void handleFailed(Error Err);
487 SymbolsResolvedCallback NotifyComplete;
488 SymbolDependenceMap QueryRegistrations;
489 SymbolMap ResolvedSymbols;
490 size_t OutstandingSymbolsCount;
491 SymbolState RequiredState;
494 /// A symbol table that supports asynchoronous symbol queries.
496 /// Represents a virtual shared object. Instances can not be copied or moved, so
497 /// their addresses may be used as keys for resource management.
498 /// JITDylib state changes must be made via an ExecutionSession to guarantee
499 /// that they are synchronized with respect to other JITDylib operations.
501 friend class AsynchronousSymbolQuery;
502 friend class ExecutionSession;
503 friend class MaterializationResponsibility;
505 using GeneratorFunction = std::function<Expected<SymbolNameSet>(
506 JITDylib &Parent, const SymbolNameSet &Names)>;
508 using AsynchronousSymbolQuerySet =
509 std::set<std::shared_ptr<AsynchronousSymbolQuery>>;
511 JITDylib(const JITDylib &) = delete;
512 JITDylib &operator=(const JITDylib &) = delete;
513 JITDylib(JITDylib &&) = delete;
514 JITDylib &operator=(JITDylib &&) = delete;
516 /// Get the name for this JITDylib.
517 const std::string &getName() const { return JITDylibName; }
519 /// Get a reference to the ExecutionSession for this JITDylib.
520 ExecutionSession &getExecutionSession() const { return ES; }
522 /// Set a definition generator. If set, whenever a symbol fails to resolve
523 /// within this JITDylib, lookup and lookupFlags will pass the unresolved
524 /// symbols set to the definition generator. The generator can optionally
525 /// add a definition for the unresolved symbols to the dylib.
526 void setGenerator(GeneratorFunction DefGenerator) {
527 this->DefGenerator = std::move(DefGenerator);
530 /// Set the search order to be used when fixing up definitions in JITDylib.
531 /// This will replace the previous search order, and apply to any symbol
532 /// resolutions made for definitions in this JITDylib after the call to
533 /// setSearchOrder (even if the definition itself was added before the
536 /// If SearchThisJITDylibFirst is set, which by default it is, then this
537 /// JITDylib will add itself to the beginning of the SearchOrder (Clients
538 /// should *not* put this JITDylib in the list in this case, to avoid
539 /// redundant lookups).
541 /// If SearchThisJITDylibFirst is false then the search order will be used as
542 /// given. The main motivation for this feature is to support deliberate
543 /// shadowing of symbols in this JITDylib by a facade JITDylib. For example,
544 /// the facade may resolve function names to stubs, and the stubs may compile
545 /// lazily by looking up symbols in this dylib. Adding the facade dylib
546 /// as the first in the search order (instead of this dylib) ensures that
547 /// definitions within this dylib resolve to the lazy-compiling stubs,
548 /// rather than immediately materializing the definitions in this dylib.
549 void setSearchOrder(JITDylibSearchList NewSearchOrder,
550 bool SearchThisJITDylibFirst = true,
551 bool MatchNonExportedInThisDylib = true);
553 /// Add the given JITDylib to the search order for definitions in this
555 void addToSearchOrder(JITDylib &JD, bool MatcNonExported = false);
557 /// Replace OldJD with NewJD in the search order if OldJD is present.
558 /// Otherwise this operation is a no-op.
559 void replaceInSearchOrder(JITDylib &OldJD, JITDylib &NewJD,
560 bool MatchNonExported = false);
562 /// Remove the given JITDylib from the search order for this JITDylib if it is
563 /// present. Otherwise this operation is a no-op.
564 void removeFromSearchOrder(JITDylib &JD);
566 /// Do something with the search order (run under the session lock).
567 template <typename Func>
568 auto withSearchOrderDo(Func &&F)
569 -> decltype(F(std::declval<const JITDylibSearchList &>()));
571 /// Define all symbols provided by the materialization unit to be part of this
574 /// This overload always takes ownership of the MaterializationUnit. If any
575 /// errors occur, the MaterializationUnit consumed.
576 template <typename MaterializationUnitType>
577 Error define(std::unique_ptr<MaterializationUnitType> &&MU);
579 /// Define all symbols provided by the materialization unit to be part of this
582 /// This overload only takes ownership of the MaterializationUnit no error is
583 /// generated. If an error occurs, ownership remains with the caller. This
584 /// may allow the caller to modify the MaterializationUnit to correct the
585 /// issue, then re-call define.
586 template <typename MaterializationUnitType>
587 Error define(std::unique_ptr<MaterializationUnitType> &MU);
589 /// Tries to remove the given symbols.
591 /// If any symbols are not defined in this JITDylib this method will return
592 /// a SymbolsNotFound error covering the missing symbols.
594 /// If all symbols are found but some symbols are in the process of being
595 /// materialized this method will return a SymbolsCouldNotBeRemoved error.
597 /// On success, all symbols are removed. On failure, the JITDylib state is
598 /// left unmodified (no symbols are removed).
599 Error remove(const SymbolNameSet &Names);
601 /// Search the given JITDylib for the symbols in Symbols. If found, store
602 /// the flags for each symbol in Flags. Returns any unresolved symbols.
603 Expected<SymbolFlagsMap> lookupFlags(const SymbolNameSet &Names);
605 /// Dump current JITDylib state to OS.
606 void dump(raw_ostream &OS);
608 /// FIXME: Remove this when we remove the old ORC layers.
609 /// Search the given JITDylibs in order for the symbols in Symbols. Results
610 /// (once they become available) will be returned via the given Query.
612 /// If any symbol is not found then the unresolved symbols will be returned,
613 /// and the query will not be applied. The Query is not failed and can be
614 /// re-used in a subsequent lookup once the symbols have been added, or
616 Expected<SymbolNameSet>
617 legacyLookup(std::shared_ptr<AsynchronousSymbolQuery> Q, SymbolNameSet Names);
620 using AsynchronousSymbolQueryList =
621 std::vector<std::shared_ptr<AsynchronousSymbolQuery>>;
623 struct UnmaterializedInfo {
624 UnmaterializedInfo(std::unique_ptr<MaterializationUnit> MU)
625 : MU(std::move(MU)) {}
627 std::unique_ptr<MaterializationUnit> MU;
630 using UnmaterializedInfosMap =
631 DenseMap<SymbolStringPtr, std::shared_ptr<UnmaterializedInfo>>;
633 struct MaterializingInfo {
634 SymbolDependenceMap Dependants;
635 SymbolDependenceMap UnemittedDependencies;
636 bool IsEmitted = false;
638 void addQuery(std::shared_ptr<AsynchronousSymbolQuery> Q);
639 void removeQuery(const AsynchronousSymbolQuery &Q);
640 AsynchronousSymbolQueryList takeQueriesMeeting(SymbolState RequiredState);
641 AsynchronousSymbolQueryList takeAllQueries();
642 bool hasQueriesPending() const { return !PendingQueries.empty(); }
643 const AsynchronousSymbolQueryList &pendingQueries() const {
644 return PendingQueries;
648 AsynchronousSymbolQueryList PendingQueries;
651 using MaterializingInfosMap = DenseMap<SymbolStringPtr, MaterializingInfo>;
653 class SymbolTableEntry {
655 SymbolTableEntry() = default;
656 SymbolTableEntry(JITSymbolFlags Flags)
657 : Flags(Flags), State(static_cast<uint8_t>(SymbolState::NeverSearched)),
658 MaterializerAttached(false), PendingRemoval(false) {}
660 JITTargetAddress getAddress() const { return Addr; }
661 JITSymbolFlags getFlags() const { return Flags; }
662 SymbolState getState() const { return static_cast<SymbolState>(State); }
664 bool isInMaterializationPhase() const {
665 return getState() == SymbolState::Materializing ||
666 getState() == SymbolState::Resolved;
669 bool hasMaterializerAttached() const { return MaterializerAttached; }
670 bool isPendingRemoval() const { return PendingRemoval; }
672 void setAddress(JITTargetAddress Addr) { this->Addr = Addr; }
673 void setFlags(JITSymbolFlags Flags) { this->Flags = Flags; }
674 void setState(SymbolState State) {
675 assert(static_cast<uint8_t>(State) < (1 << 6) &&
676 "State does not fit in bitfield");
677 this->State = static_cast<uint8_t>(State);
680 void setMaterializerAttached(bool MaterializerAttached) {
681 this->MaterializerAttached = MaterializerAttached;
684 void setPendingRemoval(bool PendingRemoval) {
685 this->PendingRemoval = PendingRemoval;
688 JITEvaluatedSymbol getSymbol() const {
689 return JITEvaluatedSymbol(Addr, Flags);
693 JITTargetAddress Addr = 0;
694 JITSymbolFlags Flags;
696 uint8_t MaterializerAttached : 1;
697 uint8_t PendingRemoval : 1;
700 using SymbolTable = DenseMap<SymbolStringPtr, SymbolTableEntry>;
702 JITDylib(ExecutionSession &ES, std::string Name);
704 Error defineImpl(MaterializationUnit &MU);
706 Expected<SymbolNameSet> lookupFlagsImpl(SymbolFlagsMap &Flags,
707 const SymbolNameSet &Names);
709 Error lodgeQuery(std::shared_ptr<AsynchronousSymbolQuery> &Q,
710 SymbolNameSet &Unresolved, bool MatchNonExported,
711 MaterializationUnitList &MUs);
713 void lodgeQueryImpl(std::shared_ptr<AsynchronousSymbolQuery> &Q,
714 SymbolNameSet &Unresolved, bool MatchNonExported,
715 MaterializationUnitList &MUs);
717 bool lookupImpl(std::shared_ptr<AsynchronousSymbolQuery> &Q,
718 std::vector<std::unique_ptr<MaterializationUnit>> &MUs,
719 SymbolNameSet &Unresolved);
721 void detachQueryHelper(AsynchronousSymbolQuery &Q,
722 const SymbolNameSet &QuerySymbols);
724 void transferEmittedNodeDependencies(MaterializingInfo &DependantMI,
725 const SymbolStringPtr &DependantName,
726 MaterializingInfo &EmittedMI);
728 Error defineMaterializing(const SymbolFlagsMap &SymbolFlags);
730 void replace(std::unique_ptr<MaterializationUnit> MU);
732 SymbolNameSet getRequestedSymbols(const SymbolFlagsMap &SymbolFlags) const;
734 void addDependencies(const SymbolStringPtr &Name,
735 const SymbolDependenceMap &Dependants);
737 void resolve(const SymbolMap &Resolved);
739 void emit(const SymbolFlagsMap &Emitted);
741 void notifyFailed(const SymbolNameSet &FailedSymbols);
743 ExecutionSession &ES;
744 std::string JITDylibName;
746 UnmaterializedInfosMap UnmaterializedInfos;
747 MaterializingInfosMap MaterializingInfos;
748 GeneratorFunction DefGenerator;
749 JITDylibSearchList SearchOrder;
752 /// An ExecutionSession represents a running JIT program.
753 class ExecutionSession {
754 // FIXME: Remove this when we remove the old ORC layers.
755 friend class JITDylib;
758 /// For reporting errors.
759 using ErrorReporter = std::function<void(Error)>;
761 /// For dispatching MaterializationUnit::materialize calls.
762 using DispatchMaterializationFunction = std::function<void(
763 JITDylib &JD, std::unique_ptr<MaterializationUnit> MU)>;
765 /// Construct an ExecutionSession.
767 /// SymbolStringPools may be shared between ExecutionSessions.
768 ExecutionSession(std::shared_ptr<SymbolStringPool> SSP = nullptr);
770 /// Add a symbol name to the SymbolStringPool and return a pointer to it.
771 SymbolStringPtr intern(StringRef SymName) { return SSP->intern(SymName); }
773 /// Returns a shared_ptr to the SymbolStringPool for this ExecutionSession.
774 std::shared_ptr<SymbolStringPool> getSymbolStringPool() const { return SSP; }
776 /// Run the given lambda with the session mutex locked.
777 template <typename Func> auto runSessionLocked(Func &&F) -> decltype(F()) {
778 std::lock_guard<std::recursive_mutex> Lock(SessionMutex);
782 /// Get the "main" JITDylib, which is created automatically on construction of
783 /// the ExecutionSession.
784 JITDylib &getMainJITDylib();
786 /// Return a pointer to the "name" JITDylib.
787 /// Ownership of JITDylib remains within Execution Session
788 JITDylib *getJITDylibByName(StringRef Name);
790 /// Add a new JITDylib to this ExecutionSession.
792 /// The JITDylib Name is required to be unique. Clients should verify that
793 /// names are not being re-used (e.g. by calling getJITDylibByName) if names
794 /// are based on user input.
795 JITDylib &createJITDylib(std::string Name,
796 bool AddToMainDylibSearchOrder = true);
798 /// Allocate a module key for a new module to add to the JIT.
799 VModuleKey allocateVModule() {
800 return runSessionLocked([this]() { return ++LastKey; });
803 /// Return a module key to the ExecutionSession so that it can be
804 /// re-used. This should only be done once all resources associated
805 /// with the original key have been released.
806 void releaseVModule(VModuleKey Key) { /* FIXME: Recycle keys */
809 /// Set the error reporter function.
810 ExecutionSession &setErrorReporter(ErrorReporter ReportError) {
811 this->ReportError = std::move(ReportError);
815 /// Report a error for this execution session.
817 /// Unhandled errors can be sent here to log them.
818 void reportError(Error Err) { ReportError(std::move(Err)); }
820 /// Set the materialization dispatch function.
821 ExecutionSession &setDispatchMaterialization(
822 DispatchMaterializationFunction DispatchMaterialization) {
823 this->DispatchMaterialization = std::move(DispatchMaterialization);
827 void legacyFailQuery(AsynchronousSymbolQuery &Q, Error Err);
829 using LegacyAsyncLookupFunction = std::function<SymbolNameSet(
830 std::shared_ptr<AsynchronousSymbolQuery> Q, SymbolNameSet Names)>;
832 /// A legacy lookup function for JITSymbolResolverAdapter.
833 /// Do not use -- this will be removed soon.
835 legacyLookup(LegacyAsyncLookupFunction AsyncLookup, SymbolNameSet Names,
836 SymbolState RequiredState,
837 RegisterDependenciesFunction RegisterDependencies);
839 /// Search the given JITDylib list for the given symbols.
841 /// SearchOrder lists the JITDylibs to search. For each dylib, the associated
842 /// boolean indicates whether the search should match against non-exported
843 /// (hidden visibility) symbols in that dylib (true means match against
844 /// non-exported symbols, false means do not match).
846 /// The NotifyComplete callback will be called once all requested symbols
847 /// reach the required state.
849 /// If all symbols are found, the RegisterDependencies function will be called
850 /// while the session lock is held. This gives clients a chance to register
851 /// dependencies for on the queried symbols for any symbols they are
852 /// materializing (if a MaterializationResponsibility instance is present,
853 /// this can be implemented by calling
854 /// MaterializationResponsibility::addDependencies). If there are no
855 /// dependenant symbols for this query (e.g. it is being made by a top level
856 /// client to get an address to call) then the value NoDependenciesToRegister
858 void lookup(const JITDylibSearchList &SearchOrder, SymbolNameSet Symbols,
859 SymbolState RequiredState, SymbolsResolvedCallback NotifyComplete,
860 RegisterDependenciesFunction RegisterDependencies);
862 /// Blocking version of lookup above. Returns the resolved symbol map.
863 /// If WaitUntilReady is true (the default), will not return until all
864 /// requested symbols are ready (or an error occurs). If WaitUntilReady is
865 /// false, will return as soon as all requested symbols are resolved,
866 /// or an error occurs. If WaitUntilReady is false and an error occurs
867 /// after resolution, the function will return a success value, but the
868 /// error will be reported via reportErrors.
869 Expected<SymbolMap> lookup(const JITDylibSearchList &SearchOrder,
870 const SymbolNameSet &Symbols,
871 SymbolState RequiredState = SymbolState::Ready,
872 RegisterDependenciesFunction RegisterDependencies =
873 NoDependenciesToRegister);
875 /// Convenience version of blocking lookup.
876 /// Searches each of the JITDylibs in the search order in turn for the given
878 Expected<JITEvaluatedSymbol> lookup(const JITDylibSearchList &SearchOrder,
879 SymbolStringPtr Symbol);
881 /// Convenience version of blocking lookup.
882 /// Searches each of the JITDylibs in the search order in turn for the given
883 /// symbol. The search will not find non-exported symbols.
884 Expected<JITEvaluatedSymbol> lookup(ArrayRef<JITDylib *> SearchOrder,
885 SymbolStringPtr Symbol);
887 /// Convenience version of blocking lookup.
888 /// Searches each of the JITDylibs in the search order in turn for the given
889 /// symbol. The search will not find non-exported symbols.
890 Expected<JITEvaluatedSymbol> lookup(ArrayRef<JITDylib *> SearchOrder,
893 /// Materialize the given unit.
894 void dispatchMaterialization(JITDylib &JD,
895 std::unique_ptr<MaterializationUnit> MU) {
897 runSessionLocked([&]() {
898 dbgs() << "Dispatching " << *MU << " for " << JD.getName() << "\n";
901 DispatchMaterialization(JD, std::move(MU));
904 /// Dump the state of all the JITDylibs in this session.
905 void dump(raw_ostream &OS);
908 static void logErrorsToStdErr(Error Err) {
909 logAllUnhandledErrors(std::move(Err), errs(), "JIT session error: ");
913 materializeOnCurrentThread(JITDylib &JD,
914 std::unique_ptr<MaterializationUnit> MU) {
915 MU->doMaterialize(JD);
918 void runOutstandingMUs();
920 mutable std::recursive_mutex SessionMutex;
921 std::shared_ptr<SymbolStringPool> SSP;
922 VModuleKey LastKey = 0;
923 ErrorReporter ReportError = logErrorsToStdErr;
924 DispatchMaterializationFunction DispatchMaterialization =
925 materializeOnCurrentThread;
927 std::vector<std::unique_ptr<JITDylib>> JDs;
929 // FIXME: Remove this (and runOutstandingMUs) once the linking layer works
930 // with callbacks from asynchronous queries.
931 mutable std::recursive_mutex OutstandingMUsMutex;
932 std::vector<std::pair<JITDylib *, std::unique_ptr<MaterializationUnit>>>
936 template <typename Func>
937 auto JITDylib::withSearchOrderDo(Func &&F)
938 -> decltype(F(std::declval<const JITDylibSearchList &>())) {
939 return ES.runSessionLocked([&]() { return F(SearchOrder); });
942 template <typename MaterializationUnitType>
943 Error JITDylib::define(std::unique_ptr<MaterializationUnitType> &&MU) {
944 assert(MU && "Can not define with a null MU");
945 return ES.runSessionLocked([&, this]() -> Error {
946 if (auto Err = defineImpl(*MU))
949 /// defineImpl succeeded.
950 auto UMI = std::make_shared<UnmaterializedInfo>(std::move(MU));
951 for (auto &KV : UMI->MU->getSymbols())
952 UnmaterializedInfos[KV.first] = UMI;
954 return Error::success();
958 template <typename MaterializationUnitType>
959 Error JITDylib::define(std::unique_ptr<MaterializationUnitType> &MU) {
960 assert(MU && "Can not define with a null MU");
962 return ES.runSessionLocked([&, this]() -> Error {
963 if (auto Err = defineImpl(*MU))
966 /// defineImpl succeeded.
967 auto UMI = std::make_shared<UnmaterializedInfo>(std::move(MU));
968 for (auto &KV : UMI->MU->getSymbols())
969 UnmaterializedInfos[KV.first] = UMI;
971 return Error::success();
975 /// Mangles symbol names then uniques them in the context of an
976 /// ExecutionSession.
977 class MangleAndInterner {
979 MangleAndInterner(ExecutionSession &ES, const DataLayout &DL);
980 SymbolStringPtr operator()(StringRef Name);
983 ExecutionSession &ES;
984 const DataLayout &DL;
987 } // End namespace orc
988 } // End namespace llvm
990 #undef DEBUG_TYPE // "orc"
992 #endif // LLVM_EXECUTIONENGINE_ORC_CORE_H