|
@@ -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>
|