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