summaryrefslogtreecommitdiffstats
path: root/llvm
diff options
context:
space:
mode:
Diffstat (limited to 'llvm')
-rw-r--r--llvm/include/llvm/ExecutionEngine/Orc/Core.h366
-rw-r--r--llvm/lib/ExecutionEngine/Orc/Core.cpp748
-rw-r--r--llvm/lib/ExecutionEngine/Orc/Legacy.cpp2
3 files changed, 576 insertions, 540 deletions
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Core.h b/llvm/include/llvm/ExecutionEngine/Orc/Core.h
index e9eb1727596..f7a92ae0fdd 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/Core.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/Core.h
@@ -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;
-
- return Error::success();
- });
- }
+ /// 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);
+
+ /// 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)>;
- /// Construct an ExecutionEngine.
+ /// For dispatching MaterializationUnit::materialize calls.
+ using DispatchMaterializationFunction = std::function<void(
+ JITDylib &JD, std::unique_ptr<MaterializationUnit> MU)>;
+
+ /// 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(const JITDylibList &JDs,
/// 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;
};
diff --git a/llvm/lib/ExecutionEngine/Orc/Core.cpp b/llvm/lib/ExecutionEngine/Orc/Core.cpp
index 469f849b1c2..780e2fb9802 100644
--- a/llvm/lib/ExecutionEngine/Orc/Core.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/Core.cpp
@@ -142,361 +142,6 @@ void SymbolsNotFound::log(raw_ostream &OS) const {
OS << "Symbols not found: " << Symbols;
}
-void ExecutionSessionBase::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> 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());
- }
- };
-
- 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));
- };
- }
-
-#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)
- ES.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
- ES.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 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();
-
- 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]);
- }
-
- if (Unresolved.empty()) {
- // Query lodged successfully.
-
- // 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();
-
- // 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();
-}
-
-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));
- };
- }
-#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();
-
- {
- 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 ExecutionSessionBase::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;
- }
-}
-
AsynchronousSymbolQuery::AsynchronousSymbolQuery(
const SymbolNameSet &Symbols, SymbolsResolvedCallback NotifySymbolsResolved,
SymbolsReadyCallback NotifySymbolsReady)
@@ -520,10 +165,18 @@ void AsynchronousSymbolQuery::resolve(const SymbolStringPtr &Name,
void AsynchronousSymbolQuery::handleFullyResolved() {
assert(NotYetResolvedCount == 0 && "Not fully resolved?");
- assert(NotifySymbolsResolved &&
- "NotifySymbolsResolved already called or error occurred");
- NotifySymbolsResolved(std::move(ResolvedSymbols));
+
+ 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;
+ }
+
+ auto TmpNotifySymbolsResolved = std::move(NotifySymbolsResolved);
NotifySymbolsResolved = SymbolsResolvedCallback();
+ TmpNotifySymbolsResolved(std::move(ResolvedSymbols));
}
void AsynchronousSymbolQuery::notifySymbolReady() {
@@ -532,11 +185,25 @@ void AsynchronousSymbolQuery::notifySymbolReady() {
}
void AsynchronousSymbolQuery::handleFullyReady() {
+ assert(NotifySymbolsReady &&
+ "NotifySymbolsReady already called or an error occurred");
+
+ auto TmpNotifySymbolsReady = std::move(NotifySymbolsReady);
+ NotifySymbolsReady = SymbolsReadyCallback();
+
+ 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();
+ }
+
assert(QueryRegistrations.empty() &&
"Query is still registered with some symbols");
assert(!NotifySymbolsResolved && "Resolution not applied yet");
- NotifySymbolsReady(Error::success());
- NotifySymbolsReady = SymbolsReadyCallback();
+ TmpNotifySymbolsReady(Error::success());
}
bool AsynchronousSymbolQuery::canStillFail() {
@@ -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);
}
@@ -1678,7 +1345,7 @@ void JITDylib::transferEmittedNodeDependencies(
}
ExecutionSession::ExecutionSession(std::shared_ptr<SymbolStringPool> SSP)
- : ExecutionSessionBase(std::move(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>")));
}
@@ -1698,6 +1365,360 @@ JITDylib &ExecutionSession::createJITDylib(std::string Name,
});
}
+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]);
+ }
+
+ if (Unresolved.empty()) {
+ // Query lodged successfully.
+
+ // 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();
+
+ // 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();
+}
+
+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());
+ }
+ };
+
+ 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
+
+ // 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();
+
+ {
+ 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::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) {
if (JDs.empty())
@@ -1720,8 +1741,7 @@ Expected<JITEvaluatedSymbol> lookup(const JITDylibList &JDs,
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) {
diff --git a/llvm/lib/ExecutionEngine/Orc/Legacy.cpp b/llvm/lib/ExecutionEngine/Orc/Legacy.cpp
index 517176e5f42..925729e0eee 100644
--- a/llvm/lib/ExecutionEngine/Orc/Legacy.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/Legacy.cpp
@@ -35,7 +35,7 @@ JITSymbolResolverAdapter::lookup(const LookupSet &Symbols) {
};
auto InternedResult =
- ES.legacyLookup(ES, std::move(LookupFn), std::move(InternedSymbols),
+ ES.legacyLookup(std::move(LookupFn), std::move(InternedSymbols),
false, RegisterDependencies);
if (!InternedResult)
OpenPOWER on IntegriCloud