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