[llvm] r342087 - [ORC] Merge ExecutionSessionBase with ExecutionSession by moving a couple of
Lang Hames via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 12 14:49:02 PDT 2018
Author: lhames
Date: Wed Sep 12 14:49:02 2018
New Revision: 342087
URL: http://llvm.org/viewvc/llvm-project?rev=342087&view=rev
Log:
[ORC] Merge ExecutionSessionBase with ExecutionSession by moving a couple of
template methods in JITDylib out-of-line.
This also splits JITDylib::define into a pair of template methods, one taking an
lvalue reference and the other an rvalue reference. This simplifies the
templates at the cost of a small amount of code duplication.
Modified:
llvm/trunk/include/llvm/ExecutionEngine/Orc/Core.h
llvm/trunk/lib/ExecutionEngine/Orc/Core.cpp
llvm/trunk/lib/ExecutionEngine/Orc/Legacy.cpp
Modified: llvm/trunk/include/llvm/ExecutionEngine/Orc/Core.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/Orc/Core.h?rev=342087&r1=342086&r2=342087&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ExecutionEngine/Orc/Core.h (original)
+++ llvm/trunk/include/llvm/ExecutionEngine/Orc/Core.h Wed Sep 12 14:49:02 2018
@@ -366,146 +366,12 @@ private:
SymbolPredicate Allow;
};
-/// Base utilities for ExecutionSession.
-class ExecutionSessionBase {
- // FIXME: Remove this when we remove the old ORC layers.
- friend class JITDylib;
-
-public:
- /// For reporting errors.
- using ErrorReporter = std::function<void(Error)>;
-
- /// For dispatching MaterializationUnit::materialize calls.
- using DispatchMaterializationFunction = std::function<void(
- JITDylib &JD, 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 JITDylib 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 JITDylibList &JDs, 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 JITDylibList &JDs,
- const SymbolNameSet &Symbols,
- RegisterDependenciesFunction RegisterDependencies,
- bool WaitUntilReady = true);
-
- /// Materialize the given unit.
- void dispatchMaterialization(JITDylib &JD,
- std::unique_ptr<MaterializationUnit> MU) {
- DispatchMaterialization(JD, std::move(MU));
- }
-
-private:
- static void logErrorsToStdErr(Error Err) {
- logAllUnhandledErrors(std::move(Err), errs(), "JIT session error: ");
- }
-
- static void
- materializeOnCurrentThread(JITDylib &JD,
- std::unique_ptr<MaterializationUnit> MU) {
- MU->doMaterialize(JD);
- }
-
- 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<JITDylib *, 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 ExecutionSession;
friend class JITDylib;
public:
@@ -568,7 +434,6 @@ private:
class JITDylib {
friend class AsynchronousSymbolQuery;
friend class ExecutionSession;
- friend class ExecutionSessionBase;
friend class MaterializationResponsibility;
public:
using FallbackDefinitionGeneratorFunction = std::function<SymbolNameSet(
@@ -586,7 +451,7 @@ public:
const std::string &getName() const { return JITDylibName; }
/// Get a reference to the ExecutionSession for this JITDylib.
- ExecutionSessionBase &getExecutionSession() const { return ES; }
+ ExecutionSession &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,
@@ -633,33 +498,25 @@ public:
/// Do something with the search order (run under the session lock).
template <typename Func>
auto withSearchOrderDo(Func &&F)
- -> decltype(F(std::declval<const JITDylibList &>())) {
- return ES.runSessionLocked([&]() { return F(SearchOrder); });
- }
+ -> decltype(F(std::declval<const JITDylibList &>()));
- /// Define all symbols provided by the materialization unit to be part
- /// of the given JITDylib.
- 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;
+ /// Define all symbols provided by the materialization unit to be part of this
+ /// JITDylib.
+ ///
+ /// This overload always takes ownership of the MaterializationUnit. If any
+ /// errors occur, the MaterializationUnit consumed.
+ template <typename MaterializationUnitType>
+ Error define(std::unique_ptr<MaterializationUnitType> &&MU);
- return Error::success();
- });
- }
+ /// Define all symbols provided by the materialization unit to be part of this
+ /// JITDylib.
+ ///
+ /// This overload only takes ownership of the MaterializationUnit no error is
+ /// generated. If an error occurs, ownership remains with the caller. This
+ /// may allow the caller to modify the MaterializationUnit to correct the
+ /// issue, then re-call define.
+ template <typename MaterializationUnitType>
+ Error define(std::unique_ptr<MaterializationUnitType> &MU);
/// Search the given JITDylib for the symbols in Symbols. If found, store
/// the flags for each symbol in Flags. Returns any unresolved symbols.
@@ -709,7 +566,7 @@ private:
LLVM_MARK_AS_BITMASK_ENUM(NotifyFullyReady)
};
- JITDylib(ExecutionSessionBase &ES, std::string Name);
+ JITDylib(ExecutionSession &ES, std::string Name);
Error defineImpl(MaterializationUnit &MU);
@@ -749,7 +606,7 @@ private:
void notifyFailed(const SymbolNameSet &FailedSymbols);
- ExecutionSessionBase &ES;
+ ExecutionSession &ES;
std::string JITDylibName;
SymbolMap Symbols;
UnmaterializedInfosMap UnmaterializedInfos;
@@ -759,15 +616,32 @@ private:
};
/// An ExecutionSession represents a running JIT program.
-class ExecutionSession : public ExecutionSessionBase {
+class ExecutionSession {
+ // FIXME: Remove this when we remove the old ORC layers.
+ friend class JITDylib;
+
public:
- using ExecutionSessionBase::lookup;
+ /// For reporting errors.
+ using ErrorReporter = std::function<void(Error)>;
+
+ /// For dispatching MaterializationUnit::materialize calls.
+ using DispatchMaterializationFunction = std::function<void(
+ JITDylib &JD, std::unique_ptr<MaterializationUnit> MU)>;
- /// Construct an ExecutionEngine.
+ /// Construct an ExecutionSession.
///
/// SymbolStringPools may be shared between ExecutionSessions.
ExecutionSession(std::shared_ptr<SymbolStringPool> SSP = nullptr);
+ /// 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();
+ }
+
/// Get the "main" JITDylib, which is created automatically on construction of
/// the ExecutionSession.
JITDylib &getMainJITDylib();
@@ -776,21 +650,163 @@ public:
JITDylib &createJITDylib(std::string Name,
bool AddToMainDylibSearchOrder = true);
- /// Convenience version of the blocking version of lookup in
- /// ExecutionSessionBase. Uses the main JITDylib's search order as the lookup
- /// order, and registers no dependencies.
+ /// 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 */
+ }
+
+ /// Set the error reporter function.
+ ExecutionSession &setErrorReporter(ErrorReporter ReportError) {
+ this->ReportError = std::move(ReportError);
+ 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)); }
+
+ /// Set the materialization dispatch function.
+ ExecutionSession &setDispatchMaterialization(
+ DispatchMaterializationFunction DispatchMaterialization) {
+ this->DispatchMaterialization = std::move(DispatchMaterialization);
+ return *this;
+ }
+
+ 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(LegacyAsyncLookupFunction AsyncLookup, SymbolNameSet Names,
+ bool WaiUntilReady,
+ RegisterDependenciesFunction RegisterDependencies);
+
+ /// Search the given JITDylib 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 JITDylibList &JDs, 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 JITDylibList &JDs,
+ const SymbolNameSet &Symbols,
+ RegisterDependenciesFunction RegisterDependencies,
+ bool WaitUntilReady = true);
+
+ /// Convenience version of the blocking version of lookup above. Uses the main
+ /// JITDylib's search order as the lookup order, and registers no
+ /// dependencies.
Expected<SymbolMap> lookup(const SymbolNameSet &Symbols) {
return getMainJITDylib().withSearchOrderDo(
[&](const JITDylibList &SearchOrder) {
- return ExecutionSessionBase::lookup(SearchOrder, Symbols,
- NoDependenciesToRegister, true);
+ return lookup(SearchOrder, Symbols, NoDependenciesToRegister, true);
});
}
+ /// Materialize the given unit.
+ void dispatchMaterialization(JITDylib &JD,
+ std::unique_ptr<MaterializationUnit> MU) {
+ DispatchMaterialization(JD, std::move(MU));
+ }
+
private:
+ static void logErrorsToStdErr(Error Err) {
+ logAllUnhandledErrors(std::move(Err), errs(), "JIT session error: ");
+ }
+
+ static void
+ materializeOnCurrentThread(JITDylib &JD,
+ std::unique_ptr<MaterializationUnit> MU) {
+ MU->doMaterialize(JD);
+ }
+
+ void runOutstandingMUs();
+
+ mutable std::recursive_mutex SessionMutex;
+ std::shared_ptr<SymbolStringPool> SSP;
+ VModuleKey LastKey = 0;
+ ErrorReporter ReportError = logErrorsToStdErr;
+ DispatchMaterializationFunction DispatchMaterialization =
+ materializeOnCurrentThread;
+
std::vector<std::unique_ptr<JITDylib>> JDs;
+
+ // FIXME: Remove this (and runOutstandingMUs) once the linking layer works
+ // with callbacks from asynchronous queries.
+ mutable std::recursive_mutex OutstandingMUsMutex;
+ std::vector<std::pair<JITDylib *, std::unique_ptr<MaterializationUnit>>>
+ OutstandingMUs;
};
+template <typename Func>
+auto JITDylib::withSearchOrderDo(Func &&F)
+ -> decltype(F(std::declval<const JITDylibList &>())) {
+ return ES.runSessionLocked([&]() { return F(SearchOrder); });
+}
+
+template <typename MaterializationUnitType>
+Error JITDylib::define(std::unique_ptr<MaterializationUnitType> &&MU) {
+ assert(MU && "Can not define with a null MU");
+ return ES.runSessionLocked([&, this]() -> Error {
+ 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();
+ });
+}
+
+template <typename MaterializationUnitType>
+Error JITDylib::define(std::unique_ptr<MaterializationUnitType> &MU) {
+ assert(MU && "Can not define with a null MU");
+
+ return ES.runSessionLocked([&, this]() -> Error {
+ 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();
+ });
+}
+
/// Look up the given names in the given JITDylibs.
/// JDs will be searched in order and no JITDylib pointer may be null.
/// All symbols must be found within the given JITDylibs or an error
@@ -805,11 +821,11 @@ Expected<JITEvaluatedSymbol> lookup(cons
/// ExecutionSession.
class MangleAndInterner {
public:
- MangleAndInterner(ExecutionSessionBase &ES, const DataLayout &DL);
+ MangleAndInterner(ExecutionSession &ES, const DataLayout &DL);
SymbolStringPtr operator()(StringRef Name);
private:
- ExecutionSessionBase &ES;
+ ExecutionSession &ES;
const DataLayout &DL;
};
Modified: llvm/trunk/lib/ExecutionEngine/Orc/Core.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/Orc/Core.cpp?rev=342087&r1=342086&r2=342087&view=diff
==============================================================================
--- llvm/trunk/lib/ExecutionEngine/Orc/Core.cpp (original)
+++ llvm/trunk/lib/ExecutionEngine/Orc/Core.cpp Wed Sep 12 14:49:02 2018
@@ -142,586 +142,253 @@ void SymbolsNotFound::log(raw_ostream &O
OS << "Symbols not found: " << Symbols;
}
-void ExecutionSessionBase::legacyFailQuery(AsynchronousSymbolQuery &Q,
- Error Err) {
- assert(!!Err && "Error should be in failure state");
+AsynchronousSymbolQuery::AsynchronousSymbolQuery(
+ const SymbolNameSet &Symbols, SymbolsResolvedCallback NotifySymbolsResolved,
+ SymbolsReadyCallback NotifySymbolsReady)
+ : NotifySymbolsResolved(std::move(NotifySymbolsResolved)),
+ NotifySymbolsReady(std::move(NotifySymbolsReady)) {
+ NotYetResolvedCount = NotYetReadyCount = Symbols.size();
- bool SendErrorToQuery;
- runSessionLocked([&]() {
- Q.detach();
- SendErrorToQuery = Q.canStillFail();
- });
+ for (auto &S : Symbols)
+ ResolvedSymbols[S] = nullptr;
+}
- if (SendErrorToQuery)
- Q.handleFailed(std::move(Err));
- else
- reportError(std::move(Err));
+void AsynchronousSymbolQuery::resolve(const SymbolStringPtr &Name,
+ JITEvaluatedSymbol Sym) {
+ auto I = ResolvedSymbols.find(Name);
+ assert(I != ResolvedSymbols.end() &&
+ "Resolving symbol outside the requested set");
+ assert(I->second.getAddress() == 0 && "Redundantly resolving symbol Name");
+ I->second = std::move(Sym);
+ --NotYetResolvedCount;
}
-Expected<SymbolMap> ExecutionSessionBase::legacyLookup(
- ExecutionSessionBase &ES, LegacyAsyncLookupFunction AsyncLookup,
- SymbolNameSet Names, bool WaitUntilReady,
- RegisterDependenciesFunction RegisterDependencies) {
-#if LLVM_ENABLE_THREADS
- // In the threaded case we use promises to return the results.
- std::promise<SymbolMap> PromisedResult;
- std::mutex ErrMutex;
- Error ResolutionError = Error::success();
- std::promise<void> PromisedReady;
- Error ReadyError = Error::success();
- auto OnResolve = [&](Expected<SymbolMap> R) {
- if (R)
- PromisedResult.set_value(std::move(*R));
- else {
- {
- ErrorAsOutParameter _(&ResolutionError);
- std::lock_guard<std::mutex> Lock(ErrMutex);
- ResolutionError = R.takeError();
- }
- PromisedResult.set_value(SymbolMap());
- }
- };
+void AsynchronousSymbolQuery::handleFullyResolved() {
+ assert(NotYetResolvedCount == 0 && "Not fully resolved?");
- std::function<void(Error)> OnReady;
- if (WaitUntilReady) {
- OnReady = [&](Error Err) {
- if (Err) {
- ErrorAsOutParameter _(&ReadyError);
- std::lock_guard<std::mutex> Lock(ErrMutex);
- ReadyError = std::move(Err);
- }
- PromisedReady.set_value();
- };
- } else {
- OnReady = [&](Error Err) {
- if (Err)
- ES.reportError(std::move(Err));
- };
+ if (!NotifySymbolsResolved) {
+ // handleFullyResolved may be called by handleFullyReady (see comments in
+ // that method), in which case this is a no-op, so bail out.
+ assert(!NotifySymbolsReady &&
+ "NotifySymbolsResolved already called or an error occurred");
+ return;
}
-#else
- SymbolMap Result;
- Error ResolutionError = Error::success();
- Error ReadyError = Error::success();
+ auto TmpNotifySymbolsResolved = std::move(NotifySymbolsResolved);
+ NotifySymbolsResolved = SymbolsResolvedCallback();
+ TmpNotifySymbolsResolved(std::move(ResolvedSymbols));
+}
- auto OnResolve = [&](Expected<SymbolMap> R) {
- ErrorAsOutParameter _(&ResolutionError);
- if (R)
- Result = std::move(*R);
- else
- ResolutionError = R.takeError();
- };
+void AsynchronousSymbolQuery::notifySymbolReady() {
+ assert(NotYetReadyCount != 0 && "All symbols already emitted");
+ --NotYetReadyCount;
+}
- std::function<void(Error)> OnReady;
- if (WaitUntilReady) {
- OnReady = [&](Error Err) {
- ErrorAsOutParameter _(&ReadyError);
- if (Err)
- ReadyError = std::move(Err);
- };
- } else {
- OnReady = [&](Error Err) {
- if (Err)
- ES.reportError(std::move(Err));
- };
- }
-#endif
+void AsynchronousSymbolQuery::handleFullyReady() {
+ assert(NotifySymbolsReady &&
+ "NotifySymbolsReady already called or an error occurred");
- auto Query = std::make_shared<AsynchronousSymbolQuery>(
- Names, std::move(OnResolve), std::move(OnReady));
- // FIXME: This should be run session locked along with the registration code
- // and error reporting below.
- SymbolNameSet UnresolvedSymbols = AsyncLookup(Query, std::move(Names));
+ auto TmpNotifySymbolsReady = std::move(NotifySymbolsReady);
+ NotifySymbolsReady = SymbolsReadyCallback();
- // If the query was lodged successfully then register the dependencies,
- // otherwise fail it with an error.
- if (UnresolvedSymbols.empty())
- RegisterDependencies(Query->QueryRegistrations);
- else {
- bool DeliverError = runSessionLocked([&]() {
- Query->detach();
- return Query->canStillFail();
- });
- auto Err = make_error<SymbolsNotFound>(std::move(UnresolvedSymbols));
- if (DeliverError)
- Query->handleFailed(std::move(Err));
- else
- ES.reportError(std::move(Err));
+ if (NotYetResolvedCount == 0 && NotifySymbolsResolved) {
+ // The NotifyResolved callback of one query must have caused this query to
+ // become ready (i.e. there is still a handleFullyResolved callback waiting
+ // to be made back up the stack). Fold the handleFullyResolved call into
+ // this one before proceeding. This will cause the call further up the
+ // stack to become a no-op.
+ handleFullyResolved();
}
-#if LLVM_ENABLE_THREADS
- auto ResultFuture = PromisedResult.get_future();
- auto Result = ResultFuture.get();
+ assert(QueryRegistrations.empty() &&
+ "Query is still registered with some symbols");
+ assert(!NotifySymbolsResolved && "Resolution not applied yet");
+ TmpNotifySymbolsReady(Error::success());
+}
- {
- std::lock_guard<std::mutex> Lock(ErrMutex);
- if (ResolutionError) {
- // ReadyError will never be assigned. Consume the success value.
- cantFail(std::move(ReadyError));
- return std::move(ResolutionError);
- }
- }
+bool AsynchronousSymbolQuery::canStillFail() {
+ return (NotifySymbolsResolved || NotifySymbolsReady);
+}
- if (WaitUntilReady) {
- auto ReadyFuture = PromisedReady.get_future();
- ReadyFuture.get();
+void AsynchronousSymbolQuery::handleFailed(Error Err) {
+ assert(QueryRegistrations.empty() && ResolvedSymbols.empty() &&
+ NotYetResolvedCount == 0 && NotYetReadyCount == 0 &&
+ "Query should already have been abandoned");
+ if (NotifySymbolsResolved) {
+ NotifySymbolsResolved(std::move(Err));
+ NotifySymbolsResolved = SymbolsResolvedCallback();
+ } else {
+ assert(NotifySymbolsReady && "Failed after both callbacks issued?");
+ NotifySymbolsReady(std::move(Err));
+ }
+ NotifySymbolsReady = SymbolsReadyCallback();
+}
- {
- std::lock_guard<std::mutex> Lock(ErrMutex);
- if (ReadyError)
- return std::move(ReadyError);
- }
- } else
- cantFail(std::move(ReadyError));
+void AsynchronousSymbolQuery::addQueryDependence(JITDylib &JD,
+ SymbolStringPtr Name) {
+ bool Added = QueryRegistrations[&JD].insert(std::move(Name)).second;
+ (void)Added;
+ assert(Added && "Duplicate dependence notification?");
+}
- return std::move(Result);
+void AsynchronousSymbolQuery::removeQueryDependence(
+ JITDylib &JD, const SymbolStringPtr &Name) {
+ auto QRI = QueryRegistrations.find(&JD);
+ assert(QRI != QueryRegistrations.end() &&
+ "No dependencies registered for JD");
+ assert(QRI->second.count(Name) && "No dependency on Name in JD");
+ QRI->second.erase(Name);
+ if (QRI->second.empty())
+ QueryRegistrations.erase(QRI);
+}
-#else
- if (ResolutionError) {
- // ReadyError will never be assigned. Consume the success value.
- cantFail(std::move(ReadyError));
- return std::move(ResolutionError);
- }
+void AsynchronousSymbolQuery::detach() {
+ ResolvedSymbols.clear();
+ NotYetResolvedCount = 0;
+ NotYetReadyCount = 0;
+ for (auto &KV : QueryRegistrations)
+ KV.first->detachQueryHelper(*this, KV.second);
+ QueryRegistrations.clear();
+}
- if (ReadyError)
- return std::move(ReadyError);
+MaterializationResponsibility::MaterializationResponsibility(
+ JITDylib &JD, SymbolFlagsMap SymbolFlags)
+ : JD(JD), SymbolFlags(std::move(SymbolFlags)) {
+ assert(!this->SymbolFlags.empty() && "Materializing nothing?");
- return Result;
+#ifndef NDEBUG
+ for (auto &KV : this->SymbolFlags)
+ KV.second |= JITSymbolFlags::Materializing;
#endif
}
-void ExecutionSessionBase::lookup(
- const JITDylibList &JDs, const SymbolNameSet &Symbols,
- SymbolsResolvedCallback OnResolve, SymbolsReadyCallback OnReady,
- RegisterDependenciesFunction RegisterDependencies) {
-
- // lookup can be re-entered recursively if running on a single thread. Run any
- // outstanding MUs in case this query depends on them, otherwise the main
- // thread will starve waiting for a result from an MU that it failed to run.
- runOutstandingMUs();
+MaterializationResponsibility::~MaterializationResponsibility() {
+ assert(SymbolFlags.empty() &&
+ "All symbols should have been explicitly materialized or failed");
+}
- auto Unresolved = std::move(Symbols);
- std::map<JITDylib *, MaterializationUnitList> MUsMap;
- auto Q = std::make_shared<AsynchronousSymbolQuery>(
- Symbols, std::move(OnResolve), std::move(OnReady));
- bool QueryIsFullyResolved = false;
- bool QueryIsFullyReady = false;
- bool QueryFailed = false;
+SymbolNameSet MaterializationResponsibility::getRequestedSymbols() {
+ return JD.getRequestedSymbols(SymbolFlags);
+}
- runSessionLocked([&]() {
- for (auto *JD : JDs) {
- assert(JD && "JITDylibList entries must not be null");
- assert(!MUsMap.count(JD) &&
- "JITDylibList should not contain duplicate entries");
- JD->lodgeQuery(Q, Unresolved, MUsMap[JD]);
- }
+void MaterializationResponsibility::resolve(const SymbolMap &Symbols) {
+#ifndef NDEBUG
+ for (auto &KV : Symbols) {
+ auto I = SymbolFlags.find(KV.first);
+ assert(I != SymbolFlags.end() &&
+ "Resolving symbol outside this responsibility set");
+ assert(I->second.isMaterializing() && "Duplicate resolution");
+ I->second &= ~JITSymbolFlags::Materializing;
+ if (I->second.isWeak())
+ assert(I->second == (KV.second.getFlags() | JITSymbolFlags::Weak) &&
+ "Resolving symbol with incorrect flags");
+ else
+ assert(I->second == KV.second.getFlags() &&
+ "Resolving symbol with incorrect flags");
+ }
+#endif
- if (Unresolved.empty()) {
- // Query lodged successfully.
+ JD.resolve(Symbols);
+}
- // Record whether this query is fully ready / resolved. We will use
- // this to call handleFullyResolved/handleFullyReady outside the session
- // lock.
- QueryIsFullyResolved = Q->isFullyResolved();
- QueryIsFullyReady = Q->isFullyReady();
+void MaterializationResponsibility::emit() {
+#ifndef NDEBUG
+ for (auto &KV : SymbolFlags)
+ assert(!KV.second.isMaterializing() &&
+ "Failed to resolve symbol before emission");
+#endif // NDEBUG
- // Call the register dependencies function.
- if (RegisterDependencies && !Q->QueryRegistrations.empty())
- RegisterDependencies(Q->QueryRegistrations);
- } else {
- // Query failed due to unresolved symbols.
- QueryFailed = true;
-
- // Disconnect the query from its dependencies.
- Q->detach();
-
- // Replace the MUs.
- for (auto &KV : MUsMap)
- for (auto &MU : KV.second)
- KV.first->replace(std::move(MU));
- }
- });
-
- if (QueryFailed) {
- Q->handleFailed(make_error<SymbolsNotFound>(std::move(Unresolved)));
- return;
- } else {
- if (QueryIsFullyResolved)
- Q->handleFullyResolved();
- if (QueryIsFullyReady)
- Q->handleFullyReady();
- }
-
- // Move the MUs to the OutstandingMUs list, then materialize.
- {
- std::lock_guard<std::recursive_mutex> Lock(OutstandingMUsMutex);
-
- for (auto &KV : MUsMap)
- for (auto &MU : KV.second)
- OutstandingMUs.push_back(std::make_pair(KV.first, std::move(MU)));
- }
-
- runOutstandingMUs();
+ JD.emit(SymbolFlags);
+ SymbolFlags.clear();
}
-Expected<SymbolMap> ExecutionSessionBase::lookup(
- const JITDylibList &JDs, const SymbolNameSet &Symbols,
- RegisterDependenciesFunction RegisterDependencies, bool WaitUntilReady) {
-#if LLVM_ENABLE_THREADS
- // In the threaded case we use promises to return the results.
- std::promise<SymbolMap> PromisedResult;
- std::mutex ErrMutex;
- Error ResolutionError = Error::success();
- std::promise<void> PromisedReady;
- Error ReadyError = Error::success();
- auto OnResolve = [&](Expected<SymbolMap> R) {
- if (R)
- PromisedResult.set_value(std::move(*R));
- else {
- {
- ErrorAsOutParameter _(&ResolutionError);
- std::lock_guard<std::mutex> Lock(ErrMutex);
- ResolutionError = R.takeError();
- }
- PromisedResult.set_value(SymbolMap());
- }
- };
-
- std::function<void(Error)> OnReady;
- if (WaitUntilReady) {
- OnReady = [&](Error Err) {
- if (Err) {
- ErrorAsOutParameter _(&ReadyError);
- std::lock_guard<std::mutex> Lock(ErrMutex);
- ReadyError = std::move(Err);
- }
- PromisedReady.set_value();
- };
- } else {
- OnReady = [&](Error Err) {
- if (Err)
- reportError(std::move(Err));
- };
- }
-
-#else
- SymbolMap Result;
- Error ResolutionError = Error::success();
- Error ReadyError = Error::success();
-
- auto OnResolve = [&](Expected<SymbolMap> R) {
- ErrorAsOutParameter _(&ResolutionError);
- if (R)
- Result = std::move(*R);
- else
- ResolutionError = R.takeError();
- };
-
- std::function<void(Error)> OnReady;
- if (WaitUntilReady) {
- OnReady = [&](Error Err) {
- ErrorAsOutParameter _(&ReadyError);
- if (Err)
- ReadyError = std::move(Err);
- };
- } else {
- OnReady = [&](Error Err) {
- if (Err)
- reportError(std::move(Err));
- };
- }
+Error MaterializationResponsibility::defineMaterializing(
+ const SymbolFlagsMap &NewSymbolFlags) {
+ // Add the given symbols to this responsibility object.
+ // It's ok if we hit a duplicate here: In that case the new version will be
+ // discarded, and the JITDylib::defineMaterializing method will return a
+ // duplicate symbol error.
+ for (auto &KV : NewSymbolFlags) {
+ auto I = SymbolFlags.insert(KV).first;
+ (void)I;
+#ifndef NDEBUG
+ I->second |= JITSymbolFlags::Materializing;
#endif
-
- // Perform the asynchronous lookup.
- lookup(JDs, Symbols, OnResolve, OnReady, RegisterDependencies);
-
-#if LLVM_ENABLE_THREADS
- auto ResultFuture = PromisedResult.get_future();
- auto Result = ResultFuture.get();
-
- {
- std::lock_guard<std::mutex> Lock(ErrMutex);
- if (ResolutionError) {
- // ReadyError will never be assigned. Consume the success value.
- cantFail(std::move(ReadyError));
- return std::move(ResolutionError);
- }
}
- if (WaitUntilReady) {
- auto ReadyFuture = PromisedReady.get_future();
- ReadyFuture.get();
+ return JD.defineMaterializing(NewSymbolFlags);
+}
- {
- std::lock_guard<std::mutex> Lock(ErrMutex);
- if (ReadyError)
- return std::move(ReadyError);
- }
- } else
- cantFail(std::move(ReadyError));
+void MaterializationResponsibility::failMaterialization() {
- return std::move(Result);
+ SymbolNameSet FailedSymbols;
+ for (auto &KV : SymbolFlags)
+ FailedSymbols.insert(KV.first);
-#else
- if (ResolutionError) {
- // ReadyError will never be assigned. Consume the success value.
- cantFail(std::move(ReadyError));
- return std::move(ResolutionError);
- }
+ JD.notifyFailed(FailedSymbols);
+ SymbolFlags.clear();
+}
- if (ReadyError)
- return std::move(ReadyError);
+void MaterializationResponsibility::replace(
+ std::unique_ptr<MaterializationUnit> MU) {
+ for (auto &KV : MU->getSymbols())
+ SymbolFlags.erase(KV.first);
- return Result;
-#endif
+ JD.replace(std::move(MU));
}
-void ExecutionSessionBase::runOutstandingMUs() {
- while (1) {
- std::pair<JITDylib *, std::unique_ptr<MaterializationUnit>> JITDylibAndMU;
+MaterializationResponsibility
+MaterializationResponsibility::delegate(const SymbolNameSet &Symbols) {
+ SymbolFlagsMap DelegatedFlags;
- {
- std::lock_guard<std::recursive_mutex> Lock(OutstandingMUsMutex);
- if (!OutstandingMUs.empty()) {
- JITDylibAndMU = std::move(OutstandingMUs.back());
- OutstandingMUs.pop_back();
- }
- }
+ for (auto &Name : Symbols) {
+ auto I = SymbolFlags.find(Name);
+ assert(I != SymbolFlags.end() &&
+ "Symbol is not tracked by this MaterializationResponsibility "
+ "instance");
- if (JITDylibAndMU.first) {
- assert(JITDylibAndMU.second && "JITDylib, but no MU?");
- dispatchMaterialization(*JITDylibAndMU.first,
- std::move(JITDylibAndMU.second));
- } else
- break;
+ DelegatedFlags[Name] = std::move(I->second);
+ SymbolFlags.erase(I);
}
-}
-
-AsynchronousSymbolQuery::AsynchronousSymbolQuery(
- const SymbolNameSet &Symbols, SymbolsResolvedCallback NotifySymbolsResolved,
- SymbolsReadyCallback NotifySymbolsReady)
- : NotifySymbolsResolved(std::move(NotifySymbolsResolved)),
- NotifySymbolsReady(std::move(NotifySymbolsReady)) {
- NotYetResolvedCount = NotYetReadyCount = Symbols.size();
- for (auto &S : Symbols)
- ResolvedSymbols[S] = nullptr;
+ return MaterializationResponsibility(JD, std::move(DelegatedFlags));
}
-void AsynchronousSymbolQuery::resolve(const SymbolStringPtr &Name,
- JITEvaluatedSymbol Sym) {
- auto I = ResolvedSymbols.find(Name);
- assert(I != ResolvedSymbols.end() &&
- "Resolving symbol outside the requested set");
- assert(I->second.getAddress() == 0 && "Redundantly resolving symbol Name");
- I->second = std::move(Sym);
- --NotYetResolvedCount;
+void MaterializationResponsibility::addDependencies(
+ const SymbolStringPtr &Name, const SymbolDependenceMap &Dependencies) {
+ assert(SymbolFlags.count(Name) &&
+ "Symbol not covered by this MaterializationResponsibility instance");
+ JD.addDependencies(Name, Dependencies);
}
-void AsynchronousSymbolQuery::handleFullyResolved() {
- assert(NotYetResolvedCount == 0 && "Not fully resolved?");
- assert(NotifySymbolsResolved &&
- "NotifySymbolsResolved already called or error occurred");
- NotifySymbolsResolved(std::move(ResolvedSymbols));
- NotifySymbolsResolved = SymbolsResolvedCallback();
+void MaterializationResponsibility::addDependenciesForAll(
+ const SymbolDependenceMap &Dependencies) {
+ for (auto &KV : SymbolFlags)
+ JD.addDependencies(KV.first, Dependencies);
}
-void AsynchronousSymbolQuery::notifySymbolReady() {
- assert(NotYetReadyCount != 0 && "All symbols already emitted");
- --NotYetReadyCount;
+AbsoluteSymbolsMaterializationUnit::AbsoluteSymbolsMaterializationUnit(
+ SymbolMap Symbols)
+ : MaterializationUnit(extractFlags(Symbols)), Symbols(std::move(Symbols)) {}
+
+void AbsoluteSymbolsMaterializationUnit::materialize(
+ MaterializationResponsibility R) {
+ R.resolve(Symbols);
+ R.emit();
}
-void AsynchronousSymbolQuery::handleFullyReady() {
- assert(QueryRegistrations.empty() &&
- "Query is still registered with some symbols");
- assert(!NotifySymbolsResolved && "Resolution not applied yet");
- NotifySymbolsReady(Error::success());
- NotifySymbolsReady = SymbolsReadyCallback();
+void AbsoluteSymbolsMaterializationUnit::discard(const JITDylib &JD,
+ SymbolStringPtr Name) {
+ assert(Symbols.count(Name) && "Symbol is not part of this MU");
+ Symbols.erase(Name);
}
-bool AsynchronousSymbolQuery::canStillFail() {
- return (NotifySymbolsResolved || NotifySymbolsReady);
-}
-
-void AsynchronousSymbolQuery::handleFailed(Error Err) {
- assert(QueryRegistrations.empty() && ResolvedSymbols.empty() &&
- NotYetResolvedCount == 0 && NotYetReadyCount == 0 &&
- "Query should already have been abandoned");
- if (NotifySymbolsResolved) {
- NotifySymbolsResolved(std::move(Err));
- NotifySymbolsResolved = SymbolsResolvedCallback();
- } else {
- assert(NotifySymbolsReady && "Failed after both callbacks issued?");
- NotifySymbolsReady(std::move(Err));
- }
- NotifySymbolsReady = SymbolsReadyCallback();
-}
-
-void AsynchronousSymbolQuery::addQueryDependence(JITDylib &JD,
- SymbolStringPtr Name) {
- bool Added = QueryRegistrations[&JD].insert(std::move(Name)).second;
- (void)Added;
- assert(Added && "Duplicate dependence notification?");
-}
-
-void AsynchronousSymbolQuery::removeQueryDependence(
- JITDylib &JD, const SymbolStringPtr &Name) {
- auto QRI = QueryRegistrations.find(&JD);
- assert(QRI != QueryRegistrations.end() &&
- "No dependencies registered for JD");
- assert(QRI->second.count(Name) && "No dependency on Name in JD");
- QRI->second.erase(Name);
- if (QRI->second.empty())
- QueryRegistrations.erase(QRI);
-}
-
-void AsynchronousSymbolQuery::detach() {
- ResolvedSymbols.clear();
- NotYetResolvedCount = 0;
- NotYetReadyCount = 0;
- for (auto &KV : QueryRegistrations)
- KV.first->detachQueryHelper(*this, KV.second);
- QueryRegistrations.clear();
-}
-
-MaterializationResponsibility::MaterializationResponsibility(
- JITDylib &JD, SymbolFlagsMap SymbolFlags)
- : JD(JD), SymbolFlags(std::move(SymbolFlags)) {
- assert(!this->SymbolFlags.empty() && "Materializing nothing?");
-
-#ifndef NDEBUG
- for (auto &KV : this->SymbolFlags)
- KV.second |= JITSymbolFlags::Materializing;
-#endif
-}
-
-MaterializationResponsibility::~MaterializationResponsibility() {
- assert(SymbolFlags.empty() &&
- "All symbols should have been explicitly materialized or failed");
-}
-
-SymbolNameSet MaterializationResponsibility::getRequestedSymbols() {
- return JD.getRequestedSymbols(SymbolFlags);
-}
-
-void MaterializationResponsibility::resolve(const SymbolMap &Symbols) {
-#ifndef NDEBUG
- for (auto &KV : Symbols) {
- auto I = SymbolFlags.find(KV.first);
- assert(I != SymbolFlags.end() &&
- "Resolving symbol outside this responsibility set");
- assert(I->second.isMaterializing() && "Duplicate resolution");
- I->second &= ~JITSymbolFlags::Materializing;
- if (I->second.isWeak())
- assert(I->second == (KV.second.getFlags() | JITSymbolFlags::Weak) &&
- "Resolving symbol with incorrect flags");
- else
- assert(I->second == KV.second.getFlags() &&
- "Resolving symbol with incorrect flags");
- }
-#endif
-
- JD.resolve(Symbols);
-}
-
-void MaterializationResponsibility::emit() {
-#ifndef NDEBUG
- for (auto &KV : SymbolFlags)
- assert(!KV.second.isMaterializing() &&
- "Failed to resolve symbol before emission");
-#endif // NDEBUG
-
- JD.emit(SymbolFlags);
- SymbolFlags.clear();
-}
-
-Error MaterializationResponsibility::defineMaterializing(
- const SymbolFlagsMap &NewSymbolFlags) {
- // Add the given symbols to this responsibility object.
- // It's ok if we hit a duplicate here: In that case the new version will be
- // discarded, and the JITDylib::defineMaterializing method will return a
- // duplicate symbol error.
- for (auto &KV : NewSymbolFlags) {
- auto I = SymbolFlags.insert(KV).first;
- (void)I;
-#ifndef NDEBUG
- I->second |= JITSymbolFlags::Materializing;
-#endif
- }
-
- return JD.defineMaterializing(NewSymbolFlags);
-}
-
-void MaterializationResponsibility::failMaterialization() {
-
- SymbolNameSet FailedSymbols;
- for (auto &KV : SymbolFlags)
- FailedSymbols.insert(KV.first);
-
- JD.notifyFailed(FailedSymbols);
- SymbolFlags.clear();
-}
-
-void MaterializationResponsibility::replace(
- std::unique_ptr<MaterializationUnit> MU) {
- for (auto &KV : MU->getSymbols())
- SymbolFlags.erase(KV.first);
-
- JD.replace(std::move(MU));
-}
-
-MaterializationResponsibility
-MaterializationResponsibility::delegate(const SymbolNameSet &Symbols) {
- SymbolFlagsMap DelegatedFlags;
-
- for (auto &Name : Symbols) {
- auto I = SymbolFlags.find(Name);
- assert(I != SymbolFlags.end() &&
- "Symbol is not tracked by this MaterializationResponsibility "
- "instance");
-
- DelegatedFlags[Name] = std::move(I->second);
- SymbolFlags.erase(I);
- }
-
- return MaterializationResponsibility(JD, std::move(DelegatedFlags));
-}
-
-void MaterializationResponsibility::addDependencies(
- const SymbolStringPtr &Name, const SymbolDependenceMap &Dependencies) {
- assert(SymbolFlags.count(Name) &&
- "Symbol not covered by this MaterializationResponsibility instance");
- JD.addDependencies(Name, Dependencies);
-}
-
-void MaterializationResponsibility::addDependenciesForAll(
- const SymbolDependenceMap &Dependencies) {
- for (auto &KV : SymbolFlags)
- JD.addDependencies(KV.first, Dependencies);
-}
-
-AbsoluteSymbolsMaterializationUnit::AbsoluteSymbolsMaterializationUnit(
- SymbolMap Symbols)
- : MaterializationUnit(extractFlags(Symbols)), Symbols(std::move(Symbols)) {}
-
-void AbsoluteSymbolsMaterializationUnit::materialize(
- MaterializationResponsibility R) {
- R.resolve(Symbols);
- R.emit();
-}
-
-void AbsoluteSymbolsMaterializationUnit::discard(const JITDylib &JD,
- SymbolStringPtr Name) {
- assert(Symbols.count(Name) && "Symbol is not part of this MU");
- Symbols.erase(Name);
-}
-
-SymbolFlagsMap
-AbsoluteSymbolsMaterializationUnit::extractFlags(const SymbolMap &Symbols) {
- SymbolFlagsMap Flags;
- for (const auto &KV : Symbols)
- Flags[KV.first] = KV.second.getFlags();
- return Flags;
+SymbolFlagsMap
+AbsoluteSymbolsMaterializationUnit::extractFlags(const SymbolMap &Symbols) {
+ SymbolFlagsMap Flags;
+ for (const auto &KV : Symbols)
+ Flags[KV.first] = KV.second.getFlags();
+ return Flags;
}
ReExportsMaterializationUnit::ReExportsMaterializationUnit(
@@ -1549,7 +1216,7 @@ void JITDylib::dump(raw_ostream &OS) {
});
}
-JITDylib::JITDylib(ExecutionSessionBase &ES, std::string Name)
+JITDylib::JITDylib(ExecutionSession &ES, std::string Name)
: ES(ES), JITDylibName(std::move(Name)) {
SearchOrder.push_back(this);
}
@@ -1564,138 +1231,492 @@ Error JITDylib::defineImpl(Materializati
};
std::vector<ExistingDefOverriddenEntry> ExistingDefsOverridden;
- for (auto &KV : MU.getSymbols()) {
- assert(!KV.second.isLazy() && "Lazy flag should be managed internally.");
- assert(!KV.second.isMaterializing() &&
- "Materializing flags should be managed internally.");
+ for (auto &KV : MU.getSymbols()) {
+ assert(!KV.second.isLazy() && "Lazy flag should be managed internally.");
+ assert(!KV.second.isMaterializing() &&
+ "Materializing flags should be managed internally.");
+
+ SymbolMap::iterator EntryItr;
+ bool Added;
+
+ auto NewFlags = KV.second;
+ NewFlags |= JITSymbolFlags::Lazy;
+
+ std::tie(EntryItr, Added) = Symbols.insert(
+ std::make_pair(KV.first, JITEvaluatedSymbol(0, NewFlags)));
+
+ if (!Added) {
+ if (KV.second.isStrong()) {
+ if (EntryItr->second.getFlags().isStrong() ||
+ (EntryItr->second.getFlags() & JITSymbolFlags::Materializing))
+ Duplicates.insert(KV.first);
+ else
+ ExistingDefsOverridden.push_back({EntryItr, NewFlags});
+ } else
+ MUDefsOverridden.insert(KV.first);
+ }
+ }
+
+ if (!Duplicates.empty()) {
+ // We need to remove the symbols we added.
+ for (auto &KV : MU.getSymbols()) {
+ if (Duplicates.count(KV.first))
+ continue;
+
+ bool Found = false;
+ for (const auto &EDO : ExistingDefsOverridden)
+ if (EDO.ExistingDefItr->first == KV.first)
+ Found = true;
+
+ if (!Found)
+ Symbols.erase(KV.first);
+ }
+
+ // FIXME: Return all duplicates.
+ return make_error<DuplicateDefinition>(**Duplicates.begin());
+ }
+
+ // Update flags on existing defs and call discard on their materializers.
+ for (auto &EDO : ExistingDefsOverridden) {
+ assert(EDO.ExistingDefItr->second.getFlags().isLazy() &&
+ !EDO.ExistingDefItr->second.getFlags().isMaterializing() &&
+ "Overridden existing def should be in the Lazy state");
+
+ EDO.ExistingDefItr->second.setFlags(EDO.NewFlags);
+
+ auto UMII = UnmaterializedInfos.find(EDO.ExistingDefItr->first);
+ assert(UMII != UnmaterializedInfos.end() &&
+ "Overridden existing def should have an UnmaterializedInfo");
+
+ UMII->second->MU->doDiscard(*this, EDO.ExistingDefItr->first);
+ }
+
+ // Discard overridden symbols povided by MU.
+ for (auto &Sym : MUDefsOverridden)
+ MU.doDiscard(*this, Sym);
+
+ return Error::success();
+}
+
+void JITDylib::detachQueryHelper(AsynchronousSymbolQuery &Q,
+ const SymbolNameSet &QuerySymbols) {
+ for (auto &QuerySymbol : QuerySymbols) {
+ assert(MaterializingInfos.count(QuerySymbol) &&
+ "QuerySymbol does not have MaterializingInfo");
+ auto &MI = MaterializingInfos[QuerySymbol];
+
+ auto IdenticalQuery =
+ [&](const std::shared_ptr<AsynchronousSymbolQuery> &R) {
+ return R.get() == &Q;
+ };
+
+ auto I = std::find_if(MI.PendingQueries.begin(), MI.PendingQueries.end(),
+ IdenticalQuery);
+ assert(I != MI.PendingQueries.end() &&
+ "Query Q should be in the PendingQueries list for QuerySymbol");
+ MI.PendingQueries.erase(I);
+ }
+}
+
+void JITDylib::transferEmittedNodeDependencies(
+ MaterializingInfo &DependantMI, const SymbolStringPtr &DependantName,
+ MaterializingInfo &EmittedMI) {
+ for (auto &KV : EmittedMI.UnemittedDependencies) {
+ auto &DependencyJD = *KV.first;
+ SymbolNameSet *UnemittedDependenciesOnDependencyJD = nullptr;
+
+ for (auto &DependencyName : KV.second) {
+ auto &DependencyMI = DependencyJD.MaterializingInfos[DependencyName];
+
+ // Do not add self dependencies.
+ if (&DependencyMI == &DependantMI)
+ continue;
+
+ // If we haven't looked up the dependencies for DependencyJD yet, do it
+ // now and cache the result.
+ if (!UnemittedDependenciesOnDependencyJD)
+ UnemittedDependenciesOnDependencyJD =
+ &DependantMI.UnemittedDependencies[&DependencyJD];
+
+ DependencyMI.Dependants[this].insert(DependantName);
+ UnemittedDependenciesOnDependencyJD->insert(DependencyName);
+ }
+ }
+}
+
+ExecutionSession::ExecutionSession(std::shared_ptr<SymbolStringPool> SSP)
+ : SSP(SSP ? std::move(SSP) : std::make_shared<SymbolStringPool>()) {
+ // Construct the main dylib.
+ JDs.push_back(std::unique_ptr<JITDylib>(new JITDylib(*this, "<main>")));
+}
+
+JITDylib &ExecutionSession::getMainJITDylib() {
+ return runSessionLocked([this]() -> JITDylib & { return *JDs.front(); });
+}
+
+JITDylib &ExecutionSession::createJITDylib(std::string Name,
+ bool AddToMainDylibSearchOrder) {
+ return runSessionLocked([&, this]() -> JITDylib & {
+ JDs.push_back(
+ std::unique_ptr<JITDylib>(new JITDylib(*this, std::move(Name))));
+ if (AddToMainDylibSearchOrder)
+ JDs.front()->addToSearchOrder(*JDs.back());
+ return *JDs.back();
+ });
+}
+
+void ExecutionSession::legacyFailQuery(AsynchronousSymbolQuery &Q, Error Err) {
+ assert(!!Err && "Error should be in failure state");
+
+ bool SendErrorToQuery;
+ runSessionLocked([&]() {
+ Q.detach();
+ SendErrorToQuery = Q.canStillFail();
+ });
+
+ if (SendErrorToQuery)
+ Q.handleFailed(std::move(Err));
+ else
+ reportError(std::move(Err));
+}
+
+Expected<SymbolMap> ExecutionSession::legacyLookup(
+ LegacyAsyncLookupFunction AsyncLookup, SymbolNameSet Names,
+ bool WaitUntilReady, RegisterDependenciesFunction RegisterDependencies) {
+#if LLVM_ENABLE_THREADS
+ // In the threaded case we use promises to return the results.
+ std::promise<SymbolMap> PromisedResult;
+ std::mutex ErrMutex;
+ Error ResolutionError = Error::success();
+ std::promise<void> PromisedReady;
+ Error ReadyError = Error::success();
+ auto OnResolve = [&](Expected<SymbolMap> R) {
+ if (R)
+ PromisedResult.set_value(std::move(*R));
+ else {
+ {
+ ErrorAsOutParameter _(&ResolutionError);
+ std::lock_guard<std::mutex> Lock(ErrMutex);
+ ResolutionError = R.takeError();
+ }
+ PromisedResult.set_value(SymbolMap());
+ }
+ };
+
+ std::function<void(Error)> OnReady;
+ if (WaitUntilReady) {
+ OnReady = [&](Error Err) {
+ if (Err) {
+ ErrorAsOutParameter _(&ReadyError);
+ std::lock_guard<std::mutex> Lock(ErrMutex);
+ ReadyError = std::move(Err);
+ }
+ PromisedReady.set_value();
+ };
+ } else {
+ OnReady = [&](Error Err) {
+ if (Err)
+ reportError(std::move(Err));
+ };
+ }
+
+#else
+ SymbolMap Result;
+ Error ResolutionError = Error::success();
+ Error ReadyError = Error::success();
+
+ auto OnResolve = [&](Expected<SymbolMap> R) {
+ ErrorAsOutParameter _(&ResolutionError);
+ if (R)
+ Result = std::move(*R);
+ else
+ ResolutionError = R.takeError();
+ };
+
+ std::function<void(Error)> OnReady;
+ if (WaitUntilReady) {
+ OnReady = [&](Error Err) {
+ ErrorAsOutParameter _(&ReadyError);
+ if (Err)
+ ReadyError = std::move(Err);
+ };
+ } else {
+ OnReady = [&](Error Err) {
+ if (Err)
+ reportError(std::move(Err));
+ };
+ }
+#endif
+
+ auto Query = std::make_shared<AsynchronousSymbolQuery>(
+ Names, std::move(OnResolve), std::move(OnReady));
+ // FIXME: This should be run session locked along with the registration code
+ // and error reporting below.
+ SymbolNameSet UnresolvedSymbols = AsyncLookup(Query, std::move(Names));
+
+ // If the query was lodged successfully then register the dependencies,
+ // otherwise fail it with an error.
+ if (UnresolvedSymbols.empty())
+ RegisterDependencies(Query->QueryRegistrations);
+ else {
+ bool DeliverError = runSessionLocked([&]() {
+ Query->detach();
+ return Query->canStillFail();
+ });
+ auto Err = make_error<SymbolsNotFound>(std::move(UnresolvedSymbols));
+ if (DeliverError)
+ Query->handleFailed(std::move(Err));
+ else
+ reportError(std::move(Err));
+ }
+
+#if LLVM_ENABLE_THREADS
+ auto ResultFuture = PromisedResult.get_future();
+ auto Result = ResultFuture.get();
+
+ {
+ std::lock_guard<std::mutex> Lock(ErrMutex);
+ if (ResolutionError) {
+ // ReadyError will never be assigned. Consume the success value.
+ cantFail(std::move(ReadyError));
+ return std::move(ResolutionError);
+ }
+ }
+
+ if (WaitUntilReady) {
+ auto ReadyFuture = PromisedReady.get_future();
+ ReadyFuture.get();
+
+ {
+ std::lock_guard<std::mutex> Lock(ErrMutex);
+ if (ReadyError)
+ return std::move(ReadyError);
+ }
+ } else
+ cantFail(std::move(ReadyError));
+
+ return std::move(Result);
+
+#else
+ if (ResolutionError) {
+ // ReadyError will never be assigned. Consume the success value.
+ cantFail(std::move(ReadyError));
+ return std::move(ResolutionError);
+ }
+
+ if (ReadyError)
+ return std::move(ReadyError);
+
+ return Result;
+#endif
+}
+
+void ExecutionSession::lookup(
+ const JITDylibList &JDs, const SymbolNameSet &Symbols,
+ SymbolsResolvedCallback OnResolve, SymbolsReadyCallback OnReady,
+ RegisterDependenciesFunction RegisterDependencies) {
+
+ // lookup can be re-entered recursively if running on a single thread. Run any
+ // outstanding MUs in case this query depends on them, otherwise the main
+ // thread will starve waiting for a result from an MU that it failed to run.
+ runOutstandingMUs();
+
+ auto Unresolved = std::move(Symbols);
+ std::map<JITDylib *, MaterializationUnitList> MUsMap;
+ auto Q = std::make_shared<AsynchronousSymbolQuery>(
+ Symbols, std::move(OnResolve), std::move(OnReady));
+ bool QueryIsFullyResolved = false;
+ bool QueryIsFullyReady = false;
+ bool QueryFailed = false;
+
+ runSessionLocked([&]() {
+ for (auto *JD : JDs) {
+ assert(JD && "JITDylibList entries must not be null");
+ assert(!MUsMap.count(JD) &&
+ "JITDylibList should not contain duplicate entries");
+ JD->lodgeQuery(Q, Unresolved, MUsMap[JD]);
+ }
- SymbolMap::iterator EntryItr;
- bool Added;
+ if (Unresolved.empty()) {
+ // Query lodged successfully.
- auto NewFlags = KV.second;
- NewFlags |= JITSymbolFlags::Lazy;
+ // Record whether this query is fully ready / resolved. We will use
+ // this to call handleFullyResolved/handleFullyReady outside the session
+ // lock.
+ QueryIsFullyResolved = Q->isFullyResolved();
+ QueryIsFullyReady = Q->isFullyReady();
- std::tie(EntryItr, Added) = Symbols.insert(
- std::make_pair(KV.first, JITEvaluatedSymbol(0, NewFlags)));
+ // Call the register dependencies function.
+ if (RegisterDependencies && !Q->QueryRegistrations.empty())
+ RegisterDependencies(Q->QueryRegistrations);
+ } else {
+ // Query failed due to unresolved symbols.
+ QueryFailed = true;
- if (!Added) {
- if (KV.second.isStrong()) {
- if (EntryItr->second.getFlags().isStrong() ||
- (EntryItr->second.getFlags() & JITSymbolFlags::Materializing))
- Duplicates.insert(KV.first);
- else
- ExistingDefsOverridden.push_back({EntryItr, NewFlags});
- } else
- MUDefsOverridden.insert(KV.first);
+ // Disconnect the query from its dependencies.
+ Q->detach();
+
+ // Replace the MUs.
+ for (auto &KV : MUsMap)
+ for (auto &MU : KV.second)
+ KV.first->replace(std::move(MU));
}
+ });
+
+ if (QueryFailed) {
+ Q->handleFailed(make_error<SymbolsNotFound>(std::move(Unresolved)));
+ return;
+ } else {
+ if (QueryIsFullyResolved)
+ Q->handleFullyResolved();
+ if (QueryIsFullyReady)
+ Q->handleFullyReady();
}
- if (!Duplicates.empty()) {
- // We need to remove the symbols we added.
- for (auto &KV : MU.getSymbols()) {
- if (Duplicates.count(KV.first))
- continue;
+ // Move the MUs to the OutstandingMUs list, then materialize.
+ {
+ std::lock_guard<std::recursive_mutex> Lock(OutstandingMUsMutex);
- bool Found = false;
- for (const auto &EDO : ExistingDefsOverridden)
- if (EDO.ExistingDefItr->first == KV.first)
- Found = true;
+ for (auto &KV : MUsMap)
+ for (auto &MU : KV.second)
+ OutstandingMUs.push_back(std::make_pair(KV.first, std::move(MU)));
+ }
- if (!Found)
- Symbols.erase(KV.first);
+ runOutstandingMUs();
+}
+
+Expected<SymbolMap>
+ExecutionSession::lookup(const JITDylibList &JDs, const SymbolNameSet &Symbols,
+ RegisterDependenciesFunction RegisterDependencies,
+ bool WaitUntilReady) {
+#if LLVM_ENABLE_THREADS
+ // In the threaded case we use promises to return the results.
+ std::promise<SymbolMap> PromisedResult;
+ std::mutex ErrMutex;
+ Error ResolutionError = Error::success();
+ std::promise<void> PromisedReady;
+ Error ReadyError = Error::success();
+ auto OnResolve = [&](Expected<SymbolMap> R) {
+ if (R)
+ PromisedResult.set_value(std::move(*R));
+ else {
+ {
+ ErrorAsOutParameter _(&ResolutionError);
+ std::lock_guard<std::mutex> Lock(ErrMutex);
+ ResolutionError = R.takeError();
+ }
+ PromisedResult.set_value(SymbolMap());
}
+ };
- // FIXME: Return all duplicates.
- return make_error<DuplicateDefinition>(**Duplicates.begin());
+ std::function<void(Error)> OnReady;
+ if (WaitUntilReady) {
+ OnReady = [&](Error Err) {
+ if (Err) {
+ ErrorAsOutParameter _(&ReadyError);
+ std::lock_guard<std::mutex> Lock(ErrMutex);
+ ReadyError = std::move(Err);
+ }
+ PromisedReady.set_value();
+ };
+ } else {
+ OnReady = [&](Error Err) {
+ if (Err)
+ reportError(std::move(Err));
+ };
}
- // Update flags on existing defs and call discard on their materializers.
- for (auto &EDO : ExistingDefsOverridden) {
- assert(EDO.ExistingDefItr->second.getFlags().isLazy() &&
- !EDO.ExistingDefItr->second.getFlags().isMaterializing() &&
- "Overridden existing def should be in the Lazy state");
-
- EDO.ExistingDefItr->second.setFlags(EDO.NewFlags);
+#else
+ SymbolMap Result;
+ Error ResolutionError = Error::success();
+ Error ReadyError = Error::success();
- auto UMII = UnmaterializedInfos.find(EDO.ExistingDefItr->first);
- assert(UMII != UnmaterializedInfos.end() &&
- "Overridden existing def should have an UnmaterializedInfo");
+ auto OnResolve = [&](Expected<SymbolMap> R) {
+ ErrorAsOutParameter _(&ResolutionError);
+ if (R)
+ Result = std::move(*R);
+ else
+ ResolutionError = R.takeError();
+ };
- UMII->second->MU->doDiscard(*this, EDO.ExistingDefItr->first);
+ std::function<void(Error)> OnReady;
+ if (WaitUntilReady) {
+ OnReady = [&](Error Err) {
+ ErrorAsOutParameter _(&ReadyError);
+ if (Err)
+ ReadyError = std::move(Err);
+ };
+ } else {
+ OnReady = [&](Error Err) {
+ if (Err)
+ reportError(std::move(Err));
+ };
}
+#endif
- // Discard overridden symbols povided by MU.
- for (auto &Sym : MUDefsOverridden)
- MU.doDiscard(*this, Sym);
-
- return Error::success();
-}
-
-void JITDylib::detachQueryHelper(AsynchronousSymbolQuery &Q,
- const SymbolNameSet &QuerySymbols) {
- for (auto &QuerySymbol : QuerySymbols) {
- assert(MaterializingInfos.count(QuerySymbol) &&
- "QuerySymbol does not have MaterializingInfo");
- auto &MI = MaterializingInfos[QuerySymbol];
+ // Perform the asynchronous lookup.
+ lookup(JDs, Symbols, OnResolve, OnReady, RegisterDependencies);
- auto IdenticalQuery =
- [&](const std::shared_ptr<AsynchronousSymbolQuery> &R) {
- return R.get() == &Q;
- };
+#if LLVM_ENABLE_THREADS
+ auto ResultFuture = PromisedResult.get_future();
+ auto Result = ResultFuture.get();
- auto I = std::find_if(MI.PendingQueries.begin(), MI.PendingQueries.end(),
- IdenticalQuery);
- assert(I != MI.PendingQueries.end() &&
- "Query Q should be in the PendingQueries list for QuerySymbol");
- MI.PendingQueries.erase(I);
+ {
+ std::lock_guard<std::mutex> Lock(ErrMutex);
+ if (ResolutionError) {
+ // ReadyError will never be assigned. Consume the success value.
+ cantFail(std::move(ReadyError));
+ return std::move(ResolutionError);
+ }
}
-}
-
-void JITDylib::transferEmittedNodeDependencies(
- MaterializingInfo &DependantMI, const SymbolStringPtr &DependantName,
- MaterializingInfo &EmittedMI) {
- for (auto &KV : EmittedMI.UnemittedDependencies) {
- auto &DependencyJD = *KV.first;
- SymbolNameSet *UnemittedDependenciesOnDependencyJD = nullptr;
- for (auto &DependencyName : KV.second) {
- auto &DependencyMI = DependencyJD.MaterializingInfos[DependencyName];
+ if (WaitUntilReady) {
+ auto ReadyFuture = PromisedReady.get_future();
+ ReadyFuture.get();
- // Do not add self dependencies.
- if (&DependencyMI == &DependantMI)
- continue;
+ {
+ std::lock_guard<std::mutex> Lock(ErrMutex);
+ if (ReadyError)
+ return std::move(ReadyError);
+ }
+ } else
+ cantFail(std::move(ReadyError));
- // If we haven't looked up the dependencies for DependencyJD yet, do it
- // now and cache the result.
- if (!UnemittedDependenciesOnDependencyJD)
- UnemittedDependenciesOnDependencyJD =
- &DependantMI.UnemittedDependencies[&DependencyJD];
+ return std::move(Result);
- DependencyMI.Dependants[this].insert(DependantName);
- UnemittedDependenciesOnDependencyJD->insert(DependencyName);
- }
+#else
+ if (ResolutionError) {
+ // ReadyError will never be assigned. Consume the success value.
+ cantFail(std::move(ReadyError));
+ return std::move(ResolutionError);
}
-}
-ExecutionSession::ExecutionSession(std::shared_ptr<SymbolStringPool> SSP)
- : ExecutionSessionBase(std::move(SSP)) {
- // Construct the main dylib.
- JDs.push_back(std::unique_ptr<JITDylib>(new JITDylib(*this, "<main>")));
-}
+ if (ReadyError)
+ return std::move(ReadyError);
-JITDylib &ExecutionSession::getMainJITDylib() {
- return runSessionLocked([this]() -> JITDylib & { return *JDs.front(); });
+ return Result;
+#endif
}
-JITDylib &ExecutionSession::createJITDylib(std::string Name,
- bool AddToMainDylibSearchOrder) {
- return runSessionLocked([&, this]() -> JITDylib & {
- JDs.push_back(
- std::unique_ptr<JITDylib>(new JITDylib(*this, std::move(Name))));
- if (AddToMainDylibSearchOrder)
- JDs.front()->addToSearchOrder(*JDs.back());
- return *JDs.back();
- });
+void ExecutionSession::runOutstandingMUs() {
+ while (1) {
+ std::pair<JITDylib *, std::unique_ptr<MaterializationUnit>> JITDylibAndMU;
+
+ {
+ std::lock_guard<std::recursive_mutex> Lock(OutstandingMUsMutex);
+ if (!OutstandingMUs.empty()) {
+ JITDylibAndMU = std::move(OutstandingMUs.back());
+ OutstandingMUs.pop_back();
+ }
+ }
+
+ if (JITDylibAndMU.first) {
+ assert(JITDylibAndMU.second && "JITDylib, but no MU?");
+ dispatchMaterialization(*JITDylibAndMU.first,
+ std::move(JITDylibAndMU.second));
+ } else
+ break;
+ }
}
Expected<SymbolMap> lookup(const JITDylibList &JDs, SymbolNameSet Names) {
@@ -1720,8 +1741,7 @@ Expected<JITEvaluatedSymbol> lookup(cons
return ResultMap.takeError();
}
-MangleAndInterner::MangleAndInterner(ExecutionSessionBase &ES,
- const DataLayout &DL)
+MangleAndInterner::MangleAndInterner(ExecutionSession &ES, const DataLayout &DL)
: ES(ES), DL(DL) {}
SymbolStringPtr MangleAndInterner::operator()(StringRef Name) {
Modified: llvm/trunk/lib/ExecutionEngine/Orc/Legacy.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/Orc/Legacy.cpp?rev=342087&r1=342086&r2=342087&view=diff
==============================================================================
--- llvm/trunk/lib/ExecutionEngine/Orc/Legacy.cpp (original)
+++ llvm/trunk/lib/ExecutionEngine/Orc/Legacy.cpp Wed Sep 12 14:49:02 2018
@@ -35,7 +35,7 @@ JITSymbolResolverAdapter::lookup(const L
};
auto InternedResult =
- ES.legacyLookup(ES, std::move(LookupFn), std::move(InternedSymbols),
+ ES.legacyLookup(std::move(LookupFn), std::move(InternedSymbols),
false, RegisterDependencies);
if (!InternedResult)
More information about the llvm-commits
mailing list