[ORC] Fix a FIXME: Propagate errors to dependencies.

When symbols are failed (via MaterializationResponsibility::failMaterialization)
any symbols depending on them will now be moved to an error state. Attempting
to resolve or emit a symbol in the error state (via the notifyResolved or
notifyEmitted methods on MaterializationResponsibility) will result in an error.
If notifyResolved or notifyEmitted return an error due to failure of a
dependence then the caller should log or discard the error and call
failMaterialization to propagate the failure to any queries waiting on the
symbols being resolved/emitted (plus their dependencies).

llvm-svn: 369808
This commit is contained in:
Lang Hames 2019-08-23 20:37:31 +00:00
parent a47d622240
commit e00585c77c
8 changed files with 629 additions and 164 deletions

View File

@ -123,13 +123,13 @@ class FailedToMaterialize : public ErrorInfo<FailedToMaterialize> {
public:
static char ID;
FailedToMaterialize(SymbolNameSet Symbols);
FailedToMaterialize(std::shared_ptr<SymbolDependenceMap> Symbols);
std::error_code convertToErrorCode() const override;
void log(raw_ostream &OS) const override;
const SymbolNameSet &getSymbols() const { return Symbols; }
const SymbolDependenceMap &getSymbols() const { return *Symbols; }
private:
SymbolNameSet Symbols;
std::shared_ptr<SymbolDependenceMap> Symbols;
};
/// Used to notify clients when symbols can not be found during a lookup.
@ -204,12 +204,26 @@ public:
/// symbols must be ones covered by this MaterializationResponsibility
/// instance. Individual calls to this method may resolve a subset of the
/// symbols, but all symbols must have been resolved prior to calling emit.
void notifyResolved(const SymbolMap &Symbols);
///
/// This method will return an error if any symbols being resolved have been
/// moved to the error state due to the failure of a dependency. If this
/// method returns an error then clients should log it and call
/// failMaterialize. If no dependencies have been registered for the
/// symbols covered by this MaterializationResponsibiility then this method
/// is guaranteed to return Error::success() and can be wrapped with cantFail.
Error notifyResolved(const SymbolMap &Symbols);
/// Notifies the target JITDylib (and any pending queries on that JITDylib)
/// that all symbols covered by this MaterializationResponsibility instance
/// have been emitted.
void notifyEmitted();
///
/// This method will return an error if any symbols being resolved have been
/// moved to the error state due to the failure of a dependency. If this
/// method returns an error then clients should log it and call
/// failMaterialize. If no dependencies have been registered for the
/// symbols covered by this MaterializationResponsibiility then this method
/// is guaranteed to return Error::success() and can be wrapped with cantFail.
Error notifyEmitted();
/// Adds new symbols to the JITDylib and this responsibility instance.
/// JITDylib entries start out in the materializing state.
@ -628,11 +642,13 @@ private:
void addQuery(std::shared_ptr<AsynchronousSymbolQuery> Q);
void removeQuery(const AsynchronousSymbolQuery &Q);
AsynchronousSymbolQueryList takeQueriesMeeting(SymbolState RequiredState);
AsynchronousSymbolQueryList takeAllPendingQueries() {
return std::move(PendingQueries);
}
bool hasQueriesPending() const { return !PendingQueries.empty(); }
const AsynchronousSymbolQueryList &pendingQueries() const {
return PendingQueries;
}
private:
AsynchronousSymbolQueryList PendingQueries;
};
@ -699,9 +715,9 @@ private:
SymbolNameSet &Unresolved, bool MatchNonExported,
MaterializationUnitList &MUs);
void lodgeQueryImpl(std::shared_ptr<AsynchronousSymbolQuery> &Q,
SymbolNameSet &Unresolved, bool MatchNonExported,
MaterializationUnitList &MUs);
Error lodgeQueryImpl(std::shared_ptr<AsynchronousSymbolQuery> &Q,
SymbolNameSet &Unresolved, bool MatchNonExported,
MaterializationUnitList &MUs);
bool lookupImpl(std::shared_ptr<AsynchronousSymbolQuery> &Q,
std::vector<std::unique_ptr<MaterializationUnit>> &MUs,
@ -720,14 +736,21 @@ private:
SymbolNameSet getRequestedSymbols(const SymbolFlagsMap &SymbolFlags) const;
// Move a symbol to the failure state.
// Detaches the symbol from all dependencies, moves all dependants to the
// error state (but does not fail them), deletes the MaterializingInfo for
// the symbol (if present) and returns the set of queries that need to be
// notified of the failure.
AsynchronousSymbolQuerySet failSymbol(const SymbolStringPtr &Name);
void addDependencies(const SymbolStringPtr &Name,
const SymbolDependenceMap &Dependants);
void resolve(const SymbolMap &Resolved);
Error resolve(const SymbolMap &Resolved);
void emit(const SymbolFlagsMap &Emitted);
Error emit(const SymbolFlagsMap &Emitted);
void notifyFailed(const SymbolNameSet &FailedSymbols);
void notifyFailed(const SymbolFlagsMap &FailedSymbols);
ExecutionSession &ES;
std::string JITDylibName;

View File

@ -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");
assert((Sym.getFlags() & ~JITSymbolFlags::Weak) ==
(I->second.getFlags() & ~JITSymbolFlags::Weak) &&
"Resolved flags should match the declared flags");
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");
// Once resolved, symbols can never be weak.
JITSymbolFlags ResolvedFlags = Sym.getFlags();
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();
auto &Name = SymI->first;
// 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);
}
}
// 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.
// 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);
}
}
// 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>

