Skip to content

Commit 535448e

Browse files
committed
[ORC] Add a 'remove' method to JITDylib to remove symbols.
Symbols can be removed provided that all are present in the JITDylib and none are currently in the materializing state. On success all requested symbols are removed. On failure an error is returned and no symbols are removed. llvm-svn: 343928
1 parent cb5702c commit 535448e

File tree

3 files changed

+180
-0
lines changed

3 files changed

+180
-0
lines changed

llvm/include/llvm/ExecutionEngine/Orc/Core.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,20 @@ class SymbolsNotFound : public ErrorInfo<SymbolsNotFound> {
134134
SymbolNameSet Symbols;
135135
};
136136

137+
/// Used to notify clients that a set of symbols could not be removed.
138+
class SymbolsCouldNotBeRemoved : public ErrorInfo<SymbolsCouldNotBeRemoved> {
139+
public:
140+
static char ID;
141+
142+
SymbolsCouldNotBeRemoved(SymbolNameSet Symbols);
143+
std::error_code convertToErrorCode() const override;
144+
void log(raw_ostream &OS) const override;
145+
const SymbolNameSet &getSymbols() const { return Symbols; }
146+
147+
private:
148+
SymbolNameSet Symbols;
149+
};
150+
137151
/// Tracks responsibility for materialization, and mediates interactions between
138152
/// MaterializationUnits and JDs.
139153
///
@@ -546,6 +560,18 @@ class JITDylib {
546560
template <typename MaterializationUnitType>
547561
Error define(std::unique_ptr<MaterializationUnitType> &MU);
548562

563+
/// Tries to remove the given symbols.
564+
///
565+
/// If any symbols are not defined in this JITDylib this method will return
566+
/// a SymbolsNotFound error covering the missing symbols.
567+
///
568+
/// If all symbols are found but some symbols are in the process of being
569+
/// materialized this method will return a SymbolsCouldNotBeRemoved error.
570+
///
571+
/// On success, all symbols are removed. On failure, the JITDylib state is
572+
/// left unmodified (no symbols are removed).
573+
Error remove(const SymbolNameSet &Names);
574+
549575
/// Search the given JITDylib for the symbols in Symbols. If found, store
550576
/// the flags for each symbol in Flags. Returns any unresolved symbols.
551577
SymbolFlagsMap lookupFlags(const SymbolNameSet &Names);

llvm/lib/ExecutionEngine/Orc/Core.cpp

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ namespace orc {
136136

137137
char FailedToMaterialize::ID = 0;
138138
char SymbolsNotFound::ID = 0;
139+
char SymbolsCouldNotBeRemoved::ID = 0;
139140

140141
RegisterDependenciesFunction NoDependenciesToRegister =
141142
RegisterDependenciesFunction();
@@ -242,6 +243,19 @@ void SymbolsNotFound::log(raw_ostream &OS) const {
242243
OS << "Symbols not found: " << Symbols;
243244
}
244245

246+
SymbolsCouldNotBeRemoved::SymbolsCouldNotBeRemoved(SymbolNameSet Symbols)
247+
: Symbols(std::move(Symbols)) {
248+
assert(!this->Symbols.empty() && "Can not fail to resolve an empty set");
249+
}
250+
251+
std::error_code SymbolsCouldNotBeRemoved::convertToErrorCode() const {
252+
return orcError(OrcErrorCode::UnknownORCError);
253+
}
254+
255+
void SymbolsCouldNotBeRemoved::log(raw_ostream &OS) const {
256+
OS << "Symbols could not be removed: " << Symbols;
257+
}
258+
245259
AsynchronousSymbolQuery::AsynchronousSymbolQuery(
246260
const SymbolNameSet &Symbols, SymbolsResolvedCallback NotifySymbolsResolved,
247261
SymbolsReadyCallback NotifySymbolsReady)
@@ -1045,6 +1059,60 @@ void JITDylib::removeFromSearchOrder(JITDylib &JD) {
10451059
});
10461060
}
10471061

