| //===------ Core.h -- Core ORC APIs (Layer, JITDylib, etc.) -----*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // Contains core ORC APIs. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_EXECUTIONENGINE_ORC_CORE_H |
| #define LLVM_EXECUTIONENGINE_ORC_CORE_H |
| |
| #include "llvm/ADT/BitmaskEnum.h" |
| #include "llvm/ExecutionEngine/JITSymbol.h" |
| #include "llvm/ExecutionEngine/Orc/SymbolStringPool.h" |
| #include "llvm/IR/Module.h" |
| |
| #include <list> |
| #include <map> |
| #include <memory> |
| #include <set> |
| #include <vector> |
| |
| namespace llvm { |
| namespace orc { |
| |
| // Forward declare some classes. |
| class AsynchronousSymbolQuery; |
| class ExecutionSession; |
| class MaterializationUnit; |
| class MaterializationResponsibility; |
| class VSO; |
| |
| /// VModuleKey provides a unique identifier (allocated and managed by |
| /// ExecutionSessions) for a module added to the JIT. |
| using VModuleKey = uint64_t; |
| |
| /// A set of symbol names (represented by SymbolStringPtrs for |
| // efficiency). |
| using SymbolNameSet = std::set<SymbolStringPtr>; |
| |
| /// Render a SymbolNameSet to an ostream. |
| raw_ostream &operator<<(raw_ostream &OS, const SymbolNameSet &Symbols); |
| |
| /// A map from symbol names (as SymbolStringPtrs) to JITSymbols |
| /// (address/flags pairs). |
| using SymbolMap = std::map<SymbolStringPtr, JITEvaluatedSymbol>; |
| |
| /// Render a SymbolMap to an ostream. |
| raw_ostream &operator<<(raw_ostream &OS, const SymbolMap &Symbols); |
| |
| /// A map from symbol names (as SymbolStringPtrs) to JITSymbolFlags. |
| using SymbolFlagsMap = std::map<SymbolStringPtr, JITSymbolFlags>; |
| |
| /// Render a SymbolMap to an ostream. |
| raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap &Symbols); |
| |
| /// A base class for materialization failures that allows the failing |
| /// symbols to be obtained for logging. |
| using SymbolDependenceMap = std::map<VSO *, SymbolNameSet>; |
| |
| /// Render a SymbolDependendeMap. |
| raw_ostream &operator<<(raw_ostream &OS, const SymbolDependenceMap &Deps); |
| |
| /// A list of VSO pointers. |
| using VSOList = std::vector<VSO *>; |
| |
| /// Render a VSOList. |
| raw_ostream &operator<<(raw_ostream &OS, const VSOList &VSOs); |
| |
| /// Callback to notify client that symbols have been resolved. |
| using SymbolsResolvedCallback = std::function<void(Expected<SymbolMap>)>; |
| |
| /// Callback to notify client that symbols are ready for execution. |
| using SymbolsReadyCallback = std::function<void(Error)>; |
| |
| /// Callback to register the dependencies for a given query. |
| using RegisterDependenciesFunction = |
| std::function<void(const SymbolDependenceMap &)>; |
| |
| /// This can be used as the value for a RegisterDependenciesFunction if there |
| /// are no dependants to register with. |
| extern RegisterDependenciesFunction NoDependenciesToRegister; |
| |
| /// Used to notify a VSO that the given set of symbols failed to materialize. |
| class FailedToMaterialize : public ErrorInfo<FailedToMaterialize> { |
| public: |
| static char ID; |
| |
| FailedToMaterialize(SymbolNameSet Symbols); |
| std::error_code convertToErrorCode() const override; |
| void log(raw_ostream &OS) const override; |
| const SymbolNameSet &getSymbols() const { return Symbols; } |
| |
| private: |
| SymbolNameSet Symbols; |
| }; |
| |
| /// Used to notify clients when symbols can not be found during a lookup. |
| class SymbolsNotFound : public ErrorInfo<SymbolsNotFound> { |
| public: |
| static char ID; |
| |
| SymbolsNotFound(SymbolNameSet Symbols); |
| std::error_code convertToErrorCode() const override; |
| void log(raw_ostream &OS) const override; |
| const SymbolNameSet &getSymbols() const { return Symbols; } |
| |
| private: |
| SymbolNameSet Symbols; |
| }; |
| |
| /// Tracks responsibility for materialization, and mediates interactions between |
| /// MaterializationUnits and VSOs. |
| /// |
| /// An instance of this class is passed to MaterializationUnits when their |
| /// materialize method is called. It allows MaterializationUnits to resolve and |
| /// finalize symbols, or abandon materialization by notifying any unmaterialized |
| /// symbols of an error. |
| class MaterializationResponsibility { |
| friend class MaterializationUnit; |
| public: |
| MaterializationResponsibility(MaterializationResponsibility &&) = default; |
| MaterializationResponsibility & |
| operator=(MaterializationResponsibility &&) = default; |
| |
| /// Destruct a MaterializationResponsibility instance. In debug mode |
| /// this asserts that all symbols being tracked have been either |
| /// finalized or notified of an error. |
| ~MaterializationResponsibility(); |
| |
| /// Returns the target VSO that these symbols are being materialized |
| /// into. |
| VSO &getTargetVSO() const { return V; } |
| |
| /// Returns the symbol flags map for this responsibility instance. |
| SymbolFlagsMap getSymbols() { return SymbolFlags; } |
| |
| /// Returns the names of any symbols covered by this |
| /// MaterializationResponsibility object that have queries pending. This |
| /// information can be used to return responsibility for unrequested symbols |
| /// back to the VSO via the delegate method. |
| SymbolNameSet getRequestedSymbols(); |
| |
| /// Resolves the given symbols. Individual calls to this method may |
| /// resolve a subset of the symbols, but all symbols must have been |
| /// resolved prior to calling finalize. |
| void resolve(const SymbolMap &Symbols); |
| |
| /// Finalizes all symbols tracked by this instance. |
| void finalize(); |
| |
| /// Adds new symbols to the VSO and this responsibility instance. |
| /// VSO entries start out in the materializing state. |
| /// |
| /// This method can be used by materialization units that want to add |
| /// additional symbols at materialization time (e.g. stubs, compile |
| /// callbacks, metadata). |
| Error defineMaterializing(const SymbolFlagsMap &SymbolFlags); |
| |
| /// Notify all unfinalized symbols that an error has occurred. |
| /// This will remove all symbols covered by this MaterializationResponsibilty |
| /// from V, and send an error to any queries waiting on these symbols. |
| void failMaterialization(); |
| |
| /// Transfers responsibility to the given MaterializationUnit for all |
| /// symbols defined by that MaterializationUnit. This allows |
| /// materializers to break up work based on run-time information (e.g. |
| /// by introspecting which symbols have actually been looked up and |
| /// materializing only those). |
| void replace(std::unique_ptr<MaterializationUnit> MU); |
| |
| /// Delegates responsibility for the given symbols to the returned |
| /// materialization responsibility. Useful for breaking up work between |
| /// threads, or different kinds of materialization processes. |
| MaterializationResponsibility delegate(const SymbolNameSet &Symbols); |
| |
| void addDependencies(const SymbolStringPtr &Name, |
| const SymbolDependenceMap &Dependencies); |
| |
| /// Add dependencies that apply to all symbols covered by this instance. |
| void addDependenciesForAll(const SymbolDependenceMap &Dependencies); |
| |
| private: |
| /// Create a MaterializationResponsibility for the given VSO and |
| /// initial symbols. |
| MaterializationResponsibility(VSO &V, SymbolFlagsMap SymbolFlags); |
| |
| VSO &V; |
| SymbolFlagsMap SymbolFlags; |
| }; |
| |
| /// A MaterializationUnit represents a set of symbol definitions that can |
| /// be materialized as a group, or individually discarded (when |
| /// overriding definitions are encountered). |
| /// |
| /// MaterializationUnits are used when providing lazy definitions of symbols to |
| /// VSOs. The VSO will call materialize when the address of a symbol is |
| /// requested via the lookup method. The VSO will call discard if a stronger |
| /// definition is added or already present. |
| class MaterializationUnit { |
| public: |
| MaterializationUnit(SymbolFlagsMap InitalSymbolFlags) |
| : SymbolFlags(std::move(InitalSymbolFlags)) {} |
| |
| virtual ~MaterializationUnit() {} |
| |
| /// Return the set of symbols that this source provides. |
| const SymbolFlagsMap &getSymbols() const { return SymbolFlags; } |
| |
| /// Called by materialization dispatchers (see |
| /// ExecutionSession::DispatchMaterializationFunction) to trigger |
| /// materialization of this MaterializationUnit. |
| void doMaterialize(VSO &V) { |
| materialize(MaterializationResponsibility(V, std::move(SymbolFlags))); |
| } |
| |
| /// Called by VSOs to notify MaterializationUnits that the given symbol has |
| /// been overridden. |
| void doDiscard(const VSO &V, SymbolStringPtr Name) { |
| SymbolFlags.erase(Name); |
| discard(V, std::move(Name)); |
| } |
| |
| protected: |
| SymbolFlagsMap SymbolFlags; |
| |
| private: |
| virtual void anchor(); |
| |
| /// Implementations of this method should materialize all symbols |
| /// in the materialzation unit, except for those that have been |
| /// previously discarded. |
| virtual void materialize(MaterializationResponsibility R) = 0; |
| |
| /// Implementations of this method should discard the given symbol |
| /// from the source (e.g. if the source is an LLVM IR Module and the |
| /// symbol is a function, delete the function body or mark it available |
| /// externally). |
| virtual void discard(const VSO &V, SymbolStringPtr Name) = 0; |
| }; |
| |
| using MaterializationUnitList = |
| std::vector<std::unique_ptr<MaterializationUnit>>; |
| |
| /// A MaterializationUnit implementation for pre-existing absolute symbols. |
| /// |
| /// All symbols will be resolved and marked ready as soon as the unit is |
| /// materialized. |
| class AbsoluteSymbolsMaterializationUnit : public MaterializationUnit { |
| public: |
| AbsoluteSymbolsMaterializationUnit(SymbolMap Symbols); |
| |
| private: |
| void materialize(MaterializationResponsibility R) override; |
| void discard(const VSO &V, SymbolStringPtr Name) override; |
| static SymbolFlagsMap extractFlags(const SymbolMap &Symbols); |
| |
| SymbolMap Symbols; |
| }; |
| |
| /// Create an AbsoluteSymbolsMaterializationUnit with the given symbols. |
| /// Useful for inserting absolute symbols into a VSO. E.g.: |
| /// \code{.cpp} |
| /// VSO &V = ...; |
| /// SymbolStringPtr Foo = ...; |
| /// JITEvaluatedSymbol FooSym = ...; |
| /// if (auto Err = V.define(absoluteSymbols({{Foo, FooSym}}))) |
| /// return Err; |
| /// \endcode |
| /// |
| inline std::unique_ptr<AbsoluteSymbolsMaterializationUnit> |
| absoluteSymbols(SymbolMap Symbols) { |
| return llvm::make_unique<AbsoluteSymbolsMaterializationUnit>( |
| std::move(Symbols)); |
| } |
| |
| struct SymbolAliasMapEntry { |
| SymbolAliasMapEntry() = default; |
| SymbolAliasMapEntry(SymbolStringPtr Aliasee, JITSymbolFlags AliasFlags) |
| : Aliasee(std::move(Aliasee)), AliasFlags(AliasFlags) {} |
| |
| SymbolStringPtr Aliasee; |
| JITSymbolFlags AliasFlags; |
| }; |
| |
| /// A map of Symbols to (Symbol, Flags) pairs. |
| using SymbolAliasMap = std::map<SymbolStringPtr, SymbolAliasMapEntry>; |
| |
| /// A materialization unit for symbol aliases. Allows existing symbols to be |
| /// aliased with alternate flags. |
| class ReExportsMaterializationUnit : public MaterializationUnit { |
| public: |
| /// SourceVSO is allowed to be nullptr, in which case the source VSO is |
| /// taken to be whatever VSO these definitions are materialized in. This |
| /// is useful for defining aliases within a VSO. |
| /// |
| /// Note: Care must be taken that no sets of aliases form a cycle, as such |
| /// a cycle will result in a deadlock when any symbol in the cycle is |
| /// resolved. |
| ReExportsMaterializationUnit(VSO *SourceVSO, SymbolAliasMap Aliases); |
| |
| private: |
| void materialize(MaterializationResponsibility R) override; |
| void discard(const VSO &V, SymbolStringPtr Name) override; |
| static SymbolFlagsMap extractFlags(const SymbolAliasMap &Aliases); |
| |
| VSO *SourceVSO = nullptr; |
| SymbolAliasMap Aliases; |
| }; |
| |
| /// Create a ReExportsMaterializationUnit with the given aliases. |
| /// Useful for defining symbol aliases.: E.g., given a VSO V containing symbols |
| /// "foo" and "bar", we can define aliases "baz" (for "foo") and "qux" (for |
| /// "bar") with: |
| /// \code{.cpp} |
| /// SymbolStringPtr Baz = ...; |
| /// SymbolStringPtr Qux = ...; |
| /// if (auto Err = V.define(symbolAliases({ |
| /// {Baz, { Foo, JITSymbolFlags::Exported }}, |
| /// {Qux, { Bar, JITSymbolFlags::Weak }}})) |
| /// return Err; |
| /// \endcode |
| inline std::unique_ptr<ReExportsMaterializationUnit> |
| symbolAliases(SymbolAliasMap Aliases) { |
| return llvm::make_unique<ReExportsMaterializationUnit>(nullptr, |
| std::move(Aliases)); |
| } |
| |
| /// Create a materialization unit for re-exporting symbols from another VSO |
| /// with alternative names/flags. |
| inline std::unique_ptr<ReExportsMaterializationUnit> |
| reexports(VSO &SourceV, SymbolAliasMap Aliases) { |
| return llvm::make_unique<ReExportsMaterializationUnit>(&SourceV, |
| std::move(Aliases)); |
| } |
| |
| /// Build a SymbolAliasMap for the common case where you want to re-export |
| /// symbols from another VSO with the same linkage/flags. |
| Expected<SymbolAliasMap> |
| buildSimpleReexportsAliasMap(VSO &SourceV, const SymbolNameSet &Symbols); |
| |
| /// Base utilities for ExecutionSession. |
| class ExecutionSessionBase { |
| // FIXME: Remove this when we remove the old ORC layers. |
| friend class VSO; |
| |
| public: |
| /// For reporting errors. |
| using ErrorReporter = std::function<void(Error)>; |
| |
| /// For dispatching MaterializationUnit::materialize calls. |
| using DispatchMaterializationFunction = |
| std::function<void(VSO &V, std::unique_ptr<MaterializationUnit> MU)>; |
| |
| /// Construct an ExecutionSessionBase. |
| /// |
| /// SymbolStringPools may be shared between ExecutionSessions. |
| ExecutionSessionBase(std::shared_ptr<SymbolStringPool> SSP = nullptr) |
| : SSP(SSP ? std::move(SSP) : std::make_shared<SymbolStringPool>()) {} |
| |
| /// Returns the SymbolStringPool for this ExecutionSession. |
| SymbolStringPool &getSymbolStringPool() const { return *SSP; } |
| |
| /// Run the given lambda with the session mutex locked. |
| template <typename Func> auto runSessionLocked(Func &&F) -> decltype(F()) { |
| std::lock_guard<std::recursive_mutex> Lock(SessionMutex); |
| return F(); |
| } |
| |
| /// Set the error reporter function. |
| ExecutionSessionBase &setErrorReporter(ErrorReporter ReportError) { |
| this->ReportError = std::move(ReportError); |
| return *this; |
| } |
| |
| /// Set the materialization dispatch function. |
| ExecutionSessionBase &setDispatchMaterialization( |
| DispatchMaterializationFunction DispatchMaterialization) { |
| this->DispatchMaterialization = std::move(DispatchMaterialization); |
| return *this; |
| } |
| |
| /// Report a error for this execution session. |
| /// |
| /// Unhandled errors can be sent here to log them. |
| void reportError(Error Err) { ReportError(std::move(Err)); } |
| |
| /// Allocate a module key for a new module to add to the JIT. |
| VModuleKey allocateVModule() { return ++LastKey; } |
| |
| /// Return a module key to the ExecutionSession so that it can be |
| /// re-used. This should only be done once all resources associated |
| /// with the original key have been released. |
| void releaseVModule(VModuleKey Key) { /* FIXME: Recycle keys */ |
| } |
| |
| void legacyFailQuery(AsynchronousSymbolQuery &Q, Error Err); |
| |
| using LegacyAsyncLookupFunction = std::function<SymbolNameSet( |
| std::shared_ptr<AsynchronousSymbolQuery> Q, SymbolNameSet Names)>; |
| |
| /// A legacy lookup function for JITSymbolResolverAdapter. |
| /// Do not use -- this will be removed soon. |
| Expected<SymbolMap> |
| legacyLookup(ExecutionSessionBase &ES, LegacyAsyncLookupFunction AsyncLookup, |
| SymbolNameSet Names, bool WaiUntilReady, |
| RegisterDependenciesFunction RegisterDependencies); |
| |
| /// Search the given VSO list for the given symbols. |
| /// |
| /// |
| /// The OnResolve callback will be called once all requested symbols are |
| /// resolved, or if an error occurs prior to resolution. |
| /// |
| /// The OnReady callback will be called once all requested symbols are ready, |
| /// or if an error occurs after resolution but before all symbols are ready. |
| /// |
| /// If all symbols are found, the RegisterDependencies function will be called |
| /// while the session lock is held. This gives clients a chance to register |
| /// dependencies for on the queried symbols for any symbols they are |
| /// materializing (if a MaterializationResponsibility instance is present, |
| /// this can be implemented by calling |
| /// MaterializationResponsibility::addDependencies). If there are no |
| /// dependenant symbols for this query (e.g. it is being made by a top level |
| /// client to get an address to call) then the value NoDependenciesToRegister |
| /// can be used. |
| void lookup(const VSOList &VSOs, const SymbolNameSet &Symbols, |
| SymbolsResolvedCallback OnResolve, SymbolsReadyCallback OnReady, |
| RegisterDependenciesFunction RegisterDependencies); |
| |
| /// Blocking version of lookup above. Returns the resolved symbol map. |
| /// If WaitUntilReady is true (the default), will not return until all |
| /// requested symbols are ready (or an error occurs). If WaitUntilReady is |
| /// false, will return as soon as all requested symbols are resolved, |
| /// or an error occurs. If WaitUntilReady is false and an error occurs |
| /// after resolution, the function will return a success value, but the |
| /// error will be reported via reportErrors. |
| Expected<SymbolMap> lookup(const VSOList &VSOs, const SymbolNameSet &Symbols, |
| RegisterDependenciesFunction RegisterDependencies, |
| bool WaitUntilReady = true); |
| |
| /// Materialize the given unit. |
| void dispatchMaterialization(VSO &V, |
| std::unique_ptr<MaterializationUnit> MU) { |
| DispatchMaterialization(V, std::move(MU)); |
| } |
| |
| private: |
| static void logErrorsToStdErr(Error Err) { |
| logAllUnhandledErrors(std::move(Err), errs(), "JIT session error: "); |
| } |
| |
| static void |
| materializeOnCurrentThread(VSO &V, std::unique_ptr<MaterializationUnit> MU) { |
| MU->doMaterialize(V); |
| } |
| |
| void runOutstandingMUs(); |
| |
| mutable std::recursive_mutex SessionMutex; |
| std::shared_ptr<SymbolStringPool> SSP; |
| VModuleKey LastKey = 0; |
| ErrorReporter ReportError = logErrorsToStdErr; |
| DispatchMaterializationFunction DispatchMaterialization = |
| materializeOnCurrentThread; |
| |
| // FIXME: Remove this (and runOutstandingMUs) once the linking layer works |
| // with callbacks from asynchronous queries. |
| mutable std::recursive_mutex OutstandingMUsMutex; |
| std::vector<std::pair<VSO *, std::unique_ptr<MaterializationUnit>>> |
| OutstandingMUs; |
| }; |
| |
| /// A symbol query that returns results via a callback when results are |
| /// ready. |
| /// |
| /// makes a callback when all symbols are available. |
| class AsynchronousSymbolQuery { |
| friend class ExecutionSessionBase; |
| friend class VSO; |
| |
| public: |
| |
| /// Create a query for the given symbols, notify-resolved and |
| /// notify-ready callbacks. |
| AsynchronousSymbolQuery(const SymbolNameSet &Symbols, |
| SymbolsResolvedCallback NotifySymbolsResolved, |
| SymbolsReadyCallback NotifySymbolsReady); |
| |
| /// Set the resolved symbol information for the given symbol name. |
| void resolve(const SymbolStringPtr &Name, JITEvaluatedSymbol Sym); |
| |
| /// Returns true if all symbols covered by this query have been |
| /// resolved. |
| bool isFullyResolved() const { return NotYetResolvedCount == 0; } |
| |
| /// Call the NotifySymbolsResolved callback. |
| /// |
| /// This should only be called if all symbols covered by the query have been |
| /// resolved. |
| void handleFullyResolved(); |
| |
| /// Notify the query that a requested symbol is ready for execution. |
| void notifySymbolReady(); |
| |
| /// Returns true if all symbols covered by this query are ready. |
| bool isFullyReady() const { return NotYetReadyCount == 0; } |
| |
| /// Calls the NotifySymbolsReady callback. |
| /// |
| /// This should only be called if all symbols covered by this query are ready. |
| void handleFullyReady(); |
| |
| private: |
| void addQueryDependence(VSO &V, SymbolStringPtr Name); |
| |
| void removeQueryDependence(VSO &V, const SymbolStringPtr &Name); |
| |
| bool canStillFail(); |
| |
| void handleFailed(Error Err); |
| |
| void detach(); |
| |
| SymbolsResolvedCallback NotifySymbolsResolved; |
| SymbolsReadyCallback NotifySymbolsReady; |
| SymbolDependenceMap QueryRegistrations; |
| SymbolMap ResolvedSymbols; |
| size_t NotYetResolvedCount; |
| size_t NotYetReadyCount; |
| }; |
| |
| /// A symbol table that supports asynchoronous symbol queries. |
| /// |
| /// Represents a virtual shared object. Instances can not be copied or moved, so |
| /// their addresses may be used as keys for resource management. |
| /// VSO state changes must be made via an ExecutionSession to guarantee that |
| /// they are synchronized with respect to other VSO operations. |
| class VSO { |
| friend class AsynchronousSymbolQuery; |
| friend class ExecutionSession; |
| friend class ExecutionSessionBase; |
| friend class MaterializationResponsibility; |
| public: |
| using FallbackDefinitionGeneratorFunction = |
| std::function<SymbolNameSet(VSO &Parent, const SymbolNameSet &Names)>; |
| |
| using AsynchronousSymbolQuerySet = |
| std::set<std::shared_ptr<AsynchronousSymbolQuery>>; |
| |
| VSO(const VSO &) = delete; |
| VSO &operator=(const VSO &) = delete; |
| VSO(VSO &&) = delete; |
| VSO &operator=(VSO &&) = delete; |
| |
| /// Get the name for this VSO. |
| const std::string &getName() const { return VSOName; } |
| |
| /// Get a reference to the ExecutionSession for this VSO. |
| ExecutionSessionBase &getExecutionSession() const { return ES; } |
| |
| /// Set a fallback defenition generator. If set, lookup and lookupFlags will |
| /// pass the unresolved symbols set to the fallback definition generator, |
| /// allowing it to add a new definition to the VSO. |
| void setFallbackDefinitionGenerator( |
| FallbackDefinitionGeneratorFunction FallbackDefinitionGenerator) { |
| this->FallbackDefinitionGenerator = std::move(FallbackDefinitionGenerator); |
| } |
| |
| /// Set the search order to be used when fixing up definitions in VSO. |
| /// This will replace the previous search order, and apply to any symbol |
| /// resolutions made for definitions in this VSO after the call to |
| /// setSearchOrder (even if the definition itself was added before the |
| /// call). |
| /// |
| /// If SearchThisVSOFirst is set, which by default it is, then this VSO will |
| /// add itself to the beginning of the SearchOrder (Clients should *not* |
| /// put this VSO in the list in this case, to avoid redundant lookups). |
| /// |
| /// If SearchThisVSOFirst is false then the search order will be used as |
| /// given. The main motivation for this feature is to support deliberate |
| /// shadowing of symbols in this VSO by a facade VSO. For example, the |
| /// facade may resolve function names to stubs, and the stubs may compile |
| /// lazily by looking up symbols in this dylib. Adding the facade dylib |
| /// as the first in the search order (instead of this dylib) ensures that |
| /// definitions within this dylib resolve to the lazy-compiling stubs, |
| /// rather than immediately materializing the definitions in this dylib. |
| void setSearchOrder(VSOList NewSearchOrder, bool SearchThisVSOFirst = true); |
| |
| /// Add the given VSO to the search order for definitions in this VSO. |
| void addToSearchOrder(VSO &V); |
| |
| /// Replace OldV with NewV in the search order if OldV is present. Otherwise |
| /// this operation is a no-op. |
| void replaceInSearchOrder(VSO &OldV, VSO &NewV); |
| |
| /// Remove the given VSO from the search order for this VSO if it is |
| /// present. Otherwise this operation is a no-op. |
| void removeFromSearchOrder(VSO &V); |
| |
| /// Do something with the search order (run under the session lock). |
| template <typename Func> |
| auto withSearchOrderDo(Func &&F) |
| -> decltype(F(std::declval<const VSOList &>())) { |
| return ES.runSessionLocked([&]() { return F(SearchOrder); }); |
| } |
| |
| /// Define all symbols provided by the materialization unit to be part |
| /// of the given VSO. |
| template <typename UniquePtrToMaterializationUnit> |
| typename std::enable_if< |
| std::is_convertible< |
| typename std::decay<UniquePtrToMaterializationUnit>::type, |
| std::unique_ptr<MaterializationUnit>>::value, |
| Error>::type |
| define(UniquePtrToMaterializationUnit &&MU) { |
| return ES.runSessionLocked([&, this]() -> Error { |
| assert(MU && "Can't define with a null MU"); |
| |
| if (auto Err = defineImpl(*MU)) |
| return Err; |
| |
| /// defineImpl succeeded. |
| auto UMI = std::make_shared<UnmaterializedInfo>(std::move(MU)); |
| for (auto &KV : UMI->MU->getSymbols()) |
| UnmaterializedInfos[KV.first] = UMI; |
| |
| return Error::success(); |
| }); |
| } |
| |
| /// Search the given VSO for the symbols in Symbols. If found, store |
| /// the flags for each symbol in Flags. Returns any unresolved symbols. |
| SymbolFlagsMap lookupFlags(const SymbolNameSet &Names); |
| |
| /// Dump current VSO state to OS. |
| void dump(raw_ostream &OS); |
| |
| /// FIXME: Remove this when we remove the old ORC layers. |
| /// Search the given VSOs in order for the symbols in Symbols. Results |
| /// (once they become available) will be returned via the given Query. |
| /// |
| /// If any symbol is not found then the unresolved symbols will be returned, |
| /// and the query will not be applied. The Query is not failed and can be |
| /// re-used in a subsequent lookup once the symbols have been added, or |
| /// manually failed. |
| SymbolNameSet legacyLookup(std::shared_ptr<AsynchronousSymbolQuery> Q, |
| SymbolNameSet Names); |
| |
| private: |
| using AsynchronousSymbolQueryList = |
| std::vector<std::shared_ptr<AsynchronousSymbolQuery>>; |
| |
| struct UnmaterializedInfo { |
| UnmaterializedInfo(std::unique_ptr<MaterializationUnit> MU) |
| : MU(std::move(MU)) {} |
| |
| std::unique_ptr<MaterializationUnit> MU; |
| }; |
| |
| using UnmaterializedInfosMap = |
| std::map<SymbolStringPtr, std::shared_ptr<UnmaterializedInfo>>; |
| |
| struct MaterializingInfo { |
| AsynchronousSymbolQueryList PendingQueries; |
| SymbolDependenceMap Dependants; |
| SymbolDependenceMap UnfinalizedDependencies; |
| bool IsFinalized = false; |
| }; |
| |
| using MaterializingInfosMap = std::map<SymbolStringPtr, MaterializingInfo>; |
| |
| using LookupImplActionFlags = enum { |
| None = 0, |
| NotifyFullyResolved = 1 << 0U, |
| NotifyFullyReady = 1 << 1U, |
| LLVM_MARK_AS_BITMASK_ENUM(NotifyFullyReady) |
| }; |
| |
| VSO(ExecutionSessionBase &ES, std::string Name); |
| |
| Error defineImpl(MaterializationUnit &MU); |
| |
| SymbolNameSet lookupFlagsImpl(SymbolFlagsMap &Flags, |
| const SymbolNameSet &Names); |
| |
| void lodgeQuery(std::shared_ptr<AsynchronousSymbolQuery> &Q, |
| SymbolNameSet &Unresolved, MaterializationUnitList &MUs); |
| |
| void lodgeQueryImpl(std::shared_ptr<AsynchronousSymbolQuery> &Q, |
| SymbolNameSet &Unresolved, MaterializationUnitList &MUs); |
| |
| LookupImplActionFlags |
| lookupImpl(std::shared_ptr<AsynchronousSymbolQuery> &Q, |
| std::vector<std::unique_ptr<MaterializationUnit>> &MUs, |
| SymbolNameSet &Unresolved); |
| |
| void detachQueryHelper(AsynchronousSymbolQuery &Q, |
| const SymbolNameSet &QuerySymbols); |
| |
| void transferFinalizedNodeDependencies(MaterializingInfo &DependantMI, |
| const SymbolStringPtr &DependantName, |
| MaterializingInfo &FinalizedMI); |
| |
| Error defineMaterializing(const SymbolFlagsMap &SymbolFlags); |
| |
| void replace(std::unique_ptr<MaterializationUnit> MU); |
| |
| SymbolNameSet getRequestedSymbols(const SymbolFlagsMap &SymbolFlags); |
| |
| void addDependencies(const SymbolStringPtr &Name, |
| const SymbolDependenceMap &Dependants); |
| |
| void resolve(const SymbolMap &Resolved); |
| |
| void finalize(const SymbolFlagsMap &Finalized); |
| |
| void notifyFailed(const SymbolNameSet &FailedSymbols); |
| |
| ExecutionSessionBase &ES; |
| std::string VSOName; |
| SymbolMap Symbols; |
| UnmaterializedInfosMap UnmaterializedInfos; |
| MaterializingInfosMap MaterializingInfos; |
| FallbackDefinitionGeneratorFunction FallbackDefinitionGenerator; |
| VSOList SearchOrder; |
| }; |
| |
| /// An ExecutionSession represents a running JIT program. |
| class ExecutionSession : public ExecutionSessionBase { |
| public: |
| using ErrorReporter = std::function<void(Error)>; |
| |
| using DispatchMaterializationFunction = |
| std::function<void(VSO &V, std::unique_ptr<MaterializationUnit> MU)>; |
| |
| /// Construct an ExecutionEngine. |
| /// |
| /// SymbolStringPools may be shared between ExecutionSessions. |
| ExecutionSession(std::shared_ptr<SymbolStringPool> SSP = nullptr) |
| : ExecutionSessionBase(std::move(SSP)) {} |
| |
| /// Add a new VSO to this ExecutionSession. |
| VSO &createVSO(std::string Name); |
| |
| private: |
| std::vector<std::unique_ptr<VSO>> VSOs; |
| }; |
| |
| /// Look up the given names in the given VSOs. |
| /// VSOs will be searched in order and no VSO pointer may be null. |
| /// All symbols must be found within the given VSOs or an error |
| /// will be returned. |
| Expected<SymbolMap> lookup(const VSOList &VSOs, SymbolNameSet Names); |
| |
| /// Look up a symbol by searching a list of VSOs. |
| Expected<JITEvaluatedSymbol> lookup(const VSOList &VSOs, SymbolStringPtr Name); |
| |
| /// Mangles symbol names then uniques them in the context of an |
| /// ExecutionSession. |
| class MangleAndInterner { |
| public: |
| MangleAndInterner(ExecutionSessionBase &ES, const DataLayout &DL); |
| SymbolStringPtr operator()(StringRef Name); |
| |
| private: |
| ExecutionSessionBase &ES; |
| const DataLayout &DL; |
| }; |
| |
| } // End namespace orc |
| } // End namespace llvm |
| |
| #endif // LLVM_EXECUTIONENGINE_ORC_CORE_H |