mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-29 22:30:33 +00:00
[ORC] Add new symbol lookup methods to ExecutionSessionBase in preparation for
deprecating SymbolResolver and AsynchronousSymbolQuery. Both lookup overloads take a VSO search order to perform the lookup. The first overload is non-blocking and takes OnResolved and OnReady callbacks. The second is blocking, takes a boolean flag to indicate whether to wait until all symbols are ready, and returns a SymbolMap. Both overloads take a RegisterDependencies function to register symbol dependencies (if any) on the query. llvm-svn: 337595
This commit is contained in:
parent
d38db2a134
commit
10fd293194
@ -69,8 +69,23 @@ raw_ostream &operator<<(raw_ostream &OS, const SymbolDependenceMap &Deps);
|
||||
/// A list of VSO pointers.
|
||||
using VSOList = std::vector<VSO *>;
|
||||
|
||||
/// Render a VSOList.
|
||||
raw_ostream &operator<<(raw_ostream &OS, const VSOList &VSOs);
|
||||
|
||||
/// Callback to notify client that symbols have been resolved.
|
||||
using SymbolsResolvedCallback = std::function<void(Expected<SymbolMap>)>;
|
||||
|
||||
/// Callback to notify client that symbols are ready for execution.
|
||||
using SymbolsReadyCallback = std::function<void(Error)>;
|
||||
|
||||
/// Callback to register the dependencies for a given query.
|
||||
using RegisterDependenciesFunction =
|
||||
std::function<void(const SymbolDependenceMap &)>;
|
||||
|
||||
/// This can be used as the value for a RegisterDependenciesFunction if there
|
||||
/// are no dependants to register with.
|
||||
extern RegisterDependenciesFunction NoDependenciesToRegister;
|
||||
|
||||
/// Used to notify a VSO that the given set of symbols failed to materialize.
|
||||
class FailedToMaterialize : public ErrorInfo<FailedToMaterialize> {
|
||||
public:
|
||||
@ -122,6 +137,9 @@ public:
|
||||
/// into.
|
||||
VSO &getTargetVSO() const { return V; }
|
||||
|
||||
/// Returns the symbol flags map for this responsibility instance.
|
||||
SymbolFlagsMap getSymbols() { return SymbolFlags; }
|
||||
|
||||
/// Returns the names of any symbols covered by this
|
||||
/// MaterializationResponsibility object that have queries pending. This
|
||||
/// information can be used to return responsibility for unrequested symbols
|
||||
@ -223,6 +241,9 @@ private:
|
||||
virtual void discard(const VSO &V, SymbolStringPtr Name) = 0;
|
||||
};
|
||||
|
||||
using MaterializationUnitList =
|
||||
std::vector<std::unique_ptr<MaterializationUnit>>;
|
||||
|
||||
/// A MaterializationUnit implementation for pre-existing absolute symbols.
|
||||
///
|
||||
/// All symbols will be resolved and marked ready as soon as the unit is
|
||||
@ -322,6 +343,9 @@ buildSimpleReexportsAliasMap(VSO &SourceV, const SymbolNameSet &Symbols);
|
||||
|
||||
/// Base utilities for ExecutionSession.
|
||||
class ExecutionSessionBase {
|
||||
// FIXME: Remove this when we remove the old ORC layers.
|
||||
friend class VSO;
|
||||
|
||||
public:
|
||||
/// For reporting errors.
|
||||
using ErrorReporter = std::function<void(Error)>;
|
||||
@ -372,11 +396,50 @@ public:
|
||||
void releaseVModule(VModuleKey Key) { /* FIXME: Recycle keys */
|
||||
}
|
||||
|
||||
/// Cause the given query to fail with the given Error.
|
||||
void legacyFailQuery(AsynchronousSymbolQuery &Q, Error Err);
|
||||
|
||||
using LegacyAsyncLookupFunction = std::function<SymbolNameSet(
|
||||
std::shared_ptr<AsynchronousSymbolQuery> Q, SymbolNameSet Names)>;
|
||||
|
||||
/// A legacy lookup function for JITSymbolResolverAdapter.
|
||||
/// Do not use -- this will be removed soon.
|
||||
Expected<SymbolMap>
|
||||
legacyLookup(ExecutionSessionBase &ES, LegacyAsyncLookupFunction AsyncLookup,
|
||||
SymbolNameSet Names, bool WaiUntilReady,
|
||||
RegisterDependenciesFunction RegisterDependencies);
|
||||
|
||||
/// Search the given VSO list for the given symbols.
|
||||
///
|
||||
/// This should only be used by legacy APIs and will be deprecated in the
|
||||
/// future.
|
||||
void failQuery(AsynchronousSymbolQuery &Q, Error Err);
|
||||
///
|
||||
/// The OnResolve callback will be called once all requested symbols are
|
||||
/// resolved, or if an error occurs prior to resolution.
|
||||
///
|
||||
/// The OnReady callback will be called once all requested symbols are ready,
|
||||
/// or if an error occurs after resolution but before all symbols are ready.
|
||||
///
|
||||
/// If all symbols are found, the RegisterDependencies function will be called
|
||||
/// while the session lock is held. This gives clients a chance to register
|
||||
/// dependencies for on the queried symbols for any symbols they are
|
||||
/// materializing (if a MaterializationResponsibility instance is present,
|
||||
/// this can be implemented by calling
|
||||
/// MaterializationResponsibility::addDependencies). If there are no
|
||||
/// dependenant symbols for this query (e.g. it is being made by a top level
|
||||
/// client to get an address to call) then the value NoDependenciesToRegister
|
||||
/// can be used.
|
||||
void lookup(const VSOList &VSOs, const SymbolNameSet &Symbols,
|
||||
SymbolsResolvedCallback OnResolve, SymbolsReadyCallback OnReady,
|
||||
RegisterDependenciesFunction RegisterDependencies);
|
||||
|
||||
/// Blocking version of lookup above. Returns the resolved symbol map.
|
||||
/// If WaitUntilReady is true (the default), will not return until all
|
||||
/// requested symbols are ready (or an error occurs). If WaitUntilReady is
|
||||
/// false, will return as soon as all requested symbols are resolved,
|
||||
/// or an error occurs. If WaitUntilReady is false and an error occurs
|
||||
/// after resolution, the function will return a success value, but the
|
||||
/// error will be reported via reportErrors.
|
||||
Expected<SymbolMap> lookup(const VSOList &VSOs, const SymbolNameSet &Symbols,
|
||||
RegisterDependenciesFunction RegisterDependencies,
|
||||
bool WaitUntilReady = true);
|
||||
|
||||
/// Materialize the given unit.
|
||||
void dispatchMaterialization(VSO &V,
|
||||
@ -394,12 +457,20 @@ private:
|
||||
MU->doMaterialize(V);
|
||||
}
|
||||
|
||||
void runOutstandingMUs();
|
||||
|
||||
mutable std::recursive_mutex SessionMutex;
|
||||
std::shared_ptr<SymbolStringPool> SSP;
|
||||
VModuleKey LastKey = 0;
|
||||
ErrorReporter ReportError = logErrorsToStdErr;
|
||||
DispatchMaterializationFunction DispatchMaterialization =
|
||||
materializeOnCurrentThread;
|
||||
|
||||
// FIXME: Remove this (and runOutstandingMUs) once the linking layer works
|
||||
// with callbacks from asynchronous queries.
|
||||
mutable std::recursive_mutex OutstandingMUsMutex;
|
||||
std::vector<std::pair<VSO *, std::unique_ptr<MaterializationUnit>>>
|
||||
OutstandingMUs;
|
||||
};
|
||||
|
||||
/// A symbol query that returns results via a callback when results are
|
||||
@ -411,21 +482,6 @@ class AsynchronousSymbolQuery {
|
||||
friend class VSO;
|
||||
|
||||
public:
|
||||
class ResolutionResult {
|
||||
public:
|
||||
ResolutionResult(SymbolMap Symbols, const SymbolDependenceMap &Dependencies)
|
||||
: Symbols(std::move(Symbols)), Dependencies(Dependencies) {}
|
||||
|
||||
SymbolMap Symbols;
|
||||
const SymbolDependenceMap &Dependencies;
|
||||
};
|
||||
|
||||
/// Callback to notify client that symbols have been resolved.
|
||||
using SymbolsResolvedCallback =
|
||||
std::function<void(Expected<ResolutionResult>)>;
|
||||
|
||||
/// Callback to notify client that symbols are ready for execution.
|
||||
using SymbolsReadyCallback = std::function<void(Error)>;
|
||||
|
||||
/// Create a query for the given symbols, notify-resolved and
|
||||
/// notify-ready callbacks.
|
||||
@ -485,6 +541,7 @@ private:
|
||||
class VSO {
|
||||
friend class AsynchronousSymbolQuery;
|
||||
friend class ExecutionSession;
|
||||
friend class ExecutionSessionBase;
|
||||
friend class MaterializationResponsibility;
|
||||
public:
|
||||
using FallbackDefinitionGeneratorFunction =
|
||||
@ -493,9 +550,6 @@ public:
|
||||
using AsynchronousSymbolQuerySet =
|
||||
std::set<std::shared_ptr<AsynchronousSymbolQuery>>;
|
||||
|
||||
using MaterializationUnitList =
|
||||
std::vector<std::unique_ptr<MaterializationUnit>>;
|
||||
|
||||
VSO(const VSO &) = delete;
|
||||
VSO &operator=(const VSO &) = delete;
|
||||
VSO(VSO &&) = delete;
|
||||
@ -547,8 +601,10 @@ public:
|
||||
void removeFromSearchOrder(VSO &V);
|
||||
|
||||
/// Do something with the search order (run under the session lock).
|
||||
template <typename Func> void withSearchOrderDo(Func F) {
|
||||
ES.runSessionLocked([&]() { F(SearchOrder); });
|
||||
template <typename Func>
|
||||
auto withSearchOrderDo(Func &&F)
|
||||
-> decltype(F(std::declval<const VSOList &>())) {
|
||||
return ES.runSessionLocked([&]() { return F(SearchOrder); });
|
||||
}
|
||||
|
||||
/// Define all symbols provided by the materialization unit to be part
|
||||
@ -579,6 +635,10 @@ public:
|
||||
/// the flags for each symbol in Flags. Returns any unresolved symbols.
|
||||
SymbolFlagsMap lookupFlags(const SymbolNameSet &Names);
|
||||
|
||||
/// Dump current VSO state to OS.
|
||||
void dump(raw_ostream &OS);
|
||||
|
||||
/// FIXME: Remove this when we remove the old ORC layers.
|
||||
/// Search the given VSOs in order for the symbols in Symbols. Results
|
||||
/// (once they become available) will be returned via the given Query.
|
||||
///
|
||||
@ -586,11 +646,8 @@ public:
|
||||
/// and the query will not be applied. The Query is not failed and can be
|
||||
/// re-used in a subsequent lookup once the symbols have been added, or
|
||||
/// manually failed.
|
||||
SymbolNameSet lookup(std::shared_ptr<AsynchronousSymbolQuery> Q,
|
||||
SymbolNameSet Names);
|
||||
|
||||
/// Dump current VSO state to OS.
|
||||
void dump(raw_ostream &OS);
|
||||
SymbolNameSet legacyLookup(std::shared_ptr<AsynchronousSymbolQuery> Q,
|
||||
SymbolNameSet Names);
|
||||
|
||||
private:
|
||||
using AsynchronousSymbolQueryList =
|
||||
@ -629,6 +686,12 @@ private:
|
||||
SymbolNameSet lookupFlagsImpl(SymbolFlagsMap &Flags,
|
||||
const SymbolNameSet &Names);
|
||||
|
||||
void lodgeQuery(std::shared_ptr<AsynchronousSymbolQuery> &Q,
|
||||
SymbolNameSet &Unresolved, MaterializationUnitList &MUs);
|
||||
|
||||
void lodgeQueryImpl(std::shared_ptr<AsynchronousSymbolQuery> &Q,
|
||||
SymbolNameSet &Unresolved, MaterializationUnitList &MUs);
|
||||
|
||||
LookupImplActionFlags
|
||||
lookupImpl(std::shared_ptr<AsynchronousSymbolQuery> &Q,
|
||||
std::vector<std::unique_ptr<MaterializationUnit>> &MUs,
|
||||
@ -647,8 +710,8 @@ private:
|
||||
|
||||
SymbolNameSet getRequestedSymbols(const SymbolFlagsMap &SymbolFlags);
|
||||
|
||||
void addDependencies(const SymbolFlagsMap &Dependents,
|
||||
const SymbolDependenceMap &Dependencies);
|
||||
void addDependencies(const SymbolStringPtr &Name,
|
||||
const SymbolDependenceMap &Dependants);
|
||||
|
||||
void resolve(const SymbolMap &Resolved);
|
||||
|
||||
@ -656,8 +719,6 @@ private:
|
||||
|
||||
void notifyFailed(const SymbolNameSet &FailedSymbols);
|
||||
|
||||
void runOutstandingMUs();
|
||||
|
||||
ExecutionSessionBase &ES;
|
||||
std::string VSOName;
|
||||
SymbolMap Symbols;
|
||||
@ -665,11 +726,6 @@ private:
|
||||
MaterializingInfosMap MaterializingInfos;
|
||||
FallbackDefinitionGeneratorFunction FallbackDefinitionGenerator;
|
||||
VSOList SearchOrder;
|
||||
|
||||
// FIXME: Remove this (and runOutstandingMUs) once the linking layer works
|
||||
// with callbacks from asynchronous queries.
|
||||
mutable std::recursive_mutex OutstandingMUsMutex;
|
||||
std::vector<std::unique_ptr<MaterializationUnit>> OutstandingMUs;
|
||||
};
|
||||
|
||||
/// An ExecutionSession represents a running JIT program.
|
||||
@ -693,15 +749,6 @@ private:
|
||||
std::vector<std::unique_ptr<VSO>> VSOs;
|
||||
};
|
||||
|
||||
using AsynchronousLookupFunction = std::function<SymbolNameSet(
|
||||
std::shared_ptr<AsynchronousSymbolQuery> Q, SymbolNameSet Names)>;
|
||||
|
||||
/// Perform a blocking lookup on the given symbols.
|
||||
Expected<SymbolMap> blockingLookup(ExecutionSessionBase &ES,
|
||||
AsynchronousLookupFunction AsyncLookup,
|
||||
SymbolNameSet Names, bool WaiUntilReady,
|
||||
MaterializationResponsibility *MR = nullptr);
|
||||
|
||||
/// Look up the given names in the given VSOs.
|
||||
/// VSOs will be searched in order and no VSO pointer may be null.
|
||||
/// All symbols must be found within the given VSOs or an error
|
||||
|
@ -146,11 +146,11 @@ lookupWithLegacyFn(ExecutionSession &ES, AsynchronousSymbolQuery &Query,
|
||||
Query.notifySymbolReady();
|
||||
NewSymbolsResolved = true;
|
||||
} else {
|
||||
ES.failQuery(Query, Addr.takeError());
|
||||
ES.legacyFailQuery(Query, Addr.takeError());
|
||||
return SymbolNameSet();
|
||||
}
|
||||
} else if (auto Err = Sym.takeError()) {
|
||||
ES.failQuery(Query, std::move(Err));
|
||||
ES.legacyFailQuery(Query, std::move(Err));
|
||||
return SymbolNameSet();
|
||||
} else
|
||||
SymbolsNotFound.insert(S);
|
||||
|
@ -23,6 +23,9 @@ namespace orc {
|
||||
char FailedToMaterialize::ID = 0;
|
||||
char SymbolsNotFound::ID = 0;
|
||||
|
||||
RegisterDependenciesFunction NoDependenciesToRegister =
|
||||
RegisterDependenciesFunction();
|
||||
|
||||
void MaterializationUnit::anchor() {}
|
||||
|
||||
raw_ostream &operator<<(raw_ostream &OS, const JITSymbolFlags &Flags) {
|
||||
@ -138,20 +141,361 @@ void SymbolsNotFound::log(raw_ostream &OS) const {
|
||||
OS << "Symbols not found: " << Symbols;
|
||||
}
|
||||
|
||||
void ExecutionSessionBase::failQuery(AsynchronousSymbolQuery &Q, Error Err) {
|
||||
bool DeliveredError = true;
|
||||
runSessionLocked([&]() -> void {
|
||||
void ExecutionSessionBase::legacyFailQuery(AsynchronousSymbolQuery &Q,
|
||||
Error Err) {
|
||||
assert(!!Err && "Error should be in failure state");
|
||||
|
||||
bool SendErrorToQuery;
|
||||
runSessionLocked([&]() {
|
||||
Q.detach();
|
||||
if (Q.canStillFail())
|
||||
Q.handleFailed(std::move(Err));
|
||||
else
|
||||
DeliveredError = false;
|
||||
SendErrorToQuery = Q.canStillFail();
|
||||
});
|
||||
|
||||
if (!DeliveredError)
|
||||
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 VSOList &VSOs, 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<VSO *, 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 *V : VSOs) {
|
||||
assert(V && "VSOList entries must not be null");
|
||||
assert(!MUsMap.count(V) &&
|
||||
"VSOList should not contain duplicate entries");
|
||||
V->lodgeQuery(Q, Unresolved, MUsMap[V]);
|
||||
}
|
||||
|
||||
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 VSOList &VSOs, 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->Symbols);
|
||||
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(VSOs, 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<VSO *, std::unique_ptr<MaterializationUnit>> VSOAndMU;
|
||||
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> Lock(OutstandingMUsMutex);
|
||||
if (!OutstandingMUs.empty()) {
|
||||
VSOAndMU = std::move(OutstandingMUs.back());
|
||||
OutstandingMUs.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
if (VSOAndMU.first) {
|
||||
assert(VSOAndMU.second && "VSO, but no MU?");
|
||||
dispatchMaterialization(*VSOAndMU.first, std::move(VSOAndMU.second));
|
||||
} else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
AsynchronousSymbolQuery::AsynchronousSymbolQuery(
|
||||
const SymbolNameSet &Symbols, SymbolsResolvedCallback NotifySymbolsResolved,
|
||||
SymbolsReadyCallback NotifySymbolsReady)
|
||||
@ -161,12 +505,6 @@ AsynchronousSymbolQuery::AsynchronousSymbolQuery(
|
||||
|
||||
for (auto &S : Symbols)
|
||||
ResolvedSymbols[S] = nullptr;
|
||||
|
||||
// If the query is empty it is trivially resolved/ready.
|
||||
if (Symbols.empty()) {
|
||||
handleFullyResolved();
|
||||
handleFullyReady();
|
||||
}
|
||||
}
|
||||
|
||||
void AsynchronousSymbolQuery::resolve(const SymbolStringPtr &Name,
|
||||
@ -183,8 +521,7 @@ void AsynchronousSymbolQuery::handleFullyResolved() {
|
||||
assert(NotYetResolvedCount == 0 && "Not fully resolved?");
|
||||
assert(NotifySymbolsResolved &&
|
||||
"NotifySymbolsResolved already called or error occurred");
|
||||
NotifySymbolsResolved(
|
||||
ResolutionResult(std::move(ResolvedSymbols), QueryRegistrations));
|
||||
NotifySymbolsResolved(std::move(ResolvedSymbols));
|
||||
NotifySymbolsResolved = SymbolsResolvedCallback();
|
||||
}
|
||||
|
||||
@ -349,7 +686,8 @@ MaterializationResponsibility::delegate(const SymbolNameSet &Symbols) {
|
||||
|
||||
void MaterializationResponsibility::addDependencies(
|
||||
const SymbolDependenceMap &Dependencies) {
|
||||
V.addDependencies(SymbolFlags, Dependencies);
|
||||
for (auto &KV : SymbolFlags)
|
||||
V.addDependencies(KV.first, Dependencies);
|
||||
}
|
||||
|
||||
AbsoluteSymbolsMaterializationUnit::AbsoluteSymbolsMaterializationUnit(
|
||||
@ -384,8 +722,9 @@ ReExportsMaterializationUnit::ReExportsMaterializationUnit(
|
||||
void ReExportsMaterializationUnit::materialize(
|
||||
MaterializationResponsibility R) {
|
||||
|
||||
VSO &SrcV = SourceVSO ? *SourceVSO : R.getTargetVSO();
|
||||
auto &ES = SrcV.getExecutionSession();
|
||||
auto &ES = R.getTargetVSO().getExecutionSession();
|
||||
VSO &TgtV = R.getTargetVSO();
|
||||
VSO &SrcV = SourceVSO ? *SourceVSO : TgtV;
|
||||
|
||||
// Find the set of requested aliases and aliasees. Return any unrequested
|
||||
// aliases back to the VSO so as to not prematurely materialize any aliasees.
|
||||
@ -434,9 +773,8 @@ void ReExportsMaterializationUnit::materialize(
|
||||
auto Tmp = I++;
|
||||
|
||||
// Chain detected. Skip this symbol for this round.
|
||||
if (&SrcV == &R.getTargetVSO() &&
|
||||
(QueryAliases.count(Tmp->second.Aliasee) ||
|
||||
RequestedAliases.count(Tmp->second.Aliasee)))
|
||||
if (&SrcV == &TgtV && (QueryAliases.count(Tmp->second.Aliasee) ||
|
||||
RequestedAliases.count(Tmp->second.Aliasee)))
|
||||
continue;
|
||||
|
||||
ResponsibilitySymbols.insert(Tmp->first);
|
||||
@ -459,49 +797,32 @@ void ReExportsMaterializationUnit::materialize(
|
||||
|
||||
QueryInfos.pop_back();
|
||||
|
||||
auto OnResolve =
|
||||
[QueryInfo,
|
||||
&SrcV](Expected<AsynchronousSymbolQuery::ResolutionResult> RR) {
|
||||
if (RR) {
|
||||
SymbolMap ResolutionMap;
|
||||
SymbolNameSet Resolved;
|
||||
for (auto &KV : QueryInfo->Aliases) {
|
||||
assert(RR->Symbols.count(KV.second.Aliasee) &&
|
||||
"Result map missing entry?");
|
||||
ResolutionMap[KV.first] = JITEvaluatedSymbol(
|
||||
RR->Symbols[KV.second.Aliasee].getAddress(),
|
||||
KV.second.AliasFlags);
|
||||
auto RegisterDependencies = [&](const SymbolDependenceMap &Deps) {
|
||||
R.addDependencies(Deps);
|
||||
};
|
||||
|
||||
// FIXME: We're creating a SymbolFlagsMap and a std::map of
|
||||
// std::sets just to add one dependency here. This needs a
|
||||
// re-think.
|
||||
Resolved.insert(KV.first);
|
||||
}
|
||||
QueryInfo->R.resolve(ResolutionMap);
|
||||
|
||||
SymbolDependenceMap Deps;
|
||||
Deps[&SrcV] = std::move(Resolved);
|
||||
QueryInfo->R.addDependencies(Deps);
|
||||
|
||||
QueryInfo->R.finalize();
|
||||
} else {
|
||||
auto &ES = QueryInfo->R.getTargetVSO().getExecutionSession();
|
||||
ES.reportError(RR.takeError());
|
||||
QueryInfo->R.failMaterialization();
|
||||
}
|
||||
};
|
||||
auto OnResolve = [QueryInfo](Expected<SymbolMap> Result) {
|
||||
if (Result) {
|
||||
SymbolMap ResolutionMap;
|
||||
for (auto &KV : QueryInfo->Aliases) {
|
||||
assert(Result->count(KV.second.Aliasee) &&
|
||||
"Result map missing entry?");
|
||||
ResolutionMap[KV.first] = JITEvaluatedSymbol(
|
||||
(*Result)[KV.second.Aliasee].getAddress(), KV.second.AliasFlags);
|
||||
}
|
||||
QueryInfo->R.resolve(ResolutionMap);
|
||||
QueryInfo->R.finalize();
|
||||
} else {
|
||||
auto &ES = QueryInfo->R.getTargetVSO().getExecutionSession();
|
||||
ES.reportError(Result.takeError());
|
||||
QueryInfo->R.failMaterialization();
|
||||
}
|
||||
};
|
||||
|
||||
auto OnReady = [&ES](Error Err) { ES.reportError(std::move(Err)); };
|
||||
|
||||
auto Q = std::make_shared<AsynchronousSymbolQuery>(
|
||||
QuerySymbols, std::move(OnResolve), std::move(OnReady));
|
||||
|
||||
auto Unresolved = SrcV.lookup(Q, std::move(QuerySymbols));
|
||||
|
||||
if (!Unresolved.empty()) {
|
||||
ES.failQuery(*Q, make_error<SymbolsNotFound>(std::move(Unresolved)));
|
||||
return;
|
||||
}
|
||||
ES.lookup({&SrcV}, QuerySymbols, std::move(OnResolve), std::move(OnReady),
|
||||
std::move(RegisterDependencies));
|
||||
}
|
||||
}
|
||||
|
||||
@ -642,40 +963,35 @@ SymbolNameSet VSO::getRequestedSymbols(const SymbolFlagsMap &SymbolFlags) {
|
||||
});
|
||||
}
|
||||
|
||||
void VSO::addDependencies(const SymbolFlagsMap &Dependants,
|
||||
void VSO::addDependencies(const SymbolStringPtr &Name,
|
||||
const SymbolDependenceMap &Dependencies) {
|
||||
ES.runSessionLocked([&, this]() {
|
||||
for (auto &KV : Dependants) {
|
||||
const auto &Name = KV.first;
|
||||
assert(Symbols.count(Name) && "Name not in symbol table");
|
||||
assert((Symbols[Name].getFlags().isLazy() ||
|
||||
Symbols[Name].getFlags().isMaterializing()) &&
|
||||
"Symbol is not lazy or materializing");
|
||||
assert(Symbols.count(Name) && "Name not in symbol table");
|
||||
assert((Symbols[Name].getFlags().isLazy() ||
|
||||
Symbols[Name].getFlags().isMaterializing()) &&
|
||||
"Symbol is not lazy or materializing");
|
||||
|
||||
auto &MI = MaterializingInfos[Name];
|
||||
assert(!MI.IsFinalized && "Can not add dependencies to finalized symbol");
|
||||
auto &MI = MaterializingInfos[Name];
|
||||
assert(!MI.IsFinalized && "Can not add dependencies to finalized symbol");
|
||||
|
||||
for (auto &KV : Dependencies) {
|
||||
assert(KV.first && "Null VSO in dependency?");
|
||||
auto &OtherVSO = *KV.first;
|
||||
auto &DepsOnOtherVSO = MI.UnfinalizedDependencies[&OtherVSO];
|
||||
for (auto &KV : Dependencies) {
|
||||
assert(KV.first && "Null VSO in dependency?");
|
||||
auto &OtherVSO = *KV.first;
|
||||
auto &DepsOnOtherVSO = MI.UnfinalizedDependencies[&OtherVSO];
|
||||
|
||||
for (auto &OtherSymbol : KV.second) {
|
||||
auto &OtherMI = OtherVSO.MaterializingInfos[OtherSymbol];
|
||||
for (auto &OtherSymbol : KV.second) {
|
||||
auto &OtherMI = OtherVSO.MaterializingInfos[OtherSymbol];
|
||||
|
||||
if (OtherMI.IsFinalized)
|
||||
transferFinalizedNodeDependencies(MI, Name, OtherMI);
|
||||
else if (&OtherVSO != this || OtherSymbol != Name) {
|
||||
OtherMI.Dependants[this].insert(Name);
|
||||
DepsOnOtherVSO.insert(OtherSymbol);
|
||||
}
|
||||
}
|
||||
|
||||
if (DepsOnOtherVSO.empty())
|
||||
MI.UnfinalizedDependencies.erase(&OtherVSO);
|
||||
if (OtherMI.IsFinalized)
|
||||
transferFinalizedNodeDependencies(MI, Name, OtherMI);
|
||||
else if (&OtherVSO != this || OtherSymbol != Name) {
|
||||
OtherMI.Dependants[this].insert(Name);
|
||||
DepsOnOtherVSO.insert(OtherSymbol);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (DepsOnOtherVSO.empty())
|
||||
MI.UnfinalizedDependencies.erase(&OtherVSO);
|
||||
}
|
||||
}
|
||||
|
||||
void VSO::resolve(const SymbolMap &Resolved) {
|
||||
@ -856,25 +1172,6 @@ void VSO::notifyFailed(const SymbolNameSet &FailedSymbols) {
|
||||
Q->handleFailed(make_error<FailedToMaterialize>(FailedSymbols));
|
||||
}
|
||||
|
||||
void VSO::runOutstandingMUs() {
|
||||
while (1) {
|
||||
std::unique_ptr<MaterializationUnit> MU;
|
||||
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> Lock(OutstandingMUsMutex);
|
||||
if (!OutstandingMUs.empty()) {
|
||||
MU = std::move(OutstandingMUs.back());
|
||||
OutstandingMUs.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
if (MU)
|
||||
ES.dispatchMaterialization(*this, std::move(MU));
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void VSO::setSearchOrder(VSOList NewSearchOrder, bool SearchThisVSOFirst) {
|
||||
if (SearchThisVSOFirst && NewSearchOrder.front() != this)
|
||||
NewSearchOrder.insert(NewSearchOrder.begin(), this);
|
||||
@ -939,11 +1236,89 @@ SymbolNameSet VSO::lookupFlagsImpl(SymbolFlagsMap &Flags,
|
||||
return Unresolved;
|
||||
}
|
||||
|
||||
SymbolNameSet VSO::lookup(std::shared_ptr<AsynchronousSymbolQuery> Q,
|
||||
SymbolNameSet Names) {
|
||||
void VSO::lodgeQuery(std::shared_ptr<AsynchronousSymbolQuery> &Q,
|
||||
SymbolNameSet &Unresolved, MaterializationUnitList &MUs) {
|
||||
assert(Q && "Query can not be null");
|
||||
|
||||
runOutstandingMUs();
|
||||
lodgeQueryImpl(Q, Unresolved, MUs);
|
||||
if (FallbackDefinitionGenerator && !Unresolved.empty()) {
|
||||
auto FallbackDefs = FallbackDefinitionGenerator(*this, Unresolved);
|
||||
if (!FallbackDefs.empty()) {
|
||||
for (auto &D : FallbackDefs)
|
||||
Unresolved.erase(D);
|
||||
lodgeQueryImpl(Q, FallbackDefs, MUs);
|
||||
assert(FallbackDefs.empty() &&
|
||||
"All fallback defs should have been found by lookupImpl");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VSO::lodgeQueryImpl(
|
||||
std::shared_ptr<AsynchronousSymbolQuery> &Q, SymbolNameSet &Unresolved,
|
||||
std::vector<std::unique_ptr<MaterializationUnit>> &MUs) {
|
||||
for (auto I = Unresolved.begin(), E = Unresolved.end(); I != E;) {
|
||||
auto TmpI = I++;
|
||||
auto Name = *TmpI;
|
||||
|
||||
// Search for the name in Symbols. Skip it if not found.
|
||||
auto SymI = Symbols.find(Name);
|
||||
if (SymI == Symbols.end())
|
||||
continue;
|
||||
|
||||
// If we found Name in V, remove it frome the Unresolved set and add it
|
||||
// to the added set.
|
||||
Unresolved.erase(TmpI);
|
||||
|
||||
// If the symbol has an address then resolve it.
|
||||
if (SymI->second.getAddress() != 0)
|
||||
Q->resolve(Name, SymI->second);
|
||||
|
||||
// If the symbol is lazy, get the MaterialiaztionUnit for it.
|
||||
if (SymI->second.getFlags().isLazy()) {
|
||||
assert(SymI->second.getAddress() == 0 &&
|
||||
"Lazy symbol should not have a resolved address");
|
||||
assert(!SymI->second.getFlags().isMaterializing() &&
|
||||
"Materializing and lazy should not both be set");
|
||||
auto UMII = UnmaterializedInfos.find(Name);
|
||||
assert(UMII != UnmaterializedInfos.end() &&
|
||||
"Lazy symbol should have UnmaterializedInfo");
|
||||
auto MU = std::move(UMII->second->MU);
|
||||
assert(MU != nullptr && "Materializer should not be null");
|
||||
|
||||
// Move all symbols associated with this MaterializationUnit into
|
||||
// materializing state.
|
||||
for (auto &KV : MU->getSymbols()) {
|
||||
auto SymK = Symbols.find(KV.first);
|
||||
auto Flags = SymK->second.getFlags();
|
||||
Flags &= ~JITSymbolFlags::Lazy;
|
||||
Flags |= JITSymbolFlags::Materializing;
|
||||
SymK->second.setFlags(Flags);
|
||||
UnmaterializedInfos.erase(KV.first);
|
||||
}
|
||||
|
||||
// Add MU to the list of MaterializationUnits to be materialized.
|
||||
MUs.push_back(std::move(MU));
|
||||
} else if (!SymI->second.getFlags().isMaterializing()) {
|
||||
// The symbol is neither lazy nor materializing. Finalize it and
|
||||
// continue.
|
||||
Q->notifySymbolReady();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add the query to the PendingQueries list.
|
||||
assert(SymI->second.getFlags().isMaterializing() &&
|
||||
"By this line the symbol should be materializing");
|
||||
auto &MI = MaterializingInfos[Name];
|
||||
MI.PendingQueries.push_back(Q);
|
||||
Q->addQueryDependence(*this, Name);
|
||||
}
|
||||
}
|
||||
|
||||
SymbolNameSet VSO::legacyLookup(std::shared_ptr<AsynchronousSymbolQuery> Q,
|
||||
SymbolNameSet Names) {
|
||||
assert(Q && "Query can not be null");
|
||||
|
||||
ES.runOutstandingMUs();
|
||||
|
||||
LookupImplActionFlags ActionFlags = None;
|
||||
std::vector<std::unique_ptr<MaterializationUnit>> MUs;
|
||||
@ -978,11 +1353,11 @@ SymbolNameSet VSO::lookup(std::shared_ptr<AsynchronousSymbolQuery> Q,
|
||||
// callbacks from asynchronous queries.
|
||||
// Add MUs to the OutstandingMUs list.
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> Lock(OutstandingMUsMutex);
|
||||
std::lock_guard<std::recursive_mutex> Lock(ES.OutstandingMUsMutex);
|
||||
for (auto &MU : MUs)
|
||||
OutstandingMUs.push_back(std::move(MU));
|
||||
ES.OutstandingMUs.push_back(make_pair(this, std::move(MU)));
|
||||
}
|
||||
runOutstandingMUs();
|
||||
ES.runOutstandingMUs();
|
||||
|
||||
// Dispatch any required MaterializationUnits for materialization.
|
||||
// for (auto &MU : MUs)
|
||||
@ -1243,133 +1618,6 @@ VSO &ExecutionSession::createVSO(std::string Name) {
|
||||
});
|
||||
}
|
||||
|
||||
Expected<SymbolMap> blockingLookup(ExecutionSessionBase &ES,
|
||||
AsynchronousLookupFunction AsyncLookup,
|
||||
SymbolNameSet Names, bool WaitUntilReady,
|
||||
MaterializationResponsibility *MR) {
|
||||
|
||||
#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<AsynchronousSymbolQuery::ResolutionResult> Result) {
|
||||
if (Result) {
|
||||
if (MR)
|
||||
MR->addDependencies(Result->Dependencies);
|
||||
PromisedResult.set_value(std::move(Result->Symbols));
|
||||
} else {
|
||||
{
|
||||
ErrorAsOutParameter _(&ResolutionError);
|
||||
std::lock_guard<std::mutex> Lock(ErrMutex);
|
||||
ResolutionError = Result.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<AsynchronousSymbolQuery::ResolutionResult> R) {
|
||||
ErrorAsOutParameter _(&ResolutionError);
|
||||
if (R) {
|
||||
if (MR)
|
||||
MR->addDependencies(R->Dependencies);
|
||||
Result = std::move(R->Symbols);
|
||||
} 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));
|
||||
|
||||
SymbolNameSet UnresolvedSymbols = AsyncLookup(Query, std::move(Names));
|
||||
|
||||
// If there are unresolved symbols then the query will never return.
|
||||
// Fail it with ES.failQuery.
|
||||
if (!UnresolvedSymbols.empty())
|
||||
ES.failQuery(*Query,
|
||||
make_error<SymbolsNotFound>(std::move(UnresolvedSymbols)));
|
||||
|
||||
#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
|
||||
}
|
||||
|
||||
Expected<SymbolMap> lookup(const VSOList &VSOs, SymbolNameSet Names) {
|
||||
|
||||
if (VSOs.empty())
|
||||
@ -1377,18 +1625,7 @@ Expected<SymbolMap> lookup(const VSOList &VSOs, SymbolNameSet Names) {
|
||||
|
||||
auto &ES = (*VSOs.begin())->getExecutionSession();
|
||||
|
||||
auto LookupFn = [&](std::shared_ptr<AsynchronousSymbolQuery> Q,
|
||||
SymbolNameSet Unresolved) {
|
||||
for (auto *V : VSOs) {
|
||||
assert(V && "VSOs entries must not be null");
|
||||
if (Unresolved.empty())
|
||||
break;
|
||||
Unresolved = V->lookup(Q, std::move(Unresolved));
|
||||
}
|
||||
return Unresolved;
|
||||
};
|
||||
|
||||
return blockingLookup(ES, std::move(LookupFn), Names, true);
|
||||
return ES.lookup(VSOs, Names, NoDependenciesToRegister, true);
|
||||
}
|
||||
|
||||
/// Look up a symbol by searching a list of VSOs.
|
||||
|
@ -29,8 +29,14 @@ JITSymbolResolverAdapter::lookup(const LookupSet &Symbols) {
|
||||
return R.lookup(std::move(Q), std::move(Unresolved));
|
||||
};
|
||||
|
||||
auto InternedResult = blockingLookup(ES, std::move(LookupFn),
|
||||
std::move(InternedSymbols), false, MR);
|
||||
auto RegisterDependencies = [&](const SymbolDependenceMap &Deps) {
|
||||
if (MR)
|
||||
MR->addDependencies(Deps);
|
||||
};
|
||||
|
||||
auto InternedResult =
|
||||
ES.legacyLookup(ES, std::move(LookupFn), std::move(InternedSymbols),
|
||||
false, RegisterDependencies);
|
||||
|
||||
if (!InternedResult)
|
||||
return InternedResult.takeError();
|
||||
|
@ -156,11 +156,11 @@ private:
|
||||
Query->resolve(S, JITEvaluatedSymbol(*Addr, Sym.getFlags()));
|
||||
Query->notifySymbolReady();
|
||||
} else {
|
||||
Stack.ES.failQuery(*Query, Addr.takeError());
|
||||
Stack.ES.legacyFailQuery(*Query, Addr.takeError());
|
||||
return orc::SymbolNameSet();
|
||||
}
|
||||
} else if (auto Err = Sym.takeError()) {
|
||||
Stack.ES.failQuery(*Query, std::move(Err));
|
||||
Stack.ES.legacyFailQuery(*Query, std::move(Err));
|
||||
return orc::SymbolNameSet();
|
||||
} else
|
||||
UnresolvedSymbols.insert(S);
|
||||
|
@ -178,11 +178,11 @@ class OrcMCJITReplacement : public ExecutionEngine {
|
||||
Query->notifySymbolReady();
|
||||
NewSymbolsResolved = true;
|
||||
} else {
|
||||
M.ES.failQuery(*Query, Addr.takeError());
|
||||
M.ES.legacyFailQuery(*Query, Addr.takeError());
|
||||
return SymbolNameSet();
|
||||
}
|
||||
} else if (auto Err = Sym.takeError()) {
|
||||
M.ES.failQuery(*Query, std::move(Err));
|
||||
M.ES.legacyFailQuery(*Query, std::move(Err));
|
||||
return SymbolNameSet();
|
||||
} else {
|
||||
if (auto Sym2 = M.ClientResolver->findSymbol(*S)) {
|
||||
@ -191,11 +191,11 @@ class OrcMCJITReplacement : public ExecutionEngine {
|
||||
Query->notifySymbolReady();
|
||||
NewSymbolsResolved = true;
|
||||
} else {
|
||||
M.ES.failQuery(*Query, Addr.takeError());
|
||||
M.ES.legacyFailQuery(*Query, Addr.takeError());
|
||||
return SymbolNameSet();
|
||||
}
|
||||
} else if (auto Err = Sym2.takeError()) {
|
||||
M.ES.failQuery(*Query, std::move(Err));
|
||||
M.ES.legacyFailQuery(*Query, std::move(Err));
|
||||
return SymbolNameSet();
|
||||
} else
|
||||
UnresolvedSymbols.insert(S);
|
||||
|
@ -16,30 +16,23 @@ using namespace llvm::orc;
|
||||
|
||||
class VSOSearchOrderResolver : public JITSymbolResolver {
|
||||
public:
|
||||
VSOSearchOrderResolver(ExecutionSession &ES,
|
||||
MaterializationResponsibility &MR)
|
||||
: ES(ES), MR(MR) {}
|
||||
VSOSearchOrderResolver(MaterializationResponsibility &MR) : MR(MR) {}
|
||||
|
||||
Expected<LookupResult> lookup(const LookupSet &Symbols) {
|
||||
auto &ES = MR.getTargetVSO().getExecutionSession();
|
||||
SymbolNameSet InternedSymbols;
|
||||
|
||||
for (auto &S : Symbols)
|
||||
InternedSymbols.insert(ES.getSymbolStringPool().intern(S));
|
||||
|
||||
auto AsyncLookup = [&](std::shared_ptr<AsynchronousSymbolQuery> Q,
|
||||
SymbolNameSet Names) {
|
||||
SymbolNameSet Unresolved = std::move(Names);
|
||||
MR.getTargetVSO().withSearchOrderDo([&](const VSOList &SearchOrder) {
|
||||
for (auto *V : SearchOrder) {
|
||||
assert(V && "VSOList entry can not be null");
|
||||
Unresolved = V->lookup(Q, std::move(Unresolved));
|
||||
}
|
||||
});
|
||||
return Unresolved;
|
||||
auto RegisterDependencies = [&](const SymbolDependenceMap &Deps) {
|
||||
MR.addDependencies(Deps);
|
||||
};
|
||||
|
||||
auto InternedResult = blockingLookup(
|
||||
ES, std::move(AsyncLookup), std::move(InternedSymbols), false, &MR);
|
||||
auto InternedResult =
|
||||
MR.getTargetVSO().withSearchOrderDo([&](const VSOList &VSOs) {
|
||||
return ES.lookup(VSOs, InternedSymbols, RegisterDependencies, false);
|
||||
});
|
||||
|
||||
if (!InternedResult)
|
||||
return InternedResult.takeError();
|
||||
@ -52,6 +45,8 @@ public:
|
||||
}
|
||||
|
||||
Expected<LookupFlagsResult> lookupFlags(const LookupSet &Symbols) {
|
||||
auto &ES = MR.getTargetVSO().getExecutionSession();
|
||||
|
||||
SymbolNameSet InternedSymbols;
|
||||
|
||||
for (auto &S : Symbols)
|
||||
@ -75,7 +70,6 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
ExecutionSession &ES;
|
||||
MaterializationResponsibility &MR;
|
||||
};
|
||||
|
||||
@ -106,7 +100,7 @@ void RTDyldObjectLinkingLayer2::emit(MaterializationResponsibility R,
|
||||
|
||||
auto MemoryManager = GetMemoryManager(K);
|
||||
|
||||
VSOSearchOrderResolver Resolver(ES, R);
|
||||
VSOSearchOrderResolver Resolver(R);
|
||||
auto RTDyld = llvm::make_unique<RuntimeDyld>(*MemoryManager, Resolver);
|
||||
RTDyld->setProcessAllSections(ProcessAllSections);
|
||||
|
||||
|
@ -59,51 +59,57 @@ private:
|
||||
DestructorFunction Destructor;
|
||||
};
|
||||
|
||||
|
||||
TEST_F(CoreAPIsStandardTest, AsynchronousSymbolQuerySuccessfulResolutionOnly) {
|
||||
TEST_F(CoreAPIsStandardTest, BasicSuccessfulLookup) {
|
||||
bool OnResolutionRun = false;
|
||||
bool OnReadyRun = false;
|
||||
auto OnResolution =
|
||||
[&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) {
|
||||
EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error";
|
||||
auto &Resolved = Result->Symbols;
|
||||
auto I = Resolved.find(Foo);
|
||||
EXPECT_NE(I, Resolved.end()) << "Could not find symbol definition";
|
||||
EXPECT_EQ(I->second.getAddress(), FooAddr)
|
||||
<< "Resolution returned incorrect result";
|
||||
OnResolutionRun = true;
|
||||
};
|
||||
|
||||
auto OnResolution = [&](Expected<SymbolMap> Result) {
|
||||
EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error";
|
||||
auto &Resolved = *Result;
|
||||
auto I = Resolved.find(Foo);
|
||||
EXPECT_NE(I, Resolved.end()) << "Could not find symbol definition";
|
||||
EXPECT_EQ(I->second.getAddress(), FooAddr)
|
||||
<< "Resolution returned incorrect result";
|
||||
OnResolutionRun = true;
|
||||
};
|
||||
auto OnReady = [&](Error Err) {
|
||||
cantFail(std::move(Err));
|
||||
OnReadyRun = true;
|
||||
};
|
||||
|
||||
AsynchronousSymbolQuery Q(SymbolNameSet({Foo}), OnResolution, OnReady);
|
||||
std::shared_ptr<MaterializationResponsibility> FooMR;
|
||||
|
||||
Q.resolve(Foo, FooSym);
|
||||
cantFail(V.define(llvm::make_unique<SimpleMaterializationUnit>(
|
||||
SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
|
||||
[&](MaterializationResponsibility R) {
|
||||
FooMR = std::make_shared<MaterializationResponsibility>(std::move(R));
|
||||
})));
|
||||
|
||||
EXPECT_TRUE(Q.isFullyResolved()) << "Expected query to be fully resolved";
|
||||
ES.lookup({&V}, {Foo}, OnResolution, OnReady, NoDependenciesToRegister);
|
||||
|
||||
if (!Q.isFullyResolved())
|
||||
return;
|
||||
EXPECT_FALSE(OnResolutionRun) << "Should not have been resolved yet";
|
||||
EXPECT_FALSE(OnReadyRun) << "Should not have been marked ready yet";
|
||||
|
||||
Q.handleFullyResolved();
|
||||
FooMR->resolve({{Foo, FooSym}});
|
||||
|
||||
EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run";
|
||||
EXPECT_FALSE(OnReadyRun) << "OnReady unexpectedly run";
|
||||
EXPECT_TRUE(OnResolutionRun) << "Should have been resolved";
|
||||
EXPECT_FALSE(OnReadyRun) << "Should not have been marked ready yet";
|
||||
|
||||
FooMR->finalize();
|
||||
|
||||
EXPECT_TRUE(OnReadyRun) << "Should have been marked ready";
|
||||
}
|
||||
|
||||
TEST_F(CoreAPIsStandardTest, ExecutionSessionFailQuery) {
|
||||
bool OnResolutionRun = false;
|
||||
bool OnReadyRun = false;
|
||||
|
||||
auto OnResolution =
|
||||
[&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) {
|
||||
EXPECT_FALSE(!!Result) << "Resolution unexpectedly returned success";
|
||||
auto Msg = toString(Result.takeError());
|
||||
EXPECT_EQ(Msg, "xyz") << "Resolution returned incorrect result";
|
||||
OnResolutionRun = true;
|
||||
};
|
||||
auto OnResolution = [&](Expected<SymbolMap> Result) {
|
||||
EXPECT_FALSE(!!Result) << "Resolution unexpectedly returned success";
|
||||
auto Msg = toString(Result.takeError());
|
||||
EXPECT_EQ(Msg, "xyz") << "Resolution returned incorrect result";
|
||||
OnResolutionRun = true;
|
||||
};
|
||||
auto OnReady = [&](Error Err) {
|
||||
cantFail(std::move(Err));
|
||||
OnReadyRun = true;
|
||||
@ -111,62 +117,28 @@ TEST_F(CoreAPIsStandardTest, ExecutionSessionFailQuery) {
|
||||
|
||||
AsynchronousSymbolQuery Q(SymbolNameSet({Foo}), OnResolution, OnReady);
|
||||
|
||||
ES.failQuery(Q, make_error<StringError>("xyz", inconvertibleErrorCode()));
|
||||
ES.legacyFailQuery(Q,
|
||||
make_error<StringError>("xyz", inconvertibleErrorCode()));
|
||||
|
||||
EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run";
|
||||
EXPECT_FALSE(OnReadyRun) << "OnReady unexpectedly run";
|
||||
}
|
||||
|
||||
TEST_F(CoreAPIsStandardTest, SimpleAsynchronousSymbolQueryAgainstVSO) {
|
||||
bool OnResolutionRun = false;
|
||||
TEST_F(CoreAPIsStandardTest, EmptyLookup) {
|
||||
bool OnResolvedRun = false;
|
||||
bool OnReadyRun = false;
|
||||
|
||||
auto OnResolution =
|
||||
[&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) {
|
||||
EXPECT_TRUE(!!Result) << "Query unexpectedly returned error";
|
||||
auto &Resolved = Result->Symbols;
|
||||
auto I = Resolved.find(Foo);
|
||||
EXPECT_NE(I, Resolved.end()) << "Could not find symbol definition";
|
||||
EXPECT_EQ(I->second.getAddress(), FooSym.getAddress())
|
||||
<< "Resolution returned incorrect result";
|
||||
OnResolutionRun = true;
|
||||
};
|
||||
auto OnResolution = [&](Expected<SymbolMap> Result) {
|
||||
cantFail(std::move(Result));
|
||||
OnResolvedRun = true;
|
||||
};
|
||||
|
||||
auto OnReady = [&](Error Err) {
|
||||
cantFail(std::move(Err));
|
||||
OnReadyRun = true;
|
||||
};
|
||||
|
||||
SymbolNameSet Names({Foo});
|
||||
|
||||
auto Q =
|
||||
std::make_shared<AsynchronousSymbolQuery>(Names, OnResolution, OnReady);
|
||||
|
||||
auto Defs = absoluteSymbols({{Foo, FooSym}});
|
||||
cantFail(V.define(Defs));
|
||||
assert(Defs == nullptr && "Defs should have been accepted");
|
||||
V.lookup(Q, Names);
|
||||
|
||||
EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run";
|
||||
EXPECT_TRUE(OnReadyRun) << "OnReady was not run";
|
||||
}
|
||||
|
||||
TEST_F(CoreAPIsStandardTest, EmptyVSOAndQueryLookup) {
|
||||
bool OnResolvedRun = false;
|
||||
bool OnReadyRun = false;
|
||||
|
||||
auto Q = std::make_shared<AsynchronousSymbolQuery>(
|
||||
SymbolNameSet(),
|
||||
[&](Expected<AsynchronousSymbolQuery::ResolutionResult> RR) {
|
||||
cantFail(std::move(RR));
|
||||
OnResolvedRun = true;
|
||||
},
|
||||
[&](Error Err) {
|
||||
cantFail(std::move(Err));
|
||||
OnReadyRun = true;
|
||||
});
|
||||
|
||||
V.lookup(std::move(Q), {});
|
||||
ES.lookup({&V}, {}, OnResolution, OnReady, NoDependenciesToRegister);
|
||||
|
||||
EXPECT_TRUE(OnResolvedRun) << "OnResolved was not run for empty query";
|
||||
EXPECT_TRUE(OnReadyRun) << "OnReady was not run for empty query";
|
||||
@ -182,8 +154,8 @@ TEST_F(CoreAPIsStandardTest, ChainedVSOLookup) {
|
||||
|
||||
auto Q = std::make_shared<AsynchronousSymbolQuery>(
|
||||
SymbolNameSet({Foo}),
|
||||
[&](Expected<AsynchronousSymbolQuery::ResolutionResult> RR) {
|
||||
cantFail(std::move(RR));
|
||||
[&](Expected<SymbolMap> Result) {
|
||||
cantFail(std::move(Result));
|
||||
OnResolvedRun = true;
|
||||
},
|
||||
[&](Error Err) {
|
||||
@ -191,7 +163,7 @@ TEST_F(CoreAPIsStandardTest, ChainedVSOLookup) {
|
||||
OnReadyRun = true;
|
||||
});
|
||||
|
||||
V2.lookup(Q, V.lookup(Q, {Foo}));
|
||||
V2.legacyLookup(Q, V.legacyLookup(Q, {Foo}));
|
||||
|
||||
EXPECT_TRUE(OnResolvedRun) << "OnResolved was not run for empty query";
|
||||
EXPECT_TRUE(OnReadyRun) << "OnReady was not run for empty query";
|
||||
@ -268,20 +240,15 @@ TEST_F(CoreAPIsStandardTest, TestTrivialCircularDependency) {
|
||||
cantFail(V.define(FooMU));
|
||||
|
||||
bool FooReady = false;
|
||||
auto Q =
|
||||
std::make_shared<AsynchronousSymbolQuery>(
|
||||
SymbolNameSet({ Foo }),
|
||||
[](Expected<AsynchronousSymbolQuery::ResolutionResult> R) {
|
||||
cantFail(std::move(R));
|
||||
},
|
||||
[&](Error Err) {
|
||||
cantFail(std::move(Err));
|
||||
FooReady = true;
|
||||
});
|
||||
auto OnResolution = [](Expected<SymbolMap> R) { cantFail(std::move(R)); };
|
||||
auto OnReady = [&](Error Err) {
|
||||
cantFail(std::move(Err));
|
||||
FooReady = true;
|
||||
};
|
||||
|
||||
V.lookup(std::move(Q), { Foo });
|
||||
ES.lookup({&V}, {Foo}, std::move(OnResolution), std::move(OnReady),
|
||||
NoDependenciesToRegister);
|
||||
|
||||
FooR->addDependencies({{&V, {Foo}}});
|
||||
FooR->resolve({{Foo, FooSym}});
|
||||
FooR->finalize();
|
||||
|
||||
@ -323,54 +290,52 @@ TEST_F(CoreAPIsStandardTest, TestCircularDependenceInOneVSO) {
|
||||
// Query each of the symbols to trigger materialization.
|
||||
bool FooResolved = false;
|
||||
bool FooReady = false;
|
||||
auto FooQ = std::make_shared<AsynchronousSymbolQuery>(
|
||||
SymbolNameSet({Foo}),
|
||||
[&](Expected<AsynchronousSymbolQuery::ResolutionResult> RR) {
|
||||
cantFail(std::move(RR));
|
||||
FooResolved = true;
|
||||
},
|
||||
[&](Error Err) {
|
||||
cantFail(std::move(Err));
|
||||
FooReady = true;
|
||||
});
|
||||
{
|
||||
auto Unresolved = V.lookup(FooQ, {Foo});
|
||||
EXPECT_TRUE(Unresolved.empty()) << "Failed to resolve \"Foo\"";
|
||||
}
|
||||
|
||||
auto OnFooResolution = [&](Expected<SymbolMap> Result) {
|
||||
cantFail(std::move(Result));
|
||||
FooResolved = true;
|
||||
};
|
||||
|
||||
auto OnFooReady = [&](Error Err) {
|
||||
cantFail(std::move(Err));
|
||||
FooReady = true;
|
||||
};
|
||||
|
||||
// Issue a lookup for Foo. Use NoDependenciesToRegister: We're going to add
|
||||
// the dependencies manually below.
|
||||
ES.lookup({&V}, {Foo}, std::move(OnFooResolution), std::move(OnFooReady),
|
||||
NoDependenciesToRegister);
|
||||
|
||||
bool BarResolved = false;
|
||||
bool BarReady = false;
|
||||
auto BarQ = std::make_shared<AsynchronousSymbolQuery>(
|
||||
SymbolNameSet({Bar}),
|
||||
[&](Expected<AsynchronousSymbolQuery::ResolutionResult> RR) {
|
||||
cantFail(std::move(RR));
|
||||
BarResolved = true;
|
||||
},
|
||||
[&](Error Err) {
|
||||
cantFail(std::move(Err));
|
||||
BarReady = true;
|
||||
});
|
||||
{
|
||||
auto Unresolved = V.lookup(BarQ, {Bar});
|
||||
EXPECT_TRUE(Unresolved.empty()) << "Failed to resolve \"Bar\"";
|
||||
}
|
||||
auto OnBarResolution = [&](Expected<SymbolMap> Result) {
|
||||
cantFail(std::move(Result));
|
||||
BarResolved = true;
|
||||
};
|
||||
|
||||
auto OnBarReady = [&](Error Err) {
|
||||
cantFail(std::move(Err));
|
||||
BarReady = true;
|
||||
};
|
||||
|
||||
ES.lookup({&V}, {Bar}, std::move(OnBarResolution), std::move(OnBarReady),
|
||||
NoDependenciesToRegister);
|
||||
|
||||
bool BazResolved = false;
|
||||
bool BazReady = false;
|
||||
auto BazQ = std::make_shared<AsynchronousSymbolQuery>(
|
||||
SymbolNameSet({Baz}),
|
||||
[&](Expected<AsynchronousSymbolQuery::ResolutionResult> RR) {
|
||||
cantFail(std::move(RR));
|
||||
BazResolved = true;
|
||||
},
|
||||
[&](Error Err) {
|
||||
cantFail(std::move(Err));
|
||||
BazReady = true;
|
||||
});
|
||||
{
|
||||
auto Unresolved = V.lookup(BazQ, {Baz});
|
||||
EXPECT_TRUE(Unresolved.empty()) << "Failed to resolve \"Baz\"";
|
||||
}
|
||||
|
||||
auto OnBazResolution = [&](Expected<SymbolMap> Result) {
|
||||
cantFail(std::move(Result));
|
||||
BazResolved = true;
|
||||
};
|
||||
|
||||
auto OnBazReady = [&](Error Err) {
|
||||
cantFail(std::move(Err));
|
||||
BazReady = true;
|
||||
};
|
||||
|
||||
ES.lookup({&V}, {Baz}, std::move(OnBazResolution), std::move(OnBazReady),
|
||||
NoDependenciesToRegister);
|
||||
|
||||
// Add a circular dependency: Foo -> Bar, Bar -> Baz, Baz -> Foo.
|
||||
FooR->addDependencies({{&V, SymbolNameSet({Bar})}});
|
||||
@ -478,28 +443,23 @@ TEST_F(CoreAPIsStandardTest, AddAndMaterializeLazySymbol) {
|
||||
bool OnResolutionRun = false;
|
||||
bool OnReadyRun = false;
|
||||
|
||||
auto OnResolution =
|
||||
[&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) {
|
||||
EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error";
|
||||
auto I = Result->Symbols.find(Foo);
|
||||
EXPECT_NE(I, Result->Symbols.end())
|
||||
<< "Could not find symbol definition";
|
||||
EXPECT_EQ(I->second.getAddress(), FooSym.getAddress())
|
||||
<< "Resolution returned incorrect result";
|
||||
OnResolutionRun = true;
|
||||
};
|
||||
auto OnResolution = [&](Expected<SymbolMap> Result) {
|
||||
EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error";
|
||||
auto I = Result->find(Foo);
|
||||
EXPECT_NE(I, Result->end()) << "Could not find symbol definition";
|
||||
EXPECT_EQ(I->second.getAddress(), FooSym.getAddress())
|
||||
<< "Resolution returned incorrect result";
|
||||
OnResolutionRun = true;
|
||||
};
|
||||
|
||||
auto OnReady = [&](Error Err) {
|
||||
cantFail(std::move(Err));
|
||||
OnReadyRun = true;
|
||||
};
|
||||
|
||||
auto Q =
|
||||
std::make_shared<AsynchronousSymbolQuery>(Names, OnResolution, OnReady);
|
||||
ES.lookup({&V}, Names, std::move(OnResolution), std::move(OnReady),
|
||||
NoDependenciesToRegister);
|
||||
|
||||
auto Unresolved = V.lookup(std::move(Q), Names);
|
||||
|
||||
EXPECT_TRUE(Unresolved.empty()) << "Could not find Foo in dylib";
|
||||
EXPECT_TRUE(FooMaterialized) << "Foo was not materialized";
|
||||
EXPECT_TRUE(BarDiscarded) << "Bar was not discarded";
|
||||
EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run";
|
||||
@ -714,13 +674,14 @@ TEST_F(CoreAPIsStandardTest, TestMaterializeWeakSymbol) {
|
||||
});
|
||||
|
||||
cantFail(V.define(MU));
|
||||
auto Q = std::make_shared<AsynchronousSymbolQuery>(
|
||||
SymbolNameSet({Foo}),
|
||||
[](Expected<AsynchronousSymbolQuery::ResolutionResult> R) {
|
||||
cantFail(std::move(R));
|
||||
},
|
||||
[](Error Err) { cantFail(std::move(Err)); });
|
||||
V.lookup(std::move(Q), SymbolNameSet({Foo}));
|
||||
auto OnResolution = [](Expected<SymbolMap> Result) {
|
||||
cantFail(std::move(Result));
|
||||
};
|
||||
|
||||
auto OnReady = [](Error Err) { cantFail(std::move(Err)); };
|
||||
|
||||
ES.lookup({&V}, {Foo}, std::move(OnResolution), std::move(OnReady),
|
||||
NoDependenciesToRegister);
|
||||
|
||||
auto MU2 = llvm::make_unique<SimpleMaterializationUnit>(
|
||||
SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}}),
|
||||
|
@ -24,7 +24,7 @@ TEST_F(LegacyAPIsStandardTest, TestLambdaSymbolResolver) {
|
||||
auto Resolver = createSymbolResolver(
|
||||
[&](const SymbolNameSet &Symbols) { return V.lookupFlags(Symbols); },
|
||||
[&](std::shared_ptr<AsynchronousSymbolQuery> Q, SymbolNameSet Symbols) {
|
||||
return V.lookup(std::move(Q), Symbols);
|
||||
return V.legacyLookup(std::move(Q), Symbols);
|
||||
});
|
||||
|
||||
SymbolNameSet Symbols({Foo, Bar, Baz});
|
||||
@ -42,21 +42,17 @@ TEST_F(LegacyAPIsStandardTest, TestLambdaSymbolResolver) {
|
||||
|
||||
bool OnResolvedRun = false;
|
||||
|
||||
auto OnResolved =
|
||||
[&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) {
|
||||
OnResolvedRun = true;
|
||||
EXPECT_TRUE(!!Result) << "Unexpected error";
|
||||
EXPECT_EQ(Result->Symbols.size(), 2U)
|
||||
<< "Unexpected number of resolved symbols";
|
||||
EXPECT_EQ(Result->Symbols.count(Foo), 1U)
|
||||
<< "Missing lookup result for foo";
|
||||
EXPECT_EQ(Result->Symbols.count(Bar), 1U)
|
||||
<< "Missing lookup result for bar";
|
||||
EXPECT_EQ(Result->Symbols[Foo].getAddress(), FooSym.getAddress())
|
||||
<< "Incorrect address for foo";
|
||||
EXPECT_EQ(Result->Symbols[Bar].getAddress(), BarSym.getAddress())
|
||||
<< "Incorrect address for bar";
|
||||
};
|
||||
auto OnResolved = [&](Expected<SymbolMap> Result) {
|
||||
OnResolvedRun = true;
|
||||
EXPECT_TRUE(!!Result) << "Unexpected error";
|
||||
EXPECT_EQ(Result->size(), 2U) << "Unexpected number of resolved symbols";
|
||||
EXPECT_EQ(Result->count(Foo), 1U) << "Missing lookup result for foo";
|
||||
EXPECT_EQ(Result->count(Bar), 1U) << "Missing lookup result for bar";
|
||||
EXPECT_EQ((*Result)[Foo].getAddress(), FooSym.getAddress())
|
||||
<< "Incorrect address for foo";
|
||||
EXPECT_EQ((*Result)[Bar].getAddress(), BarSym.getAddress())
|
||||
<< "Incorrect address for bar";
|
||||
};
|
||||
auto OnReady = [&](Error Err) {
|
||||
EXPECT_FALSE(!!Err) << "Finalization should never fail in this test";
|
||||
};
|
||||
@ -85,7 +81,7 @@ TEST(LegacyAPIInteropTest, QueryAgainstVSO) {
|
||||
|
||||
auto Lookup = [&](std::shared_ptr<AsynchronousSymbolQuery> Query,
|
||||
SymbolNameSet Symbols) {
|
||||
return V.lookup(std::move(Query), Symbols);
|
||||
return V.legacyLookup(std::move(Query), Symbols);
|
||||
};
|
||||
|
||||
auto UnderlyingResolver =
|
||||
@ -158,22 +154,18 @@ TEST(LegacyAPIInteropTset, LegacyLookupHelpersFn) {
|
||||
|
||||
bool OnResolvedRun = false;
|
||||
bool OnReadyRun = false;
|
||||
auto OnResolved =
|
||||
[&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) {
|
||||
OnResolvedRun = true;
|
||||
EXPECT_TRUE(!!Result) << "lookuWithLegacy failed to resolve";
|
||||
auto OnResolved = [&](Expected<SymbolMap> Result) {
|
||||
OnResolvedRun = true;
|
||||
EXPECT_TRUE(!!Result) << "lookuWithLegacy failed to resolve";
|
||||
|
||||
auto &Resolved = Result->Symbols;
|
||||
EXPECT_EQ(Resolved.size(), 2U) << "Wrong number of symbols resolved";
|
||||
EXPECT_EQ(Resolved.count(Foo), 1U) << "Result for foo missing";
|
||||
EXPECT_EQ(Resolved.count(Bar), 1U) << "Result for bar missing";
|
||||
EXPECT_EQ(Resolved[Foo].getAddress(), FooAddr)
|
||||
<< "Wrong address for foo";
|
||||
EXPECT_EQ(Resolved[Foo].getFlags(), FooFlags) << "Wrong flags for foo";
|
||||
EXPECT_EQ(Resolved[Bar].getAddress(), BarAddr)
|
||||
<< "Wrong address for bar";
|
||||
EXPECT_EQ(Resolved[Bar].getFlags(), BarFlags) << "Wrong flags for bar";
|
||||
};
|
||||
EXPECT_EQ(Result->size(), 2U) << "Wrong number of symbols resolved";
|
||||
EXPECT_EQ(Result->count(Foo), 1U) << "Result for foo missing";
|
||||
EXPECT_EQ(Result->count(Bar), 1U) << "Result for bar missing";
|
||||
EXPECT_EQ((*Result)[Foo].getAddress(), FooAddr) << "Wrong address for foo";
|
||||
EXPECT_EQ((*Result)[Foo].getFlags(), FooFlags) << "Wrong flags for foo";
|
||||
EXPECT_EQ((*Result)[Bar].getAddress(), BarAddr) << "Wrong address for bar";
|
||||
EXPECT_EQ((*Result)[Bar].getFlags(), BarFlags) << "Wrong flags for bar";
|
||||
};
|
||||
auto OnReady = [&](Error Err) {
|
||||
EXPECT_FALSE(!!Err) << "Finalization unexpectedly failed";
|
||||
OnReadyRun = true;
|
||||
|
Loading…
Reference in New Issue
Block a user