[Alignment][NFC] Use Align with TargetLowering::setMinFunctionAlignment
[llvm-core.git] / include / llvm / ExecutionEngine / Orc / Core.h
blob2f06deef0c90ebee188913dd193bccf065db563e
1 //===------ Core.h -- Core ORC APIs (Layer, JITDylib, etc.) -----*- C++ -*-===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 //
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"
23 #include <memory>
24 #include <vector>
26 #define DEBUG_TYPE "orc"
28 namespace llvm {
29 namespace orc {
31 // Forward declare some classes.
32 class AsynchronousSymbolQuery;
33 class ExecutionSession;
34 class MaterializationUnit;
35 class MaterializationResponsibility;
36 class JITDylib;
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
44 // efficiency).
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 map from JITDylibs to sets of symbols.
55 using SymbolDependenceMap = DenseMap<JITDylib *, SymbolNameSet>;
57 /// A list of (JITDylib*, bool) pairs.
58 using JITDylibSearchList = std::vector<std::pair<JITDylib *, bool>>;
60 struct SymbolAliasMapEntry {
61 SymbolAliasMapEntry() = default;
62 SymbolAliasMapEntry(SymbolStringPtr Aliasee, JITSymbolFlags AliasFlags)
63 : Aliasee(std::move(Aliasee)), AliasFlags(AliasFlags) {}
65 SymbolStringPtr Aliasee;
66 JITSymbolFlags AliasFlags;
69 /// A map of Symbols to (Symbol, Flags) pairs.
70 using SymbolAliasMap = DenseMap<SymbolStringPtr, SymbolAliasMapEntry>;
72 /// Render a SymbolStringPtr.
73 raw_ostream &operator<<(raw_ostream &OS, const SymbolStringPtr &Sym);
75 /// Render a SymbolNameSet.
76 raw_ostream &operator<<(raw_ostream &OS, const SymbolNameSet &Symbols);
78 /// Render a SymbolFlagsMap entry.
79 raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap::value_type &KV);
81 /// Render a SymbolMap entry.
82 raw_ostream &operator<<(raw_ostream &OS, const SymbolMap::value_type &KV);
84 /// Render a SymbolFlagsMap.
85 raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap &SymbolFlags);
87 /// Render a SymbolMap.
88 raw_ostream &operator<<(raw_ostream &OS, const SymbolMap &Symbols);
90 /// Render a SymbolDependenceMap entry.
91 raw_ostream &operator<<(raw_ostream &OS,
92 const SymbolDependenceMap::value_type &KV);
94 /// Render a SymbolDependendeMap.
95 raw_ostream &operator<<(raw_ostream &OS, const SymbolDependenceMap &Deps);
97 /// Render a MaterializationUnit.
98 raw_ostream &operator<<(raw_ostream &OS, const MaterializationUnit &MU);
100 /// Render a JITDylibSearchList.
101 raw_ostream &operator<<(raw_ostream &OS, const JITDylibSearchList &JDs);
103 /// Render a SymbolAliasMap.
104 raw_ostream &operator<<(raw_ostream &OS, const SymbolAliasMap &Aliases);
106 /// Render a SymbolState.
107 raw_ostream &operator<<(raw_ostream &OS, const SymbolState &S);
109 /// Callback to notify client that symbols have been resolved.
110 using SymbolsResolvedCallback = std::function<void(Expected<SymbolMap>)>;
112 /// Callback to register the dependencies for a given query.
113 using RegisterDependenciesFunction =
114 std::function<void(const SymbolDependenceMap &)>;
116 /// This can be used as the value for a RegisterDependenciesFunction if there
117 /// are no dependants to register with.
118 extern RegisterDependenciesFunction NoDependenciesToRegister;
120 /// Used to notify a JITDylib that the given set of symbols failed to
121 /// materialize.
122 class FailedToMaterialize : public ErrorInfo<FailedToMaterialize> {
123 public:
124 static char ID;
126 FailedToMaterialize(std::shared_ptr<SymbolDependenceMap> Symbols);
127 std::error_code convertToErrorCode() const override;
128 void log(raw_ostream &OS) const override;
129 const SymbolDependenceMap &getSymbols() const { return *Symbols; }
131 private:
132 std::shared_ptr<SymbolDependenceMap> Symbols;
135 /// Used to notify clients when symbols can not be found during a lookup.
136 class SymbolsNotFound : public ErrorInfo<SymbolsNotFound> {
137 public:
138 static char ID;
140 SymbolsNotFound(SymbolNameSet Symbols);
141 std::error_code convertToErrorCode() const override;
142 void log(raw_ostream &OS) const override;
143 const SymbolNameSet &getSymbols() const { return Symbols; }
145 private:
146 SymbolNameSet Symbols;
149 /// Used to notify clients that a set of symbols could not be removed.
150 class SymbolsCouldNotBeRemoved : public ErrorInfo<SymbolsCouldNotBeRemoved> {
151 public:
152 static char ID;
154 SymbolsCouldNotBeRemoved(SymbolNameSet Symbols);
155 std::error_code convertToErrorCode() const override;
156 void log(raw_ostream &OS) const override;
157 const SymbolNameSet &getSymbols() const { return Symbols; }
159 private:
160 SymbolNameSet Symbols;
163 /// Tracks responsibility for materialization, and mediates interactions between
164 /// MaterializationUnits and JDs.
166 /// An instance of this class is passed to MaterializationUnits when their
167 /// materialize method is called. It allows MaterializationUnits to resolve and
168 /// emit symbols, or abandon materialization by notifying any unmaterialized
169 /// symbols of an error.
170 class MaterializationResponsibility {
171 friend class MaterializationUnit;
172 public:
173 MaterializationResponsibility(MaterializationResponsibility &&) = default;
174 MaterializationResponsibility &
175 operator=(MaterializationResponsibility &&) = delete;
177 /// Destruct a MaterializationResponsibility instance. In debug mode
178 /// this asserts that all symbols being tracked have been either
179 /// emitted or notified of an error.
180 ~MaterializationResponsibility();
182 /// Returns the target JITDylib that these symbols are being materialized
183 /// into.
184 JITDylib &getTargetJITDylib() const { return JD; }
186 /// Returns the VModuleKey for this instance.
187 VModuleKey getVModuleKey() const { return K; }
189 /// Returns the symbol flags map for this responsibility instance.
190 /// Note: The returned flags may have transient flags (Lazy, Materializing)
191 /// set. These should be stripped with JITSymbolFlags::stripTransientFlags
192 /// before using.
193 const SymbolFlagsMap &getSymbols() const { return SymbolFlags; }
195 /// Returns the names of any symbols covered by this
196 /// MaterializationResponsibility object that have queries pending. This
197 /// information can be used to return responsibility for unrequested symbols
198 /// back to the JITDylib via the delegate method.
199 SymbolNameSet getRequestedSymbols() const;
201 /// Notifies the target JITDylib that the given symbols have been resolved.
202 /// This will update the given symbols' addresses in the JITDylib, and notify
203 /// any pending queries on the given symbols of their resolution. The given
204 /// symbols must be ones covered by this MaterializationResponsibility
205 /// instance. Individual calls to this method may resolve a subset of the
206 /// symbols, but all symbols must have been resolved prior to calling emit.
208 /// This method will return an error if any symbols being resolved have been
209 /// moved to the error state due to the failure of a dependency. If this
210 /// method returns an error then clients should log it and call
211 /// failMaterialize. If no dependencies have been registered for the
212 /// symbols covered by this MaterializationResponsibiility then this method
213 /// is guaranteed to return Error::success() and can be wrapped with cantFail.
214 Error notifyResolved(const SymbolMap &Symbols);
216 /// Notifies the target JITDylib (and any pending queries on that JITDylib)
217 /// that all symbols covered by this MaterializationResponsibility instance
218 /// have been emitted.
220 /// This method will return an error if any symbols being resolved have been
221 /// moved to the error state due to the failure of a dependency. If this
222 /// method returns an error then clients should log it and call
223 /// failMaterialize. If no dependencies have been registered for the
224 /// symbols covered by this MaterializationResponsibiility then this method
225 /// is guaranteed to return Error::success() and can be wrapped with cantFail.
226 Error notifyEmitted();
228 /// Adds new symbols to the JITDylib and this responsibility instance.
229 /// JITDylib entries start out in the materializing state.
231 /// This method can be used by materialization units that want to add
232 /// additional symbols at materialization time (e.g. stubs, compile
233 /// callbacks, metadata).
234 Error defineMaterializing(const SymbolFlagsMap &SymbolFlags);
236 /// Notify all not-yet-emitted covered by this MaterializationResponsibility
237 /// instance that an error has occurred.
238 /// This will remove all symbols covered by this MaterializationResponsibilty
239 /// from the target JITDylib, and send an error to any queries waiting on
240 /// these symbols.
241 void failMaterialization();
243 /// Transfers responsibility to the given MaterializationUnit for all
244 /// symbols defined by that MaterializationUnit. This allows
245 /// materializers to break up work based on run-time information (e.g.
246 /// by introspecting which symbols have actually been looked up and
247 /// materializing only those).
248 void replace(std::unique_ptr<MaterializationUnit> MU);
250 /// Delegates responsibility for the given symbols to the returned
251 /// materialization responsibility. Useful for breaking up work between
252 /// threads, or different kinds of materialization processes.
253 MaterializationResponsibility delegate(const SymbolNameSet &Symbols,
254 VModuleKey NewKey = VModuleKey());
256 void addDependencies(const SymbolStringPtr &Name,
257 const SymbolDependenceMap &Dependencies);
259 /// Add dependencies that apply to all symbols covered by this instance.
260 void addDependenciesForAll(const SymbolDependenceMap &Dependencies);
262 private:
263 /// Create a MaterializationResponsibility for the given JITDylib and
264 /// initial symbols.
265 MaterializationResponsibility(JITDylib &JD, SymbolFlagsMap SymbolFlags,
266 VModuleKey K);
268 JITDylib &JD;
269 SymbolFlagsMap SymbolFlags;
270 VModuleKey K;
273 /// A MaterializationUnit represents a set of symbol definitions that can
274 /// be materialized as a group, or individually discarded (when
275 /// overriding definitions are encountered).
277 /// MaterializationUnits are used when providing lazy definitions of symbols to
278 /// JITDylibs. The JITDylib will call materialize when the address of a symbol
279 /// is requested via the lookup method. The JITDylib will call discard if a
280 /// stronger definition is added or already present.
281 class MaterializationUnit {
282 public:
283 MaterializationUnit(SymbolFlagsMap InitalSymbolFlags, VModuleKey K)
284 : SymbolFlags(std::move(InitalSymbolFlags)), K(std::move(K)) {}
286 virtual ~MaterializationUnit() {}
288 /// Return the name of this materialization unit. Useful for debugging
289 /// output.
290 virtual StringRef getName() const = 0;
292 /// Return the set of symbols that this source provides.
293 const SymbolFlagsMap &getSymbols() const { return SymbolFlags; }
295 /// Called by materialization dispatchers (see
296 /// ExecutionSession::DispatchMaterializationFunction) to trigger
297 /// materialization of this MaterializationUnit.
298 void doMaterialize(JITDylib &JD) {
299 materialize(MaterializationResponsibility(JD, std::move(SymbolFlags),
300 std::move(K)));
303 /// Called by JITDylibs to notify MaterializationUnits that the given symbol
304 /// has been overridden.
305 void doDiscard(const JITDylib &JD, const SymbolStringPtr &Name) {
306 SymbolFlags.erase(Name);
307 discard(JD, std::move(Name));
310 protected:
311 SymbolFlagsMap SymbolFlags;
312 VModuleKey K;
314 private:
315 virtual void anchor();
317 /// Implementations of this method should materialize all symbols
318 /// in the materialzation unit, except for those that have been
319 /// previously discarded.
320 virtual void materialize(MaterializationResponsibility R) = 0;
322 /// Implementations of this method should discard the given symbol
323 /// from the source (e.g. if the source is an LLVM IR Module and the
324 /// symbol is a function, delete the function body or mark it available
325 /// externally).
326 virtual void discard(const JITDylib &JD, const SymbolStringPtr &Name) = 0;
329 using MaterializationUnitList =
330 std::vector<std::unique_ptr<MaterializationUnit>>;
332 /// A MaterializationUnit implementation for pre-existing absolute symbols.
334 /// All symbols will be resolved and marked ready as soon as the unit is
335 /// materialized.
336 class AbsoluteSymbolsMaterializationUnit : public MaterializationUnit {
337 public:
338 AbsoluteSymbolsMaterializationUnit(SymbolMap Symbols, VModuleKey K);
340 StringRef getName() const override;
342 private:
343 void materialize(MaterializationResponsibility R) override;
344 void discard(const JITDylib &JD, const SymbolStringPtr &Name) override;
345 static SymbolFlagsMap extractFlags(const SymbolMap &Symbols);
347 SymbolMap Symbols;
350 /// Create an AbsoluteSymbolsMaterializationUnit with the given symbols.
351 /// Useful for inserting absolute symbols into a JITDylib. E.g.:
352 /// \code{.cpp}
353 /// JITDylib &JD = ...;
354 /// SymbolStringPtr Foo = ...;
355 /// JITEvaluatedSymbol FooSym = ...;
356 /// if (auto Err = JD.define(absoluteSymbols({{Foo, FooSym}})))
357 /// return Err;
358 /// \endcode
360 inline std::unique_ptr<AbsoluteSymbolsMaterializationUnit>
361 absoluteSymbols(SymbolMap Symbols, VModuleKey K = VModuleKey()) {
362 return std::make_unique<AbsoluteSymbolsMaterializationUnit>(
363 std::move(Symbols), std::move(K));
366 /// A materialization unit for symbol aliases. Allows existing symbols to be
367 /// aliased with alternate flags.
368 class ReExportsMaterializationUnit : public MaterializationUnit {
369 public:
370 /// SourceJD is allowed to be nullptr, in which case the source JITDylib is
371 /// taken to be whatever JITDylib these definitions are materialized in (and
372 /// MatchNonExported has no effect). This is useful for defining aliases
373 /// within a JITDylib.
375 /// Note: Care must be taken that no sets of aliases form a cycle, as such
376 /// a cycle will result in a deadlock when any symbol in the cycle is
377 /// resolved.
378 ReExportsMaterializationUnit(JITDylib *SourceJD, bool MatchNonExported,
379 SymbolAliasMap Aliases, VModuleKey K);
381 StringRef getName() const override;
383 private:
384 void materialize(MaterializationResponsibility R) override;
385 void discard(const JITDylib &JD, const SymbolStringPtr &Name) override;
386 static SymbolFlagsMap extractFlags(const SymbolAliasMap &Aliases);
388 JITDylib *SourceJD = nullptr;
389 bool MatchNonExported = false;
390 SymbolAliasMap Aliases;
393 /// Create a ReExportsMaterializationUnit with the given aliases.
394 /// Useful for defining symbol aliases.: E.g., given a JITDylib JD containing
395 /// symbols "foo" and "bar", we can define aliases "baz" (for "foo") and "qux"
396 /// (for "bar") with: \code{.cpp}
397 /// SymbolStringPtr Baz = ...;
398 /// SymbolStringPtr Qux = ...;
399 /// if (auto Err = JD.define(symbolAliases({
400 /// {Baz, { Foo, JITSymbolFlags::Exported }},
401 /// {Qux, { Bar, JITSymbolFlags::Weak }}}))
402 /// return Err;
403 /// \endcode
404 inline std::unique_ptr<ReExportsMaterializationUnit>
405 symbolAliases(SymbolAliasMap Aliases, VModuleKey K = VModuleKey()) {
406 return std::make_unique<ReExportsMaterializationUnit>(
407 nullptr, true, std::move(Aliases), std::move(K));
410 /// Create a materialization unit for re-exporting symbols from another JITDylib
411 /// with alternative names/flags.
412 /// If MatchNonExported is true then non-exported symbols from SourceJD can be
413 /// re-exported. If it is false, attempts to re-export a non-exported symbol
414 /// will result in a "symbol not found" error.
415 inline std::unique_ptr<ReExportsMaterializationUnit>
416 reexports(JITDylib &SourceJD, SymbolAliasMap Aliases,
417 bool MatchNonExported = false, VModuleKey K = VModuleKey()) {
418 return std::make_unique<ReExportsMaterializationUnit>(
419 &SourceJD, MatchNonExported, std::move(Aliases), std::move(K));
422 /// Build a SymbolAliasMap for the common case where you want to re-export
423 /// symbols from another JITDylib with the same linkage/flags.
424 Expected<SymbolAliasMap>
425 buildSimpleReexportsAliasMap(JITDylib &SourceJD, const SymbolNameSet &Symbols);
427 /// Represents the state that a symbol has reached during materialization.
428 enum class SymbolState : uint8_t {
429 Invalid, /// No symbol should be in this state.
430 NeverSearched, /// Added to the symbol table, never queried.
431 Materializing, /// Queried, materialization begun.
432 Resolved, /// Assigned address, still materializing.
433 Emitted, /// Emitted to memory, but waiting on transitive dependencies.
434 Ready = 0x3f /// Ready and safe for clients to access.
437 /// A symbol query that returns results via a callback when results are
438 /// ready.
440 /// makes a callback when all symbols are available.
441 class AsynchronousSymbolQuery {
442 friend class ExecutionSession;
443 friend class JITDylib;
444 friend class JITSymbolResolverAdapter;
446 public:
447 /// Create a query for the given symbols. The NotifyComplete
448 /// callback will be called once all queried symbols reach the given
449 /// minimum state.
450 AsynchronousSymbolQuery(const SymbolNameSet &Symbols,
451 SymbolState RequiredState,
452 SymbolsResolvedCallback NotifyComplete);
454 /// Notify the query that a requested symbol has reached the required state.
455 void notifySymbolMetRequiredState(const SymbolStringPtr &Name,
456 JITEvaluatedSymbol Sym);
458 /// Returns true if all symbols covered by this query have been
459 /// resolved.
460 bool isComplete() const { return OutstandingSymbolsCount == 0; }
462 /// Call the NotifyComplete callback.
464 /// This should only be called if all symbols covered by the query have
465 /// reached the specified state.
466 void handleComplete();
468 private:
469 SymbolState getRequiredState() { return RequiredState; }
471 void addQueryDependence(JITDylib &JD, SymbolStringPtr Name);
473 void removeQueryDependence(JITDylib &JD, const SymbolStringPtr &Name);
475 bool canStillFail();
477 void handleFailed(Error Err);
479 void detach();
481 SymbolsResolvedCallback NotifyComplete;
482 SymbolDependenceMap QueryRegistrations;
483 SymbolMap ResolvedSymbols;
484 size_t OutstandingSymbolsCount;
485 SymbolState RequiredState;
488 /// A symbol table that supports asynchoronous symbol queries.
490 /// Represents a virtual shared object. Instances can not be copied or moved, so
491 /// their addresses may be used as keys for resource management.
492 /// JITDylib state changes must be made via an ExecutionSession to guarantee
493 /// that they are synchronized with respect to other JITDylib operations.
494 class JITDylib {
495 friend class AsynchronousSymbolQuery;
496 friend class ExecutionSession;
497 friend class MaterializationResponsibility;
498 public:
499 class DefinitionGenerator {
500 public:
501 virtual ~DefinitionGenerator();
502 virtual Expected<SymbolNameSet>
503 tryToGenerate(JITDylib &Parent, const SymbolNameSet &Names) = 0;
506 using AsynchronousSymbolQuerySet =
507 std::set<std::shared_ptr<AsynchronousSymbolQuery>>;
509 JITDylib(const JITDylib &) = delete;
510 JITDylib &operator=(const JITDylib &) = delete;
511 JITDylib(JITDylib &&) = delete;
512 JITDylib &operator=(JITDylib &&) = delete;
514 /// Get the name for this JITDylib.
515 const std::string &getName() const { return JITDylibName; }
517 /// Get a reference to the ExecutionSession for this JITDylib.
518 ExecutionSession &getExecutionSession() const { return ES; }
520 /// Adds a definition generator to this JITDylib and returns a referenece to
521 /// it.
523 /// When JITDylibs are searched during lookup, if no existing definition of
524 /// a symbol is found, then any generators that have been added are run (in
525 /// the order that they were added) to potentially generate a definition.
526 template <typename GeneratorT>
527 GeneratorT &addGenerator(std::unique_ptr<GeneratorT> DefGenerator);
529 /// Remove a definition generator from this JITDylib.
531 /// The given generator must exist in this JITDylib's generators list (i.e.
532 /// have been added and not yet removed).
533 void removeGenerator(DefinitionGenerator &G);
535 /// Set the search order to be used when fixing up definitions in JITDylib.
536 /// This will replace the previous search order, and apply to any symbol
537 /// resolutions made for definitions in this JITDylib after the call to
538 /// setSearchOrder (even if the definition itself was added before the
539 /// call).
541 /// If SearchThisJITDylibFirst is set, which by default it is, then this
542 /// JITDylib will add itself to the beginning of the SearchOrder (Clients
543 /// should *not* put this JITDylib in the list in this case, to avoid
544 /// redundant lookups).
546 /// If SearchThisJITDylibFirst is false then the search order will be used as
547 /// given. The main motivation for this feature is to support deliberate
548 /// shadowing of symbols in this JITDylib by a facade JITDylib. For example,
549 /// the facade may resolve function names to stubs, and the stubs may compile
550 /// lazily by looking up symbols in this dylib. Adding the facade dylib
551 /// as the first in the search order (instead of this dylib) ensures that
552 /// definitions within this dylib resolve to the lazy-compiling stubs,
553 /// rather than immediately materializing the definitions in this dylib.
554 void setSearchOrder(JITDylibSearchList NewSearchOrder,
555 bool SearchThisJITDylibFirst = true,
556 bool MatchNonExportedInThisDylib = true);
558 /// Add the given JITDylib to the search order for definitions in this
559 /// JITDylib.
560 void addToSearchOrder(JITDylib &JD, bool MatcNonExported = false);
562 /// Replace OldJD with NewJD in the search order if OldJD is present.
563 /// Otherwise this operation is a no-op.
564 void replaceInSearchOrder(JITDylib &OldJD, JITDylib &NewJD,
565 bool MatchNonExported = false);
567 /// Remove the given JITDylib from the search order for this JITDylib if it is
568 /// present. Otherwise this operation is a no-op.
569 void removeFromSearchOrder(JITDylib &JD);
571 /// Do something with the search order (run under the session lock).
572 template <typename Func>
573 auto withSearchOrderDo(Func &&F)
574 -> decltype(F(std::declval<const JITDylibSearchList &>()));
576 /// Define all symbols provided by the materialization unit to be part of this
577 /// JITDylib.
579 /// This overload always takes ownership of the MaterializationUnit. If any
580 /// errors occur, the MaterializationUnit consumed.
581 template <typename MaterializationUnitType>
582 Error define(std::unique_ptr<MaterializationUnitType> &&MU);
584 /// Define all symbols provided by the materialization unit to be part of this
585 /// JITDylib.
587 /// This overload only takes ownership of the MaterializationUnit no error is
588 /// generated. If an error occurs, ownership remains with the caller. This
589 /// may allow the caller to modify the MaterializationUnit to correct the
590 /// issue, then re-call define.
591 template <typename MaterializationUnitType>
592 Error define(std::unique_ptr<MaterializationUnitType> &MU);
594 /// Tries to remove the given symbols.
596 /// If any symbols are not defined in this JITDylib this method will return
597 /// a SymbolsNotFound error covering the missing symbols.
599 /// If all symbols are found but some symbols are in the process of being
600 /// materialized this method will return a SymbolsCouldNotBeRemoved error.
602 /// On success, all symbols are removed. On failure, the JITDylib state is
603 /// left unmodified (no symbols are removed).
604 Error remove(const SymbolNameSet &Names);
606 /// Search the given JITDylib for the symbols in Symbols. If found, store
607 /// the flags for each symbol in Flags. Returns any unresolved symbols.
608 Expected<SymbolFlagsMap> lookupFlags(const SymbolNameSet &Names);
610 /// Dump current JITDylib state to OS.
611 void dump(raw_ostream &OS);
613 /// FIXME: Remove this when we remove the old ORC layers.
614 /// Search the given JITDylibs in order for the symbols in Symbols. Results
615 /// (once they become available) will be returned via the given Query.
617 /// If any symbol is not found then the unresolved symbols will be returned,
618 /// and the query will not be applied. The Query is not failed and can be
619 /// re-used in a subsequent lookup once the symbols have been added, or
620 /// manually failed.
621 Expected<SymbolNameSet>
622 legacyLookup(std::shared_ptr<AsynchronousSymbolQuery> Q, SymbolNameSet Names);
624 private:
625 using AsynchronousSymbolQueryList =
626 std::vector<std::shared_ptr<AsynchronousSymbolQuery>>;
628 struct UnmaterializedInfo {
629 UnmaterializedInfo(std::unique_ptr<MaterializationUnit> MU)
630 : MU(std::move(MU)) {}
632 std::unique_ptr<MaterializationUnit> MU;
635 using UnmaterializedInfosMap =
636 DenseMap<SymbolStringPtr, std::shared_ptr<UnmaterializedInfo>>;
638 struct MaterializingInfo {
639 SymbolDependenceMap Dependants;
640 SymbolDependenceMap UnemittedDependencies;
642 void addQuery(std::shared_ptr<AsynchronousSymbolQuery> Q);
643 void removeQuery(const AsynchronousSymbolQuery &Q);
644 AsynchronousSymbolQueryList takeQueriesMeeting(SymbolState RequiredState);
645 AsynchronousSymbolQueryList takeAllPendingQueries() {
646 return std::move(PendingQueries);
648 bool hasQueriesPending() const { return !PendingQueries.empty(); }
649 const AsynchronousSymbolQueryList &pendingQueries() const {
650 return PendingQueries;
652 private:
653 AsynchronousSymbolQueryList PendingQueries;
656 using MaterializingInfosMap = DenseMap<SymbolStringPtr, MaterializingInfo>;
658 class SymbolTableEntry {
659 public:
660 SymbolTableEntry() = default;
661 SymbolTableEntry(JITSymbolFlags Flags)
662 : Flags(Flags), State(static_cast<uint8_t>(SymbolState::NeverSearched)),
663 MaterializerAttached(false), PendingRemoval(false) {}
665 JITTargetAddress getAddress() const { return Addr; }
666 JITSymbolFlags getFlags() const { return Flags; }
667 SymbolState getState() const { return static_cast<SymbolState>(State); }
669 bool isInMaterializationPhase() const {
670 return getState() == SymbolState::Materializing ||
671 getState() == SymbolState::Resolved;
674 bool hasMaterializerAttached() const { return MaterializerAttached; }
675 bool isPendingRemoval() const { return PendingRemoval; }
677 void setAddress(JITTargetAddress Addr) { this->Addr = Addr; }
678 void setFlags(JITSymbolFlags Flags) { this->Flags = Flags; }
679 void setState(SymbolState State) {
680 assert(static_cast<uint8_t>(State) < (1 << 6) &&
681 "State does not fit in bitfield");
682 this->State = static_cast<uint8_t>(State);
685 void setMaterializerAttached(bool MaterializerAttached) {
686 this->MaterializerAttached = MaterializerAttached;
689 void setPendingRemoval(bool PendingRemoval) {
690 this->PendingRemoval = PendingRemoval;
693 JITEvaluatedSymbol getSymbol() const {
694 return JITEvaluatedSymbol(Addr, Flags);
697 private:
698 JITTargetAddress Addr = 0;
699 JITSymbolFlags Flags;
700 uint8_t State : 6;
701 uint8_t MaterializerAttached : 1;
702 uint8_t PendingRemoval : 1;
705 using SymbolTable = DenseMap<SymbolStringPtr, SymbolTableEntry>;
707 JITDylib(ExecutionSession &ES, std::string Name);
709 Error defineImpl(MaterializationUnit &MU);
711 Expected<SymbolNameSet> lookupFlagsImpl(SymbolFlagsMap &Flags,
712 const SymbolNameSet &Names);
714 Error lodgeQuery(std::shared_ptr<AsynchronousSymbolQuery> &Q,
715 SymbolNameSet &Unresolved, bool MatchNonExported,
716 MaterializationUnitList &MUs);
718 Error lodgeQueryImpl(std::shared_ptr<AsynchronousSymbolQuery> &Q,
719 SymbolNameSet &Unresolved, bool MatchNonExported,
720 MaterializationUnitList &MUs);
722 bool lookupImpl(std::shared_ptr<AsynchronousSymbolQuery> &Q,
723 std::vector<std::unique_ptr<MaterializationUnit>> &MUs,
724 SymbolNameSet &Unresolved);
726 void detachQueryHelper(AsynchronousSymbolQuery &Q,
727 const SymbolNameSet &QuerySymbols);
729 void transferEmittedNodeDependencies(MaterializingInfo &DependantMI,
730 const SymbolStringPtr &DependantName,
731 MaterializingInfo &EmittedMI);
733 Error defineMaterializing(const SymbolFlagsMap &SymbolFlags);
735 void replace(std::unique_ptr<MaterializationUnit> MU);
737 SymbolNameSet getRequestedSymbols(const SymbolFlagsMap &SymbolFlags) const;
739 void addDependencies(const SymbolStringPtr &Name,
740 const SymbolDependenceMap &Dependants);
742 Error resolve(const SymbolMap &Resolved);
744 Error emit(const SymbolFlagsMap &Emitted);
746 using FailedSymbolsWorklist =
747 std::vector<std::pair<JITDylib *, SymbolStringPtr>>;
748 static void notifyFailed(FailedSymbolsWorklist FailedSymbols);
750 ExecutionSession &ES;
751 std::string JITDylibName;
752 SymbolTable Symbols;
753 UnmaterializedInfosMap UnmaterializedInfos;
754 MaterializingInfosMap MaterializingInfos;
755 std::vector<std::unique_ptr<DefinitionGenerator>> DefGenerators;
756 JITDylibSearchList SearchOrder;
759 /// An ExecutionSession represents a running JIT program.
760 class ExecutionSession {
761 // FIXME: Remove this when we remove the old ORC layers.
762 friend class JITDylib;
764 public:
765 /// For reporting errors.
766 using ErrorReporter = std::function<void(Error)>;
768 /// For dispatching MaterializationUnit::materialize calls.
769 using DispatchMaterializationFunction = std::function<void(
770 JITDylib &JD, std::unique_ptr<MaterializationUnit> MU)>;
772 /// Construct an ExecutionSession.
774 /// SymbolStringPools may be shared between ExecutionSessions.
775 ExecutionSession(std::shared_ptr<SymbolStringPool> SSP = nullptr);
777 /// Add a symbol name to the SymbolStringPool and return a pointer to it.
778 SymbolStringPtr intern(StringRef SymName) { return SSP->intern(SymName); }
780 /// Returns a shared_ptr to the SymbolStringPool for this ExecutionSession.
781 std::shared_ptr<SymbolStringPool> getSymbolStringPool() const { return SSP; }
783 /// Run the given lambda with the session mutex locked.
784 template <typename Func> auto runSessionLocked(Func &&F) -> decltype(F()) {
785 std::lock_guard<std::recursive_mutex> Lock(SessionMutex);
786 return F();
789 /// Get the "main" JITDylib, which is created automatically on construction of
790 /// the ExecutionSession.
791 JITDylib &getMainJITDylib();
793 /// Return a pointer to the "name" JITDylib.
794 /// Ownership of JITDylib remains within Execution Session
795 JITDylib *getJITDylibByName(StringRef Name);
797 /// Add a new JITDylib to this ExecutionSession.
799 /// The JITDylib Name is required to be unique. Clients should verify that
800 /// names are not being re-used (e.g. by calling getJITDylibByName) if names
801 /// are based on user input.
802 JITDylib &createJITDylib(std::string Name,
803 bool AddToMainDylibSearchOrder = true);
805 /// Allocate a module key for a new module to add to the JIT.
806 VModuleKey allocateVModule() {
807 return runSessionLocked([this]() { return ++LastKey; });
810 /// Return a module key to the ExecutionSession so that it can be
811 /// re-used. This should only be done once all resources associated
812 /// with the original key have been released.
813 void releaseVModule(VModuleKey Key) { /* FIXME: Recycle keys */
816 /// Set the error reporter function.
817 ExecutionSession &setErrorReporter(ErrorReporter ReportError) {
818 this->ReportError = std::move(ReportError);
819 return *this;
822 /// Report a error for this execution session.
824 /// Unhandled errors can be sent here to log them.
825 void reportError(Error Err) { ReportError(std::move(Err)); }
827 /// Set the materialization dispatch function.
828 ExecutionSession &setDispatchMaterialization(
829 DispatchMaterializationFunction DispatchMaterialization) {
830 this->DispatchMaterialization = std::move(DispatchMaterialization);
831 return *this;
834 void legacyFailQuery(AsynchronousSymbolQuery &Q, Error Err);
836 using LegacyAsyncLookupFunction = std::function<SymbolNameSet(
837 std::shared_ptr<AsynchronousSymbolQuery> Q, SymbolNameSet Names)>;
839 /// A legacy lookup function for JITSymbolResolverAdapter.
840 /// Do not use -- this will be removed soon.
841 Expected<SymbolMap>
842 legacyLookup(LegacyAsyncLookupFunction AsyncLookup, SymbolNameSet Names,
843 SymbolState RequiredState,
844 RegisterDependenciesFunction RegisterDependencies);
846 /// Search the given JITDylib list for the given symbols.
848 /// SearchOrder lists the JITDylibs to search. For each dylib, the associated
849 /// boolean indicates whether the search should match against non-exported
850 /// (hidden visibility) symbols in that dylib (true means match against
851 /// non-exported symbols, false means do not match).
853 /// The NotifyComplete callback will be called once all requested symbols
854 /// reach the required state.
856 /// If all symbols are found, the RegisterDependencies function will be called
857 /// while the session lock is held. This gives clients a chance to register
858 /// dependencies for on the queried symbols for any symbols they are
859 /// materializing (if a MaterializationResponsibility instance is present,
860 /// this can be implemented by calling
861 /// MaterializationResponsibility::addDependencies). If there are no
862 /// dependenant symbols for this query (e.g. it is being made by a top level
863 /// client to get an address to call) then the value NoDependenciesToRegister
864 /// can be used.
865 void lookup(const JITDylibSearchList &SearchOrder, SymbolNameSet Symbols,
866 SymbolState RequiredState, SymbolsResolvedCallback NotifyComplete,
867 RegisterDependenciesFunction RegisterDependencies);
869 /// Blocking version of lookup above. Returns the resolved symbol map.
870 /// If WaitUntilReady is true (the default), will not return until all
871 /// requested symbols are ready (or an error occurs). If WaitUntilReady is
872 /// false, will return as soon as all requested symbols are resolved,
873 /// or an error occurs. If WaitUntilReady is false and an error occurs
874 /// after resolution, the function will return a success value, but the
875 /// error will be reported via reportErrors.
876 Expected<SymbolMap> lookup(const JITDylibSearchList &SearchOrder,
877 const SymbolNameSet &Symbols,
878 SymbolState RequiredState = SymbolState::Ready,
879 RegisterDependenciesFunction RegisterDependencies =
880 NoDependenciesToRegister);
882 /// Convenience version of blocking lookup.
883 /// Searches each of the JITDylibs in the search order in turn for the given
884 /// symbol.
885 Expected<JITEvaluatedSymbol> lookup(const JITDylibSearchList &SearchOrder,
886 SymbolStringPtr Symbol);
888 /// Convenience version of blocking lookup.
889 /// Searches each of the JITDylibs in the search order in turn for the given
890 /// symbol. The search will not find non-exported symbols.
891 Expected<JITEvaluatedSymbol> lookup(ArrayRef<JITDylib *> SearchOrder,
892 SymbolStringPtr Symbol);
894 /// Convenience version of blocking lookup.
895 /// Searches each of the JITDylibs in the search order in turn for the given
896 /// symbol. The search will not find non-exported symbols.
897 Expected<JITEvaluatedSymbol> lookup(ArrayRef<JITDylib *> SearchOrder,
898 StringRef Symbol);
900 /// Materialize the given unit.
901 void dispatchMaterialization(JITDylib &JD,
902 std::unique_ptr<MaterializationUnit> MU) {
903 LLVM_DEBUG({
904 runSessionLocked([&]() {
905 dbgs() << "Dispatching " << *MU << " for " << JD.getName() << "\n";
908 DispatchMaterialization(JD, std::move(MU));
911 /// Dump the state of all the JITDylibs in this session.
912 void dump(raw_ostream &OS);
914 private:
915 static void logErrorsToStdErr(Error Err) {
916 logAllUnhandledErrors(std::move(Err), errs(), "JIT session error: ");
919 static void
920 materializeOnCurrentThread(JITDylib &JD,
921 std::unique_ptr<MaterializationUnit> MU) {
922 MU->doMaterialize(JD);
925 void runOutstandingMUs();
927 mutable std::recursive_mutex SessionMutex;
928 std::shared_ptr<SymbolStringPool> SSP;
929 VModuleKey LastKey = 0;
930 ErrorReporter ReportError = logErrorsToStdErr;
931 DispatchMaterializationFunction DispatchMaterialization =
932 materializeOnCurrentThread;
934 std::vector<std::unique_ptr<JITDylib>> JDs;
936 // FIXME: Remove this (and runOutstandingMUs) once the linking layer works
937 // with callbacks from asynchronous queries.
938 mutable std::recursive_mutex OutstandingMUsMutex;
939 std::vector<std::pair<JITDylib *, std::unique_ptr<MaterializationUnit>>>
940 OutstandingMUs;
943 template <typename GeneratorT>
944 GeneratorT &JITDylib::addGenerator(std::unique_ptr<GeneratorT> DefGenerator) {
945 auto &G = *DefGenerator;
946 ES.runSessionLocked(
947 [&]() { DefGenerators.push_back(std::move(DefGenerator)); });
948 return G;
951 template <typename Func>
952 auto JITDylib::withSearchOrderDo(Func &&F)
953 -> decltype(F(std::declval<const JITDylibSearchList &>())) {
954 return ES.runSessionLocked([&]() { return F(SearchOrder); });
957 template <typename MaterializationUnitType>
958 Error JITDylib::define(std::unique_ptr<MaterializationUnitType> &&MU) {
959 assert(MU && "Can not define with a null MU");
960 return ES.runSessionLocked([&, this]() -> Error {
961 if (auto Err = defineImpl(*MU))
962 return Err;
964 /// defineImpl succeeded.
965 auto UMI = std::make_shared<UnmaterializedInfo>(std::move(MU));
966 for (auto &KV : UMI->MU->getSymbols())
967 UnmaterializedInfos[KV.first] = UMI;
969 return Error::success();
973 template <typename MaterializationUnitType>
974 Error JITDylib::define(std::unique_ptr<MaterializationUnitType> &MU) {
975 assert(MU && "Can not define with a null MU");
977 return ES.runSessionLocked([&, this]() -> Error {
978 if (auto Err = defineImpl(*MU))
979 return Err;
981 /// defineImpl succeeded.
982 auto UMI = std::make_shared<UnmaterializedInfo>(std::move(MU));
983 for (auto &KV : UMI->MU->getSymbols())
984 UnmaterializedInfos[KV.first] = UMI;
986 return Error::success();
990 /// ReexportsGenerator can be used with JITDylib::setGenerator to automatically
991 /// re-export a subset of the source JITDylib's symbols in the target.
992 class ReexportsGenerator : public JITDylib::DefinitionGenerator {
993 public:
994 using SymbolPredicate = std::function<bool(SymbolStringPtr)>;
996 /// Create a reexports generator. If an Allow predicate is passed, only
997 /// symbols for which the predicate returns true will be reexported. If no
998 /// Allow predicate is passed, all symbols will be exported.
999 ReexportsGenerator(JITDylib &SourceJD, bool MatchNonExported = false,
1000 SymbolPredicate Allow = SymbolPredicate());
1002 Expected<SymbolNameSet> tryToGenerate(JITDylib &JD,
1003 const SymbolNameSet &Names) override;
1005 private:
1006 JITDylib &SourceJD;
1007 bool MatchNonExported = false;
1008 SymbolPredicate Allow;
1011 /// Mangles symbol names then uniques them in the context of an
1012 /// ExecutionSession.
1013 class MangleAndInterner {
1014 public:
1015 MangleAndInterner(ExecutionSession &ES, const DataLayout &DL);
1016 SymbolStringPtr operator()(StringRef Name);
1018 private:
1019 ExecutionSession &ES;
1020 const DataLayout &DL;
1023 } // End namespace orc
1024 } // End namespace llvm
1026 #undef DEBUG_TYPE // "orc"
1028 #endif // LLVM_EXECUTIONENGINE_ORC_CORE_H