llvm.org GIT mirror llvm / 9a1c768
[ORC] Allow JITDylib definition generators to return Errors. Background: A definition generator can be attached to a JITDylib to generate new definitions in response to queries. For example: a generator that forwards calls to dlsym can map symbols from a dynamic library into the JIT process on demand. If definition generation fails then the generator should be able to return an error. This allows the JIT API to distinguish between the case where a generator does not provide a definition, and the case where it was not able to determine whether it provided a definition due to an error. The immediate motivation for this is cross-process symbol lookups: If the remote-lookup generator is attached to a JITDylib early in the search list, and if a generator failure is misinterpreted as "no definition in this JITDylib" then lookup may continue and bind to a different definition in a later JITDylib, which is a bug. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@359521 91177308-0d34-0410-b5e6-96231b3b80d8 Lang Hames 1 year, 6 months ago
6 changed file(s) with 136 addition(s) and 80 deletion(s). Raw diff Collapse all Expand all
417417 ReexportsGenerator(JITDylib &SourceJD, bool MatchNonExported = false,
418418 SymbolPredicate Allow = SymbolPredicate());
419419
420 SymbolNameSet operator()(JITDylib &JD, const SymbolNameSet &Names);
420 Expected operator()(JITDylib &JD, const SymbolNameSet &Names);
421421
422422 private:
423423 JITDylib &SourceJD;
496496 friend class ExecutionSession;
497497 friend class MaterializationResponsibility;
498498 public:
499 using GeneratorFunction = std::function<SymbolNameSet(
499 using GeneratorFunction = std::function<Expected(
500500 JITDylib &Parent, const SymbolNameSet &Names)>;
501501
502502 using AsynchronousSymbolQuerySet =
594594
595595 /// Search the given JITDylib for the symbols in Symbols. If found, store
596596 /// the flags for each symbol in Flags. Returns any unresolved symbols.
597 SymbolFlagsMap lookupFlags(const SymbolNameSet &Names);
597 Expected lookupFlags(const SymbolNameSet &Names);
598598
599599 /// Dump current JITDylib state to OS.
600600 void dump(raw_ostream &OS);
607607 /// and the query will not be applied. The Query is not failed and can be
608608 /// re-used in a subsequent lookup once the symbols have been added, or
609609 /// manually failed.
610 SymbolNameSet legacyLookup(std::shared_ptr Q,
611 SymbolNameSet Names);
610 Expected
611 legacyLookup(std::shared_ptr Q, SymbolNameSet Names);
612612
613613 private:
614614 using AsynchronousSymbolQueryList =
644644
645645 Error defineImpl(MaterializationUnit &MU);
646646
647 SymbolNameSet lookupFlagsImpl(SymbolFlagsMap &Flags,
648 const SymbolNameSet &Names);
649
650 void lodgeQuery(std::shared_ptr &Q,
651 SymbolNameSet &Unresolved, bool MatchNonExported,
652 MaterializationUnitList &MUs);
647 Expected lookupFlagsImpl(SymbolFlagsMap &Flags,
648 const SymbolNameSet &Names);
649
650 Error lodgeQuery(std::shared_ptr &Q,
651 SymbolNameSet &Unresolved, bool MatchNonExported,
652 MaterializationUnitList &MUs);
653653
654654 void lodgeQueryImpl(std::shared_ptr &Q,
655655 SymbolNameSet &Unresolved, bool MatchNonExported,
238238 return Load(nullptr, GlobalPrefix, std::move(Allow));
239239 }
240240
241 SymbolNameSet operator()(JITDylib &JD, const SymbolNameSet &Names);
241 Expected operator()(JITDylib &JD, const SymbolNameSet &Names);
242242
243243 private:
244244 sys::DynamicLibrary Dylib;
695695 buildSimpleReexportsAliasMap(JITDylib &SourceJD, const SymbolNameSet &Symbols) {
696696 auto Flags = SourceJD.lookupFlags(Symbols);
697697
698 if (Flags.size() != Symbols.size()) {
698 if (!Flags)
699 return Flags.takeError();
700
701 if (Flags->size() != Symbols.size()) {
699702 SymbolNameSet Unresolved = Symbols;
700 for (auto &KV : Flags)
703 for (auto &KV : *Flags)
701704 Unresolved.erase(KV.first);
702705 return make_error(std::move(Unresolved));
703706 }
704707
705708 SymbolAliasMap Result;
706709 for (auto &Name : Symbols) {
707 assert(Flags.count(Name) && "Missing entry in flags map");
708 Result[Name] = SymbolAliasMapEntry(Name, Flags[Name]);
710 assert(Flags->count(Name) && "Missing entry in flags map");
711 Result[Name] = SymbolAliasMapEntry(Name, (*Flags)[Name]);
709712 }
710713
711714 return Result;
717720 : SourceJD(SourceJD), MatchNonExported(MatchNonExported),
718721 Allow(std::move(Allow)) {}
719722
720 SymbolNameSet ReexportsGenerator::operator()(JITDylib &JD,
721 const SymbolNameSet &Names) {
723 Expected
724 ReexportsGenerator::operator()(JITDylib &JD, const SymbolNameSet &Names) {
722725 orc::SymbolNameSet Added;
723726 orc::SymbolAliasMap AliasMap;
724727
725728 auto Flags = SourceJD.lookupFlags(Names);
726729
727 for (auto &KV : Flags) {
730 if (!Flags)
731 return Flags.takeError();
732
733 for (auto &KV : *Flags) {
728734 if (Allow && !Allow(KV.first))
729735 continue;
730736 AliasMap[KV.first] = SymbolAliasMapEntry(KV.first, KV.second);
11701176 });
11711177 }
11721178
1173 SymbolFlagsMap JITDylib::lookupFlags(const SymbolNameSet &Names) {
1174 return ES.runSessionLocked([&, this]() {
1179 Expected JITDylib::lookupFlags(const SymbolNameSet &Names) {
1180 return ES.runSessionLocked([&, this]() -> Expected {
11751181 SymbolFlagsMap Result;
11761182 auto Unresolved = lookupFlagsImpl(Result, Names);
1177 if (DefGenerator && !Unresolved.empty()) {
1178 auto NewDefs = DefGenerator(*this, Unresolved);
1179 if (!NewDefs.empty()) {
1180 auto Unresolved2 = lookupFlagsImpl(Result, NewDefs);
1183 if (!Unresolved)
1184 return Unresolved.takeError();
1185
1186 if (DefGenerator && !Unresolved->empty()) {
1187 auto NewDefs = DefGenerator(*this, *Unresolved);
1188 if (!NewDefs)
1189 return NewDefs.takeError();
1190 if (!NewDefs->empty()) {
1191 auto Unresolved2 = lookupFlagsImpl(Result, *NewDefs);
1192 if (!Unresolved2)
1193 return Unresolved2.takeError();
11811194 (void)Unresolved2;
1182 assert(Unresolved2.empty() &&
1195 assert(Unresolved2->empty() &&
11831196 "All fallback defs should have been found by lookupFlagsImpl");
11841197 }
11851198 };
11871200 });
11881201 }
11891202
1190 SymbolNameSet JITDylib::lookupFlagsImpl(SymbolFlagsMap &Flags,
1191 const SymbolNameSet &Names) {
1203 Expected JITDylib::lookupFlagsImpl(SymbolFlagsMap &Flags,
1204 const SymbolNameSet &Names) {
11921205 SymbolNameSet Unresolved;
11931206
11941207 for (auto &Name : Names) {
12061219 return Unresolved;
12071220 }
12081221
1209 void JITDylib::lodgeQuery(std::shared_ptr &Q,
1210 SymbolNameSet &Unresolved, bool MatchNonExported,
1211 MaterializationUnitList &MUs) {
1222 Error JITDylib::lodgeQuery(std::shared_ptr &Q,
1223 SymbolNameSet &Unresolved, bool MatchNonExported,
1224 MaterializationUnitList &MUs) {
12121225 assert(Q && "Query can not be null");
12131226
12141227 lodgeQueryImpl(Q, Unresolved, MatchNonExported, MUs);
12151228 if (DefGenerator && !Unresolved.empty()) {
12161229 auto NewDefs = DefGenerator(*this, Unresolved);
1217 if (!NewDefs.empty()) {
1218 for (auto &D : NewDefs)
1230 if (!NewDefs)
1231 return NewDefs.takeError();
1232 if (!NewDefs->empty()) {
1233 for (auto &D : *NewDefs)
12191234 Unresolved.erase(D);
1220 lodgeQueryImpl(Q, NewDefs, MatchNonExported, MUs);
1221 assert(NewDefs.empty() &&
1235 lodgeQueryImpl(Q, *NewDefs, MatchNonExported, MUs);
1236 assert(NewDefs->empty() &&
12221237 "All fallback defs should have been found by lookupImpl");
12231238 }
12241239 }
1240
1241 return Error::success();
12251242 }
12261243
12271244 void JITDylib::lodgeQueryImpl(
12931310 Unresolved.erase(Name);
12941311 }
12951312
1296 SymbolNameSet JITDylib::legacyLookup(std::shared_ptr Q,
1297 SymbolNameSet Names) {
1313 Expected
1314 JITDylib::legacyLookup(std::shared_ptr Q,
1315 SymbolNameSet Names) {
12981316 assert(Q && "Query can not be null");
12991317
13001318 ES.runOutstandingMUs();
13031321 std::vector> MUs;
13041322
13051323 SymbolNameSet Unresolved = std::move(Names);
1306 ES.runSessionLocked([&, this]() {
1324 auto Err = ES.runSessionLocked([&, this]() -> Error {
13071325 ActionFlags = lookupImpl(Q, MUs, Unresolved);
13081326 if (DefGenerator && !Unresolved.empty()) {
13091327 assert(ActionFlags == None &&
13101328 "ActionFlags set but unresolved symbols remain?");
13111329 auto NewDefs = DefGenerator(*this, Unresolved);
1312 if (!NewDefs.empty()) {
1313 for (auto &D : NewDefs)
1330 if (!NewDefs)
1331 return NewDefs.takeError();
1332 if (!NewDefs->empty()) {
1333 for (auto &D : *NewDefs)
13141334 Unresolved.erase(D);
1315 ActionFlags = lookupImpl(Q, MUs, NewDefs);
1316 assert(NewDefs.empty() &&
1335 ActionFlags = lookupImpl(Q, MUs, *NewDefs);
1336 assert(NewDefs->empty() &&
13171337 "All fallback defs should have been found by lookupImpl");
13181338 }
13191339 }
1340 return Error::success();
13201341 });
1342
1343 if (Err)
1344 return std::move(Err);
13211345
13221346 assert((MUs.empty() || ActionFlags == None) &&
13231347 "If action flags are set, there should be no work to do (so no MUs)");
17601784 Unresolved, std::move(OnResolve), std::move(OnReady));
17611785 bool QueryIsFullyResolved = false;
17621786 bool QueryIsFullyReady = false;
1763 bool QueryFailed = false;
1764
1765 runSessionLocked([&]() {
1766 for (auto &KV : SearchOrder) {
1767 assert(KV.first && "JITDylibList entries must not be null");
1768 assert(!CollectedMUsMap.count(KV.first) &&
1769 "JITDylibList should not contain duplicate entries");
1770
1771 auto &JD = *KV.first;
1772 auto MatchNonExported = KV.second;
1773 JD.lodgeQuery(Q, Unresolved, MatchNonExported, CollectedMUsMap[&JD]);
1774 }
1775
1776 if (Unresolved.empty()) {
1777 // Query lodged successfully.
1778
1779 // Record whether this query is fully ready / resolved. We will use
1780 // this to call handleFullyResolved/handleFullyReady outside the session
1781 // lock.
1782 QueryIsFullyResolved = Q->isFullyResolved();
1783 QueryIsFullyReady = Q->isFullyReady();
1784
1785 // Call the register dependencies function.
1786 if (RegisterDependencies && !Q->QueryRegistrations.empty())
1787 RegisterDependencies(Q->QueryRegistrations);
1788 } else {
1789 // Query failed due to unresolved symbols.
1790 QueryFailed = true;
1787
1788 auto LodgingErr = runSessionLocked([&]() -> Error {
1789 auto LodgeQuery = [&]() -> Error {
1790 for (auto &KV : SearchOrder) {
1791 assert(KV.first && "JITDylibList entries must not be null");
1792 assert(!CollectedMUsMap.count(KV.first) &&
1793 "JITDylibList should not contain duplicate entries");
1794
1795 auto &JD = *KV.first;
1796 auto MatchNonExported = KV.second;
1797 if (auto Err = JD.lodgeQuery(Q, Unresolved, MatchNonExported,
1798 CollectedMUsMap[&JD]))
1799 return Err;
1800 }
1801
1802 if (!Unresolved.empty())
1803 return make_error(std::move(Unresolved));
1804
1805 return Error::success();
1806 };
1807
1808 if (auto Err = LodgeQuery()) {
1809 // Query failed.
17911810
17921811 // Disconnect the query from its dependencies.
17931812 Q->detach();
17961815 for (auto &KV : CollectedMUsMap)
17971816 for (auto &MU : KV.second)
17981817 KV.first->replace(std::move(MU));
1799 }
1818
1819 return Err;
1820 }
1821
1822 // Query lodged successfully.
1823
1824 // Record whether this query is fully ready / resolved. We will use
1825 // this to call handleFullyResolved/handleFullyReady outside the session
1826 // lock.
1827 QueryIsFullyResolved = Q->isFullyResolved();
1828 QueryIsFullyReady = Q->isFullyReady();
1829
1830 // Call the register dependencies function.
1831 if (RegisterDependencies && !Q->QueryRegistrations.empty())
1832 RegisterDependencies(Q->QueryRegistrations);
1833
1834 return Error::success();
18001835 });
18011836
1802 if (QueryFailed) {
1803 Q->handleFailed(make_error(std::move(Unresolved)));
1837 if (LodgingErr) {
1838 Q->handleFailed(std::move(LodgingErr));
18041839 return;
18051840 } else {
18061841 if (QueryIsFullyResolved)
192192 std::move(Allow));
193193 }
194194
195 SymbolNameSet DynamicLibrarySearchGenerator::
196 operator()(JITDylib &JD, const SymbolNameSet &Names) {
195 Expected
196 DynamicLibrarySearchGenerator::operator()(JITDylib &JD,
197 const SymbolNameSet &Names) {
197198 orc::SymbolNameSet Added;
198199 orc::SymbolMap NewSymbols;
199200
215215 OnReadyRun = true;
216216 });
217217
218 JD2.legacyLookup(Q, JD.legacyLookup(Q, {Foo}));
218 cantFail(JD2.legacyLookup(Q, cantFail(JD.legacyLookup(Q, {Foo}))));
219219
220220 EXPECT_TRUE(OnResolvedRun) << "OnResolved was not run for empty query";
221221 EXPECT_TRUE(OnReadyRun) << "OnReady was not run for empty query";
259259
260260 SymbolNameSet Names({Foo, Bar, Baz});
261261
262 auto SymbolFlags = JD.lookupFlags(Names);
262 auto SymbolFlags = cantFail(JD.lookupFlags(Names));
263263
264264 EXPECT_EQ(SymbolFlags.size(), 2U)
265265 << "Returned symbol flags contains unexpected results";
272272 << "Incorrect flags returned for Bar";
273273 }
274274
275 TEST_F(CoreAPIsStandardTest, LookupWithGeneratorFailure) {
276
277 class BadGenerator {
278 public:
279 Expected operator()(JITDylib &, const SymbolNameSet &) {
280 return make_error("BadGenerator", inconvertibleErrorCode());
281 }
282 };
283
284 JD.setGenerator(BadGenerator());
285
286 EXPECT_THAT_ERROR(JD.lookupFlags({Foo}).takeError(), Failed())
287 << "Generator failure did not propagate through lookupFlags";
288
289 EXPECT_THAT_ERROR(
290 ES.lookup(JITDylibSearchList({{&JD, false}}), {Foo}).takeError(),
291 Failed())
292 << "Generator failure did not propagate through lookup";
293 }
294
275295 TEST_F(CoreAPIsStandardTest, TestBasicAliases) {
276296 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}, {Bar, BarSym}})));
277297 cantFail(JD.define(symbolAliases({{Baz, {Foo, JITSymbolFlags::Exported}},
355375
356376 JD.setGenerator(ReexportsGenerator(JD2, false, Filter));
357377
358 auto Flags = JD.lookupFlags({Foo, Bar, Baz});
378 auto Flags = cantFail(JD.lookupFlags({Foo, Bar, Baz}));
359379 EXPECT_EQ(Flags.size(), 1U) << "Unexpected number of results";
360380 EXPECT_EQ(Flags[Foo], FooSym.getFlags()) << "Unexpected flags for Foo";
361381
2323
2424 auto Resolver = createSymbolResolver(
2525 [&](const SymbolNameSet &Symbols) {
26 auto FlagsMap = JD.lookupFlags(Symbols);
26 auto FlagsMap = cantFail(JD.lookupFlags(Symbols));
2727 SymbolNameSet Result;
2828 for (auto &KV : FlagsMap)
2929 if (!KV.second.isStrong())
3131 return Result;
3232 },
3333 [&](std::shared_ptr Q, SymbolNameSet Symbols) {
34 return JD.legacyLookup(std::move(Q), Symbols);
34 return cantFail(JD.legacyLookup(std::move(Q), Symbols));
3535 });
3636
3737 auto RS = Resolver->getResponsibilitySet(SymbolNameSet({Bar, Baz}));