|
@@ -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);
|
|
|
-
|
|
|
- // 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);
|
|
|
+ auto RegisterDependencies = [&](const SymbolDependenceMap &Deps) {
|
|
|
+ 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");
|
|
|
-
|
|
|
- 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 &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);
|
|
|
+ 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");
|
|
|
+
|
|
|
+ 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];
|
|
|
+
|
|
|
+ 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.
|