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/ADT/DenseSet.h"
18 #include "llvm/ADT/FunctionExtras.h"
19 #include "llvm/ADT/IntrusiveRefCntPtr.h"
20 #include "llvm/ExecutionEngine/JITSymbol.h"
21 #include "llvm/ExecutionEngine/Orc/SymbolStringPool.h"
22 #include "llvm/ExecutionEngine/OrcV1Deprecation.h"
23 #include "llvm/Support/Debug.h"
32 // Forward declare some classes.
33 class AsynchronousSymbolQuery;
34 class ExecutionSession;
35 class MaterializationUnit;
36 class MaterializationResponsibility;
38 class ResourceTracker;
40 enum class SymbolState : uint8_t;
42 using ResourceTrackerSP = IntrusiveRefCntPtr<ResourceTracker>;
43 using JITDylibSP = IntrusiveRefCntPtr<JITDylib>;
45 using ResourceKey = uintptr_t;
47 /// API to remove / transfer ownership of JIT resources.
48 class ResourceTracker : public ThreadSafeRefCountedBase<ResourceTracker> {
50 friend class ExecutionSession;
51 friend class JITDylib;
52 friend class MaterializationResponsibility;
55 ResourceTracker(const ResourceTracker &) = delete;
56 ResourceTracker &operator=(const ResourceTracker &) = delete;
57 ResourceTracker(ResourceTracker &&) = delete;
58 ResourceTracker &operator=(ResourceTracker &) = delete;
62 /// Return the JITDylib targeted by this tracker.
63 JITDylib &getJITDylib() const {
64 return *reinterpret_cast<JITDylib *>(JDAndFlag.load() &
65 ~static_cast<uintptr_t>(1));
68 /// Remove all resources associated with this key.
71 /// Transfer all resources associated with this key to the given
72 /// tracker, which must target the same JITDylib as this one.
73 void transferTo(ResourceTracker &DstRT);
75 /// Return true if this tracker has become defunct.
76 bool isDefunct() const { return JDAndFlag.load() & 0x1; }
78 /// Returns the key associated with this tracker.
79 /// This method should not be used except for debug logging: there is no
80 /// guarantee that the returned value will remain valid.
81 ResourceKey getKeyUnsafe() const { return reinterpret_cast<uintptr_t>(this); }
84 ResourceTracker(JITDylibSP JD);
88 std::atomic_uintptr_t JDAndFlag;
91 /// Listens for ResourceTracker operations.
92 class ResourceManager {
94 virtual ~ResourceManager();
95 virtual Error handleRemoveResources(ResourceKey K) = 0;
96 virtual void handleTransferResources(ResourceKey DstK, ResourceKey SrcK) = 0;
99 /// A set of symbol names (represented by SymbolStringPtrs for
101 using SymbolNameSet = DenseSet<SymbolStringPtr>;
103 /// A vector of symbol names.
104 using SymbolNameVector = std::vector<SymbolStringPtr>;
106 /// A map from symbol names (as SymbolStringPtrs) to JITSymbols
107 /// (address/flags pairs).
108 using SymbolMap = DenseMap<SymbolStringPtr, JITEvaluatedSymbol>;
110 /// A map from symbol names (as SymbolStringPtrs) to JITSymbolFlags.
111 using SymbolFlagsMap = DenseMap<SymbolStringPtr, JITSymbolFlags>;
113 /// A map from JITDylibs to sets of symbols.
114 using SymbolDependenceMap = DenseMap<JITDylib *, SymbolNameSet>;
116 /// Lookup flags that apply to each dylib in the search order for a lookup.
118 /// If MatchHiddenSymbolsOnly is used (the default) for a given dylib, then
119 /// only symbols in that Dylib's interface will be searched. If
120 /// MatchHiddenSymbols is used then symbols with hidden visibility will match
122 enum class JITDylibLookupFlags { MatchExportedSymbolsOnly, MatchAllSymbols };
124 /// Lookup flags that apply to each symbol in a lookup.
126 /// If RequiredSymbol is used (the default) for a given symbol then that symbol
127 /// must be found during the lookup or the lookup will fail returning a
128 /// SymbolNotFound error. If WeaklyReferencedSymbol is used and the given
129 /// symbol is not found then the query will continue, and no result for the
130 /// missing symbol will be present in the result (assuming the rest of the
131 /// lookup succeeds).
132 enum class SymbolLookupFlags { RequiredSymbol, WeaklyReferencedSymbol };
134 /// Describes the kind of lookup being performed. The lookup kind is passed to
135 /// symbol generators (if they're invoked) to help them determine what
136 /// definitions to generate.
138 /// Static -- Lookup is being performed as-if at static link time (e.g.
139 /// generators representing static archives should pull in new
142 /// DLSym -- Lookup is being performed as-if at runtime (e.g. generators
143 /// representing static archives should not pull in new definitions).
144 enum class LookupKind { Static, DLSym };
146 /// A list of (JITDylib*, JITDylibLookupFlags) pairs to be used as a search
147 /// order during symbol lookup.
148 using JITDylibSearchOrder =
149 std::vector<std::pair<JITDylib *, JITDylibLookupFlags>>;
151 /// Convenience function for creating a search order from an ArrayRef of
152 /// JITDylib*, all with the same flags.
153 inline JITDylibSearchOrder makeJITDylibSearchOrder(
154 ArrayRef<JITDylib *> JDs,
155 JITDylibLookupFlags Flags = JITDylibLookupFlags::MatchExportedSymbolsOnly) {
156 JITDylibSearchOrder O;
157 O.reserve(JDs.size());
159 O.push_back(std::make_pair(JD, Flags));
163 /// A set of symbols to look up, each associated with a SymbolLookupFlags
166 /// This class is backed by a vector and optimized for fast insertion,
167 /// deletion and iteration. It does not guarantee a stable order between
168 /// operations, and will not automatically detect duplicate elements (they
169 /// can be manually checked by calling the validate method).
170 class SymbolLookupSet {
172 using value_type = std::pair<SymbolStringPtr, SymbolLookupFlags>;
173 using UnderlyingVector = std::vector<value_type>;
174 using iterator = UnderlyingVector::iterator;
175 using const_iterator = UnderlyingVector::const_iterator;
177 SymbolLookupSet() = default;
179 explicit SymbolLookupSet(
180 SymbolStringPtr Name,
181 SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) {
182 add(std::move(Name), Flags);
185 /// Construct a SymbolLookupSet from an initializer list of SymbolStringPtrs.
186 explicit SymbolLookupSet(
187 std::initializer_list<SymbolStringPtr> Names,
188 SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) {
189 Symbols.reserve(Names.size());
190 for (auto &Name : Names)
191 add(std::move(Name), Flags);
194 /// Construct a SymbolLookupSet from a SymbolNameSet with the given
195 /// Flags used for each value.
196 explicit SymbolLookupSet(
197 const SymbolNameSet &Names,
198 SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) {
199 Symbols.reserve(Names.size());
200 for (const auto &Name : Names)
204 /// Construct a SymbolLookupSet from a vector of symbols with the given Flags
205 /// used for each value.
206 /// If the ArrayRef contains duplicates it is up to the client to remove these
207 /// before using this instance for lookup.
208 explicit SymbolLookupSet(
209 ArrayRef<SymbolStringPtr> Names,
210 SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) {
211 Symbols.reserve(Names.size());
212 for (const auto &Name : Names)
216 /// Add an element to the set. The client is responsible for checking that
217 /// duplicates are not added.
218 void add(SymbolStringPtr Name,
219 SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) {
220 Symbols.push_back(std::make_pair(std::move(Name), Flags));
223 bool empty() const { return Symbols.empty(); }
224 UnderlyingVector::size_type size() const { return Symbols.size(); }
225 iterator begin() { return Symbols.begin(); }
226 iterator end() { return Symbols.end(); }
227 const_iterator begin() const { return Symbols.begin(); }
228 const_iterator end() const { return Symbols.end(); }
230 /// Removes the Ith element of the vector, replacing it with the last element.
231 void remove(UnderlyingVector::size_type I) {
232 std::swap(Symbols[I], Symbols.back());
236 /// Removes the element pointed to by the given iterator. This iterator and
237 /// all subsequent ones (including end()) are invalidated.
238 void remove(iterator I) { remove(I - begin()); }
240 /// Removes all elements matching the given predicate, which must be callable
241 /// as bool(const SymbolStringPtr &, SymbolLookupFlags Flags).
242 template <typename PredFn> void remove_if(PredFn &&Pred) {
243 UnderlyingVector::size_type I = 0;
244 while (I != Symbols.size()) {
245 const auto &Name = Symbols[I].first;
246 auto Flags = Symbols[I].second;
247 if (Pred(Name, Flags))
254 /// Loop over the elements of this SymbolLookupSet, applying the Body function
255 /// to each one. Body must be callable as
256 /// bool(const SymbolStringPtr &, SymbolLookupFlags).
257 /// If Body returns true then the element just passed in is removed from the
258 /// set. If Body returns false then the element is retained.
259 template <typename BodyFn>
260 auto forEachWithRemoval(BodyFn &&Body) -> std::enable_if_t<
261 std::is_same<decltype(Body(std::declval<const SymbolStringPtr &>(),
262 std::declval<SymbolLookupFlags>())),
264 UnderlyingVector::size_type I = 0;
265 while (I != Symbols.size()) {
266 const auto &Name = Symbols[I].first;
267 auto Flags = Symbols[I].second;
268 if (Body(Name, Flags))
275 /// Loop over the elements of this SymbolLookupSet, applying the Body function
276 /// to each one. Body must be callable as
277 /// Expected<bool>(const SymbolStringPtr &, SymbolLookupFlags).
278 /// If Body returns a failure value, the loop exits immediately. If Body
279 /// returns true then the element just passed in is removed from the set. If
280 /// Body returns false then the element is retained.
281 template <typename BodyFn>
282 auto forEachWithRemoval(BodyFn &&Body) -> std::enable_if_t<
283 std::is_same<decltype(Body(std::declval<const SymbolStringPtr &>(),
284 std::declval<SymbolLookupFlags>())),
285 Expected<bool>>::value,
287 UnderlyingVector::size_type I = 0;
288 while (I != Symbols.size()) {
289 const auto &Name = Symbols[I].first;
290 auto Flags = Symbols[I].second;
291 auto Remove = Body(Name, Flags);
293 return Remove.takeError();
299 return Error::success();
302 /// Construct a SymbolNameVector from this instance by dropping the Flags
304 SymbolNameVector getSymbolNames() const {
305 SymbolNameVector Names;
306 Names.reserve(Symbols.size());
307 for (auto &KV : Symbols)
308 Names.push_back(KV.first);
312 /// Sort the lookup set by pointer value. This sort is fast but sensitive to
313 /// allocation order and so should not be used where a consistent order is
315 void sortByAddress() {
316 llvm::sort(Symbols, [](const value_type &LHS, const value_type &RHS) {
317 return LHS.first < RHS.first;
321 /// Sort the lookup set lexicographically. This sort is slow but the order
322 /// is unaffected by allocation order.
324 llvm::sort(Symbols, [](const value_type &LHS, const value_type &RHS) {
325 return *LHS.first < *RHS.first;
329 /// Remove any duplicate elements. If a SymbolLookupSet is not duplicate-free
330 /// by construction, this method can be used to turn it into a proper set.
331 void removeDuplicates() {
333 auto LastI = std::unique(Symbols.begin(), Symbols.end());
334 Symbols.erase(LastI, Symbols.end());
338 /// Returns true if this set contains any duplicates. This should only be used
340 bool containsDuplicates() {
341 if (Symbols.size() < 2)
344 for (UnderlyingVector::size_type I = 1; I != Symbols.size(); ++I)
345 if (Symbols[I].first == Symbols[I - 1].first)
352 UnderlyingVector Symbols;
355 struct SymbolAliasMapEntry {
356 SymbolAliasMapEntry() = default;
357 SymbolAliasMapEntry(SymbolStringPtr Aliasee, JITSymbolFlags AliasFlags)
358 : Aliasee(std::move(Aliasee)), AliasFlags(AliasFlags) {}
360 SymbolStringPtr Aliasee;
361 JITSymbolFlags AliasFlags;
364 /// A map of Symbols to (Symbol, Flags) pairs.
365 using SymbolAliasMap = DenseMap<SymbolStringPtr, SymbolAliasMapEntry>;
367 /// Callback to notify client that symbols have been resolved.
368 using SymbolsResolvedCallback = unique_function<void(Expected<SymbolMap>)>;
370 /// Callback to register the dependencies for a given query.
371 using RegisterDependenciesFunction =
372 std::function<void(const SymbolDependenceMap &)>;
374 /// This can be used as the value for a RegisterDependenciesFunction if there
375 /// are no dependants to register with.
376 extern RegisterDependenciesFunction NoDependenciesToRegister;
378 class ResourceTrackerDefunct : public ErrorInfo<ResourceTrackerDefunct> {
382 ResourceTrackerDefunct(ResourceTrackerSP RT);
383 std::error_code convertToErrorCode() const override;
384 void log(raw_ostream &OS) const override;
387 ResourceTrackerSP RT;
390 /// Used to notify a JITDylib that the given set of symbols failed to
392 class FailedToMaterialize : public ErrorInfo<FailedToMaterialize> {
396 FailedToMaterialize(std::shared_ptr<SymbolDependenceMap> Symbols);
397 std::error_code convertToErrorCode() const override;
398 void log(raw_ostream &OS) const override;
399 const SymbolDependenceMap &getSymbols() const { return *Symbols; }
402 std::shared_ptr<SymbolDependenceMap> Symbols;
405 /// Used to notify clients when symbols can not be found during a lookup.
406 class SymbolsNotFound : public ErrorInfo<SymbolsNotFound> {
410 SymbolsNotFound(SymbolNameSet Symbols);
411 SymbolsNotFound(SymbolNameVector Symbols);
412 std::error_code convertToErrorCode() const override;
413 void log(raw_ostream &OS) const override;
414 const SymbolNameVector &getSymbols() const { return Symbols; }
417 SymbolNameVector Symbols;
420 /// Used to notify clients that a set of symbols could not be removed.
421 class SymbolsCouldNotBeRemoved : public ErrorInfo<SymbolsCouldNotBeRemoved> {
425 SymbolsCouldNotBeRemoved(SymbolNameSet Symbols);
426 std::error_code convertToErrorCode() const override;
427 void log(raw_ostream &OS) const override;
428 const SymbolNameSet &getSymbols() const { return Symbols; }
431 SymbolNameSet Symbols;
434 /// Errors of this type should be returned if a module fails to include
435 /// definitions that are claimed by the module's associated
436 /// MaterializationResponsibility. If this error is returned it is indicative of
437 /// a broken transformation / compiler / object cache.
438 class MissingSymbolDefinitions : public ErrorInfo<MissingSymbolDefinitions> {
442 MissingSymbolDefinitions(std::string ModuleName, SymbolNameVector Symbols)
443 : ModuleName(std::move(ModuleName)), Symbols(std::move(Symbols)) {}
444 std::error_code convertToErrorCode() const override;
445 void log(raw_ostream &OS) const override;
446 const std::string &getModuleName() const { return ModuleName; }
447 const SymbolNameVector &getSymbols() const { return Symbols; }
449 std::string ModuleName;
450 SymbolNameVector Symbols;
453 /// Errors of this type should be returned if a module contains definitions for
454 /// symbols that are not claimed by the module's associated
455 /// MaterializationResponsibility. If this error is returned it is indicative of
456 /// a broken transformation / compiler / object cache.
457 class UnexpectedSymbolDefinitions : public ErrorInfo<UnexpectedSymbolDefinitions> {
461 UnexpectedSymbolDefinitions(std::string ModuleName, SymbolNameVector Symbols)
462 : ModuleName(std::move(ModuleName)), Symbols(std::move(Symbols)) {}
463 std::error_code convertToErrorCode() const override;
464 void log(raw_ostream &OS) const override;
465 const std::string &getModuleName() const { return ModuleName; }
466 const SymbolNameVector &getSymbols() const { return Symbols; }
468 std::string ModuleName;
469 SymbolNameVector Symbols;
472 /// Tracks responsibility for materialization, and mediates interactions between
473 /// MaterializationUnits and JDs.
475 /// An instance of this class is passed to MaterializationUnits when their
476 /// materialize method is called. It allows MaterializationUnits to resolve and
477 /// emit symbols, or abandon materialization by notifying any unmaterialized
478 /// symbols of an error.
479 class MaterializationResponsibility {
480 friend class ExecutionSession;
483 MaterializationResponsibility(MaterializationResponsibility &&) = delete;
484 MaterializationResponsibility &
485 operator=(MaterializationResponsibility &&) = delete;
487 /// Destruct a MaterializationResponsibility instance. In debug mode
488 /// this asserts that all symbols being tracked have been either
489 /// emitted or notified of an error.
490 ~MaterializationResponsibility();
492 /// Returns the ResourceTracker for this instance.
493 template <typename Func> Error withResourceKeyDo(Func &&F) const;
495 /// Returns the target JITDylib that these symbols are being materialized
497 JITDylib &getTargetJITDylib() const { return *JD; }
499 /// Returns the ExecutionSession for this instance.
500 ExecutionSession &getExecutionSession();
502 /// Returns the symbol flags map for this responsibility instance.
503 /// Note: The returned flags may have transient flags (Lazy, Materializing)
504 /// set. These should be stripped with JITSymbolFlags::stripTransientFlags
506 const SymbolFlagsMap &getSymbols() const { return SymbolFlags; }
508 /// Returns the initialization pseudo-symbol, if any. This symbol will also
509 /// be present in the SymbolFlagsMap for this MaterializationResponsibility
511 const SymbolStringPtr &getInitializerSymbol() const { return InitSymbol; }
513 /// Returns the names of any symbols covered by this
514 /// MaterializationResponsibility object that have queries pending. This
515 /// information can be used to return responsibility for unrequested symbols
516 /// back to the JITDylib via the delegate method.
517 SymbolNameSet getRequestedSymbols() const;
519 /// Notifies the target JITDylib that the given symbols have been resolved.
520 /// This will update the given symbols' addresses in the JITDylib, and notify
521 /// any pending queries on the given symbols of their resolution. The given
522 /// symbols must be ones covered by this MaterializationResponsibility
523 /// instance. Individual calls to this method may resolve a subset of the
524 /// symbols, but all symbols must have been resolved prior to calling emit.
526 /// This method will return an error if any symbols being resolved have been
527 /// moved to the error state due to the failure of a dependency. If this
528 /// method returns an error then clients should log it and call
529 /// failMaterialize. If no dependencies have been registered for the
530 /// symbols covered by this MaterializationResponsibiility then this method
531 /// is guaranteed to return Error::success() and can be wrapped with cantFail.
532 Error notifyResolved(const SymbolMap &Symbols);
534 /// Notifies the target JITDylib (and any pending queries on that JITDylib)
535 /// that all symbols covered by this MaterializationResponsibility instance
536 /// have been emitted.
538 /// This method will return an error if any symbols being resolved have been
539 /// moved to the error state due to the failure of a dependency. If this
540 /// method returns an error then clients should log it and call
541 /// failMaterialize. If no dependencies have been registered for the
542 /// symbols covered by this MaterializationResponsibiility then this method
543 /// is guaranteed to return Error::success() and can be wrapped with cantFail.
544 Error notifyEmitted();
546 /// Attempt to claim responsibility for new definitions. This method can be
547 /// used to claim responsibility for symbols that are added to a
548 /// materialization unit during the compilation process (e.g. literal pool
549 /// symbols). Symbol linkage rules are the same as for symbols that are
550 /// defined up front: duplicate strong definitions will result in errors.
551 /// Duplicate weak definitions will be discarded (in which case they will
552 /// not be added to this responsibility instance).
554 /// This method can be used by materialization units that want to add
555 /// additional symbols at materialization time (e.g. stubs, compile
556 /// callbacks, metadata).
557 Error defineMaterializing(SymbolFlagsMap SymbolFlags);
559 /// Define the given symbols as non-existent, removing it from the symbol
560 /// table and notifying any pending queries. Queries that lookup up the
561 /// symbol using the SymbolLookupFlags::WeaklyReferencedSymbol flag will
562 /// behave as if the symbol had not been matched in the first place. Queries
563 /// that required this symbol will fail with a missing symbol definition
566 /// This method is intended to support cleanup of special symbols like
567 /// initializer symbols: Queries using
568 /// SymbolLookupFlags::WeaklyReferencedSymbol can be used to trigger their
569 /// emission, and this method can be used to remove them from the JITDylib
570 /// once materialization is complete.
571 void defineNonExistent(ArrayRef<SymbolStringPtr> Symbols);
573 /// Notify all not-yet-emitted covered by this MaterializationResponsibility
574 /// instance that an error has occurred.
575 /// This will remove all symbols covered by this MaterializationResponsibilty
576 /// from the target JITDylib, and send an error to any queries waiting on
578 void failMaterialization();
580 /// Transfers responsibility to the given MaterializationUnit for all
581 /// symbols defined by that MaterializationUnit. This allows
582 /// materializers to break up work based on run-time information (e.g.
583 /// by introspecting which symbols have actually been looked up and
584 /// materializing only those).
585 Error replace(std::unique_ptr<MaterializationUnit> MU);
587 /// Delegates responsibility for the given symbols to the returned
588 /// materialization responsibility. Useful for breaking up work between
589 /// threads, or different kinds of materialization processes.
590 Expected<std::unique_ptr<MaterializationResponsibility>>
591 delegate(const SymbolNameSet &Symbols);
593 void addDependencies(const SymbolStringPtr &Name,
594 const SymbolDependenceMap &Dependencies);
596 /// Add dependencies that apply to all symbols covered by this instance.
597 void addDependenciesForAll(const SymbolDependenceMap &Dependencies);
600 /// Create a MaterializationResponsibility for the given JITDylib and
602 MaterializationResponsibility(JITDylibSP JD, SymbolFlagsMap SymbolFlags,
603 SymbolStringPtr InitSymbol)
604 : JD(std::move(JD)), SymbolFlags(std::move(SymbolFlags)),
605 InitSymbol(std::move(InitSymbol)) {
606 assert(this->JD && "Cannot initialize with null JITDylib");
607 assert(!this->SymbolFlags.empty() && "Materializing nothing?");
611 SymbolFlagsMap SymbolFlags;
612 SymbolStringPtr InitSymbol;
615 /// A MaterializationUnit represents a set of symbol definitions that can
616 /// be materialized as a group, or individually discarded (when
617 /// overriding definitions are encountered).
619 /// MaterializationUnits are used when providing lazy definitions of symbols to
620 /// JITDylibs. The JITDylib will call materialize when the address of a symbol
621 /// is requested via the lookup method. The JITDylib will call discard if a
622 /// stronger definition is added or already present.
623 class MaterializationUnit {
624 friend class ExecutionSession;
625 friend class JITDylib;
628 MaterializationUnit(SymbolFlagsMap InitalSymbolFlags,
629 SymbolStringPtr InitSymbol)
630 : SymbolFlags(std::move(InitalSymbolFlags)),
631 InitSymbol(std::move(InitSymbol)) {
632 assert((!this->InitSymbol || this->SymbolFlags.count(this->InitSymbol)) &&
633 "If set, InitSymbol should appear in InitialSymbolFlags map");
636 virtual ~MaterializationUnit() {}
638 /// Return the name of this materialization unit. Useful for debugging
640 virtual StringRef getName() const = 0;
642 /// Return the set of symbols that this source provides.
643 const SymbolFlagsMap &getSymbols() const { return SymbolFlags; }
645 /// Returns the initialization symbol for this MaterializationUnit (if any).
646 const SymbolStringPtr &getInitializerSymbol() const { return InitSymbol; }
648 /// Implementations of this method should materialize all symbols
649 /// in the materialzation unit, except for those that have been
650 /// previously discarded.
652 materialize(std::unique_ptr<MaterializationResponsibility> R) = 0;
654 /// Called by JITDylibs to notify MaterializationUnits that the given symbol
655 /// has been overridden.
656 void doDiscard(const JITDylib &JD, const SymbolStringPtr &Name) {
657 SymbolFlags.erase(Name);
658 discard(JD, std::move(Name));
662 SymbolFlagsMap SymbolFlags;
663 SymbolStringPtr InitSymbol;
666 virtual void anchor();
668 /// Implementations of this method should discard the given symbol
669 /// from the source (e.g. if the source is an LLVM IR Module and the
670 /// symbol is a function, delete the function body or mark it available
672 virtual void discard(const JITDylib &JD, const SymbolStringPtr &Name) = 0;
675 /// A MaterializationUnit implementation for pre-existing absolute symbols.
677 /// All symbols will be resolved and marked ready as soon as the unit is
679 class AbsoluteSymbolsMaterializationUnit : public MaterializationUnit {
681 AbsoluteSymbolsMaterializationUnit(SymbolMap Symbols);
683 StringRef getName() const override;
686 void materialize(std::unique_ptr<MaterializationResponsibility> R) override;
687 void discard(const JITDylib &JD, const SymbolStringPtr &Name) override;
688 static SymbolFlagsMap extractFlags(const SymbolMap &Symbols);
693 /// Create an AbsoluteSymbolsMaterializationUnit with the given symbols.
694 /// Useful for inserting absolute symbols into a JITDylib. E.g.:
696 /// JITDylib &JD = ...;
697 /// SymbolStringPtr Foo = ...;
698 /// JITEvaluatedSymbol FooSym = ...;
699 /// if (auto Err = JD.define(absoluteSymbols({{Foo, FooSym}})))
703 inline std::unique_ptr<AbsoluteSymbolsMaterializationUnit>
704 absoluteSymbols(SymbolMap Symbols) {
705 return std::make_unique<AbsoluteSymbolsMaterializationUnit>(
709 /// A materialization unit for symbol aliases. Allows existing symbols to be
710 /// aliased with alternate flags.
711 class ReExportsMaterializationUnit : public MaterializationUnit {
713 /// SourceJD is allowed to be nullptr, in which case the source JITDylib is
714 /// taken to be whatever JITDylib these definitions are materialized in (and
715 /// MatchNonExported has no effect). This is useful for defining aliases
716 /// within a JITDylib.
718 /// Note: Care must be taken that no sets of aliases form a cycle, as such
719 /// a cycle will result in a deadlock when any symbol in the cycle is
721 ReExportsMaterializationUnit(JITDylib *SourceJD,
722 JITDylibLookupFlags SourceJDLookupFlags,
723 SymbolAliasMap Aliases);
725 StringRef getName() const override;
728 void materialize(std::unique_ptr<MaterializationResponsibility> R) override;
729 void discard(const JITDylib &JD, const SymbolStringPtr &Name) override;
730 static SymbolFlagsMap extractFlags(const SymbolAliasMap &Aliases);
732 JITDylib *SourceJD = nullptr;
733 JITDylibLookupFlags SourceJDLookupFlags;
734 SymbolAliasMap Aliases;
737 /// Create a ReExportsMaterializationUnit with the given aliases.
738 /// Useful for defining symbol aliases.: E.g., given a JITDylib JD containing
739 /// symbols "foo" and "bar", we can define aliases "baz" (for "foo") and "qux"
740 /// (for "bar") with: \code{.cpp}
741 /// SymbolStringPtr Baz = ...;
742 /// SymbolStringPtr Qux = ...;
743 /// if (auto Err = JD.define(symbolAliases({
744 /// {Baz, { Foo, JITSymbolFlags::Exported }},
745 /// {Qux, { Bar, JITSymbolFlags::Weak }}}))
748 inline std::unique_ptr<ReExportsMaterializationUnit>
749 symbolAliases(SymbolAliasMap Aliases) {
750 return std::make_unique<ReExportsMaterializationUnit>(
751 nullptr, JITDylibLookupFlags::MatchAllSymbols, std::move(Aliases));
754 /// Create a materialization unit for re-exporting symbols from another JITDylib
755 /// with alternative names/flags.
756 /// SourceJD will be searched using the given JITDylibLookupFlags.
757 inline std::unique_ptr<ReExportsMaterializationUnit>
758 reexports(JITDylib &SourceJD, SymbolAliasMap Aliases,
759 JITDylibLookupFlags SourceJDLookupFlags =
760 JITDylibLookupFlags::MatchExportedSymbolsOnly) {
761 return std::make_unique<ReExportsMaterializationUnit>(
762 &SourceJD, SourceJDLookupFlags, std::move(Aliases));
765 /// Build a SymbolAliasMap for the common case where you want to re-export
766 /// symbols from another JITDylib with the same linkage/flags.
767 Expected<SymbolAliasMap>
768 buildSimpleReexportsAAliasMap(JITDylib &SourceJD, const SymbolNameSet &Symbols);
770 /// Represents the state that a symbol has reached during materialization.
771 enum class SymbolState : uint8_t {
772 Invalid, /// No symbol should be in this state.
773 NeverSearched, /// Added to the symbol table, never queried.
774 Materializing, /// Queried, materialization begun.
775 Resolved, /// Assigned address, still materializing.
776 Emitted, /// Emitted to memory, but waiting on transitive dependencies.
777 Ready = 0x3f /// Ready and safe for clients to access.
780 /// A symbol query that returns results via a callback when results are
783 /// makes a callback when all symbols are available.
784 class AsynchronousSymbolQuery {
785 friend class ExecutionSession;
786 friend class JITDylib;
787 friend class JITSymbolResolverAdapter;
788 friend class MaterializationResponsibility;
791 /// Create a query for the given symbols. The NotifyComplete
792 /// callback will be called once all queried symbols reach the given
794 AsynchronousSymbolQuery(const SymbolLookupSet &Symbols,
795 SymbolState RequiredState,
796 SymbolsResolvedCallback NotifyComplete);
798 /// Notify the query that a requested symbol has reached the required state.
799 void notifySymbolMetRequiredState(const SymbolStringPtr &Name,
800 JITEvaluatedSymbol Sym);
802 /// Returns true if all symbols covered by this query have been
804 bool isComplete() const { return OutstandingSymbolsCount == 0; }
806 /// Call the NotifyComplete callback.
808 /// This should only be called if all symbols covered by the query have
809 /// reached the specified state.
810 void handleComplete();
813 SymbolState getRequiredState() { return RequiredState; }
815 void addQueryDependence(JITDylib &JD, SymbolStringPtr Name);
817 void removeQueryDependence(JITDylib &JD, const SymbolStringPtr &Name);
819 void dropSymbol(const SymbolStringPtr &Name);
821 void handleFailed(Error Err);
825 SymbolsResolvedCallback NotifyComplete;
826 SymbolDependenceMap QueryRegistrations;
827 SymbolMap ResolvedSymbols;
828 size_t OutstandingSymbolsCount;
829 SymbolState RequiredState;
832 /// A symbol table that supports asynchoronous symbol queries.
834 /// Represents a virtual shared object. Instances can not be copied or moved, so
835 /// their addresses may be used as keys for resource management.
836 /// JITDylib state changes must be made via an ExecutionSession to guarantee
837 /// that they are synchronized with respect to other JITDylib operations.
838 class JITDylib : public ThreadSafeRefCountedBase<JITDylib> {
839 friend class AsynchronousSymbolQuery;
840 friend class ExecutionSession;
841 friend class Platform;
842 friend class MaterializationResponsibility;
844 /// Definition generators can be attached to JITDylibs to generate new
845 /// definitions for otherwise unresolved symbols during lookup.
846 class DefinitionGenerator {
848 virtual ~DefinitionGenerator();
850 /// DefinitionGenerators should override this method to insert new
851 /// definitions into the parent JITDylib. K specifies the kind of this
852 /// lookup. JD specifies the target JITDylib being searched, and
853 /// JDLookupFlags specifies whether the search should match against
854 /// hidden symbols. Finally, Symbols describes the set of unresolved
855 /// symbols and their associated lookup flags.
856 virtual Error tryToGenerate(LookupKind K, JITDylib &JD,
857 JITDylibLookupFlags JDLookupFlags,
858 const SymbolLookupSet &LookupSet) = 0;
861 using AsynchronousSymbolQuerySet =
862 std::set<std::shared_ptr<AsynchronousSymbolQuery>>;
864 JITDylib(const JITDylib &) = delete;
865 JITDylib &operator=(const JITDylib &) = delete;
866 JITDylib(JITDylib &&) = delete;
867 JITDylib &operator=(JITDylib &&) = delete;
869 /// Get the name for this JITDylib.
870 const std::string &getName() const { return JITDylibName; }
872 /// Get a reference to the ExecutionSession for this JITDylib.
873 ExecutionSession &getExecutionSession() const { return ES; }
875 /// Calls remove on all trackers currently associated with this JITDylib.
876 /// Does not run static deinits.
878 /// Note that removal happens outside the session lock, so new code may be
879 /// added concurrently while the clear is underway, and the newly added
880 /// code will *not* be cleared. Adding new code concurrently with a clear
881 /// is usually a bug and should be avoided.
884 /// Get the default resource tracker for this JITDylib.
885 ResourceTrackerSP getDefaultResourceTracker();
887 /// Create a resource tracker for this JITDylib.
888 ResourceTrackerSP createResourceTracker();
890 /// Adds a definition generator to this JITDylib and returns a referenece to
893 /// When JITDylibs are searched during lookup, if no existing definition of
894 /// a symbol is found, then any generators that have been added are run (in
895 /// the order that they were added) to potentially generate a definition.
896 template <typename GeneratorT>
897 GeneratorT &addGenerator(std::unique_ptr<GeneratorT> DefGenerator);
899 /// Remove a definition generator from this JITDylib.
901 /// The given generator must exist in this JITDylib's generators list (i.e.
902 /// have been added and not yet removed).
903 void removeGenerator(DefinitionGenerator &G);
905 /// Set the link order to be used when fixing up definitions in JITDylib.
906 /// This will replace the previous link order, and apply to any symbol
907 /// resolutions made for definitions in this JITDylib after the call to
908 /// setLinkOrder (even if the definition itself was added before the
911 /// If LinkAgainstThisJITDylibFirst is true (the default) then this JITDylib
912 /// will add itself to the beginning of the LinkOrder (Clients should not
913 /// put this JITDylib in the list in this case, to avoid redundant lookups).
915 /// If LinkAgainstThisJITDylibFirst is false then the link order will be used
916 /// as-is. The primary motivation for this feature is to support deliberate
917 /// shadowing of symbols in this JITDylib by a facade JITDylib. For example,
918 /// the facade may resolve function names to stubs, and the stubs may compile
919 /// lazily by looking up symbols in this dylib. Adding the facade dylib
920 /// as the first in the link order (instead of this dylib) ensures that
921 /// definitions within this dylib resolve to the lazy-compiling stubs,
922 /// rather than immediately materializing the definitions in this dylib.
923 void setLinkOrder(JITDylibSearchOrder NewSearchOrder,
924 bool LinkAgainstThisJITDylibFirst = true);
926 /// Add the given JITDylib to the link order for definitions in this
928 void addToLinkOrder(JITDylib &JD,
929 JITDylibLookupFlags JDLookupFlags =
930 JITDylibLookupFlags::MatchExportedSymbolsOnly);
932 /// Replace OldJD with NewJD in the link order if OldJD is present.
933 /// Otherwise this operation is a no-op.
934 void replaceInLinkOrder(JITDylib &OldJD, JITDylib &NewJD,
935 JITDylibLookupFlags JDLookupFlags =
936 JITDylibLookupFlags::MatchExportedSymbolsOnly);
938 /// Remove the given JITDylib from the link order for this JITDylib if it is
939 /// present. Otherwise this operation is a no-op.
940 void removeFromLinkOrder(JITDylib &JD);
942 /// Do something with the link order (run under the session lock).
943 template <typename Func>
944 auto withLinkOrderDo(Func &&F)
945 -> decltype(F(std::declval<const JITDylibSearchOrder &>()));
947 /// Define all symbols provided by the materialization unit to be part of this
950 /// If RT is not specified then the default resource tracker will be used.
952 /// This overload always takes ownership of the MaterializationUnit. If any
953 /// errors occur, the MaterializationUnit consumed.
954 template <typename MaterializationUnitType>
955 Error define(std::unique_ptr<MaterializationUnitType> &&MU,
956 ResourceTrackerSP RT = nullptr);
958 /// Define all symbols provided by the materialization unit to be part of this
961 /// This overload only takes ownership of the MaterializationUnit no error is
962 /// generated. If an error occurs, ownership remains with the caller. This
963 /// may allow the caller to modify the MaterializationUnit to correct the
964 /// issue, then re-call define.
965 template <typename MaterializationUnitType>
966 Error define(std::unique_ptr<MaterializationUnitType> &MU,
967 ResourceTrackerSP RT = nullptr);
969 /// Tries to remove the given symbols.
971 /// If any symbols are not defined in this JITDylib this method will return
972 /// a SymbolsNotFound error covering the missing symbols.
974 /// If all symbols are found but some symbols are in the process of being
975 /// materialized this method will return a SymbolsCouldNotBeRemoved error.
977 /// On success, all symbols are removed. On failure, the JITDylib state is
978 /// left unmodified (no symbols are removed).
979 Error remove(const SymbolNameSet &Names);
981 /// Search the given JITDylib for the symbols in Symbols. If found, store
982 /// the flags for each symbol in Flags. If any required symbols are not found
983 /// then an error will be returned.
984 Expected<SymbolFlagsMap> lookupFlags(LookupKind K,
985 JITDylibLookupFlags JDLookupFlags,
986 SymbolLookupSet LookupSet);
988 /// Dump current JITDylib state to OS.
989 void dump(raw_ostream &OS);
991 /// Returns the given JITDylibs and all of their transitive dependencies in
992 /// DFS order (based on linkage relationships). Each JITDylib will appear
994 static std::vector<JITDylibSP> getDFSLinkOrder(ArrayRef<JITDylibSP> JDs);
996 /// Returns the given JITDylibs and all of their transitive dependensies in
997 /// reverse DFS order (based on linkage relationships). Each JITDylib will
998 /// appear only once.
999 static std::vector<JITDylibSP>
1000 getReverseDFSLinkOrder(ArrayRef<JITDylibSP> JDs);
1002 /// Return this JITDylib and its transitive dependencies in DFS order
1003 /// based on linkage relationships.
1004 std::vector<JITDylibSP> getDFSLinkOrder();
1006 /// Rteurn this JITDylib and its transitive dependencies in reverse DFS order
1007 /// based on linkage relationships.
1008 std::vector<JITDylibSP> getReverseDFSLinkOrder();
1011 using AsynchronousSymbolQueryList =
1012 std::vector<std::shared_ptr<AsynchronousSymbolQuery>>;
1014 struct UnmaterializedInfo {
1015 UnmaterializedInfo(std::unique_ptr<MaterializationUnit> MU,
1016 ResourceTracker *RT)
1017 : MU(std::move(MU)), RT(RT) {}
1019 std::unique_ptr<MaterializationUnit> MU;
1020 ResourceTracker *RT;
1023 using UnmaterializedInfosMap =
1024 DenseMap<SymbolStringPtr, std::shared_ptr<UnmaterializedInfo>>;
1026 using UnmaterializedInfosList =
1027 std::vector<std::shared_ptr<UnmaterializedInfo>>;
1029 struct MaterializingInfo {
1030 SymbolDependenceMap Dependants;
1031 SymbolDependenceMap UnemittedDependencies;
1033 void addQuery(std::shared_ptr<AsynchronousSymbolQuery> Q);
1034 void removeQuery(const AsynchronousSymbolQuery &Q);
1035 AsynchronousSymbolQueryList takeQueriesMeeting(SymbolState RequiredState);
1036 AsynchronousSymbolQueryList takeAllPendingQueries() {
1037 return std::move(PendingQueries);
1039 bool hasQueriesPending() const { return !PendingQueries.empty(); }
1040 const AsynchronousSymbolQueryList &pendingQueries() const {
1041 return PendingQueries;
1044 AsynchronousSymbolQueryList PendingQueries;
1047 using MaterializingInfosMap = DenseMap<SymbolStringPtr, MaterializingInfo>;
1049 class SymbolTableEntry {
1051 SymbolTableEntry() = default;
1052 SymbolTableEntry(JITSymbolFlags Flags)
1053 : Flags(Flags), State(static_cast<uint8_t>(SymbolState::NeverSearched)),
1054 MaterializerAttached(false), PendingRemoval(false) {}
1056 JITTargetAddress getAddress() const { return Addr; }
1057 JITSymbolFlags getFlags() const { return Flags; }
1058 SymbolState getState() const { return static_cast<SymbolState>(State); }
1060 bool hasMaterializerAttached() const { return MaterializerAttached; }
1061 bool isPendingRemoval() const { return PendingRemoval; }
1063 void setAddress(JITTargetAddress Addr) { this->Addr = Addr; }
1064 void setFlags(JITSymbolFlags Flags) { this->Flags = Flags; }
1065 void setState(SymbolState State) {
1066 assert(static_cast<uint8_t>(State) < (1 << 6) &&
1067 "State does not fit in bitfield");
1068 this->State = static_cast<uint8_t>(State);
1071 void setMaterializerAttached(bool MaterializerAttached) {
1072 this->MaterializerAttached = MaterializerAttached;
1075 void setPendingRemoval(bool PendingRemoval) {
1076 this->PendingRemoval = PendingRemoval;
1079 JITEvaluatedSymbol getSymbol() const {
1080 return JITEvaluatedSymbol(Addr, Flags);
1084 JITTargetAddress Addr = 0;
1085 JITSymbolFlags Flags;
1087 uint8_t MaterializerAttached : 1;
1088 uint8_t PendingRemoval : 1;
1091 using SymbolTable = DenseMap<SymbolStringPtr, SymbolTableEntry>;
1093 JITDylib(ExecutionSession &ES, std::string Name);
1095 ResourceTrackerSP getTracker(MaterializationResponsibility &MR);
1096 std::pair<AsynchronousSymbolQuerySet, std::shared_ptr<SymbolDependenceMap>>
1097 removeTracker(ResourceTracker &RT);
1099 void transferTracker(ResourceTracker &DstRT, ResourceTracker &SrcRT);
1101 Error defineImpl(MaterializationUnit &MU);
1103 void installMaterializationUnit(std::unique_ptr<MaterializationUnit> MU,
1104 ResourceTracker &RT);
1106 void lookupFlagsImpl(SymbolFlagsMap &Result, LookupKind K,
1107 JITDylibLookupFlags JDLookupFlags,
1108 SymbolLookupSet &Unresolved);
1110 Error lodgeQuery(UnmaterializedInfosList &UMIs,
1111 std::shared_ptr<AsynchronousSymbolQuery> &Q, LookupKind K,
1112 JITDylibLookupFlags JDLookupFlags,
1113 SymbolLookupSet &Unresolved);
1115 Error lodgeQueryImpl(UnmaterializedInfosList &UMIs,
1116 std::shared_ptr<AsynchronousSymbolQuery> &Q,
1117 LookupKind K, JITDylibLookupFlags JDLookupFlags,
1118 SymbolLookupSet &Unresolved);
1120 void detachQueryHelper(AsynchronousSymbolQuery &Q,
1121 const SymbolNameSet &QuerySymbols);
1123 void transferEmittedNodeDependencies(MaterializingInfo &DependantMI,
1124 const SymbolStringPtr &DependantName,
1125 MaterializingInfo &EmittedMI);
1127 Expected<SymbolFlagsMap> defineMaterializing(SymbolFlagsMap SymbolFlags);
1129 Error replace(MaterializationResponsibility &FromMR,
1130 std::unique_ptr<MaterializationUnit> MU);
1132 Expected<std::unique_ptr<MaterializationResponsibility>>
1133 delegate(MaterializationResponsibility &FromMR, SymbolFlagsMap SymbolFlags,
1134 SymbolStringPtr InitSymbol);
1136 SymbolNameSet getRequestedSymbols(const SymbolFlagsMap &SymbolFlags) const;
1138 void addDependencies(const SymbolStringPtr &Name,
1139 const SymbolDependenceMap &Dependants);
1141 Error resolve(MaterializationResponsibility &MR, const SymbolMap &Resolved);
1143 Error emit(MaterializationResponsibility &MR, const SymbolFlagsMap &Emitted);
1145 void unlinkMaterializationResponsibility(MaterializationResponsibility &MR);
1147 using FailedSymbolsWorklist =
1148 std::vector<std::pair<JITDylib *, SymbolStringPtr>>;
1150 static std::pair<AsynchronousSymbolQuerySet,
1151 std::shared_ptr<SymbolDependenceMap>>
1152 failSymbols(FailedSymbolsWorklist);
1154 ExecutionSession &ES;
1155 std::string JITDylibName;
1157 SymbolTable Symbols;
1158 UnmaterializedInfosMap UnmaterializedInfos;
1159 MaterializingInfosMap MaterializingInfos;
1160 std::vector<std::unique_ptr<DefinitionGenerator>> DefGenerators;
1161 JITDylibSearchOrder LinkOrder;
1162 ResourceTrackerSP DefaultTracker;
1164 // Map trackers to sets of symbols tracked.
1165 DenseMap<ResourceTracker *, SymbolNameVector> TrackerSymbols;
1166 DenseMap<MaterializationResponsibility *, ResourceTracker *> MRTrackers;
1169 /// Platforms set up standard symbols and mediate interactions between dynamic
1170 /// initializers (e.g. C++ static constructors) and ExecutionSession state.
1171 /// Note that Platforms do not automatically run initializers: clients are still
1172 /// responsible for doing this.
1175 virtual ~Platform();
1177 /// This method will be called outside the session lock each time a JITDylib
1178 /// is created (unless it is created with EmptyJITDylib set) to allow the
1179 /// Platform to install any JITDylib specific standard symbols (e.g
1181 virtual Error setupJITDylib(JITDylib &JD) = 0;
1183 /// This method will be called under the ExecutionSession lock each time a
1184 /// MaterializationUnit is added to a JITDylib.
1185 virtual Error notifyAdding(ResourceTracker &RT,
1186 const MaterializationUnit &MU) = 0;
1188 /// This method will be called under the ExecutionSession lock when a
1189 /// ResourceTracker is removed.
1190 virtual Error notifyRemoving(ResourceTracker &RT) = 0;
1192 /// A utility function for looking up initializer symbols. Performs a blocking
1193 /// lookup for the given symbols in each of the given JITDylibs.
1194 static Expected<DenseMap<JITDylib *, SymbolMap>>
1195 lookupInitSymbols(ExecutionSession &ES,
1196 const DenseMap<JITDylib *, SymbolLookupSet> &InitSyms);
1199 /// An ExecutionSession represents a running JIT program.
1200 class ExecutionSession {
1201 // FIXME: Remove this when we remove the old ORC layers.
1202 friend class JITDylib;
1203 friend class ResourceTracker;
1206 /// For reporting errors.
1207 using ErrorReporter = std::function<void(Error)>;
1209 /// For dispatching MaterializationUnit::materialize calls.
1210 using DispatchMaterializationFunction =
1211 std::function<void(std::unique_ptr<MaterializationUnit> MU,
1212 std::unique_ptr<MaterializationResponsibility> MR)>;
1214 /// Construct an ExecutionSession.
1216 /// SymbolStringPools may be shared between ExecutionSessions.
1217 ExecutionSession(std::shared_ptr<SymbolStringPool> SSP = nullptr);
1219 /// End the session. Closes all JITDylibs.
1222 /// Add a symbol name to the SymbolStringPool and return a pointer to it.
1223 SymbolStringPtr intern(StringRef SymName) { return SSP->intern(SymName); }
1225 /// Returns a shared_ptr to the SymbolStringPool for this ExecutionSession.
1226 std::shared_ptr<SymbolStringPool> getSymbolStringPool() const { return SSP; }
1228 /// Set the Platform for this ExecutionSession.
1229 void setPlatform(std::unique_ptr<Platform> P) { this->P = std::move(P); }
1231 /// Get the Platform for this session.
1232 /// Will return null if no Platform has been set for this ExecutionSession.
1233 Platform *getPlatform() { return P.get(); }
1235 /// Run the given lambda with the session mutex locked.
1236 template <typename Func> decltype(auto) runSessionLocked(Func &&F) {
1237 std::lock_guard<std::recursive_mutex> Lock(SessionMutex);
1241 /// Register the given ResourceManager with this ExecutionSession.
1242 /// Managers will be notified of events in reverse order of registration.
1243 void registerResourceManager(ResourceManager &RM);
1245 /// Deregister the given ResourceManager with this ExecutionSession.
1246 /// Manager must have been previously registered.
1247 void deregisterResourceManager(ResourceManager &RM);
1249 /// Return a pointer to the "name" JITDylib.
1250 /// Ownership of JITDylib remains within Execution Session
1251 JITDylib *getJITDylibByName(StringRef Name);
1253 /// Add a new bare JITDylib to this ExecutionSession.
1255 /// The JITDylib Name is required to be unique. Clients should verify that
1256 /// names are not being re-used (E.g. by calling getJITDylibByName) if names
1257 /// are based on user input.
1259 /// This call does not install any library code or symbols into the newly
1260 /// created JITDylib. The client is responsible for all configuration.
1261 JITDylib &createBareJITDylib(std::string Name);
1263 /// Add a new JITDylib to this ExecutionSession.
1265 /// The JITDylib Name is required to be unique. Clients should verify that
1266 /// names are not being re-used (e.g. by calling getJITDylibByName) if names
1267 /// are based on user input.
1269 /// If a Platform is attached then Platform::setupJITDylib will be called to
1270 /// install standard platform symbols (e.g. standard library interposes).
1271 /// If no Platform is attached this call is equivalent to createBareJITDylib.
1272 Expected<JITDylib &> createJITDylib(std::string Name);
1274 /// Set the error reporter function.
1275 ExecutionSession &setErrorReporter(ErrorReporter ReportError) {
1276 this->ReportError = std::move(ReportError);
1280 /// Report a error for this execution session.
1282 /// Unhandled errors can be sent here to log them.
1283 void reportError(Error Err) { ReportError(std::move(Err)); }
1285 /// Set the materialization dispatch function.
1286 ExecutionSession &setDispatchMaterialization(
1287 DispatchMaterializationFunction DispatchMaterialization) {
1288 this->DispatchMaterialization = std::move(DispatchMaterialization);
1292 /// Search the given JITDylib list for the given symbols.
1294 /// SearchOrder lists the JITDylibs to search. For each dylib, the associated
1295 /// boolean indicates whether the search should match against non-exported
1296 /// (hidden visibility) symbols in that dylib (true means match against
1297 /// non-exported symbols, false means do not match).
1299 /// The NotifyComplete callback will be called once all requested symbols
1300 /// reach the required state.
1302 /// If all symbols are found, the RegisterDependencies function will be called
1303 /// while the session lock is held. This gives clients a chance to register
1304 /// dependencies for on the queried symbols for any symbols they are
1305 /// materializing (if a MaterializationResponsibility instance is present,
1306 /// this can be implemented by calling
1307 /// MaterializationResponsibility::addDependencies). If there are no
1308 /// dependenant symbols for this query (e.g. it is being made by a top level
1309 /// client to get an address to call) then the value NoDependenciesToRegister
1311 void lookup(LookupKind K, const JITDylibSearchOrder &SearchOrder,
1312 SymbolLookupSet Symbols, SymbolState RequiredState,
1313 SymbolsResolvedCallback NotifyComplete,
1314 RegisterDependenciesFunction RegisterDependencies);
1316 /// Blocking version of lookup above. Returns the resolved symbol map.
1317 /// If WaitUntilReady is true (the default), will not return until all
1318 /// requested symbols are ready (or an error occurs). If WaitUntilReady is
1319 /// false, will return as soon as all requested symbols are resolved,
1320 /// or an error occurs. If WaitUntilReady is false and an error occurs
1321 /// after resolution, the function will return a success value, but the
1322 /// error will be reported via reportErrors.
1323 Expected<SymbolMap> lookup(const JITDylibSearchOrder &SearchOrder,
1324 const SymbolLookupSet &Symbols,
1325 LookupKind K = LookupKind::Static,
1326 SymbolState RequiredState = SymbolState::Ready,
1327 RegisterDependenciesFunction RegisterDependencies =
1328 NoDependenciesToRegister);
1330 /// Convenience version of blocking lookup.
1331 /// Searches each of the JITDylibs in the search order in turn for the given
1333 Expected<JITEvaluatedSymbol>
1334 lookup(const JITDylibSearchOrder &SearchOrder, SymbolStringPtr Symbol,
1335 SymbolState RequiredState = SymbolState::Ready);
1337 /// Convenience version of blocking lookup.
1338 /// Searches each of the JITDylibs in the search order in turn for the given
1339 /// symbol. The search will not find non-exported symbols.
1340 Expected<JITEvaluatedSymbol>
1341 lookup(ArrayRef<JITDylib *> SearchOrder, SymbolStringPtr Symbol,
1342 SymbolState RequiredState = SymbolState::Ready);
1344 /// Convenience version of blocking lookup.
1345 /// Searches each of the JITDylibs in the search order in turn for the given
1346 /// symbol. The search will not find non-exported symbols.
1347 Expected<JITEvaluatedSymbol>
1348 lookup(ArrayRef<JITDylib *> SearchOrder, StringRef Symbol,
1349 SymbolState RequiredState = SymbolState::Ready);
1351 /// Materialize the given unit.
1353 dispatchMaterialization(std::unique_ptr<MaterializationUnit> MU,
1354 std::unique_ptr<MaterializationResponsibility> MR) {
1355 assert(MU && "MU must be non-null");
1356 DEBUG_WITH_TYPE("orc", dumpDispatchInfo(MR->getTargetJITDylib(), *MU));
1357 DispatchMaterialization(std::move(MU), std::move(MR));
1360 /// Dump the state of all the JITDylibs in this session.
1361 void dump(raw_ostream &OS);
1364 static void logErrorsToStdErr(Error Err) {
1365 logAllUnhandledErrors(std::move(Err), errs(), "JIT session error: ");
1368 static void materializeOnCurrentThread(
1369 std::unique_ptr<MaterializationUnit> MU,
1370 std::unique_ptr<MaterializationResponsibility> MR) {
1371 MU->materialize(std::move(MR));
1374 void runOutstandingMUs();
1376 static std::unique_ptr<MaterializationResponsibility>
1377 createMaterializationResponsibility(ResourceTracker &RT,
1378 SymbolFlagsMap Symbols,
1379 SymbolStringPtr InitSymbol) {
1380 auto &JD = RT.getJITDylib();
1381 std::unique_ptr<MaterializationResponsibility> MR(
1382 new MaterializationResponsibility(&JD, std::move(Symbols),
1383 std::move(InitSymbol)));
1384 JD.MRTrackers[MR.get()] = &RT;
1388 Error removeResourceTracker(ResourceTracker &RT);
1389 void transferResourceTracker(ResourceTracker &DstRT, ResourceTracker &SrcRT);
1390 void destroyResourceTracker(ResourceTracker &RT);
1393 void dumpDispatchInfo(JITDylib &JD, MaterializationUnit &MU);
1396 mutable std::recursive_mutex SessionMutex;
1397 bool SessionOpen = true;
1398 std::shared_ptr<SymbolStringPool> SSP;
1399 std::unique_ptr<Platform> P;
1400 ErrorReporter ReportError = logErrorsToStdErr;
1401 DispatchMaterializationFunction DispatchMaterialization =
1402 materializeOnCurrentThread;
1404 std::vector<ResourceManager *> ResourceManagers;
1406 std::vector<JITDylibSP> JDs;
1408 // FIXME: Remove this (and runOutstandingMUs) once the linking layer works
1409 // with callbacks from asynchronous queries.
1410 mutable std::recursive_mutex OutstandingMUsMutex;
1411 std::vector<std::pair<std::unique_ptr<MaterializationUnit>,
1412 std::unique_ptr<MaterializationResponsibility>>>
1416 inline ExecutionSession &MaterializationResponsibility::getExecutionSession() {
1417 return JD->getExecutionSession();
1420 template <typename Func>
1421 Error MaterializationResponsibility::withResourceKeyDo(Func &&F) const {
1422 return JD->getExecutionSession().runSessionLocked([&]() -> Error {
1423 auto I = JD->MRTrackers.find(this);
1424 assert(I != JD->MRTrackers.end() && "No tracker for this MR");
1425 if (I->second->isDefunct())
1426 return make_error<ResourceTrackerDefunct>(I->second);
1427 F(I->second->getKeyUnsafe());
1428 return Error::success();
1432 template <typename GeneratorT>
1433 GeneratorT &JITDylib::addGenerator(std::unique_ptr<GeneratorT> DefGenerator) {
1434 auto &G = *DefGenerator;
1435 ES.runSessionLocked(
1436 [&]() { DefGenerators.push_back(std::move(DefGenerator)); });
1440 template <typename Func>
1441 auto JITDylib::withLinkOrderDo(Func &&F)
1442 -> decltype(F(std::declval<const JITDylibSearchOrder &>())) {
1443 return ES.runSessionLocked([&]() { return F(LinkOrder); });
1446 template <typename MaterializationUnitType>
1447 Error JITDylib::define(std::unique_ptr<MaterializationUnitType> &&MU,
1448 ResourceTrackerSP RT) {
1449 assert(MU && "Can not define with a null MU");
1451 if (MU->getSymbols().empty()) {
1452 // Empty MUs are allowable but pathological, so issue a warning.
1453 DEBUG_WITH_TYPE("orc", {
1454 dbgs() << "Warning: Discarding empty MU " << MU->getName() << " for "
1455 << getName() << "\n";
1457 return Error::success();
1459 DEBUG_WITH_TYPE("orc", {
1460 dbgs() << "Defining MU " << MU->getName() << " for " << getName() << "\n";
1463 return ES.runSessionLocked([&, this]() -> Error {
1464 if (auto Err = defineImpl(*MU))
1468 RT = getDefaultResourceTracker();
1470 if (auto *P = ES.getPlatform()) {
1471 if (auto Err = P->notifyAdding(*RT, *MU))
1475 installMaterializationUnit(std::move(MU), *RT);
1476 return Error::success();
1480 template <typename MaterializationUnitType>
1481 Error JITDylib::define(std::unique_ptr<MaterializationUnitType> &MU,
1482 ResourceTrackerSP RT) {
1483 assert(MU && "Can not define with a null MU");
1485 if (MU->getSymbols().empty()) {
1486 // Empty MUs are allowable but pathological, so issue a warning.
1487 DEBUG_WITH_TYPE("orc", {
1488 dbgs() << "Warning: Discarding empty MU " << MU->getName() << getName()
1491 return Error::success();
1493 DEBUG_WITH_TYPE("orc", {
1494 dbgs() << "Defining MU " << MU->getName() << " for " << getName() << "\n";
1497 return ES.runSessionLocked([&, this]() -> Error {
1498 if (auto Err = defineImpl(*MU))
1502 RT = getDefaultResourceTracker();
1504 if (auto *P = ES.getPlatform()) {
1505 if (auto Err = P->notifyAdding(*RT, *MU))
1509 installMaterializationUnit(std::move(MU), *RT);
1510 return Error::success();
1514 /// ReexportsGenerator can be used with JITDylib::addGenerator to automatically
1515 /// re-export a subset of the source JITDylib's symbols in the target.
1516 class ReexportsGenerator : public JITDylib::DefinitionGenerator {
1518 using SymbolPredicate = std::function<bool(SymbolStringPtr)>;
1520 /// Create a reexports generator. If an Allow predicate is passed, only
1521 /// symbols for which the predicate returns true will be reexported. If no
1522 /// Allow predicate is passed, all symbols will be exported.
1523 ReexportsGenerator(JITDylib &SourceJD,
1524 JITDylibLookupFlags SourceJDLookupFlags,
1525 SymbolPredicate Allow = SymbolPredicate());
1527 Error tryToGenerate(LookupKind K, JITDylib &JD,
1528 JITDylibLookupFlags JDLookupFlags,
1529 const SymbolLookupSet &LookupSet) override;
1533 JITDylibLookupFlags SourceJDLookupFlags;
1534 SymbolPredicate Allow;
1537 } // End namespace orc
1538 } // End namespace llvm
1540 #endif // LLVM_EXECUTIONENGINE_ORC_CORE_H