1062+
Error JITDylib::remove(const SymbolNameSet &Names) {
1063+
return ES.runSessionLocked([&]() -> Error {
1064+
using SymbolMaterializerItrPair =
1065+
std::pair<SymbolMap::iterator, UnmaterializedInfosMap::iterator>;
1066+
std::vector<SymbolMaterializerItrPair> SymbolsToRemove;
1067+
SymbolNameSet Missing;
1068+
SymbolNameSet Materializing;
1069+
1070+
for (auto &Name : Names) {
1071+
auto I = Symbols.find(Name);
1072+
1073+
// Note symbol missing.
1074+
if (I == Symbols.end()) {
1075+
Missing.insert(Name);
1076+
continue;
1077+
}
1078+
1079+
// Note symbol materializing.
1080+
if (I->second.getFlags().isMaterializing()) {
1081+
Materializing.insert(Name);
1082+
continue;
1083+
}
1084+
1085+
auto UMII = I->second.getFlags().isLazy() ? UnmaterializedInfos.find(Name)
1086+
: UnmaterializedInfos.end();
1087+
SymbolsToRemove.push_back(std::make_pair(I, UMII));
1088+
}
1089+
1090+
// If any of the symbols are not defined, return an error.
1091+
if (!Missing.empty())
1092+
return make_error<SymbolsNotFound>(std::move(Missing));
1093+
1094+
// If any of the symbols are currently materializing, return an error.
1095+
if (!Materializing.empty())
1096+
return make_error<SymbolsCouldNotBeRemoved>(std::move(Materializing));
1097+
1098+
// Remove the symbols.
1099+
for (auto &SymbolMaterializerItrPair : SymbolsToRemove) {
1100+
auto UMII = SymbolMaterializerItrPair.second;
1101+
1102+
// If there is a materializer attached, call discard.
1103+
if (UMII != UnmaterializedInfos.end()) {
1104+
UMII->second->MU->doDiscard(*this, UMII->first);
1105+
UnmaterializedInfos.erase(UMII);
1106+
}
1107+
1108+
auto SymI = SymbolMaterializerItrPair.first;
1109+
Symbols.erase(SymI);
1110+
}
1111+
1112+
return Error::success();
1113+
});
1114+
}
1115+
10481116
SymbolFlagsMap JITDylib::lookupFlags(const SymbolNameSet &Names) {
10491117
return ES.runSessionLocked([&, this]() {
10501118
SymbolFlagsMap Result;

llvm/unittests/ExecutionEngine/Orc/CoreAPIsTest.cpp

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,92 @@ TEST_F(CoreAPIsStandardTest, EmptyLookup) {
107107
EXPECT_TRUE(OnReadyRun) << "OnReady was not run for empty query";
108108
}
109109

110+
TEST_F(CoreAPIsStandardTest, RemoveSymbolsTest) {
111+
// Test that:
112+
// (1) Missing symbols generate a SymbolsNotFound error.
113+
// (2) Materializing symbols generate a SymbolCouldNotBeRemoved error.
114+
// (3) Removal of unmaterialized symbols triggers discard on the
115+
// materialization unit.
116+
// (4) Removal of symbols destroys empty materialization units.
117+
// (5) Removal of materialized symbols works.
118+
119+
// Foo will be fully materialized.
120+
cantFail(JD.define(absoluteSymbols({{Foo, FooSym}})));
121+
122+
// Bar will be unmaterialized.
123+
bool BarDiscarded = false;
124+
bool BarMaterializerDestructed = false;
125+
cantFail(JD.define(llvm::make_unique<SimpleMaterializationUnit>(
126+
SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
127+
[this](MaterializationResponsibility R) {
128+
ADD_FAILURE() << "Unexpected materialization of \"Bar\"";
129+
R.resolve({{Bar, BarSym}});
130+
R.emit();
131+
},
132+
[&](const JITDylib &JD, const SymbolStringPtr &Name) {
133+
EXPECT_EQ(Name, Bar) << "Expected \"Bar\" to be discarded";
134+
if (Name == Bar)
135+
BarDiscarded = true;
136+
},
137+
[&]() { BarMaterializerDestructed = true; })));
138+
139+
// Baz will be in the materializing state initially, then
140+
// materialized for the final removal attempt.
141+
Optional<MaterializationResponsibility> BazR;
142+
cantFail(JD.define(llvm::make_unique<SimpleMaterializationUnit>(
143+
SymbolFlagsMap({{Baz, BazSym.getFlags()}}),
144+
[&](MaterializationResponsibility R) { BazR.emplace(std::move(R)); },
145+
[](const JITDylib &JD, const SymbolStringPtr &Name) {
146+
ADD_FAILURE() << "\"Baz\" discarded unexpectedly";
147+
})));
148+
149+
bool OnResolvedRun = false;
150+
bool OnReadyRun = false;
151+
ES.lookup({&JD}, {Foo, Baz},
152+
[&](Expected<SymbolMap> Result) {
153+
EXPECT_TRUE(!!Result) << "OnResolved failed unexpectedly";
154+
consumeError(Result.takeError());
155+
OnResolvedRun = true;
156+
},
157+
[&](Error Err) {
158+
EXPECT_FALSE(!!Err) << "OnReady failed unexpectedly";
159+
consumeError(std::move(Err));
160+
OnReadyRun = true;
161+
},
162+
NoDependenciesToRegister);
163+
164+
{
165+
// Attempt 1: Search for a missing symbol, Qux.
166+
auto Err = JD.remove({Foo, Bar, Baz, Qux});
167+
EXPECT_TRUE(!!Err) << "Expected failure";
168+
EXPECT_TRUE(Err.isA<SymbolsNotFound>())
169+
<< "Expected a SymbolsNotFound error";
170+
}
171+
172+
{
173+
// Attempt 2: Search for a symbol that is still materializing, Baz.
174+
auto Err = JD.remove({Foo, Bar, Baz});
175+
EXPECT_TRUE(!!Err) << "Expected failure";
176+
EXPECT_TRUE(Err.isA<SymbolsCouldNotBeRemoved>())
177+
<< "Expected a SymbolsNotFound error";
178+
}
179+
180+
BazR->resolve({{Baz, BazSym}});
181+
BazR->emit();
182+
{
183+
// Attempt 3: Search now that all symbols are fully materialized
184+
// (Foo, Baz), or not yet materialized (Bar).
185+
auto Err = JD.remove({Foo, Bar, Baz});
186+
EXPECT_FALSE(!!Err) << "Expected failure";
187+
}
188+
189+
EXPECT_TRUE(BarDiscarded) << "\"Bar\" should have been discarded";
190+
EXPECT_TRUE(BarMaterializerDestructed)
191+
<< "\"Bar\"'s materializer should have been destructed";
192+
EXPECT_TRUE(OnResolvedRun) << "OnResolved should have been run";
193+
EXPECT_TRUE(OnReadyRun) << "OnReady should have been run";
194+
}
195+
110196
TEST_F(CoreAPIsStandardTest, ChainedJITDylibLookup) {
111197
cantFail(JD.define(absoluteSymbols({{Foo, FooSym}})));
112198

0 commit comments

Comments
 (0)