xref: /llvm-project/llvm/unittests/ExecutionEngine/Orc/CoreAPIsTest.cpp (revision 199034e8acd602d5a2475d537ae8265c4e3ee5a7)
1 //===----------- CoreAPIsTest.cpp - Unit tests for Core ORC APIs ----------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "OrcTestCommon.h"
10 #include "llvm/ADT/ScopeExit.h"
11 #include "llvm/Config/llvm-config.h"
12 #include "llvm/ExecutionEngine/Orc/Core.h"
13 #include "llvm/ExecutionEngine/Orc/Shared/OrcError.h"
14 #include "llvm/Testing/Support/Error.h"
15 
16 #include <set>
17 #include <thread>
18 
19 using namespace llvm;
20 using namespace llvm::orc;
21 
22 class CoreAPIsStandardTest : public CoreAPIsBasedStandardTest {};
23 
24 namespace {
25 
26 TEST_F(CoreAPIsStandardTest, JITDylibAddToLinkOrder) {
27   // Check that the JITDylib::addToLinkOrder methods behave as expected.
28   auto &JD2 = ES.createBareJITDylib("JD2");
29   auto &JD3 = ES.createBareJITDylib("JD3");
30 
31   JD.addToLinkOrder(JD2);
32   JD.withLinkOrderDo([&](const JITDylibSearchOrder &SO) {
33     EXPECT_EQ(SO.size(), 2U);
34     EXPECT_EQ(SO[0].first, &JD);
35     EXPECT_EQ(SO[1].first, &JD2);
36   });
37 
38   JD.addToLinkOrder(makeJITDylibSearchOrder({&JD2, &JD3}));
39   JD.withLinkOrderDo([&](const JITDylibSearchOrder &SO) {
40     // JD2 was already in the search order, so we expect just one extra item
41     // here.
42     EXPECT_EQ(SO.size(), 3U);
43     EXPECT_EQ(SO[0].first, &JD);
44     EXPECT_EQ(SO[1].first, &JD2);
45     EXPECT_EQ(SO[2].first, &JD3);
46   });
47 }
48 
49 TEST_F(CoreAPIsStandardTest, BasicSuccessfulLookup) {
50   bool OnCompletionRun = false;
51 
52   auto OnCompletion = [&](Expected<SymbolMap> Result) {
53     EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error";
54     auto &Resolved = *Result;
55     auto I = Resolved.find(Foo);
56     EXPECT_NE(I, Resolved.end()) << "Could not find symbol definition";
57     EXPECT_EQ(I->second.getAddress(), FooAddr)
58         << "Resolution returned incorrect result";
59     OnCompletionRun = true;
60   };
61 
62   std::unique_ptr<MaterializationResponsibility> FooMR;
63 
64   cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(
65       SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
66       [&](std::unique_ptr<MaterializationResponsibility> R) {
67         FooMR = std::move(R);
68       })));
69 
70   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
71             SymbolLookupSet(Foo), SymbolState::Ready, OnCompletion,
72             NoDependenciesToRegister);
73 
74   EXPECT_FALSE(OnCompletionRun) << "Should not have been resolved yet";
75 
76   cantFail(FooMR->notifyResolved({{Foo, FooSym}}));
77 
78   EXPECT_FALSE(OnCompletionRun) << "Should not be ready yet";
79 
80   cantFail(FooMR->notifyEmitted());
81 
82   EXPECT_TRUE(OnCompletionRun) << "Should have been marked ready";
83 }
84 
85 TEST_F(CoreAPIsStandardTest, EmptyLookup) {
86   bool OnCompletionRun = false;
87 
88   auto OnCompletion = [&](Expected<SymbolMap> Result) {
89     cantFail(std::move(Result));
90     OnCompletionRun = true;
91   };
92 
93   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), SymbolLookupSet(),
94             SymbolState::Ready, OnCompletion, NoDependenciesToRegister);
95 
96   EXPECT_TRUE(OnCompletionRun) << "OnCompletion was not run for empty query";
97 }
98 
99 TEST_F(CoreAPIsStandardTest, ResolveUnrequestedSymbol) {
100   // Test that all symbols in a MaterializationUnit materialize corretly when
101   // only a subset of symbols is looked up.
102   // The aim here is to ensure that we're not relying on the query to set up
103   // state needed to materialize the unrequested symbols.
104 
105   cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(
106       SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}),
107       [this](std::unique_ptr<MaterializationResponsibility> R) {
108         cantFail(R->notifyResolved({{Foo, FooSym}, {Bar, BarSym}}));
109         cantFail(R->notifyEmitted());
110       })));
111 
112   auto Result =
113       cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Foo})));
114   EXPECT_EQ(Result.size(), 1U) << "Unexpected number of results";
115   EXPECT_TRUE(Result.count(Foo)) << "Expected result for \"Foo\"";
116 }
117 
118 TEST_F(CoreAPIsStandardTest, MaterializationSideEffctsOnlyBasic) {
119   // Test that basic materialization-side-effects-only symbols work as expected:
120   // that they can be emitted without being resolved, that queries for them
121   // don't return until they're emitted, and that they don't appear in query
122   // results.
123 
124   std::unique_ptr<MaterializationResponsibility> FooR;
125   std::optional<SymbolMap> Result;
126 
127   cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(
128       SymbolFlagsMap(
129           {{Foo, JITSymbolFlags::Exported |
130                      JITSymbolFlags::MaterializationSideEffectsOnly}}),
131       [&](std::unique_ptr<MaterializationResponsibility> R) {
132         FooR = std::move(R);
133       })));
134 
135   ES.lookup(
136       LookupKind::Static, makeJITDylibSearchOrder(&JD),
137       SymbolLookupSet(Foo, SymbolLookupFlags::WeaklyReferencedSymbol),
138       SymbolState::Ready,
139       [&](Expected<SymbolMap> LookupResult) {
140         if (LookupResult)
141           Result = std::move(*LookupResult);
142         else
143           ADD_FAILURE() << "Unexpected lookup error: "
144                         << toString(LookupResult.takeError());
145       },
146       NoDependenciesToRegister);
147 
148   EXPECT_FALSE(Result) << "Lookup returned unexpectedly";
149   EXPECT_TRUE(FooR) << "Lookup failed to trigger materialization";
150   EXPECT_THAT_ERROR(FooR->notifyEmitted(), Succeeded())
151       << "Emission of materialization-side-effects-only symbol failed";
152 
153   EXPECT_TRUE(Result) << "Lookup failed to return";
154   EXPECT_TRUE(Result->empty()) << "Lookup result contained unexpected value";
155 }
156 
157 TEST_F(CoreAPIsStandardTest, MaterializationSideEffectsOnlyFailuresPersist) {
158   // Test that when a MaterializationSideEffectsOnly symbol is failed it
159   // remains in the failure state rather than vanishing.
160 
161   cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(
162       SymbolFlagsMap(
163           {{Foo, JITSymbolFlags::Exported |
164                      JITSymbolFlags::MaterializationSideEffectsOnly}}),
165       [&](std::unique_ptr<MaterializationResponsibility> R) {
166         R->failMaterialization();
167       })));
168 
169   EXPECT_THAT_EXPECTED(
170       ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Foo})),
171       Failed());
172   EXPECT_THAT_EXPECTED(
173       ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Foo})),
174       Failed());
175 }
176 
177 TEST_F(CoreAPIsStandardTest, RemoveSymbolsTest) {
178   // Test that:
179   // (1) Missing symbols generate a SymbolsNotFound error.
180   // (2) Materializing symbols generate a SymbolCouldNotBeRemoved error.
181   // (3) Removal of unmaterialized symbols triggers discard on the
182   //     materialization unit.
183   // (4) Removal of symbols destroys empty materialization units.
184   // (5) Removal of materialized symbols works.
185 
186   // Foo will be fully materialized.
187   cantFail(JD.define(absoluteSymbols({{Foo, FooSym}})));
188 
189   // Bar will be unmaterialized.
190   bool BarDiscarded = false;
191   bool BarMaterializerDestructed = false;
192   cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(
193       SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
194       [this](std::unique_ptr<MaterializationResponsibility> R) {
195         ADD_FAILURE() << "Unexpected materialization of \"Bar\"";
196         cantFail(R->notifyResolved({{Bar, BarSym}}));
197         cantFail(R->notifyEmitted());
198       },
199       nullptr,
200       [&](const JITDylib &JD, const SymbolStringPtr &Name) {
201         EXPECT_EQ(Name, Bar) << "Expected \"Bar\" to be discarded";
202         if (Name == Bar)
203           BarDiscarded = true;
204       },
205       [&]() { BarMaterializerDestructed = true; })));
206 
207   // Baz will be in the materializing state initially, then
208   // materialized for the final removal attempt.
209   std::unique_ptr<MaterializationResponsibility> BazR;
210   cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(
211       SymbolFlagsMap({{Baz, BazSym.getFlags()}}),
212       [&](std::unique_ptr<MaterializationResponsibility> R) {
213         BazR = std::move(R);
214       },
215       nullptr,
216       [](const JITDylib &JD, const SymbolStringPtr &Name) {
217         ADD_FAILURE() << "\"Baz\" discarded unexpectedly";
218       })));
219 
220   bool OnCompletionRun = false;
221   ES.lookup(
222       LookupKind::Static, makeJITDylibSearchOrder(&JD),
223       SymbolLookupSet({Foo, Baz}), SymbolState::Ready,
224       [&](Expected<SymbolMap> Result) {
225         cantFail(Result.takeError());
226         OnCompletionRun = true;
227       },
228       NoDependenciesToRegister);
229 
230   {
231     // Attempt 1: Search for a missing symbol, Qux.
232     auto Err = JD.remove({Foo, Bar, Baz, Qux});
233     EXPECT_TRUE(!!Err) << "Expected failure";
234     EXPECT_TRUE(Err.isA<SymbolsNotFound>())
235         << "Expected a SymbolsNotFound error";
236     consumeError(std::move(Err));
237   }
238 
239   {
240     // Attempt 2: Search for a symbol that is still materializing, Baz.
241     auto Err = JD.remove({Foo, Bar, Baz});
242     EXPECT_TRUE(!!Err) << "Expected failure";
243     EXPECT_TRUE(Err.isA<SymbolsCouldNotBeRemoved>())
244         << "Expected a SymbolsNotFound error";
245     consumeError(std::move(Err));
246   }
247 
248   cantFail(BazR->notifyResolved({{Baz, BazSym}}));
249   cantFail(BazR->notifyEmitted());
250   {
251     // Attempt 3: Search now that all symbols are fully materialized
252     // (Foo, Baz), or not yet materialized (Bar).
253     auto Err = JD.remove({Foo, Bar, Baz});
254     EXPECT_FALSE(!!Err) << "Expected success";
255   }
256 
257   EXPECT_TRUE(BarDiscarded) << "\"Bar\" should have been discarded";
258   EXPECT_TRUE(BarMaterializerDestructed)
259       << "\"Bar\"'s materializer should have been destructed";
260   EXPECT_TRUE(OnCompletionRun) << "OnCompletion should have been run";
261 }
262 
263 TEST_F(CoreAPIsStandardTest, DiscardInitSymbol) {
264   SymbolStringPtr ForwardedDiscardSym = nullptr;
265 
266   auto MU = std::make_unique<SimpleMaterializationUnit>(
267       SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}),
268       [](std::unique_ptr<MaterializationResponsibility> R) {
269         llvm_unreachable("Materialize called unexpectedly?");
270       },
271       Foo,
272       [&](const JITDylib &, SymbolStringPtr Sym) {
273         ForwardedDiscardSym = std::move(Sym);
274       });
275 
276   MU->doDiscard(JD, Foo);
277 
278   EXPECT_EQ(ForwardedDiscardSym, Foo);
279   EXPECT_EQ(MU->getSymbols().size(), 1U);
280   EXPECT_TRUE(MU->getSymbols().count(Bar));
281   EXPECT_EQ(MU->getInitializerSymbol(), nullptr);
282 }
283 
284 TEST_F(CoreAPIsStandardTest, LookupWithHiddenSymbols) {
285   auto BarHiddenFlags = BarSym.getFlags() & ~JITSymbolFlags::Exported;
286   auto BarHiddenSym = ExecutorSymbolDef(BarSym.getAddress(), BarHiddenFlags);
287 
288   cantFail(JD.define(absoluteSymbols({{Foo, FooSym}, {Bar, BarHiddenSym}})));
289 
290   auto &JD2 = ES.createBareJITDylib("JD2");
291   cantFail(JD2.define(absoluteSymbols({{Bar, QuxSym}})));
292 
293   /// Try a blocking lookup.
294   auto Result = cantFail(ES.lookup(makeJITDylibSearchOrder({&JD, &JD2}),
295                                    SymbolLookupSet({Foo, Bar})));
296 
297   EXPECT_EQ(Result.size(), 2U) << "Unexpected number of results";
298   EXPECT_EQ(Result.count(Foo), 1U) << "Missing result for \"Foo\"";
299   EXPECT_EQ(Result.count(Bar), 1U) << "Missing result for \"Bar\"";
300   EXPECT_EQ(Result[Bar].getAddress(), QuxSym.getAddress())
301       << "Wrong result for \"Bar\"";
302 }
303 
304 TEST_F(CoreAPIsStandardTest, LookupFlagsTest) {
305   // Test that lookupFlags works on a predefined symbol, and does not trigger
306   // materialization of a lazy symbol. Make the lazy symbol weak to test that
307   // the weak flag is propagated correctly.
308 
309   BarSym.setFlags(static_cast<JITSymbolFlags::FlagNames>(
310       JITSymbolFlags::Exported | JITSymbolFlags::Weak));
311   auto MU = std::make_unique<SimpleMaterializationUnit>(
312       SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
313       [](std::unique_ptr<MaterializationResponsibility> R) {
314         llvm_unreachable("Symbol materialized on flags lookup");
315       });
316 
317   cantFail(JD.define(absoluteSymbols({{Foo, FooSym}})));
318   cantFail(JD.define(std::move(MU)));
319 
320   auto SymbolFlags = cantFail(ES.lookupFlags(
321       LookupKind::Static,
322       {{&JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}},
323       SymbolLookupSet({Foo, Bar, Baz},
324                       SymbolLookupFlags::WeaklyReferencedSymbol)));
325 
326   EXPECT_EQ(SymbolFlags.size(), 2U)
327       << "Returned symbol flags contains unexpected results";
328   EXPECT_EQ(SymbolFlags.count(Foo), 1U) << "Missing lookupFlags result for Foo";
329   EXPECT_EQ(SymbolFlags[Foo], FooSym.getFlags())
330       << "Incorrect flags returned for Foo";
331   EXPECT_EQ(SymbolFlags.count(Bar), 1U)
332       << "Missing  lookupFlags result for Bar";
333   EXPECT_EQ(SymbolFlags[Bar], BarSym.getFlags())
334       << "Incorrect flags returned for Bar";
335 }
336 
337 TEST_F(CoreAPIsStandardTest, LookupWithGeneratorFailure) {
338 
339   class BadGenerator : public DefinitionGenerator {
340   public:
341     Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &,
342                         JITDylibLookupFlags, const SymbolLookupSet &) override {
343       return make_error<StringError>("BadGenerator", inconvertibleErrorCode());
344     }
345   };
346 
347   JD.addGenerator(std::make_unique<BadGenerator>());
348 
349   EXPECT_THAT_ERROR(
350       ES.lookupFlags(LookupKind::Static,
351                      {{&JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}},
352                      SymbolLookupSet(Foo))
353           .takeError(),
354       Failed<StringError>())
355       << "Generator failure did not propagate through lookupFlags";
356 
357   EXPECT_THAT_ERROR(
358       ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet(Foo)).takeError(),
359       Failed<StringError>())
360       << "Generator failure did not propagate through lookup";
361 }
362 
363 TEST_F(CoreAPIsStandardTest, TestBasicAliases) {
364   cantFail(JD.define(absoluteSymbols({{Foo, FooSym}, {Bar, BarSym}})));
365   cantFail(JD.define(symbolAliases({{Baz, {Foo, JITSymbolFlags::Exported}},
366                                     {Qux, {Bar, JITSymbolFlags::Weak}}})));
367   cantFail(JD.define(absoluteSymbols({{Qux, QuxSym}})));
368 
369   auto Result =
370       ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Baz, Qux}));
371   EXPECT_TRUE(!!Result) << "Unexpected lookup failure";
372   EXPECT_EQ(Result->count(Baz), 1U) << "No result for \"baz\"";
373   EXPECT_EQ(Result->count(Qux), 1U) << "No result for \"qux\"";
374   EXPECT_EQ((*Result)[Baz].getAddress(), FooSym.getAddress())
375       << "\"Baz\"'s address should match \"Foo\"'s";
376   EXPECT_EQ((*Result)[Qux].getAddress(), QuxSym.getAddress())
377       << "The \"Qux\" alias should have been overriden";
378 }
379 
380 TEST_F(CoreAPIsStandardTest, TestChainedAliases) {
381   cantFail(JD.define(absoluteSymbols({{Foo, FooSym}})));
382   cantFail(JD.define(symbolAliases(
383       {{Baz, {Bar, BazSym.getFlags()}}, {Bar, {Foo, BarSym.getFlags()}}})));
384 
385   auto Result =
386       ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Bar, Baz}));
387   EXPECT_TRUE(!!Result) << "Unexpected lookup failure";
388   EXPECT_EQ(Result->count(Bar), 1U) << "No result for \"bar\"";
389   EXPECT_EQ(Result->count(Baz), 1U) << "No result for \"baz\"";
390   EXPECT_EQ((*Result)[Bar].getAddress(), FooSym.getAddress())
391       << "\"Bar\"'s address should match \"Foo\"'s";
392   EXPECT_EQ((*Result)[Baz].getAddress(), FooSym.getAddress())
393       << "\"Baz\"'s address should match \"Foo\"'s";
394 }
395 
396 TEST_F(CoreAPIsStandardTest, TestBasicReExports) {
397   // Test that the basic use case of re-exporting a single symbol from another
398   // JITDylib works.
399   cantFail(JD.define(absoluteSymbols({{Foo, FooSym}})));
400 
401   auto &JD2 = ES.createBareJITDylib("JD2");
402 
403   cantFail(JD2.define(reexports(JD, {{Bar, {Foo, BarSym.getFlags()}}})));
404 
405   auto Result = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD2), Bar));
406   EXPECT_EQ(Result.getAddress(), FooSym.getAddress())
407       << "Re-export Bar for symbol Foo should match FooSym's address";
408 }
409 
410 TEST_F(CoreAPIsStandardTest, TestThatReExportsDontUnnecessarilyMaterialize) {
411   // Test that re-exports do not materialize symbols that have not been queried
412   // for.
413   cantFail(JD.define(absoluteSymbols({{Foo, FooSym}})));
414 
415   bool BarMaterialized = false;
416   auto BarMU = std::make_unique<SimpleMaterializationUnit>(
417       SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
418       [&](std::unique_ptr<MaterializationResponsibility> R) {
419         BarMaterialized = true;
420         cantFail(R->notifyResolved({{Bar, BarSym}}));
421         cantFail(R->notifyEmitted());
422       });
423 
424   cantFail(JD.define(BarMU));
425 
426   auto &JD2 = ES.createBareJITDylib("JD2");
427 
428   cantFail(JD2.define(reexports(
429       JD, {{Baz, {Foo, BazSym.getFlags()}}, {Qux, {Bar, QuxSym.getFlags()}}})));
430 
431   auto Result = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD2), Baz));
432   EXPECT_EQ(Result.getAddress(), FooSym.getAddress())
433       << "Re-export Baz for symbol Foo should match FooSym's address";
434 
435   EXPECT_FALSE(BarMaterialized) << "Bar should not have been materialized";
436 }
437 
438 TEST_F(CoreAPIsStandardTest, TestReexportsGenerator) {
439   // Test that a re-exports generator can dynamically generate reexports.
440 
441   auto &JD2 = ES.createBareJITDylib("JD2");
442   cantFail(JD2.define(absoluteSymbols({{Foo, FooSym}, {Bar, BarSym}})));
443 
444   auto Filter = [this](SymbolStringPtr Name) { return Name != Bar; };
445 
446   JD.addGenerator(std::make_unique<ReexportsGenerator>(
447       JD2, JITDylibLookupFlags::MatchExportedSymbolsOnly, Filter));
448 
449   auto Flags = cantFail(ES.lookupFlags(
450       LookupKind::Static,
451       {{&JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}},
452       SymbolLookupSet({Foo, Bar, Baz},
453                       SymbolLookupFlags::WeaklyReferencedSymbol)));
454   EXPECT_EQ(Flags.size(), 1U) << "Unexpected number of results";
455   EXPECT_EQ(Flags[Foo], FooSym.getFlags()) << "Unexpected flags for Foo";
456 
457   auto Result = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Foo));
458 
459   EXPECT_EQ(Result.getAddress(), FooSym.getAddress())
460       << "Incorrect reexported symbol address";
461 }
462 
463 TEST_F(CoreAPIsStandardTest, TestTrivialCircularDependency) {
464   std::unique_ptr<MaterializationResponsibility> FooR;
465   auto FooMU = std::make_unique<SimpleMaterializationUnit>(
466       SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
467       [&](std::unique_ptr<MaterializationResponsibility> R) {
468         FooR = std::move(R);
469       });
470 
471   cantFail(JD.define(FooMU));
472 
473   bool FooReady = false;
474   auto OnCompletion = [&](Expected<SymbolMap> Result) {
475     cantFail(std::move(Result));
476     FooReady = true;
477   };
478 
479   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
480             SymbolLookupSet({Foo}), SymbolState::Ready, OnCompletion,
481             NoDependenciesToRegister);
482 
483   FooR->addDependenciesForAll({{&JD, SymbolNameSet({Foo})}});
484   EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Succeeded())
485       << "No symbols marked failed, but Foo failed to resolve";
486   EXPECT_THAT_ERROR(FooR->notifyEmitted(), Succeeded())
487       << "No symbols marked failed, but Foo failed to emit";
488 
489   EXPECT_TRUE(FooReady)
490     << "Self-dependency prevented symbol from being marked ready";
491 }
492 
493 TEST_F(CoreAPIsStandardTest, TestCircularDependenceInOneJITDylib) {
494   // Test that a circular symbol dependency between three symbols in a JITDylib
495   // does not prevent any symbol from becoming 'ready' once all symbols are
496   // emitted.
497 
498   std::unique_ptr<MaterializationResponsibility> FooR;
499   std::unique_ptr<MaterializationResponsibility> BarR;
500   std::unique_ptr<MaterializationResponsibility> BazR;
501 
502   // Create a MaterializationUnit for each symbol that moves the
503   // MaterializationResponsibility into one of the locals above.
504   auto FooMU = std::make_unique<SimpleMaterializationUnit>(
505       SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
506       [&](std::unique_ptr<MaterializationResponsibility> R) {
507         FooR = std::move(R);
508       });
509 
510   auto BarMU = std::make_unique<SimpleMaterializationUnit>(
511       SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
512       [&](std::unique_ptr<MaterializationResponsibility> R) {
513         BarR = std::move(R);
514       });
515 
516   auto BazMU = std::make_unique<SimpleMaterializationUnit>(
517       SymbolFlagsMap({{Baz, BazSym.getFlags()}}),
518       [&](std::unique_ptr<MaterializationResponsibility> R) {
519         BazR = std::move(R);
520       });
521 
522   // Define the symbols.
523   cantFail(JD.define(FooMU));
524   cantFail(JD.define(BarMU));
525   cantFail(JD.define(BazMU));
526 
527   // Query each of the symbols to trigger materialization.
528   bool FooResolved = false;
529   bool FooReady = false;
530 
531   auto OnFooResolution = [&](Expected<SymbolMap> Result) {
532     cantFail(std::move(Result));
533     FooResolved = true;
534   };
535 
536   auto OnFooReady = [&](Expected<SymbolMap> Result) {
537     cantFail(std::move(Result));
538     FooReady = true;
539   };
540 
541   // Issue lookups for Foo. Use NoDependenciesToRegister: We're going to add
542   // the dependencies manually below.
543   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
544             SymbolLookupSet(Foo), SymbolState::Resolved,
545             std::move(OnFooResolution), NoDependenciesToRegister);
546 
547   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
548             SymbolLookupSet(Foo), SymbolState::Ready, std::move(OnFooReady),
549             NoDependenciesToRegister);
550 
551   bool BarResolved = false;
552   bool BarReady = false;
553   auto OnBarResolution = [&](Expected<SymbolMap> Result) {
554     cantFail(std::move(Result));
555     BarResolved = true;
556   };
557 
558   auto OnBarReady = [&](Expected<SymbolMap> Result) {
559     cantFail(std::move(Result));
560     BarReady = true;
561   };
562 
563   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
564             SymbolLookupSet(Bar), SymbolState::Resolved,
565             std::move(OnBarResolution), NoDependenciesToRegister);
566 
567   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
568             SymbolLookupSet(Bar), SymbolState::Ready, std::move(OnBarReady),
569             NoDependenciesToRegister);
570 
571   bool BazResolved = false;
572   bool BazReady = false;
573 
574   auto OnBazResolution = [&](Expected<SymbolMap> Result) {
575     cantFail(std::move(Result));
576     BazResolved = true;
577   };
578 
579   auto OnBazReady = [&](Expected<SymbolMap> Result) {
580     cantFail(std::move(Result));
581     BazReady = true;
582   };
583 
584   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
585             SymbolLookupSet(Baz), SymbolState::Resolved,
586             std::move(OnBazResolution), NoDependenciesToRegister);
587 
588   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
589             SymbolLookupSet(Baz), SymbolState::Ready, std::move(OnBazReady),
590             NoDependenciesToRegister);
591 
592   // Add a circular dependency: Foo -> Bar, Bar -> Baz, Baz -> Foo.
593   FooR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}});
594   BarR->addDependenciesForAll({{&JD, SymbolNameSet({Baz})}});
595   BazR->addDependenciesForAll({{&JD, SymbolNameSet({Foo})}});
596 
597   // Add self-dependencies for good measure. This tests that the implementation
598   // of addDependencies filters these out.
599   FooR->addDependenciesForAll({{&JD, SymbolNameSet({Foo})}});
600   BarR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}});
601   BazR->addDependenciesForAll({{&JD, SymbolNameSet({Baz})}});
602 
603   // Check that nothing has been resolved yet.
604   EXPECT_FALSE(FooResolved) << "\"Foo\" should not be resolved yet";
605   EXPECT_FALSE(BarResolved) << "\"Bar\" should not be resolved yet";
606   EXPECT_FALSE(BazResolved) << "\"Baz\" should not be resolved yet";
607 
608   // Resolve the symbols (but do not emit them).
609   EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Succeeded())
610       << "No symbols failed, but Foo failed to resolve";
611   EXPECT_THAT_ERROR(BarR->notifyResolved({{Bar, BarSym}}), Succeeded())
612       << "No symbols failed, but Bar failed to resolve";
613   EXPECT_THAT_ERROR(BazR->notifyResolved({{Baz, BazSym}}), Succeeded())
614       << "No symbols failed, but Baz failed to resolve";
615 
616   // Verify that the symbols have been resolved, but are not ready yet.
617   EXPECT_TRUE(FooResolved) << "\"Foo\" should be resolved now";
618   EXPECT_TRUE(BarResolved) << "\"Bar\" should be resolved now";
619   EXPECT_TRUE(BazResolved) << "\"Baz\" should be resolved now";
620 
621   EXPECT_FALSE(FooReady) << "\"Foo\" should not be ready yet";
622   EXPECT_FALSE(BarReady) << "\"Bar\" should not be ready yet";
623   EXPECT_FALSE(BazReady) << "\"Baz\" should not be ready yet";
624 
625   // Emit two of the symbols.
626   EXPECT_THAT_ERROR(FooR->notifyEmitted(), Succeeded())
627       << "No symbols failed, but Foo failed to emit";
628   EXPECT_THAT_ERROR(BarR->notifyEmitted(), Succeeded())
629       << "No symbols failed, but Bar failed to emit";
630 
631   // Verify that nothing is ready until the circular dependence is resolved.
632   EXPECT_FALSE(FooReady) << "\"Foo\" still should not be ready";
633   EXPECT_FALSE(BarReady) << "\"Bar\" still should not be ready";
634   EXPECT_FALSE(BazReady) << "\"Baz\" still should not be ready";
635 
636   // Emit the last symbol.
637   EXPECT_THAT_ERROR(BazR->notifyEmitted(), Succeeded())
638       << "No symbols failed, but Baz failed to emit";
639 
640   // Verify that everything becomes ready once the circular dependence resolved.
641   EXPECT_TRUE(FooReady) << "\"Foo\" should be ready now";
642   EXPECT_TRUE(BarReady) << "\"Bar\" should be ready now";
643   EXPECT_TRUE(BazReady) << "\"Baz\" should be ready now";
644 }
645 
646 TEST_F(CoreAPIsStandardTest, FailureInDependency) {
647   std::unique_ptr<MaterializationResponsibility> FooR;
648   std::unique_ptr<MaterializationResponsibility> BarR;
649 
650   // Create a MaterializationUnit for each symbol that moves the
651   // MaterializationResponsibility into one of the locals above.
652   auto FooMU = std::make_unique<SimpleMaterializationUnit>(
653       SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
654       [&](std::unique_ptr<MaterializationResponsibility> R) {
655         FooR = std::move(R);
656       });
657 
658   auto BarMU = std::make_unique<SimpleMaterializationUnit>(
659       SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
660       [&](std::unique_ptr<MaterializationResponsibility> R) {
661         BarR = std::move(R);
662       });
663 
664   // Define the symbols.
665   cantFail(JD.define(FooMU));
666   cantFail(JD.define(BarMU));
667 
668   bool OnFooReadyRun = false;
669   auto OnFooReady = [&](Expected<SymbolMap> Result) {
670     EXPECT_THAT_EXPECTED(std::move(Result), Failed());
671     OnFooReadyRun = true;
672   };
673 
674   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
675             SymbolLookupSet(Foo), SymbolState::Ready, std::move(OnFooReady),
676             NoDependenciesToRegister);
677 
678   bool OnBarReadyRun = false;
679   auto OnBarReady = [&](Expected<SymbolMap> Result) {
680     EXPECT_THAT_EXPECTED(std::move(Result), Failed());
681     OnBarReadyRun = true;
682   };
683 
684   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
685             SymbolLookupSet(Bar), SymbolState::Ready, std::move(OnBarReady),
686             NoDependenciesToRegister);
687 
688   // Add a dependency by Foo on Bar.
689   FooR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}});
690 
691   // Fail bar.
692   BarR->failMaterialization();
693 
694   // Verify that queries on Bar failed, but queries on Foo have not yet.
695   EXPECT_TRUE(OnBarReadyRun) << "Query for \"Bar\" was not run";
696   EXPECT_FALSE(OnFooReadyRun) << "Query for \"Foo\" was run unexpectedly";
697 
698   // Check that we can still resolve Foo (even though it has been failed).
699   EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Failed())
700       << "Expected resolution for \"Foo\" to fail.";
701 
702   FooR->failMaterialization();
703 
704   // Verify that queries on Foo have now failed.
705   EXPECT_TRUE(OnFooReadyRun) << "Query for \"Foo\" was not run";
706 
707   // Verify that subsequent lookups on Bar and Foo fail.
708   EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Bar}), Failed())
709       << "Lookup on failed symbol should fail";
710 
711   EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Foo}), Failed())
712       << "Lookup on failed symbol should fail";
713 }
714 
715 TEST_F(CoreAPIsStandardTest, FailureInCircularDependency) {
716   std::unique_ptr<MaterializationResponsibility> FooR;
717   std::unique_ptr<MaterializationResponsibility> BarR;
718 
719   // Create a MaterializationUnit for each symbol that moves the
720   // MaterializationResponsibility into one of the locals above.
721   auto FooMU = std::make_unique<SimpleMaterializationUnit>(
722       SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
723       [&](std::unique_ptr<MaterializationResponsibility> R) {
724         FooR = std::move(R);
725       });
726 
727   auto BarMU = std::make_unique<SimpleMaterializationUnit>(
728       SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
729       [&](std::unique_ptr<MaterializationResponsibility> R) {
730         BarR = std::move(R);
731       });
732 
733   // Define the symbols.
734   cantFail(JD.define(FooMU));
735   cantFail(JD.define(BarMU));
736 
737   bool OnFooReadyRun = false;
738   auto OnFooReady = [&](Expected<SymbolMap> Result) {
739     EXPECT_THAT_EXPECTED(std::move(Result), Failed());
740     OnFooReadyRun = true;
741   };
742 
743   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
744             SymbolLookupSet(Foo), SymbolState::Ready, std::move(OnFooReady),
745             NoDependenciesToRegister);
746 
747   bool OnBarReadyRun = false;
748   auto OnBarReady = [&](Expected<SymbolMap> Result) {
749     EXPECT_THAT_EXPECTED(std::move(Result), Failed());
750     OnBarReadyRun = true;
751   };
752 
753   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
754             SymbolLookupSet(Bar), SymbolState::Ready, std::move(OnBarReady),
755             NoDependenciesToRegister);
756 
757   // Add a dependency by Foo on Bar and vice-versa.
758   FooR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}});
759   BarR->addDependenciesForAll({{&JD, SymbolNameSet({Foo})}});
760 
761   // Fail bar.
762   BarR->failMaterialization();
763 
764   // Verify that queries on Bar failed, but queries on Foo have not yet.
765   EXPECT_TRUE(OnBarReadyRun) << "Query for \"Bar\" was not run";
766   EXPECT_FALSE(OnFooReadyRun) << "Query for \"Foo\" was run unexpectedly";
767 
768   // Verify that trying to resolve Foo fails.
769   EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Failed())
770       << "Expected resolution for \"Foo\" to fail.";
771 
772   FooR->failMaterialization();
773 
774   // Verify that queries on Foo have now failed.
775   EXPECT_TRUE(OnFooReadyRun) << "Query for \"Foo\" was not run";
776 
777   // Verify that subsequent lookups on Bar and Foo fail.
778   EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Bar}), Failed())
779       << "Lookup on failed symbol should fail";
780 
781   EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Foo}), Failed())
782       << "Lookup on failed symbol should fail";
783 }
784 
785 TEST_F(CoreAPIsStandardTest, AddDependencyOnFailedSymbol) {
786   std::unique_ptr<MaterializationResponsibility> FooR;
787   std::unique_ptr<MaterializationResponsibility> BarR;
788 
789   // Create a MaterializationUnit for each symbol that moves the
790   // MaterializationResponsibility into one of the locals above.
791   auto FooMU = std::make_unique<SimpleMaterializationUnit>(
792       SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
793       [&](std::unique_ptr<MaterializationResponsibility> R) {
794         FooR = std::move(R);
795       });
796 
797   auto BarMU = std::make_unique<SimpleMaterializationUnit>(
798       SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
799       [&](std::unique_ptr<MaterializationResponsibility> R) {
800         BarR = std::move(R);
801       });
802 
803   // Define the symbols.
804   cantFail(JD.define(FooMU));
805   cantFail(JD.define(BarMU));
806 
807   bool OnFooReadyRun = false;
808   auto OnFooReady = [&](Expected<SymbolMap> Result) {
809     EXPECT_THAT_EXPECTED(std::move(Result), Failed());
810     OnFooReadyRun = true;
811   };
812 
813   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
814             SymbolLookupSet(Foo), SymbolState::Ready, std::move(OnFooReady),
815             NoDependenciesToRegister);
816 
817   bool OnBarReadyRun = false;
818   auto OnBarReady = [&](Expected<SymbolMap> Result) {
819     EXPECT_THAT_EXPECTED(std::move(Result), Failed());
820     OnBarReadyRun = true;
821   };
822 
823   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
824             SymbolLookupSet(Bar), SymbolState::Ready, std::move(OnBarReady),
825             NoDependenciesToRegister);
826 
827   // Fail bar.
828   BarR->failMaterialization();
829 
830   // We expect Bar's query to fail immediately, but Foo's query not to have run
831   // yet.
832   EXPECT_TRUE(OnBarReadyRun) << "Query for \"Bar\" was not run";
833   EXPECT_FALSE(OnFooReadyRun) << "Query for \"Foo\" should not have run yet";
834 
835   // Add dependency of Foo on Bar.
836   FooR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}});
837 
838   // Check that we can still resolve Foo (even though it has been failed).
839   EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Failed())
840       << "Expected resolution for \"Foo\" to fail.";
841 
842   FooR->failMaterialization();
843 
844   // Foo's query should have failed before we return from addDependencies.
845   EXPECT_TRUE(OnFooReadyRun) << "Query for \"Foo\" was not run";
846 
847   // Verify that subsequent lookups on Bar and Foo fail.
848   EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Bar}), Failed())
849       << "Lookup on failed symbol should fail";
850 
851   EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Foo}), Failed())
852       << "Lookup on failed symbol should fail";
853 }
854 
855 TEST_F(CoreAPIsStandardTest, FailAfterMaterialization) {
856   std::unique_ptr<MaterializationResponsibility> FooR;
857   std::unique_ptr<MaterializationResponsibility> BarR;
858 
859   // Create a MaterializationUnit for each symbol that moves the
860   // MaterializationResponsibility into one of the locals above.
861   auto FooMU = std::make_unique<SimpleMaterializationUnit>(
862       SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
863       [&](std::unique_ptr<MaterializationResponsibility> R) {
864         FooR = std::move(R);
865       });
866 
867   auto BarMU = std::make_unique<SimpleMaterializationUnit>(
868       SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
869       [&](std::unique_ptr<MaterializationResponsibility> R) {
870         BarR = std::move(R);
871       });
872 
873   // Define the symbols.
874   cantFail(JD.define(FooMU));
875   cantFail(JD.define(BarMU));
876 
877   bool OnFooReadyRun = false;
878   auto OnFooReady = [&](Expected<SymbolMap> Result) {
879     EXPECT_THAT_EXPECTED(std::move(Result), Failed());
880     OnFooReadyRun = true;
881   };
882 
883   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
884             SymbolLookupSet(Foo), SymbolState::Ready, std::move(OnFooReady),
885             NoDependenciesToRegister);
886 
887   bool OnBarReadyRun = false;
888   auto OnBarReady = [&](Expected<SymbolMap> Result) {
889     EXPECT_THAT_EXPECTED(std::move(Result), Failed());
890     OnBarReadyRun = true;
891   };
892 
893   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
894             SymbolLookupSet(Bar), SymbolState::Ready, std::move(OnBarReady),
895             NoDependenciesToRegister);
896 
897   // Add a dependency by Foo on Bar and vice-versa.
898   FooR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}});
899   BarR->addDependenciesForAll({{&JD, SymbolNameSet({Foo})}});
900 
901   // Materialize Foo.
902   EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Succeeded())
903       << "Expected resolution for \"Foo\" to succeed.";
904   EXPECT_THAT_ERROR(FooR->notifyEmitted(), Succeeded())
905       << "Expected emission for \"Foo\" to succeed.";
906 
907   // Fail bar.
908   BarR->failMaterialization();
909 
910   // Verify that both queries failed.
911   EXPECT_TRUE(OnFooReadyRun) << "Query for Foo did not run";
912   EXPECT_TRUE(OnBarReadyRun) << "Query for Bar did not run";
913 }
914 
915 TEST_F(CoreAPIsStandardTest, FailMaterializerWithUnqueriedSymbols) {
916   // Make sure that symbols with no queries aganist them still
917   // fail correctly.
918 
919   bool MaterializerRun = false;
920   auto MU = std::make_unique<SimpleMaterializationUnit>(
921       SymbolFlagsMap(
922           {{Foo, JITSymbolFlags::Exported}, {Bar, JITSymbolFlags::Exported}}),
923       [&](std::unique_ptr<MaterializationResponsibility> R) {
924         MaterializerRun = true;
925         R->failMaterialization();
926       });
927 
928   cantFail(JD.define(std::move(MU)));
929 
930   // Issue a query for Foo, but not bar.
931   EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Foo}), Failed())
932       << "Expected lookup to fail.";
933 
934   // Check that the materializer (and therefore failMaterialization) ran.
935   EXPECT_TRUE(MaterializerRun) << "Expected materializer to have run by now";
936 
937   // Check that subsequent queries against both symbols fail.
938   EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Foo}), Failed())
939       << "Expected lookup for Foo to fail.";
940   EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Bar}), Failed())
941       << "Expected lookup for Bar to fail.";
942 }
943 
944 TEST_F(CoreAPIsStandardTest, DropMaterializerWhenEmpty) {
945   bool DestructorRun = false;
946 
947   JITSymbolFlags WeakExported(JITSymbolFlags::Exported);
948   WeakExported |= JITSymbolFlags::Weak;
949 
950   auto MU = std::make_unique<SimpleMaterializationUnit>(
951       SymbolFlagsMap({{Foo, WeakExported}, {Bar, WeakExported}}),
952       [](std::unique_ptr<MaterializationResponsibility> R) {
953         llvm_unreachable("Unexpected call to materialize");
954       },
955       nullptr,
956       [&](const JITDylib &JD, SymbolStringPtr Name) {
957         EXPECT_TRUE(Name == Foo || Name == Bar)
958             << "Discard of unexpected symbol?";
959       },
960       [&]() { DestructorRun = true; });
961 
962   cantFail(JD.define(MU));
963 
964   cantFail(JD.define(absoluteSymbols({{Foo, FooSym}})));
965 
966   EXPECT_FALSE(DestructorRun)
967       << "MaterializationUnit should not have been destroyed yet";
968 
969   cantFail(JD.define(absoluteSymbols({{Bar, BarSym}})));
970 
971   EXPECT_TRUE(DestructorRun)
972       << "MaterializationUnit should have been destroyed";
973 }
974 
975 TEST_F(CoreAPIsStandardTest, AddAndMaterializeLazySymbol) {
976   bool FooMaterialized = false;
977   bool BarDiscarded = false;
978 
979   JITSymbolFlags WeakExported(JITSymbolFlags::Exported);
980   WeakExported |= JITSymbolFlags::Weak;
981 
982   auto MU = std::make_unique<SimpleMaterializationUnit>(
983       SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}, {Bar, WeakExported}}),
984       [&](std::unique_ptr<MaterializationResponsibility> R) {
985         assert(BarDiscarded && "Bar should have been discarded by this point");
986         cantFail(R->notifyResolved(SymbolMap({{Foo, FooSym}})));
987         cantFail(R->notifyEmitted());
988         FooMaterialized = true;
989       },
990       nullptr,
991       [&](const JITDylib &JD, SymbolStringPtr Name) {
992         EXPECT_EQ(Name, Bar) << "Expected Name to be Bar";
993         BarDiscarded = true;
994       });
995 
996   cantFail(JD.define(MU));
997   cantFail(JD.define(absoluteSymbols({{Bar, BarSym}})));
998 
999   bool OnCompletionRun = false;
1000 
1001   auto OnCompletion = [&](Expected<SymbolMap> Result) {
1002     EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error";
1003     auto I = Result->find(Foo);
1004     EXPECT_NE(I, Result->end()) << "Could not find symbol definition";
1005     EXPECT_EQ(I->second.getAddress(), FooSym.getAddress())
1006         << "Resolution returned incorrect result";
1007     OnCompletionRun = true;
1008   };
1009 
1010   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
1011             SymbolLookupSet(Foo), SymbolState::Ready, std::move(OnCompletion),
1012             NoDependenciesToRegister);
1013 
1014   EXPECT_TRUE(FooMaterialized) << "Foo was not materialized";
1015   EXPECT_TRUE(BarDiscarded) << "Bar was not discarded";
1016   EXPECT_TRUE(OnCompletionRun) << "OnResolutionCallback was not run";
1017 }
1018 
1019 TEST_F(CoreAPIsStandardTest, TestBasicWeakSymbolMaterialization) {
1020   // Test that weak symbols are materialized correctly when we look them up.
1021   BarSym.setFlags(BarSym.getFlags() | JITSymbolFlags::Weak);
1022 
1023   bool BarMaterialized = false;
1024   auto MU1 = std::make_unique<SimpleMaterializationUnit>(
1025       SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}),
1026       [&](std::unique_ptr<MaterializationResponsibility> R) {
1027         cantFail(R->notifyResolved(SymbolMap({{Foo, FooSym}, {Bar, BarSym}})));
1028         cantFail(R->notifyEmitted());
1029         BarMaterialized = true;
1030       });
1031 
1032   bool DuplicateBarDiscarded = false;
1033   auto MU2 = std::make_unique<SimpleMaterializationUnit>(
1034       SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
1035       [&](std::unique_ptr<MaterializationResponsibility> R) {
1036         ADD_FAILURE() << "Attempt to materialize Bar from the wrong unit";
1037         R->failMaterialization();
1038       },
1039       nullptr,
1040       [&](const JITDylib &JD, SymbolStringPtr Name) {
1041         EXPECT_EQ(Name, Bar) << "Expected \"Bar\" to be discarded";
1042         DuplicateBarDiscarded = true;
1043       });
1044 
1045   cantFail(JD.define(MU1));
1046   cantFail(JD.define(MU2));
1047 
1048   bool OnCompletionRun = false;
1049 
1050   auto OnCompletion = [&](Expected<SymbolMap> Result) {
1051     cantFail(std::move(Result));
1052     OnCompletionRun = true;
1053   };
1054 
1055   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
1056             SymbolLookupSet(Bar), SymbolState::Ready, std::move(OnCompletion),
1057             NoDependenciesToRegister);
1058 
1059   EXPECT_TRUE(OnCompletionRun) << "OnCompletion not run";
1060   EXPECT_TRUE(BarMaterialized) << "Bar was not materialized at all";
1061   EXPECT_TRUE(DuplicateBarDiscarded)
1062       << "Duplicate bar definition not discarded";
1063 }
1064 
1065 TEST_F(CoreAPIsStandardTest, RedefineBoundWeakSymbol) {
1066   // Check that redefinition of a bound weak symbol fails.
1067 
1068   JITSymbolFlags WeakExported(JITSymbolFlags::Exported);
1069   WeakExported |= JITSymbolFlags::Weak;
1070 
1071   // Define "Foo" as weak, force materialization.
1072   cantFail(JD.define(absoluteSymbols({{Foo, {FooAddr, WeakExported}}})));
1073   cantFail(ES.lookup({&JD}, Foo));
1074 
1075   // Attempt to redefine "Foo". Expect failure, despite "Foo" being weak,
1076   // since it has already been bound.
1077   EXPECT_THAT_ERROR(JD.define(absoluteSymbols({{Foo, FooSym}})), Failed());
1078 }
1079 
1080 TEST_F(CoreAPIsStandardTest, DefineMaterializingSymbol) {
1081   bool ExpectNoMoreMaterialization = false;
1082   ES.setDispatchTask([&](std::unique_ptr<Task> T) {
1083     if (ExpectNoMoreMaterialization && isa<MaterializationTask>(*T))
1084       ADD_FAILURE() << "Unexpected materialization";
1085     T->run();
1086   });
1087 
1088   auto MU = std::make_unique<SimpleMaterializationUnit>(
1089       SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
1090       [&](std::unique_ptr<MaterializationResponsibility> R) {
1091         cantFail(
1092             R->defineMaterializing(SymbolFlagsMap({{Bar, BarSym.getFlags()}})));
1093         cantFail(R->notifyResolved(SymbolMap({{Foo, FooSym}, {Bar, BarSym}})));
1094         cantFail(R->notifyEmitted());
1095       });
1096 
1097   cantFail(JD.define(MU));
1098   cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Foo));
1099 
1100   // Assert that materialization is complete by now.
1101   ExpectNoMoreMaterialization = true;
1102 
1103   // Look up bar to verify that no further materialization happens.
1104   auto BarResult = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Bar));
1105   EXPECT_EQ(BarResult.getAddress(), BarSym.getAddress())
1106       << "Expected Bar == BarSym";
1107 }
1108 
1109 TEST_F(CoreAPIsStandardTest, GeneratorTest) {
1110   ExecutorSymbolDef BazHiddenSym(BazSym.getAddress(),
1111                                  BazSym.getFlags() & ~JITSymbolFlags::Exported);
1112   cantFail(JD.define(absoluteSymbols({{Foo, FooSym}, {Baz, BazHiddenSym}})));
1113 
1114   class TestGenerator : public DefinitionGenerator {
1115   public:
1116     TestGenerator(SymbolMap Symbols) : Symbols(std::move(Symbols)) {}
1117     Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD,
1118                         JITDylibLookupFlags JDLookupFlags,
1119                         const SymbolLookupSet &Names) override {
1120       SymbolMap NewDefs;
1121 
1122       for (const auto &KV : Names) {
1123         const auto &Name = KV.first;
1124         if (Symbols.count(Name))
1125           NewDefs[Name] = Symbols[Name];
1126       }
1127 
1128       cantFail(JD.define(absoluteSymbols(std::move(NewDefs))));
1129       return Error::success();
1130     };
1131 
1132   private:
1133     SymbolMap Symbols;
1134   };
1135 
1136   JD.addGenerator(std::make_unique<TestGenerator>(
1137       SymbolMap({{Bar, BarSym}, {Baz, BazSym}})));
1138 
1139   auto Result = cantFail(
1140       ES.lookup(makeJITDylibSearchOrder(&JD),
1141                 SymbolLookupSet({Foo, Bar})
1142                     .add(Baz, SymbolLookupFlags::WeaklyReferencedSymbol)));
1143 
1144   EXPECT_EQ(Result.count(Bar), 1U) << "Expected to find fallback def for 'bar'";
1145   EXPECT_EQ(Result[Bar].getAddress(), BarSym.getAddress())
1146       << "Expected fallback def for Bar to be equal to BarSym";
1147 }
1148 
1149 TEST_F(CoreAPIsStandardTest, AsynchronousGeneratorTest) {
1150   class TestGenerator : public DefinitionGenerator {
1151   public:
1152     TestGenerator(LookupState &TLS) : TLS(TLS) {}
1153     Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD,
1154                         JITDylibLookupFlags JDLookupFlags,
1155                         const SymbolLookupSet &Name) override {
1156       TLS = std::move(LS);
1157       return Error::success();
1158     }
1159 
1160   private:
1161     LookupState &TLS;
1162   };
1163 
1164   LookupState LS;
1165   JD.addGenerator(std::make_unique<TestGenerator>(LS));
1166 
1167   bool LookupCompleted = false;
1168 
1169   ES.lookup(
1170       LookupKind::Static, makeJITDylibSearchOrder(&JD), SymbolLookupSet(Foo),
1171       SymbolState::Ready,
1172       [&](Expected<SymbolMap> Result) {
1173         LookupCompleted = true;
1174         if (!Result) {
1175           ADD_FAILURE() << "Lookup failed unexpected";
1176           logAllUnhandledErrors(Result.takeError(), errs(), "");
1177           return;
1178         }
1179 
1180         EXPECT_EQ(Result->size(), 1U) << "Unexpected number of results";
1181         EXPECT_EQ(Result->count(Foo), 1U) << "Expected result for Foo";
1182         EXPECT_EQ((*Result)[Foo].getAddress(), FooSym.getAddress())
1183             << "Bad result for Foo";
1184       },
1185       NoDependenciesToRegister);
1186 
1187   EXPECT_FALSE(LookupCompleted);
1188 
1189   cantFail(JD.define(absoluteSymbols({{Foo, FooSym}})));
1190 
1191   LS.continueLookup(Error::success());
1192 
1193   EXPECT_TRUE(LookupCompleted);
1194 }
1195 
1196 TEST_F(CoreAPIsStandardTest, FailResolution) {
1197   auto MU = std::make_unique<SimpleMaterializationUnit>(
1198       SymbolFlagsMap({{Foo, JITSymbolFlags::Exported | JITSymbolFlags::Weak},
1199                       {Bar, JITSymbolFlags::Exported | JITSymbolFlags::Weak}}),
1200       [&](std::unique_ptr<MaterializationResponsibility> R) {
1201         R->failMaterialization();
1202       });
1203 
1204   cantFail(JD.define(MU));
1205 
1206   SymbolNameSet Names({Foo, Bar});
1207   auto Result = ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet(Names));
1208 
1209   EXPECT_FALSE(!!Result) << "Expected failure";
1210   if (!Result) {
1211     handleAllErrors(
1212         Result.takeError(),
1213         [&](FailedToMaterialize &F) {
1214           EXPECT_TRUE(F.getSymbols().count(&JD))
1215               << "Expected to fail on JITDylib JD";
1216           EXPECT_EQ(F.getSymbols().find(&JD)->second, Names)
1217               << "Expected to fail on symbols in Names";
1218         },
1219         [](ErrorInfoBase &EIB) {
1220           std::string ErrMsg;
1221           {
1222             raw_string_ostream ErrOut(ErrMsg);
1223             EIB.log(ErrOut);
1224           }
1225           ADD_FAILURE() << "Expected a FailedToResolve error. Got:\n" << ErrMsg;
1226         });
1227   }
1228 }
1229 
1230 TEST_F(CoreAPIsStandardTest, FailEmissionAfterResolution) {
1231 
1232   cantFail(JD.define(absoluteSymbols({{Baz, BazSym}})));
1233 
1234   auto MU = std::make_unique<SimpleMaterializationUnit>(
1235       SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}),
1236       [&](std::unique_ptr<MaterializationResponsibility> R) {
1237         cantFail(R->notifyResolved(SymbolMap({{Foo, FooSym}, {Bar, BarSym}})));
1238 
1239         ES.lookup(
1240             LookupKind::Static, makeJITDylibSearchOrder(&JD),
1241             SymbolLookupSet({Baz}), SymbolState::Resolved,
1242             [&](Expected<SymbolMap> Result) {
1243               // Called when "baz" is resolved. We don't actually depend
1244               // on or care about baz, but use it to trigger failure of
1245               // this materialization before Baz has been finalized in
1246               // order to test that error propagation is correct in this
1247               // scenario.
1248               cantFail(std::move(Result));
1249               R->failMaterialization();
1250             },
1251             [&](const SymbolDependenceMap &Deps) {
1252               R->addDependenciesForAll(Deps);
1253             });
1254       });
1255 
1256   cantFail(JD.define(MU));
1257 
1258   auto Result =
1259       ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Foo, Bar}));
1260 
1261   EXPECT_THAT_EXPECTED(std::move(Result), Failed())
1262       << "Unexpected success while trying to test error propagation";
1263 }
1264 
1265 TEST_F(CoreAPIsStandardTest, FailAfterPartialResolution) {
1266 
1267   cantFail(JD.define(absoluteSymbols({{Foo, FooSym}})));
1268 
1269   // Fail materialization of bar.
1270   auto BarMU = std::make_unique<SimpleMaterializationUnit>(
1271       SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
1272       [&](std::unique_ptr<MaterializationResponsibility> R) {
1273         R->failMaterialization();
1274       });
1275 
1276   cantFail(JD.define(std::move(BarMU)));
1277 
1278   bool QueryHandlerRun = false;
1279   ES.lookup(
1280       LookupKind::Static, makeJITDylibSearchOrder(&JD),
1281       SymbolLookupSet({Foo, Bar}), SymbolState::Resolved,
1282       [&](Expected<SymbolMap> Result) {
1283         EXPECT_THAT_EXPECTED(std::move(Result), Failed())
1284             << "Expected query to fail";
1285         QueryHandlerRun = true;
1286       },
1287       NoDependenciesToRegister);
1288   EXPECT_TRUE(QueryHandlerRun) << "Query handler never ran";
1289 }
1290 
1291 TEST_F(CoreAPIsStandardTest, FailDefineMaterializingDueToDefunctTracker) {
1292   // Check that a defunct resource tracker causes defineMaterializing to error
1293   // immediately.
1294 
1295   std::unique_ptr<MaterializationResponsibility> FooMR;
1296   auto MU = std::make_unique<SimpleMaterializationUnit>(
1297       SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
1298       [&](std::unique_ptr<MaterializationResponsibility> R) {
1299         FooMR = std::move(R);
1300       });
1301 
1302   auto RT = JD.createResourceTracker();
1303   cantFail(JD.define(std::move(MU), RT));
1304 
1305   bool OnCompletionRan = false;
1306   auto OnCompletion = [&](Expected<SymbolMap> Result) {
1307     EXPECT_THAT_EXPECTED(Result, Failed());
1308     OnCompletionRan = true;
1309   };
1310 
1311   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
1312             SymbolLookupSet(Foo), SymbolState::Ready, OnCompletion,
1313             NoDependenciesToRegister);
1314 
1315   cantFail(RT->remove());
1316 
1317   EXPECT_THAT_ERROR(FooMR->defineMaterializing(SymbolFlagsMap()), Failed())
1318       << "defineMaterializing should have failed due to a defunct tracker";
1319 
1320   FooMR->failMaterialization();
1321 
1322   EXPECT_TRUE(OnCompletionRan) << "OnCompletion handler did not run.";
1323 }
1324 
1325 TEST_F(CoreAPIsStandardTest, TestLookupWithUnthreadedMaterialization) {
1326   auto MU = std::make_unique<SimpleMaterializationUnit>(
1327       SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}}),
1328       [&](std::unique_ptr<MaterializationResponsibility> R) {
1329         cantFail(R->notifyResolved({{Foo, FooSym}}));
1330         cantFail(R->notifyEmitted());
1331       });
1332 
1333   cantFail(JD.define(MU));
1334 
1335   auto FooLookupResult = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Foo));
1336 
1337   EXPECT_EQ(FooLookupResult.getAddress(), FooSym.getAddress())
1338       << "lookup returned an incorrect address";
1339   EXPECT_EQ(FooLookupResult.getFlags(), FooSym.getFlags())
1340       << "lookup returned incorrect flags";
1341 }
1342 
1343 TEST_F(CoreAPIsStandardTest, TestLookupWithThreadedMaterialization) {
1344 #if LLVM_ENABLE_THREADS
1345 
1346   std::mutex WorkThreadsMutex;
1347   std::vector<std::thread> WorkThreads;
1348   ES.setDispatchTask([&](std::unique_ptr<Task> T) {
1349     std::promise<void> WaitP;
1350     std::lock_guard<std::mutex> Lock(WorkThreadsMutex);
1351     WorkThreads.push_back(
1352         std::thread([T = std::move(T), WaitF = WaitP.get_future()]() mutable {
1353           WaitF.get();
1354           T->run();
1355         }));
1356     WaitP.set_value();
1357   });
1358 
1359   cantFail(JD.define(absoluteSymbols({{Foo, FooSym}})));
1360 
1361   auto FooLookupResult = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Foo));
1362 
1363   EXPECT_EQ(FooLookupResult.getAddress(), FooSym.getAddress())
1364       << "lookup returned an incorrect address";
1365   EXPECT_EQ(FooLookupResult.getFlags(), FooSym.getFlags())
1366       << "lookup returned incorrect flags";
1367 
1368   for (auto &WT : WorkThreads)
1369     WT.join();
1370 #endif
1371 }
1372 
1373 TEST_F(CoreAPIsStandardTest, TestGetRequestedSymbolsAndReplace) {
1374   // Test that GetRequestedSymbols returns the set of symbols that currently
1375   // have pending queries, and test that MaterializationResponsibility's
1376   // replace method can be used to return definitions to the JITDylib in a new
1377   // MaterializationUnit.
1378   SymbolNameSet Names({Foo, Bar});
1379 
1380   bool FooMaterialized = false;
1381   bool BarMaterialized = false;
1382 
1383   auto MU = std::make_unique<SimpleMaterializationUnit>(
1384       SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}),
1385       [&](std::unique_ptr<MaterializationResponsibility> R) {
1386         auto Requested = R->getRequestedSymbols();
1387         EXPECT_EQ(Requested.size(), 1U) << "Expected one symbol requested";
1388         EXPECT_EQ(*Requested.begin(), Foo) << "Expected \"Foo\" requested";
1389 
1390         auto NewMU = std::make_unique<SimpleMaterializationUnit>(
1391             SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
1392             [&](std::unique_ptr<MaterializationResponsibility> R2) {
1393               cantFail(R2->notifyResolved(SymbolMap({{Bar, BarSym}})));
1394               cantFail(R2->notifyEmitted());
1395               BarMaterialized = true;
1396             });
1397 
1398         cantFail(R->replace(std::move(NewMU)));
1399 
1400         cantFail(R->notifyResolved(SymbolMap({{Foo, FooSym}})));
1401         cantFail(R->notifyEmitted());
1402 
1403         FooMaterialized = true;
1404       });
1405 
1406   cantFail(JD.define(MU));
1407 
1408   EXPECT_FALSE(FooMaterialized) << "Foo should not be materialized yet";
1409   EXPECT_FALSE(BarMaterialized) << "Bar should not be materialized yet";
1410 
1411   auto FooSymResult = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Foo));
1412   EXPECT_EQ(FooSymResult.getAddress(), FooSym.getAddress())
1413       << "Address mismatch for Foo";
1414 
1415   EXPECT_TRUE(FooMaterialized) << "Foo should be materialized now";
1416   EXPECT_FALSE(BarMaterialized) << "Bar still should not be materialized";
1417 
1418   auto BarSymResult = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Bar));
1419   EXPECT_EQ(BarSymResult.getAddress(), BarSym.getAddress())
1420       << "Address mismatch for Bar";
1421   EXPECT_TRUE(BarMaterialized) << "Bar should be materialized now";
1422 }
1423 
1424 TEST_F(CoreAPIsStandardTest, TestMaterializationResponsibilityDelegation) {
1425   auto MU = std::make_unique<SimpleMaterializationUnit>(
1426       SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}),
1427       [&](std::unique_ptr<MaterializationResponsibility> R) {
1428         auto R2 = cantFail(R->delegate({Bar}));
1429 
1430         cantFail(R->notifyResolved({{Foo, FooSym}}));
1431         cantFail(R->notifyEmitted());
1432         cantFail(R2->notifyResolved({{Bar, BarSym}}));
1433         cantFail(R2->notifyEmitted());
1434       });
1435 
1436   cantFail(JD.define(MU));
1437 
1438   auto Result =
1439       ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Foo, Bar}));
1440 
1441   EXPECT_TRUE(!!Result) << "Result should be a success value";
1442   EXPECT_EQ(Result->count(Foo), 1U) << "\"Foo\" entry missing";
1443   EXPECT_EQ(Result->count(Bar), 1U) << "\"Bar\" entry missing";
1444   EXPECT_EQ((*Result)[Foo].getAddress(), FooSym.getAddress())
1445       << "Address mismatch for \"Foo\"";
1446   EXPECT_EQ((*Result)[Bar].getAddress(), BarSym.getAddress())
1447       << "Address mismatch for \"Bar\"";
1448 }
1449 
1450 TEST_F(CoreAPIsStandardTest, TestMaterializeWeakSymbol) {
1451   // Confirm that once a weak definition is selected for materialization it is
1452   // treated as strong.
1453   JITSymbolFlags WeakExported = JITSymbolFlags::Exported;
1454   WeakExported &= JITSymbolFlags::Weak;
1455 
1456   std::unique_ptr<MaterializationResponsibility> FooR;
1457   auto MU = std::make_unique<SimpleMaterializationUnit>(
1458       SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
1459       [&](std::unique_ptr<MaterializationResponsibility> R) {
1460         FooR = std::move(R);
1461       });
1462 
1463   cantFail(JD.define(MU));
1464   auto OnCompletion = [](Expected<SymbolMap> Result) {
1465     cantFail(std::move(Result));
1466   };
1467 
1468   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
1469             SymbolLookupSet({Foo}), SymbolState::Ready, std::move(OnCompletion),
1470             NoDependenciesToRegister);
1471 
1472   auto MU2 = std::make_unique<SimpleMaterializationUnit>(
1473       SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}}),
1474       [](std::unique_ptr<MaterializationResponsibility> R) {
1475         llvm_unreachable("This unit should never be materialized");
1476       });
1477 
1478   auto Err = JD.define(MU2);
1479   EXPECT_TRUE(!!Err) << "Expected failure value";
1480   EXPECT_TRUE(Err.isA<DuplicateDefinition>())
1481       << "Expected a duplicate definition error";
1482   consumeError(std::move(Err));
1483 
1484   // No dependencies registered, can't fail:
1485   cantFail(FooR->notifyResolved(SymbolMap({{Foo, FooSym}})));
1486   cantFail(FooR->notifyEmitted());
1487 }
1488 
1489 static bool linkOrdersEqual(const std::vector<JITDylibSP> &LHS,
1490                             ArrayRef<JITDylib *> RHS) {
1491   if (LHS.size() != RHS.size())
1492     return false;
1493   auto *RHSE = RHS.begin();
1494   for (auto &LHSE : LHS)
1495     if (LHSE.get() != *RHSE)
1496       return false;
1497     else
1498       ++RHSE;
1499   return true;
1500 }
1501 
1502 TEST(JITDylibTest, GetDFSLinkOrderTree) {
1503   // Test that DFS ordering behaves as expected when the linkage relationships
1504   // form a tree.
1505 
1506   ExecutionSession ES{std::make_unique<UnsupportedExecutorProcessControl>()};
1507   auto _ = make_scope_exit([&]() { cantFail(ES.endSession()); });
1508 
1509   auto &LibA = ES.createBareJITDylib("A");
1510   auto &LibB = ES.createBareJITDylib("B");
1511   auto &LibC = ES.createBareJITDylib("C");
1512   auto &LibD = ES.createBareJITDylib("D");
1513   auto &LibE = ES.createBareJITDylib("E");
1514   auto &LibF = ES.createBareJITDylib("F");
1515 
1516   // Linkage relationships:
1517   // A --- B -- D
1518   //  \      \- E
1519   //    \- C -- F
1520   LibA.setLinkOrder(makeJITDylibSearchOrder({&LibB, &LibC}));
1521   LibB.setLinkOrder(makeJITDylibSearchOrder({&LibD, &LibE}));
1522   LibC.setLinkOrder(makeJITDylibSearchOrder({&LibF}));
1523 
1524   auto DFSOrderFromB = cantFail(JITDylib::getDFSLinkOrder({&LibB}));
1525   EXPECT_TRUE(linkOrdersEqual(DFSOrderFromB, {&LibB, &LibD, &LibE}))
1526       << "Incorrect DFS link order for LibB";
1527 
1528   auto DFSOrderFromA = cantFail(JITDylib::getDFSLinkOrder({&LibA}));
1529   EXPECT_TRUE(linkOrdersEqual(DFSOrderFromA,
1530                               {&LibA, &LibB, &LibD, &LibE, &LibC, &LibF}))
1531       << "Incorrect DFS link order for libA";
1532 
1533   auto DFSOrderFromAB = cantFail(JITDylib::getDFSLinkOrder({&LibA, &LibB}));
1534   EXPECT_TRUE(linkOrdersEqual(DFSOrderFromAB,
1535                               {&LibA, &LibB, &LibD, &LibE, &LibC, &LibF}))
1536       << "Incorrect DFS link order for { libA, libB }";
1537 
1538   auto DFSOrderFromBA = cantFail(JITDylib::getDFSLinkOrder({&LibB, &LibA}));
1539   EXPECT_TRUE(linkOrdersEqual(DFSOrderFromBA,
1540                               {&LibB, &LibD, &LibE, &LibA, &LibC, &LibF}))
1541       << "Incorrect DFS link order for { libB, libA }";
1542 }
1543 
1544 TEST(JITDylibTest, GetDFSLinkOrderDiamond) {
1545   // Test that DFS ordering behaves as expected when the linkage relationships
1546   // contain a diamond.
1547 
1548   ExecutionSession ES{std::make_unique<UnsupportedExecutorProcessControl>()};
1549   auto _ = make_scope_exit([&]() { cantFail(ES.endSession()); });
1550 
1551   auto &LibA = ES.createBareJITDylib("A");
1552   auto &LibB = ES.createBareJITDylib("B");
1553   auto &LibC = ES.createBareJITDylib("C");
1554   auto &LibD = ES.createBareJITDylib("D");
1555 
1556   // Linkage relationships:
1557   // A -- B --- D
1558   //  \-- C --/
1559   LibA.setLinkOrder(makeJITDylibSearchOrder({&LibB, &LibC}));
1560   LibB.setLinkOrder(makeJITDylibSearchOrder({&LibD}));
1561   LibC.setLinkOrder(makeJITDylibSearchOrder({&LibD}));
1562 
1563   auto DFSOrderFromA = cantFail(JITDylib::getDFSLinkOrder({&LibA}));
1564   EXPECT_TRUE(linkOrdersEqual(DFSOrderFromA, {&LibA, &LibB, &LibD, &LibC}))
1565       << "Incorrect DFS link order for libA";
1566 }
1567 
1568 TEST(JITDylibTest, GetDFSLinkOrderCycle) {
1569   // Test that DFS ordering behaves as expected when the linkage relationships
1570   // contain a cycle.
1571 
1572   ExecutionSession ES{std::make_unique<UnsupportedExecutorProcessControl>()};
1573   auto _ = make_scope_exit([&]() { cantFail(ES.endSession()); });
1574 
1575   auto &LibA = ES.createBareJITDylib("A");
1576   auto &LibB = ES.createBareJITDylib("B");
1577   auto &LibC = ES.createBareJITDylib("C");
1578 
1579   // Linkage relationships:
1580   // A -- B --- C -- A
1581   LibA.setLinkOrder(makeJITDylibSearchOrder({&LibB}));
1582   LibB.setLinkOrder(makeJITDylibSearchOrder({&LibC}));
1583   LibC.setLinkOrder(makeJITDylibSearchOrder({&LibA}));
1584 
1585   auto DFSOrderFromA = cantFail(JITDylib::getDFSLinkOrder({&LibA}));
1586   EXPECT_TRUE(linkOrdersEqual(DFSOrderFromA, {&LibA, &LibB, &LibC}))
1587       << "Incorrect DFS link order for libA";
1588 
1589   auto DFSOrderFromB = cantFail(JITDylib::getDFSLinkOrder({&LibB}));
1590   EXPECT_TRUE(linkOrdersEqual(DFSOrderFromB, {&LibB, &LibC, &LibA}))
1591       << "Incorrect DFS link order for libB";
1592 
1593   auto DFSOrderFromC = cantFail(JITDylib::getDFSLinkOrder({&LibC}));
1594   EXPECT_TRUE(linkOrdersEqual(DFSOrderFromC, {&LibC, &LibA, &LibB}))
1595       << "Incorrect DFS link order for libC";
1596 }
1597 
1598 TEST_F(CoreAPIsStandardTest, RemoveJITDylibs) {
1599   // Foo will be fully materialized.
1600   cantFail(JD.define(absoluteSymbols({{Foo, FooSym}})));
1601 
1602   // Bar should not be materialized at all.
1603   bool BarMaterializerDestroyed = false;
1604   cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(
1605       SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
1606       [&](std::unique_ptr<MaterializationResponsibility> MR) {
1607         llvm_unreachable("Unexpected call to materialize");
1608       },
1609       nullptr,
1610       [](const JITDylib &, SymbolStringPtr Name) {
1611         llvm_unreachable("Unexpected call to discard");
1612       },
1613       [&]() { BarMaterializerDestroyed = true; })));
1614 
1615   // Baz will be in the materializing state.
1616   std::unique_ptr<MaterializationResponsibility> BazMR;
1617   cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(
1618       SymbolFlagsMap({{Baz, BazSym.getFlags()}}),
1619       [&](std::unique_ptr<MaterializationResponsibility> MR) {
1620         BazMR = std::move(MR);
1621       })));
1622 
1623   // Lookup to force materialization of Foo.
1624   cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Foo})));
1625 
1626   // Start a lookup to force materialization of Baz.
1627   bool BazLookupFailed = false;
1628   ES.lookup(
1629       LookupKind::Static, makeJITDylibSearchOrder(&JD), SymbolLookupSet({Baz}),
1630       SymbolState::Ready,
1631       [&](Expected<SymbolMap> Result) {
1632         if (!Result) {
1633           BazLookupFailed = true;
1634           consumeError(Result.takeError());
1635         }
1636       },
1637       NoDependenciesToRegister);
1638 
1639   // Remove the JITDylib.
1640   auto Err = ES.removeJITDylib(JD);
1641   EXPECT_THAT_ERROR(std::move(Err), Succeeded());
1642 
1643   EXPECT_TRUE(BarMaterializerDestroyed);
1644   EXPECT_TRUE(BazLookupFailed);
1645 
1646   EXPECT_THAT_ERROR(BazMR->notifyResolved({{Baz, BazSym}}), Failed());
1647 
1648   EXPECT_THAT_EXPECTED(JD.getDFSLinkOrder(), Failed());
1649 
1650   BazMR->failMaterialization();
1651 }
1652 
1653 TEST(CoreAPIsExtraTest, SessionTeardownByFailedToMaterialize) {
1654 
1655   auto RunTestCase = []() -> Error {
1656     ExecutionSession ES{std::make_unique<UnsupportedExecutorProcessControl>(
1657         std::make_shared<SymbolStringPool>())};
1658     auto Foo = ES.intern("foo");
1659     auto FooFlags = JITSymbolFlags::Exported;
1660 
1661     auto &JD = ES.createBareJITDylib("Foo");
1662     cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(
1663         SymbolFlagsMap({{Foo, FooFlags}}),
1664         [&](std::unique_ptr<MaterializationResponsibility> R) {
1665           R->failMaterialization();
1666         })));
1667 
1668     auto Sym = ES.lookup({&JD}, Foo);
1669     assert(!Sym && "Query should have failed");
1670     cantFail(ES.endSession());
1671     return Sym.takeError();
1672   };
1673 
1674   auto Err = RunTestCase();
1675   EXPECT_TRUE(!!Err); // Expect that error occurred.
1676   EXPECT_TRUE(
1677       Err.isA<FailedToMaterialize>()); // Expect FailedToMaterialize error.
1678 
1679   // Make sure that we can log errors, even though the session has been
1680   // destroyed.
1681   logAllUnhandledErrors(std::move(Err), nulls(), "");
1682 }
1683 
1684 } // namespace
1685