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