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