View File

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

View File

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

View File

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

View File

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

View File

@ -48,11 +48,11 @@ TEST_F(CoreAPIsStandardTest, BasicSuccessfulLookup) {
EXPECT_FALSE(OnCompletionRun) << "Should not have been resolved yet";
FooMR->notifyResolved({{Foo, FooSym}});
cantFail(FooMR->notifyResolved({{Foo, FooSym}}));
EXPECT_FALSE(OnCompletionRun) << "Should not be ready yet";
FooMR->notifyEmitted();
cantFail(FooMR->notifyEmitted());
EXPECT_TRUE(OnCompletionRun) << "Should have been marked ready";
}
@ -109,8 +109,8 @@ TEST_F(CoreAPIsStandardTest, RemoveSymbolsTest) {
SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
[this](MaterializationResponsibility R) {
ADD_FAILURE() << "Unexpected materialization of \"Bar\"";
R.notifyResolved({{Bar, BarSym}});
R.notifyEmitted();
cantFail(R.notifyResolved({{Bar, BarSym}}));
cantFail(R.notifyEmitted());
},
[&](const JITDylib &JD, const SymbolStringPtr &Name) {
EXPECT_EQ(Name, Bar) << "Expected \"Bar\" to be discarded";
@ -156,8 +156,8 @@ TEST_F(CoreAPIsStandardTest, RemoveSymbolsTest) {
consumeError(std::move(Err));
}
BazR->notifyResolved({{Baz, BazSym}});
BazR->notifyEmitted();
cantFail(BazR->notifyResolved({{Baz, BazSym}}));
cantFail(BazR->notifyEmitted());
{
// Attempt 3: Search now that all symbols are fully materialized
// (Foo, Baz), or not yet materialized (Bar).
@ -318,8 +318,8 @@ TEST_F(CoreAPIsStandardTest, TestThatReExportsDontUnnecessarilyMaterialize) {
SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
[&](MaterializationResponsibility R) {
BarMaterialized = true;
R.notifyResolved({{Bar, BarSym}});
R.notifyEmitted();
cantFail(R.notifyResolved({{Bar, BarSym}}));
cantFail(R.notifyEmitted());
});
cantFail(JD.define(BarMU));
@ -374,8 +374,10 @@ TEST_F(CoreAPIsStandardTest, TestTrivialCircularDependency) {
OnCompletion, NoDependenciesToRegister);
FooR->addDependenciesForAll({{&JD, SymbolNameSet({Foo})}});
FooR->notifyResolved({{Foo, FooSym}});
FooR->notifyEmitted();
EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Succeeded())
<< "No symbols marked failed, but Foo failed to resolve";
EXPECT_THAT_ERROR(FooR->notifyEmitted(), Succeeded())
<< "No symbols marked failed, but Foo failed to emit";
EXPECT_TRUE(FooReady)
<< "Self-dependency prevented symbol from being marked ready";
@ -488,9 +490,12 @@ TEST_F(CoreAPIsStandardTest, TestCircularDependenceInOneJITDylib) {
EXPECT_FALSE(BazResolved) << "\"Baz\" should not be resolved yet";
// Resolve the symbols (but do not emit them).
FooR->notifyResolved({{Foo, FooSym}});
BarR->notifyResolved({{Bar, BarSym}});
BazR->notifyResolved({{Baz, BazSym}});
EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Succeeded())
<< "No symbols failed, but Foo failed to resolve";
EXPECT_THAT_ERROR(BarR->notifyResolved({{Bar, BarSym}}), Succeeded())
<< "No symbols failed, but Bar failed to resolve";
EXPECT_THAT_ERROR(BazR->notifyResolved({{Baz, BazSym}}), Succeeded())
<< "No symbols failed, but Baz failed to resolve";
// Verify that the symbols have been resolved, but are not ready yet.
EXPECT_TRUE(FooResolved) << "\"Foo\" should be resolved now";
@ -502,8 +507,10 @@ TEST_F(CoreAPIsStandardTest, TestCircularDependenceInOneJITDylib) {
EXPECT_FALSE(BazReady) << "\"Baz\" should not be ready yet";
// Emit two of the symbols.
FooR->notifyEmitted();
BarR->notifyEmitted();
EXPECT_THAT_ERROR(FooR->notifyEmitted(), Succeeded())
<< "No symbols failed, but Foo failed to emit";
EXPECT_THAT_ERROR(BarR->notifyEmitted(), Succeeded())
<< "No symbols failed, but Bar failed to emit";
// Verify that nothing is ready until the circular dependence is resolved.
EXPECT_FALSE(FooReady) << "\"Foo\" still should not be ready";
@ -511,7 +518,8 @@ TEST_F(CoreAPIsStandardTest, TestCircularDependenceInOneJITDylib) {
EXPECT_FALSE(BazReady) << "\"Baz\" still should not be ready";
// Emit the last symbol.
BazR->notifyEmitted();
EXPECT_THAT_ERROR(BazR->notifyEmitted(), Succeeded())
<< "No symbols failed, but Baz failed to emit";
// Verify that everything becomes ready once the circular dependence resolved.
EXPECT_TRUE(FooReady) << "\"Foo\" should be ready now";
@ -519,6 +527,197 @@ TEST_F(CoreAPIsStandardTest, TestCircularDependenceInOneJITDylib) {
EXPECT_TRUE(BazReady) << "\"Baz\" should be ready now";
}
TEST_F(CoreAPIsStandardTest, FailureInDependency) {
Optional<MaterializationResponsibility> FooR;
Optional<MaterializationResponsibility> BarR;
// Create a MaterializationUnit for each symbol that moves the
// MaterializationResponsibility into one of the locals above.
auto FooMU = std::make_unique<SimpleMaterializationUnit>(
SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
[&](MaterializationResponsibility R) { FooR.emplace(std::move(R)); });
auto BarMU = std::make_unique<SimpleMaterializationUnit>(
SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
[&](MaterializationResponsibility R) { BarR.emplace(std::move(R)); });
// Define the symbols.
cantFail(JD.define(FooMU));
cantFail(JD.define(BarMU));
bool OnFooReadyRun = false;
auto OnFooReady = [&](Expected<SymbolMap> Result) {
EXPECT_THAT_EXPECTED(std::move(Result), Failed());
OnFooReadyRun = true;
};
ES.lookup(JITDylibSearchList({{&JD, false}}), {Foo}, SymbolState::Ready,
std::move(OnFooReady), NoDependenciesToRegister);
bool OnBarReadyRun = false;
auto OnBarReady = [&](Expected<SymbolMap> Result) {
EXPECT_THAT_EXPECTED(std::move(Result), Failed());
OnBarReadyRun = true;
};
ES.lookup(JITDylibSearchList({{&JD, false}}), {Bar}, SymbolState::Ready,
std::move(OnBarReady), NoDependenciesToRegister);
// Add a dependency by Foo on Bar.
FooR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}});
// Fail bar.
BarR->failMaterialization();
// Verify that queries on Bar failed, but queries on Foo have not yet.
EXPECT_TRUE(OnBarReadyRun) << "Query for \"Bar\" was not run";
EXPECT_FALSE(OnFooReadyRun) << "Query for \"Foo\" was run unexpectedly";
// Check that we can still resolve Foo (even though it has been failed).
EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Failed())
<< "Expected resolution for \"Foo\" to fail.";
FooR->failMaterialization();
// Verify that queries on Foo have now failed.
EXPECT_TRUE(OnFooReadyRun) << "Query for \"Foo\" was not run";
// Verify that subsequent lookups on Bar and Foo fail.
EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Bar}), Failed())
<< "Lookup on failed symbol should fail";
EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Foo}), Failed())
<< "Lookup on failed symbol should fail";
}
TEST_F(CoreAPIsStandardTest, FailureInCircularDependency) {
Optional<MaterializationResponsibility> FooR;
Optional<MaterializationResponsibility> BarR;
// Create a MaterializationUnit for each symbol that moves the
// MaterializationResponsibility into one of the locals above.
auto FooMU = std::make_unique<SimpleMaterializationUnit>(
SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
[&](MaterializationResponsibility R) { FooR.emplace(std::move(R)); });
auto BarMU = std::make_unique<SimpleMaterializationUnit>(
SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
[&](MaterializationResponsibility R) { BarR.emplace(std::move(R)); });
// Define the symbols.
cantFail(JD.define(FooMU));
cantFail(JD.define(BarMU));
bool OnFooReadyRun = false;
auto OnFooReady = [&](Expected<SymbolMap> Result) {
EXPECT_THAT_EXPECTED(std::move(Result), Failed());
OnFooReadyRun = true;
};
ES.lookup(JITDylibSearchList({{&JD, false}}), {Foo}, SymbolState::Ready,
std::move(OnFooReady), NoDependenciesToRegister);
bool OnBarReadyRun = false;
auto OnBarReady = [&](Expected<SymbolMap> Result) {
EXPECT_THAT_EXPECTED(std::move(Result), Failed());
OnBarReadyRun = true;
};
ES.lookup(JITDylibSearchList({{&JD, false}}), {Bar}, SymbolState::Ready,
std::move(OnBarReady), NoDependenciesToRegister);
// Add a dependency by Foo on Bar and vice-versa.
FooR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}});
BarR->addDependenciesForAll({{&JD, SymbolNameSet({Foo})}});
// Fail bar.
BarR->failMaterialization();
// Verify that queries on Bar failed, but queries on Foo have not yet.
EXPECT_TRUE(OnBarReadyRun) << "Query for \"Bar\" was not run";
EXPECT_FALSE(OnFooReadyRun) << "Query for \"Foo\" was run unexpectedly";
// Verify that trying to resolve Foo fails.
EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Failed())
<< "Expected resolution for \"Foo\" to fail.";
FooR->failMaterialization();
// Verify that queries on Foo have now failed.
EXPECT_TRUE(OnFooReadyRun) << "Query for \"Foo\" was not run";
// Verify that subsequent lookups on Bar and Foo fail.
EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Bar}), Failed())
<< "Lookup on failed symbol should fail";
EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Foo}), Failed())
<< "Lookup on failed symbol should fail";
}
TEST_F(CoreAPIsStandardTest, AddDependencyOnFailedSymbol) {
Optional<MaterializationResponsibility> FooR;
Optional<MaterializationResponsibility> BarR;
// Create a MaterializationUnit for each symbol that moves the
// MaterializationResponsibility into one of the locals above.
auto FooMU = std::make_unique<SimpleMaterializationUnit>(
SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
[&](MaterializationResponsibility R) { FooR.emplace(std::move(R)); });
auto BarMU = std::make_unique<SimpleMaterializationUnit>(
SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
[&](MaterializationResponsibility R) { BarR.emplace(std::move(R)); });
// Define the symbols.
cantFail(JD.define(FooMU));
cantFail(JD.define(BarMU));
bool OnFooReadyRun = false;
auto OnFooReady = [&](Expected<SymbolMap> Result) {
EXPECT_THAT_EXPECTED(std::move(Result), Failed());
OnFooReadyRun = true;
};
ES.lookup(JITDylibSearchList({{&JD, false}}), {Foo}, SymbolState::Ready,
std::move(OnFooReady), NoDependenciesToRegister);
bool OnBarReadyRun = false;
auto OnBarReady = [&](Expected<SymbolMap> Result) {
EXPECT_THAT_EXPECTED(std::move(Result), Failed());
OnBarReadyRun = true;
};
ES.lookup(JITDylibSearchList({{&JD, false}}), {Bar}, SymbolState::Ready,
std::move(OnBarReady), NoDependenciesToRegister);
// Fail bar.
BarR->failMaterialization();
// We expect Bar's query to fail immediately, but Foo's query not to have run
// yet.
EXPECT_TRUE(OnBarReadyRun) << "Query for \"Bar\" was not run";
EXPECT_FALSE(OnFooReadyRun) << "Query for \"Foo\" should not have run yet";
// Add dependency of Foo on Bar.
FooR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}});
// Check that we can still resolve Foo (even though it has been failed).
EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Failed())
<< "Expected resolution for \"Foo\" to fail.";
FooR->failMaterialization();
// Foo's query should have failed before we return from addDependencies.
EXPECT_TRUE(OnFooReadyRun) << "Query for \"Foo\" was not run";
// Verify that subsequent lookups on Bar and Foo fail.
EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Bar}), Failed())
<< "Lookup on failed symbol should fail";
EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Foo}), Failed())
<< "Lookup on failed symbol should fail";
}
TEST_F(CoreAPIsStandardTest, DropMaterializerWhenEmpty) {
bool DestructorRun = false;
@ -560,8 +759,8 @@ TEST_F(CoreAPIsStandardTest, AddAndMaterializeLazySymbol) {
SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}, {Bar, WeakExported}}),
[&](MaterializationResponsibility R) {
assert(BarDiscarded && "Bar should have been discarded by this point");
R.notifyResolved(SymbolMap({{Foo, FooSym}}));
R.notifyEmitted();
cantFail(R.notifyResolved(SymbolMap({{Foo, FooSym}})));
cantFail(R.notifyEmitted());
FooMaterialized = true;
},
[&](const JITDylib &JD, SymbolStringPtr Name) {
@ -601,7 +800,8 @@ TEST_F(CoreAPIsStandardTest, TestBasicWeakSymbolMaterialization) {
auto MU1 = std::make_unique<SimpleMaterializationUnit>(
SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}),
[&](MaterializationResponsibility R) {
R.notifyResolved(SymbolMap({{Foo, FooSym}, {Bar, BarSym}})), R.notifyEmitted();
cantFail(R.notifyResolved(SymbolMap({{Foo, FooSym}, {Bar, BarSym}})));
cantFail(R.notifyEmitted());
BarMaterialized = true;
});
@ -650,8 +850,8 @@ TEST_F(CoreAPIsStandardTest, DefineMaterializingSymbol) {
[&](MaterializationResponsibility R) {
cantFail(
R.defineMaterializing(SymbolFlagsMap({{Bar, BarSym.getFlags()}})));
R.notifyResolved(SymbolMap({{Foo, FooSym}, {Bar, BarSym}}));
R.notifyEmitted();
cantFail(R.notifyResolved(SymbolMap({{Foo, FooSym}, {Bar, BarSym}})));
cantFail(R.notifyEmitted());
});
cantFail(JD.define(MU));
@ -716,21 +916,22 @@ TEST_F(CoreAPIsStandardTest, FailResolution) {
EXPECT_FALSE(!!Result) << "Expected failure";
if (!Result) {
handleAllErrors(Result.takeError(),
[&](FailedToMaterialize &F) {
EXPECT_EQ(F.getSymbols(), Names)
<< "Expected to fail on symbols in Names";
},
[](ErrorInfoBase &EIB) {
std::string ErrMsg;
{
raw_string_ostream ErrOut(ErrMsg);
EIB.log(ErrOut);
}
ADD_FAILURE()
<< "Expected a FailedToResolve error. Got:\n"
<< ErrMsg;
});
handleAllErrors(
Result.takeError(),
[&](FailedToMaterialize &F) {
EXPECT_TRUE(F.getSymbols().count(&JD))
<< "Expected to fail on JITDylib JD";
EXPECT_EQ(F.getSymbols().find(&JD)->second, Names)
<< "Expected to fail on symbols in Names";
},
[](ErrorInfoBase &EIB) {
std::string ErrMsg;
{
raw_string_ostream ErrOut(ErrMsg);
EIB.log(ErrOut);
}
ADD_FAILURE() << "Expected a FailedToResolve error. Got:\n" << ErrMsg;
});
}
}
@ -741,7 +942,7 @@ TEST_F(CoreAPIsStandardTest, FailEmissionEarly) {
auto MU = std::make_unique<SimpleMaterializationUnit>(
SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}),
[&](MaterializationResponsibility R) {
R.notifyResolved(SymbolMap({{Foo, FooSym}, {Bar, BarSym}}));
cantFail(R.notifyResolved(SymbolMap({{Foo, FooSym}, {Bar, BarSym}})));
ES.lookup(
JITDylibSearchList({{&JD, false}}), SymbolNameSet({Baz}),
@ -773,8 +974,8 @@ TEST_F(CoreAPIsStandardTest, TestLookupWithUnthreadedMaterialization) {
auto MU = std::make_unique<SimpleMaterializationUnit>(
SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}}),
[&](MaterializationResponsibility R) {
R.notifyResolved({{Foo, FooSym}});
R.notifyEmitted();
cantFail(R.notifyResolved({{Foo, FooSym}}));
cantFail(R.notifyEmitted());
});
cantFail(JD.define(MU));
@ -832,15 +1033,15 @@ TEST_F(CoreAPIsStandardTest, TestGetRequestedSymbolsAndReplace) {
auto NewMU = std::make_unique<SimpleMaterializationUnit>(
SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
[&](MaterializationResponsibility R2) {
R2.notifyResolved(SymbolMap({{Bar, BarSym}}));
R2.notifyEmitted();
cantFail(R2.notifyResolved(SymbolMap({{Bar, BarSym}})));
cantFail(R2.notifyEmitted());
BarMaterialized = true;
});
R.replace(std::move(NewMU));
R.notifyResolved(SymbolMap({{Foo, FooSym}}));
R.notifyEmitted();
cantFail(R.notifyResolved(SymbolMap({{Foo, FooSym}})));
cantFail(R.notifyEmitted());
FooMaterialized = true;
});
@ -871,10 +1072,10 @@ TEST_F(CoreAPIsStandardTest, TestMaterializationResponsibilityDelegation) {
[&](MaterializationResponsibility R) {
auto R2 = R.delegate({Bar});
R.notifyResolved({{Foo, FooSym}});
R.notifyEmitted();
R2.notifyResolved({{Bar, BarSym}});
R2.notifyEmitted();
cantFail(R.notifyResolved({{Foo, FooSym}}));
cantFail(R.notifyEmitted());
cantFail(R2.notifyResolved({{Bar, BarSym}}));
cantFail(R2.notifyEmitted());
});
cantFail(JD.define(MU));
@ -924,8 +1125,9 @@ TEST_F(CoreAPIsStandardTest, TestMaterializeWeakSymbol) {
<< "Expected a duplicate definition error";
consumeError(std::move(Err));
FooResponsibility->notifyResolved(SymbolMap({{Foo, FooSym}}));
FooResponsibility->notifyEmitted();
// No dependencies registered, can't fail:
cantFail(FooResponsibility->notifyResolved(SymbolMap({{Foo, FooSym}})));
cantFail(FooResponsibility->notifyEmitted());
}
} // namespace

View File

@ -41,12 +41,13 @@ TEST_F(LazyReexportsTest, BasicLocalCallThroughManagerOperation) {
SymbolFlagsMap({{DummyTarget, JITSymbolFlags::Exported}}),
[&](MaterializationResponsibility R) {
DummyTargetMaterialized = true;
R.notifyResolved(
// No dependencies registered, can't fail.
cantFail(R.notifyResolved(
{{DummyTarget,
JITEvaluatedSymbol(static_cast<JITTargetAddress>(
reinterpret_cast<uintptr_t>(&dummyTarget)),
JITSymbolFlags::Exported)}});
R.notifyEmitted();
JITSymbolFlags::Exported)}}));
cantFail(R.notifyEmitted());
})));
unsigned NotifyResolvedCount = 0;