summaryrefslogtreecommitdiffstats
path: root/llvm/lib/ExecutionEngine/Orc
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/ExecutionEngine/Orc')
-rw-r--r--llvm/lib/ExecutionEngine/Orc/Core.cpp406
-rw-r--r--llvm/lib/ExecutionEngine/Orc/IndirectionUtils.cpp5
-rw-r--r--llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp5
-rw-r--r--llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp12
-rw-r--r--llvm/lib/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.cpp11
5 files changed, 339 insertions, 100 deletions
diff --git a/llvm/lib/ExecutionEngine/Orc/Core.cpp b/llvm/lib/ExecutionEngine/Orc/Core.cpp
index 5d1e574ea96..ecfa116a646 100644
--- a/llvm/lib/ExecutionEngine/Orc/Core.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/Core.cpp
@@ -151,6 +151,8 @@ raw_ostream &operator<<(raw_ostream &OS, const SymbolNameSet &Symbols) {
}
raw_ostream &operator<<(raw_ostream &OS, const JITSymbolFlags &Flags) {
+ if (Flags.hasError())
+ OS << "[*ERROR*]";
if (Flags.isCallable())
OS << "[Callable]";
else
@@ -244,9 +246,10 @@ raw_ostream &operator<<(raw_ostream &OS, const SymbolState &S) {
llvm_unreachable("Invalid state");
}
-FailedToMaterialize::FailedToMaterialize(SymbolNameSet Symbols)
+FailedToMaterialize::FailedToMaterialize(
+ std::shared_ptr<SymbolDependenceMap> Symbols)
: Symbols(std::move(Symbols)) {
- assert(!this->Symbols.empty() && "Can not fail to resolve an empty set");
+ assert(!this->Symbols->empty() && "Can not fail to resolve an empty set");
}
std::error_code FailedToMaterialize::convertToErrorCode() const {
@@ -254,7 +257,7 @@ std::error_code FailedToMaterialize::convertToErrorCode() const {
}
void FailedToMaterialize::log(raw_ostream &OS) const {
- OS << "Failed to materialize symbols: " << Symbols;
+ OS << "Failed to materialize symbols: " << *Symbols;
}
SymbolsNotFound::SymbolsNotFound(SymbolNameSet Symbols)
@@ -367,7 +370,7 @@ SymbolNameSet MaterializationResponsibility::getRequestedSymbols() const {
return JD.getRequestedSymbols(SymbolFlags);
}
-void MaterializationResponsibility::notifyResolved(const SymbolMap &Symbols) {
+Error MaterializationResponsibility::notifyResolved(const SymbolMap &Symbols) {
LLVM_DEBUG({
dbgs() << "In " << JD.getName() << " resolving " << Symbols << "\n";
});
@@ -385,17 +388,20 @@ void MaterializationResponsibility::notifyResolved(const SymbolMap &Symbols) {
}
#endif
- JD.resolve(Symbols);
+ return JD.resolve(Symbols);
}
-void MaterializationResponsibility::notifyEmitted() {
+Error MaterializationResponsibility::notifyEmitted() {
LLVM_DEBUG({
dbgs() << "In " << JD.getName() << " emitting " << SymbolFlags << "\n";
});
- JD.emit(SymbolFlags);
+ if (auto Err = JD.emit(SymbolFlags))
+ return Err;
+
SymbolFlags.clear();
+ return Error::success();
}
Error MaterializationResponsibility::defineMaterializing(
@@ -417,11 +423,7 @@ void MaterializationResponsibility::failMaterialization() {
<< SymbolFlags << "\n";
});
- SymbolNameSet FailedSymbols;
- for (auto &KV : SymbolFlags)
- FailedSymbols.insert(KV.first);
-
- JD.notifyFailed(FailedSymbols);
+ JD.notifyFailed(SymbolFlags);
SymbolFlags.clear();
}
@@ -485,8 +487,9 @@ StringRef AbsoluteSymbolsMaterializationUnit::getName() const {
void AbsoluteSymbolsMaterializationUnit::materialize(
MaterializationResponsibility R) {
- R.notifyResolved(Symbols);
- R.notifyEmitted();
+ // No dependencies, so these calls can't fail.
+ cantFail(R.notifyResolved(Symbols));
+ cantFail(R.notifyEmitted());
}
void AbsoluteSymbolsMaterializationUnit::discard(const JITDylib &JD,
@@ -625,6 +628,7 @@ void ReExportsMaterializationUnit::materialize(
};
auto OnComplete = [QueryInfo](Expected<SymbolMap> Result) {
+ auto &ES = QueryInfo->R.getTargetJITDylib().getExecutionSession();
if (Result) {
SymbolMap ResolutionMap;
for (auto &KV : QueryInfo->Aliases) {
@@ -633,10 +637,17 @@ void ReExportsMaterializationUnit::materialize(
ResolutionMap[KV.first] = JITEvaluatedSymbol(
(*Result)[KV.second.Aliasee].getAddress(), KV.second.AliasFlags);
}
- QueryInfo->R.notifyResolved(ResolutionMap);
- QueryInfo->R.notifyEmitted();
+ if (auto Err = QueryInfo->R.notifyResolved(ResolutionMap)) {
+ ES.reportError(std::move(Err));
+ QueryInfo->R.failMaterialization();
+ return;
+ }
+ if (auto Err = QueryInfo->R.notifyEmitted()) {
+ ES.reportError(std::move(Err));
+ QueryInfo->R.failMaterialization();
+ return;
+ }
} else {
- auto &ES = QueryInfo->R.getTargetJITDylib().getExecutionSession();
ES.reportError(Result.takeError());
QueryInfo->R.failMaterialization();
}
@@ -830,29 +841,115 @@ JITDylib::getRequestedSymbols(const SymbolFlagsMap &SymbolFlags) const {
});
}
+JITDylib::AsynchronousSymbolQuerySet
+JITDylib::failSymbol(const SymbolStringPtr &Name) {
+ assert(Symbols.count(Name) && "Name not in symbol table");
+ assert(Symbols[Name].getFlags().hasError() &&
+ "Failing symbol not in the error state");
+
+ auto MII = MaterializingInfos.find(Name);
+ if (MII == MaterializingInfos.end())
+ return AsynchronousSymbolQuerySet();
+
+ auto &MI = MII->second;
+
+ // Visit all dependants.
+ for (auto &KV : MI.Dependants) {
+ auto &DependantJD = *KV.first;
+ for (auto &DependantName : KV.second) {
+ assert(DependantJD.Symbols.count(DependantName) &&
+ "No symbol with DependantName in DependantJD");
+ auto &DependantSymTabEntry = DependantJD.Symbols[DependantName];
+ DependantSymTabEntry.setFlags(DependantSymTabEntry.getFlags() |
+ JITSymbolFlags::HasError);
+
+ assert(DependantJD.MaterializingInfos.count(DependantName) &&
+ "Dependant symbol does not have MaterializingInfo?");
+ auto &DependantMI = DependantJD.MaterializingInfos[DependantName];
+
+ assert(DependantMI.UnemittedDependencies.count(this) &&
+ "No unemitted dependency recorded for this JD?");
+ auto UnemittedDepsI = DependantMI.UnemittedDependencies.find(this);
+ assert(UnemittedDepsI != DependantMI.UnemittedDependencies.end() &&
+ "No unemitted dependency on this JD");
+ assert(UnemittedDepsI->second.count(Name) &&
+ "No unemitted dependency on symbol Name in this JD");
+
+ UnemittedDepsI->second.erase(Name);
+ if (UnemittedDepsI->second.empty())
+ DependantMI.UnemittedDependencies.erase(UnemittedDepsI);
+ }
+ }
+
+ // Visit all unemitted dependencies and disconnect from them.
+ for (auto &KV : MI.UnemittedDependencies) {
+ auto &DependencyJD = *KV.first;
+ for (auto &DependencyName : KV.second) {
+ assert(DependencyJD.MaterializingInfos.count(DependencyName) &&
+ "Dependency does not have MaterializingInfo");
+ auto &DependencyMI = DependencyJD.MaterializingInfos[DependencyName];
+ auto DependantsI = DependencyMI.Dependants.find(this);
+ assert(DependantsI != DependencyMI.Dependants.end() &&
+ "No dependnts entry recorded for this JD");
+ assert(DependantsI->second.count(Name) &&
+ "No dependants entry recorded for Name");
+ DependantsI->second.erase(Name);
+ if (DependantsI->second.empty())
+ DependencyMI.Dependants.erase(DependantsI);
+ }
+ }
+
+ AsynchronousSymbolQuerySet QueriesToFail;
+ for (auto &Q : MI.takeAllPendingQueries())
+ QueriesToFail.insert(std::move(Q));
+ return QueriesToFail;
+}
+
void JITDylib::addDependencies(const SymbolStringPtr &Name,
const SymbolDependenceMap &Dependencies) {
assert(Symbols.count(Name) && "Name not in symbol table");
assert(Symbols[Name].isInMaterializationPhase() &&
"Can not add dependencies for a symbol that is not materializing");
+ // If Name is already in an error state then just bail out.
+ if (Symbols[Name].getFlags().hasError())
+ return;
+
auto &MI = MaterializingInfos[Name];
assert(!MI.IsEmitted && "Can not add dependencies to an emitted symbol");
+ bool DependsOnSymbolInErrorState = false;
+
+ // Register dependencies, record whether any depenendency is in the error
+ // state.
for (auto &KV : Dependencies) {
assert(KV.first && "Null JITDylib in dependency?");
auto &OtherJITDylib = *KV.first;
auto &DepsOnOtherJITDylib = MI.UnemittedDependencies[&OtherJITDylib];
for (auto &OtherSymbol : KV.second) {
+
+ // Check the sym entry for the dependency.
+ auto SymI = OtherJITDylib.Symbols.find(OtherSymbol);
+
#ifndef NDEBUG
// Assert that this symbol exists and has not been emitted already.
- auto SymI = OtherJITDylib.Symbols.find(OtherSymbol);
assert(SymI != OtherJITDylib.Symbols.end() &&
(SymI->second.getState() != SymbolState::Ready &&
"Dependency on emitted symbol"));
#endif
+ // If the dependency is in an error state then note this and continue,
+ // we will move this symbol to the error state below.
+ if (SymI->second.getFlags().hasError()) {
+ DependsOnSymbolInErrorState = true;
+ continue;
+ }
+
+ // If the dependency was not in the error state then add it to
+ // our list of dependencies.
+ assert(OtherJITDylib.MaterializingInfos.count(OtherSymbol) &&
+ "No MaterializingInfo for dependency");
auto &OtherMI = OtherJITDylib.MaterializingInfos[OtherSymbol];
if (OtherMI.IsEmitted)
@@ -866,63 +963,133 @@ void JITDylib::addDependencies(const SymbolStringPtr &Name,
if (DepsOnOtherJITDylib.empty())
MI.UnemittedDependencies.erase(&OtherJITDylib);
}
+
+ // If this symbol dependended on any symbols in the error state then move
+ // this symbol to the error state too.
+ if (DependsOnSymbolInErrorState)
+ Symbols[Name].setFlags(Symbols[Name].getFlags() | JITSymbolFlags::HasError);
}
-void JITDylib::resolve(const SymbolMap &Resolved) {
- auto CompletedQueries = ES.runSessionLocked([&, this]() {
- AsynchronousSymbolQuerySet CompletedQueries;
+Error JITDylib::resolve(const SymbolMap &Resolved) {
+ SymbolNameSet SymbolsInErrorState;
+ AsynchronousSymbolQuerySet CompletedQueries;
+
+ ES.runSessionLocked([&, this]() {
+ struct WorklistEntry {
+ SymbolTable::iterator SymI;
+ JITEvaluatedSymbol ResolvedSym;
+ };
+
+ std::vector<WorklistEntry> Worklist;
+ Worklist.reserve(Resolved.size());
+
+ // Build worklist and check for any symbols in the error state.
for (const auto &KV : Resolved) {
- auto &Name = KV.first;
- auto Sym = KV.second;
- auto I = Symbols.find(Name);
+ assert(!KV.second.getFlags().hasError() &&
+ "Resolution result can not have error flag set");
- assert(I != Symbols.end() && "Symbol not found");
- assert(!I->second.hasMaterializerAttached() &&
+ auto SymI = Symbols.find(KV.first);
+
+ assert(SymI != Symbols.end() && "Symbol not found");
+ assert(!SymI->second.hasMaterializerAttached() &&
"Resolving symbol with materializer attached?");
- assert(I->second.getState() == SymbolState::Materializing &&
+ assert(SymI->second.getState() == SymbolState::Materializing &&
"Symbol should be materializing");
- assert(I->second.getAddress() == 0 && "Symbol has already been resolved");
+ assert(SymI->second.getAddress() == 0 &&
+ "Symbol has already been resolved");
+
+ if (SymI->second.getFlags().hasError())
+ SymbolsInErrorState.insert(KV.first);
+ else {
+ assert((KV.second.getFlags() & ~JITSymbolFlags::Weak) ==
+ (SymI->second.getFlags() & ~JITSymbolFlags::Weak) &&
+ "Resolved flags should match the declared flags");
+
+ Worklist.push_back({SymI, KV.second});
+ }
+ }
+
+ // If any symbols were in the error state then bail out.
+ if (!SymbolsInErrorState.empty())
+ return;
+
+ while (!Worklist.empty()) {
+ auto SymI = Worklist.back().SymI;
+ auto ResolvedSym = Worklist.back().ResolvedSym;
+ Worklist.pop_back();
- assert((Sym.getFlags() & ~JITSymbolFlags::Weak) ==
- (I->second.getFlags() & ~JITSymbolFlags::Weak) &&
- "Resolved flags should match the declared flags");
+ auto &Name = SymI->first;
- // Once resolved, symbols can never be weak.
- JITSymbolFlags ResolvedFlags = Sym.getFlags();
+ // Resolved symbols can not be weak: discard the weak flag.
+ JITSymbolFlags ResolvedFlags = ResolvedSym.getFlags();
ResolvedFlags &= ~JITSymbolFlags::Weak;
- I->second.setAddress(Sym.getAddress());
- I->second.setFlags(ResolvedFlags);
- I->second.setState(SymbolState::Resolved);
+ SymI->second.setAddress(ResolvedSym.getAddress());
+ SymI->second.setFlags(ResolvedFlags);
+ SymI->second.setState(SymbolState::Resolved);
auto &MI = MaterializingInfos[Name];
for (auto &Q : MI.takeQueriesMeeting(SymbolState::Resolved)) {
- Q->notifySymbolMetRequiredState(Name, Sym);
+ Q->notifySymbolMetRequiredState(Name, ResolvedSym);
if (Q->isComplete())
CompletedQueries.insert(std::move(Q));
}
}
-
- return CompletedQueries;
});
+ assert((SymbolsInErrorState.empty() || CompletedQueries.empty()) &&
+ "Can't fail symbols and completed queries at the same time");
+
+ // If we failed any symbols then return an error.
+ if (!SymbolsInErrorState.empty()) {
+ auto FailedSymbolsDepMap = std::make_shared<SymbolDependenceMap>();
+ (*FailedSymbolsDepMap)[this] = std::move(SymbolsInErrorState);
+ return make_error<FailedToMaterialize>(std::move(FailedSymbolsDepMap));
+ }
+
+ // Otherwise notify all the completed queries.
for (auto &Q : CompletedQueries) {
assert(Q->isComplete() && "Q not completed");
Q->handleComplete();
}
+
+ return Error::success();
}
-void JITDylib::emit(const SymbolFlagsMap &Emitted) {
- auto CompletedQueries = ES.runSessionLocked([&, this]() {
- AsynchronousSymbolQuerySet CompletedQueries;
+Error JITDylib::emit(const SymbolFlagsMap &Emitted) {
+ AsynchronousSymbolQuerySet CompletedQueries;
+ SymbolNameSet SymbolsInErrorState;
+ ES.runSessionLocked([&, this]() {
+ std::vector<SymbolTable::iterator> Worklist;
+
+ // Scan to build worklist, record any symbols in the erorr state.
for (const auto &KV : Emitted) {
- const auto &Name = KV.first;
+ auto &Name = KV.first;
+
+ auto SymI = Symbols.find(Name);
+ assert(SymI != Symbols.end() && "No symbol table entry for Name");
+
+ if (SymI->second.getFlags().hasError())
+ SymbolsInErrorState.insert(Name);
+ else
+ Worklist.push_back(SymI);
+ }
+
+ // If any symbols were in the error state then bail out.
+ if (!SymbolsInErrorState.empty())
+ return;
+
+ // Otherwise update dependencies and move to the emitted state.
+ while (!Worklist.empty()) {
+ auto SymI = Worklist.back();
+ Worklist.pop_back();
+
+ auto &Name = SymI->first;
auto MII = MaterializingInfos.find(Name);
assert(MII != MaterializingInfos.end() &&
"Missing MaterializingInfo entry");
-
auto &MI = MII->second;
// For each dependant, transfer this node's emitted dependencies to
@@ -939,8 +1106,12 @@ void JITDylib::emit(const SymbolFlagsMap &Emitted) {
auto &DependantMI = DependantMII->second;
// Remove the dependant's dependency on this node.
+ assert(DependantMI.UnemittedDependencies.count(this) &&
+ "Dependant does not have an unemitted dependencies record for "
+ "this JITDylib");
assert(DependantMI.UnemittedDependencies[this].count(Name) &&
"Dependant does not count this symbol as a dependency?");
+
DependantMI.UnemittedDependencies[this].erase(Name);
if (DependantMI.UnemittedDependencies[this].empty())
DependantMI.UnemittedDependencies.erase(this);
@@ -980,8 +1151,6 @@ void JITDylib::emit(const SymbolFlagsMap &Emitted) {
MI.IsEmitted = true;
if (MI.UnemittedDependencies.empty()) {
- auto SymI = Symbols.find(Name);
- assert(SymI != Symbols.end() && "Symbol has no entry in Symbols table");
SymI->second.setState(SymbolState::Ready);
for (auto &Q : MI.takeQueriesMeeting(SymbolState::Ready)) {
Q->notifySymbolMetRequiredState(Name, SymI->second.getSymbol());
@@ -992,61 +1161,98 @@ void JITDylib::emit(const SymbolFlagsMap &Emitted) {
MaterializingInfos.erase(MII);
}
}
-
- return CompletedQueries;
});
+ assert((SymbolsInErrorState.empty() || CompletedQueries.empty()) &&
+ "Can't fail symbols and completed queries at the same time");
+
+ // If we failed any symbols then return an error.
+ if (!SymbolsInErrorState.empty()) {
+ auto FailedSymbolsDepMap = std::make_shared<SymbolDependenceMap>();
+ (*FailedSymbolsDepMap)[this] = std::move(SymbolsInErrorState);
+ return make_error<FailedToMaterialize>(std::move(FailedSymbolsDepMap));
+ }
+
+ // Otherwise notify all the completed queries.
for (auto &Q : CompletedQueries) {
assert(Q->isComplete() && "Q is not complete");
Q->handleComplete();
}
+
+ return Error::success();
}
-void JITDylib::notifyFailed(const SymbolNameSet &FailedSymbols) {
+void JITDylib::notifyFailed(const SymbolFlagsMap &FailedSymbols) {
+ AsynchronousSymbolQuerySet FailedQueries;
- // FIXME: This should fail any transitively dependant symbols too.
+ ES.runSessionLocked([&]() {
+ for (auto &KV : FailedSymbols) {
+ auto &Name = KV.first;
- auto FailedQueriesToNotify = ES.runSessionLocked([&, this]() {
- AsynchronousSymbolQuerySet FailedQueries;
- std::vector<MaterializingInfosMap::iterator> MIIsToRemove;
+ assert(Symbols.count(Name) && "No symbol table entry for Name");
+ auto &Sym = Symbols[Name];
- for (auto &Name : FailedSymbols) {
- auto I = Symbols.find(Name);
- assert(I != Symbols.end() && "Symbol not present in this JITDylib");
- Symbols.erase(I);
+ // Move the symbol into the error state.
+ // Note that this may be redundant: The symbol might already have been
+ // moved to this state in response to the failure of a dependence.
+ Sym.setFlags(Sym.getFlags() | JITSymbolFlags::HasError);
+ // FIXME: Come up with a sane mapping of state to
+ // presence-of-MaterializingInfo so that we can assert presence / absence
+ // here, rather than testing it.
auto MII = MaterializingInfos.find(Name);
- // If we have not created a MaterializingInfo for this symbol yet then
- // there is nobody to notify.
if (MII == MaterializingInfos.end())
continue;
- // Remove this symbol from the dependants list of any dependencies.
- for (auto &KV : MII->second.UnemittedDependencies) {
- auto *DependencyJD = KV.first;
- auto &Dependencies = KV.second;
- for (auto &DependencyName : Dependencies) {
- auto DependencyMII =
- DependencyJD->MaterializingInfos.find(DependencyName);
- assert(DependencyMII != DependencyJD->MaterializingInfos.end() &&
- "Unemitted dependency must have a MaterializingInfo entry");
- assert(DependencyMII->second.Dependants.count(this) &&
- "Dependency's dependants list does not contain this JITDylib");
- assert(DependencyMII->second.Dependants[this].count(Name) &&
- "Dependency's dependants list does not contain dependant");
- DependencyMII->second.Dependants[this].erase(Name);
+ auto &MI = MII->second;
+
+ // Move all dependants to the error state and disconnect from them.
+ for (auto &KV : MI.Dependants) {
+ auto &DependantJD = *KV.first;
+ for (auto &DependantName : KV.second) {
+ assert(DependantJD.Symbols.count(DependantName) &&
+ "No symbol table entry for DependantName");
+ auto &DependantSym = DependantJD.Symbols[DependantName];
+ DependantSym.setFlags(DependantSym.getFlags() |
+ JITSymbolFlags::HasError);
+
+ assert(DependantJD.MaterializingInfos.count(DependantName) &&
+ "No MaterializingInfo for dependant");
+ auto &DependantMI = DependantJD.MaterializingInfos[DependantName];
+
+ auto UnemittedDepI = DependantMI.UnemittedDependencies.find(this);
+ assert(UnemittedDepI != DependantMI.UnemittedDependencies.end() &&
+ "No UnemittedDependencies entry for this JITDylib");
+ assert(UnemittedDepI->second.count(Name) &&
+ "No UnemittedDependencies entry for this symbol");
+ UnemittedDepI->second.erase(Name);
+ if (UnemittedDepI->second.empty())
+ DependantMI.UnemittedDependencies.erase(UnemittedDepI);
+ }
+ }
+
+ // Disconnect from all unemitted depenencies.
+ for (auto &KV : MI.UnemittedDependencies) {
+ auto &UnemittedDepJD = *KV.first;
+ for (auto &UnemittedDepName : KV.second) {
+ auto UnemittedDepMII =
+ UnemittedDepJD.MaterializingInfos.find(UnemittedDepName);
+ assert(UnemittedDepMII != UnemittedDepJD.MaterializingInfos.end() &&
+ "Missing MII for unemitted dependency");
+ assert(UnemittedDepMII->second.Dependants.count(this) &&
+ "JD not listed as a dependant of unemitted dependency");
+ assert(UnemittedDepMII->second.Dependants[this].count(Name) &&
+ "Name is not listed as a dependant of unemitted dependency");
+ UnemittedDepMII->second.Dependants[this].erase(Name);
+ if (UnemittedDepMII->second.Dependants[this].empty())
+ UnemittedDepMII->second.Dependants.erase(this);
}
}
- // Copy all the queries to the FailedQueries list, then abandon them.
- // This has to be a copy, and the copy has to come before the abandon
- // operation: Each Q.detach() call will reach back into this
- // PendingQueries list to remove Q.
+ // Collect queries to be failed for this MII.
for (auto &Q : MII->second.pendingQueries())
FailedQueries.insert(Q);
-
- MIIsToRemove.push_back(std::move(MII));
}
// Detach failed queries.
@@ -1054,18 +1260,17 @@ void JITDylib::notifyFailed(const SymbolNameSet &FailedSymbols) {
Q->detach();
// Remove the MaterializingInfos.
- for (auto &MII : MIIsToRemove) {
- assert(!MII->second.hasQueriesPending() &&
- "Queries remain after symbol was failed");
-
- MaterializingInfos.erase(MII);
+ for (auto &KV : FailedSymbols) {
+ assert(MaterializingInfos.count(KV.first) && "Expected MI for Name");
+ MaterializingInfos.erase(KV.first);
}
-
- return FailedQueries;
});
- for (auto &Q : FailedQueriesToNotify)
- Q->handleFailed(make_error<FailedToMaterialize>(FailedSymbols));
+ auto FailedSymbolsMap = std::make_shared<SymbolDependenceMap>();
+ for (auto &KV : FailedSymbols)
+ (*FailedSymbolsMap)[this].insert(KV.first);
+ for (auto &Q : FailedQueries)
+ Q->handleFailed(make_error<FailedToMaterialize>(FailedSymbolsMap));
}
void JITDylib::setSearchOrder(JITDylibSearchList NewSearchOrder,
@@ -1221,7 +1426,8 @@ Error JITDylib::lodgeQuery(std::shared_ptr<AsynchronousSymbolQuery> &Q,
MaterializationUnitList &MUs) {
assert(Q && "Query can not be null");
- lodgeQueryImpl(Q, Unresolved, MatchNonExported, MUs);
+ if (auto Err = lodgeQueryImpl(Q, Unresolved, MatchNonExported, MUs))
+ return Err;
// Run any definition generators.
for (auto &DG : DefGenerators) {
@@ -1233,13 +1439,21 @@ Error JITDylib::lodgeQuery(std::shared_ptr<AsynchronousSymbolQuery> &Q,
// Run the generator.
auto NewDefs = DG->tryToGenerate(*this, Unresolved);
+ // If the generator returns an error then bail out.
if (!NewDefs)
return NewDefs.takeError();
+ // If the generator was able to generate new definitions for any of the
+ // unresolved symbols then lodge the query against them.
if (!NewDefs->empty()) {
for (auto &D : *NewDefs)
Unresolved.erase(D);
- lodgeQueryImpl(Q, *NewDefs, MatchNonExported, MUs);
+
+ // Lodge query. This can not fail as any new definitions were added
+ // by the generator under the session locked. Since they can't have
+ // started materializing yet the can not have failed.
+ cantFail(lodgeQueryImpl(Q, *NewDefs, MatchNonExported, MUs));
+
assert(NewDefs->empty() &&
"All fallback defs should have been found by lookupImpl");
}
@@ -1248,7 +1462,7 @@ Error JITDylib::lodgeQuery(std::shared_ptr<AsynchronousSymbolQuery> &Q,
return Error::success();
}
-void JITDylib::lodgeQueryImpl(
+Error JITDylib::lodgeQueryImpl(
std::shared_ptr<AsynchronousSymbolQuery> &Q, SymbolNameSet &Unresolved,
bool MatchNonExported,
std::vector<std::unique_ptr<MaterializationUnit>> &MUs) {
@@ -1269,6 +1483,14 @@ void JITDylib::lodgeQueryImpl(
// Unresolved set.
ToRemove.push_back(Name);
+ // If we matched against this symbol but it is in the error state then
+ // bail out and treat it as a failure to materialize.
+ if (SymI->second.getFlags().hasError()) {
+ auto FailedSymbolsMap = std::make_shared<SymbolDependenceMap>();
+ (*FailedSymbolsMap)[this] = {Name};
+ return make_error<FailedToMaterialize>(std::move(FailedSymbolsMap));
+ }
+
// If this symbol already meets the required state for then notify the
// query and continue.
if (SymI->second.getState() >= Q->getRequiredState()) {
@@ -1311,6 +1533,8 @@ void JITDylib::lodgeQueryImpl(
// Remove any symbols that we found.
for (auto &Name : ToRemove)
Unresolved.erase(Name);
+
+ return Error::success();
}
Expected<SymbolNameSet>
diff --git a/llvm/lib/ExecutionEngine/Orc/IndirectionUtils.cpp b/llvm/lib/ExecutionEngine/Orc/IndirectionUtils.cpp
index 382a6a2951c..d59a7a6e29f 100644
--- a/llvm/lib/ExecutionEngine/Orc/IndirectionUtils.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/IndirectionUtils.cpp
@@ -37,8 +37,9 @@ private:
void materialize(MaterializationResponsibility R) override {
SymbolMap Result;
Result[Name] = JITEvaluatedSymbol(Compile(), JITSymbolFlags::Exported);
- R.notifyResolved(Result);
- R.notifyEmitted();
+ // No dependencies, so these calls cannot fail.
+ cantFail(R.notifyResolved(Result));
+ cantFail(R.notifyEmitted());
}
void discard(const JITDylib &JD, const SymbolStringPtr &Name) override {
diff --git a/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp b/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp
index 11ba2e55deb..863698eb725 100644
--- a/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp
@@ -182,8 +182,9 @@ void LazyReexportsMaterializationUnit::materialize(
for (auto &Alias : RequestedAliases)
Stubs[Alias.first] = ISManager.findStub(*Alias.first, false);
- R.notifyResolved(Stubs);
- R.notifyEmitted();
+ // No registered dependencies, so these calls cannot fail.
+ cantFail(R.notifyResolved(Stubs));
+ cantFail(R.notifyEmitted());
}
void LazyReexportsMaterializationUnit::discard(const JITDylib &JD,
diff --git a/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp b/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp
index ff9b55dbbcb..0d0b8a9c227 100644
--- a/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp
@@ -127,7 +127,11 @@ public:
if (auto Err = MR.defineMaterializing(ExtraSymbolsToClaim))
return notifyFailed(std::move(Err));
- MR.notifyResolved(InternedResult);
+ if (auto Err = MR.notifyResolved(InternedResult)) {
+ Layer.getExecutionSession().reportError(std::move(Err));
+ MR.failMaterialization();
+ return;
+ }
Layer.notifyLoaded(MR);
}
@@ -138,10 +142,12 @@ public:
if (auto Err = Layer.notifyEmitted(MR, std::move(A))) {
Layer.getExecutionSession().reportError(std::move(Err));
MR.failMaterialization();
-
return;
}
- MR.notifyEmitted();
+ if (auto Err = MR.notifyEmitted()) {
+ Layer.getExecutionSession().reportError(std::move(Err));
+ MR.failMaterialization();
+ }
}
AtomGraphPassFunction getMarkLivePass(const Triple &TT) const override {
diff --git a/llvm/lib/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.cpp b/llvm/lib/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.cpp
index b22ecd5f80a..7ea1351af8f 100644
--- a/llvm/lib/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.cpp
@@ -184,7 +184,10 @@ Error RTDyldObjectLinkingLayer::onObjLoad(
if (auto Err = R.defineMaterializing(ExtraSymbolsToClaim))
return Err;
- R.notifyResolved(Symbols);
+ if (auto Err = R.notifyResolved(Symbols)) {
+ R.failMaterialization();
+ return Err;
+ }
if (NotifyLoaded)
NotifyLoaded(K, Obj, *LoadedObjInfo);
@@ -201,7 +204,11 @@ void RTDyldObjectLinkingLayer::onObjEmit(
return;
}
- R.notifyEmitted();
+ if (auto Err = R.notifyEmitted()) {
+ getExecutionSession().reportError(std::move(Err));
+ R.failMaterialization();
+ return;
+ }
if (NotifyEmitted)
NotifyEmitted(K, std::move(ObjBuffer));
OpenPOWER on IntegriCloud