mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 03:02:36 +01:00
[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. llvm-svn: 342087
This commit is contained in:
parent
0c2a797c97
commit
1771029439
@ -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");
|
||||
/// 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);
|
||||
|
||||
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 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 {
|
||||
public:
|
||||
using ExecutionSessionBase::lookup;
|
||||
class ExecutionSession {
|
||||
// FIXME: Remove this when we remove the old ORC layers.
|
||||
friend class JITDylib;
|
||||
|
||||
/// Construct an ExecutionEngine.
|
||||
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 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;
|
||||
};
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user