1 //===----------- CoreAPIsTest.cpp - Unit tests for Core ORC APIs ----------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "OrcTestCommon.h"
11 #include "llvm/Config/llvm-config.h"
12 #include "llvm/ExecutionEngine/Orc/Core.h"
13 #include "llvm/ExecutionEngine/Orc/OrcError.h"
14 #include "gtest/gtest.h"
15 
16 #include <set>
17 #include <thread>
18 
19 using namespace llvm;
20 using namespace llvm::orc;
21 
22 namespace {
23 
24 class SimpleMaterializationUnit : public MaterializationUnit {
25 public:
26   using MaterializeFunction =
27       std::function<void(MaterializationResponsibility)>;
28   using DiscardFunction = std::function<void(const VSO &, SymbolStringPtr)>;
29   using DestructorFunction = std::function<void()>;
30 
31   SimpleMaterializationUnit(
32       SymbolFlagsMap SymbolFlags, MaterializeFunction Materialize,
33       DiscardFunction Discard = DiscardFunction(),
34       DestructorFunction Destructor = DestructorFunction())
35       : MaterializationUnit(std::move(SymbolFlags)),
36         Materialize(std::move(Materialize)), Discard(std::move(Discard)),
37         Destructor(std::move(Destructor)) {}
38 
39   ~SimpleMaterializationUnit() override {
40     if (Destructor)
41       Destructor();
42   }
43 
44   void materialize(MaterializationResponsibility R) override {
45     Materialize(std::move(R));
46   }
47 
48   void discard(const VSO &V, SymbolStringPtr Name) override {
49     if (Discard)
50       Discard(V, std::move(Name));
51     else
52       llvm_unreachable("Discard not supported");
53   }
54 
55 private:
56   MaterializeFunction Materialize;
57   DiscardFunction Discard;
58   DestructorFunction Destructor;
59 };
60 
61 TEST(CoreAPIsTest, AsynchronousSymbolQuerySuccessfulResolutionOnly) {
62   SymbolStringPool SP;
63   auto Foo = SP.intern("foo");
64   constexpr JITTargetAddress FakeAddr = 0xdeadbeef;
65   SymbolNameSet Names({Foo});
66 
67   bool OnResolutionRun = false;
68   bool OnReadyRun = false;
69   auto OnResolution =
70       [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) {
71         EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error";
72         auto &Resolved = Result->Symbols;
73         auto I = Resolved.find(Foo);
74         EXPECT_NE(I, Resolved.end()) << "Could not find symbol definition";
75         EXPECT_EQ(I->second.getAddress(), FakeAddr)
76             << "Resolution returned incorrect result";
77         OnResolutionRun = true;
78       };
79   auto OnReady = [&](Error Err) {
80     cantFail(std::move(Err));
81     OnReadyRun = true;
82   };
83 
84   AsynchronousSymbolQuery Q(Names, OnResolution, OnReady);
85 
86   Q.resolve(Foo, JITEvaluatedSymbol(FakeAddr, JITSymbolFlags::Exported));
87 
88   EXPECT_TRUE(Q.isFullyResolved()) << "Expected query to be fully resolved";
89 
90   if (!Q.isFullyResolved())
91     return;
92 
93   Q.handleFullyResolved();
94 
95   EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run";
96   EXPECT_FALSE(OnReadyRun) << "OnReady unexpectedly run";
97 }
98 
99 TEST(CoreAPIsTest, ExecutionSessionFailQuery) {
100   ExecutionSession ES;
101   auto Foo = ES.getSymbolStringPool().intern("foo");
102   SymbolNameSet Names({Foo});
103 
104   bool OnResolutionRun = false;
105   bool OnReadyRun = false;
106 
107   auto OnResolution =
108       [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) {
109         EXPECT_FALSE(!!Result) << "Resolution unexpectedly returned success";
110         auto Msg = toString(Result.takeError());
111         EXPECT_EQ(Msg, "xyz") << "Resolution returned incorrect result";
112         OnResolutionRun = true;
113       };
114   auto OnReady = [&](Error Err) {
115     cantFail(std::move(Err));
116     OnReadyRun = true;
117   };
118 
119   AsynchronousSymbolQuery Q(Names, OnResolution, OnReady);
120 
121   ES.failQuery(Q, make_error<StringError>("xyz", inconvertibleErrorCode()));
122 
123   EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run";
124   EXPECT_FALSE(OnReadyRun) << "OnReady unexpectedly run";
125 }
126 
127 TEST(CoreAPIsTest, SimpleAsynchronousSymbolQueryAgainstVSO) {
128   ExecutionSession ES;
129   auto Foo = ES.getSymbolStringPool().intern("foo");
130   constexpr JITTargetAddress FakeAddr = 0xdeadbeef;
131   SymbolNameSet Names({Foo});
132 
133   bool OnResolutionRun = false;
134   bool OnReadyRun = false;
135 
136   auto OnResolution =
137       [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) {
138         EXPECT_TRUE(!!Result) << "Query unexpectedly returned error";
139         auto &Resolved = Result->Symbols;
140         auto I = Resolved.find(Foo);
141         EXPECT_NE(I, Resolved.end()) << "Could not find symbol definition";
142         EXPECT_EQ(I->second.getAddress(), FakeAddr)
143             << "Resolution returned incorrect result";
144         OnResolutionRun = true;
145       };
146 
147   auto OnReady = [&](Error Err) {
148     cantFail(std::move(Err));
149     OnReadyRun = true;
150   };
151 
152   auto Q =
153       std::make_shared<AsynchronousSymbolQuery>(Names, OnResolution, OnReady);
154   auto &V = ES.createVSO("V");
155 
156   auto Defs = absoluteSymbols(
157       {{Foo, JITEvaluatedSymbol(FakeAddr, JITSymbolFlags::Exported)}});
158   cantFail(V.define(Defs));
159   assert(Defs == nullptr && "Defs should have been accepted");
160   V.lookup(Q, Names);
161 
162   EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run";
163   EXPECT_TRUE(OnReadyRun) << "OnReady was not run";
164 }
165 
166 TEST(CoreAPIsTest, LookupFlagsTest) {
167 
168   // Test that lookupFlags works on a predefined symbol, and does not trigger
169   // materialization of a lazy symbol.
170 
171   ExecutionSession ES;
172   auto Foo = ES.getSymbolStringPool().intern("foo");
173   auto Bar = ES.getSymbolStringPool().intern("bar");
174   auto Baz = ES.getSymbolStringPool().intern("baz");
175 
176   JITSymbolFlags FooFlags = JITSymbolFlags::Exported;
177   JITSymbolFlags BarFlags = static_cast<JITSymbolFlags::FlagNames>(
178       JITSymbolFlags::Exported | JITSymbolFlags::Weak);
179 
180   VSO &V = ES.createVSO("V");
181 
182   auto MU = llvm::make_unique<SimpleMaterializationUnit>(
183       SymbolFlagsMap({{Bar, BarFlags}}),
184       [](MaterializationResponsibility R) {
185         llvm_unreachable("Symbol materialized on flags lookup");
186       });
187 
188   cantFail(V.define(
189       absoluteSymbols({{Foo, JITEvaluatedSymbol(0xdeadbeef, FooFlags)}})));
190   cantFail(V.define(std::move(MU)));
191 
192   SymbolNameSet Names({Foo, Bar, Baz});
193 
194   SymbolFlagsMap SymbolFlags;
195   auto SymbolsNotFound = V.lookupFlags(SymbolFlags, Names);
196 
197   EXPECT_EQ(SymbolsNotFound.size(), 1U) << "Expected one not-found symbol";
198   EXPECT_EQ(SymbolsNotFound.count(Baz), 1U) << "Expected Baz to be not-found";
199   EXPECT_EQ(SymbolFlags.size(), 2U)
200       << "Returned symbol flags contains unexpected results";
201   EXPECT_EQ(SymbolFlags.count(Foo), 1U) << "Missing lookupFlags result for Foo";
202   EXPECT_EQ(SymbolFlags[Foo], FooFlags) << "Incorrect flags returned for Foo";
203   EXPECT_EQ(SymbolFlags.count(Bar), 1U)
204       << "Missing  lookupFlags result for Bar";
205   EXPECT_EQ(SymbolFlags[Bar], BarFlags) << "Incorrect flags returned for Bar";
206 }
207 
208 TEST(CoreAPIsTest, TestCircularDependenceInOneVSO) {
209 
210   ExecutionSession ES;
211 
212   auto &V = ES.createVSO("V");
213 
214   // Create three symbols: Foo, Bar and Baz.
215   auto Foo = ES.getSymbolStringPool().intern("foo");
216   auto FooFlags = JITSymbolFlags::Exported;
217   auto FooSym = JITEvaluatedSymbol(1U, FooFlags);
218 
219   auto Bar = ES.getSymbolStringPool().intern("bar");
220   auto BarFlags = JITSymbolFlags::Exported;
221   auto BarSym = JITEvaluatedSymbol(2U, BarFlags);
222 
223   auto Baz = ES.getSymbolStringPool().intern("baz");
224   auto BazFlags = JITSymbolFlags::Exported;
225   auto BazSym = JITEvaluatedSymbol(3U, BazFlags);
226 
227   // Create three MaterializationResponsibility objects: one for each symbol
228   // (these are optional because MaterializationResponsibility does not have
229   // a default constructor).
230   Optional<MaterializationResponsibility> FooR;
231   Optional<MaterializationResponsibility> BarR;
232   Optional<MaterializationResponsibility> BazR;
233 
234   // Create a MaterializationUnit for each symbol that moves the
235   // MaterializationResponsibility into one of the locals above.
236   auto FooMU = llvm::make_unique<SimpleMaterializationUnit>(
237       SymbolFlagsMap({{Foo, FooFlags}}),
238       [&](MaterializationResponsibility R) { FooR.emplace(std::move(R)); });
239 
240   auto BarMU = llvm::make_unique<SimpleMaterializationUnit>(
241       SymbolFlagsMap({{Bar, BarFlags}}),
242       [&](MaterializationResponsibility R) { BarR.emplace(std::move(R)); });
243 
244   auto BazMU = llvm::make_unique<SimpleMaterializationUnit>(
245       SymbolFlagsMap({{Baz, BazFlags}}),
246       [&](MaterializationResponsibility R) { BazR.emplace(std::move(R)); });
247 
248   // Define the symbols.
249   cantFail(V.define(FooMU));
250   cantFail(V.define(BarMU));
251   cantFail(V.define(BazMU));
252 
253   // Query each of the symbols to trigger materialization.
254   bool FooResolved = false;
255   bool FooReady = false;
256   auto FooQ = std::make_shared<AsynchronousSymbolQuery>(
257       SymbolNameSet({Foo}),
258       [&](Expected<AsynchronousSymbolQuery::ResolutionResult> RR) {
259         cantFail(std::move(RR));
260         FooResolved = true;
261       },
262       [&](Error Err) {
263         cantFail(std::move(Err));
264         FooReady = true;
265       });
266   {
267     auto Unresolved = V.lookup(FooQ, {Foo});
268     EXPECT_TRUE(Unresolved.empty()) << "Failed to resolve \"Foo\"";
269   }
270 
271   bool BarResolved = false;
272   bool BarReady = false;
273   auto BarQ = std::make_shared<AsynchronousSymbolQuery>(
274       SymbolNameSet({Bar}),
275       [&](Expected<AsynchronousSymbolQuery::ResolutionResult> RR) {
276         cantFail(std::move(RR));
277         BarResolved = true;
278       },
279       [&](Error Err) {
280         cantFail(std::move(Err));
281         BarReady = true;
282       });
283   {
284     auto Unresolved = V.lookup(BarQ, {Bar});
285     EXPECT_TRUE(Unresolved.empty()) << "Failed to resolve \"Bar\"";
286   }
287 
288   bool BazResolved = false;
289   bool BazReady = false;
290   auto BazQ = std::make_shared<AsynchronousSymbolQuery>(
291       SymbolNameSet({Baz}),
292       [&](Expected<AsynchronousSymbolQuery::ResolutionResult> RR) {
293         cantFail(std::move(RR));
294         BazResolved = true;
295       },
296       [&](Error Err) {
297         cantFail(std::move(Err));
298         BazReady = true;
299       });
300   {
301     auto Unresolved = V.lookup(BazQ, {Baz});
302     EXPECT_TRUE(Unresolved.empty()) << "Failed to resolve \"Baz\"";
303   }
304 
305   // Add a circular dependency: Foo -> Bar, Bar -> Baz, Baz -> Foo.
306   FooR->addDependencies({{&V, SymbolNameSet({Bar})}});
307   BarR->addDependencies({{&V, SymbolNameSet({Baz})}});
308   BazR->addDependencies({{&V, SymbolNameSet({Foo})}});
309 
310   // Add self-dependencies for good measure. This tests that the implementation
311   // of addDependencies filters these out.
312   FooR->addDependencies({{&V, SymbolNameSet({Foo})}});
313   BarR->addDependencies({{&V, SymbolNameSet({Bar})}});
314   BazR->addDependencies({{&V, SymbolNameSet({Baz})}});
315 
316   EXPECT_FALSE(FooResolved) << "\"Foo\" should not be resolved yet";
317   EXPECT_FALSE(BarResolved) << "\"Bar\" should not be resolved yet";
318   EXPECT_FALSE(BazResolved) << "\"Baz\" should not be resolved yet";
319 
320   FooR->resolve({{Foo, FooSym}});
321   BarR->resolve({{Bar, BarSym}});
322   BazR->resolve({{Baz, BazSym}});
323 
324   EXPECT_TRUE(FooResolved) << "\"Foo\" should be resolved now";
325   EXPECT_TRUE(BarResolved) << "\"Bar\" should be resolved now";
326   EXPECT_TRUE(BazResolved) << "\"Baz\" should be resolved now";
327 
328   EXPECT_FALSE(FooReady) << "\"Foo\" should not be ready yet";
329   EXPECT_FALSE(BarReady) << "\"Bar\" should not be ready yet";
330   EXPECT_FALSE(BazReady) << "\"Baz\" should not be ready yet";
331 
332   FooR->finalize();
333   BarR->finalize();
334 
335   // Verify that nothing is ready until the circular dependence is resolved.
336 
337   EXPECT_FALSE(FooReady) << "\"Foo\" still should not be ready";
338   EXPECT_FALSE(BarReady) << "\"Bar\" still should not be ready";
339   EXPECT_FALSE(BazReady) << "\"Baz\" still should not be ready";
340 
341   BazR->finalize();
342 
343   // Verify that everything becomes ready once the circular dependence resolved.
344   EXPECT_TRUE(FooReady) << "\"Foo\" should be ready now";
345   EXPECT_TRUE(BarReady) << "\"Bar\" should be ready now";
346   EXPECT_TRUE(BazReady) << "\"Baz\" should be ready now";
347 }
348 
349 TEST(CoreAPIsTest, DropMaterializerWhenEmpty) {
350   ExecutionSession ES;
351   auto Foo = ES.getSymbolStringPool().intern("foo");
352   auto Bar = ES.getSymbolStringPool().intern("bar");
353 
354   bool DestructorRun = false;
355 
356   auto MU = llvm::make_unique<SimpleMaterializationUnit>(
357       SymbolFlagsMap(
358           {{Foo, JITSymbolFlags::Weak}, {Bar, JITSymbolFlags::Weak}}),
359       [](MaterializationResponsibility R) {
360         llvm_unreachable("Unexpected call to materialize");
361       },
362       [&](const VSO &V, SymbolStringPtr Name) {
363         EXPECT_TRUE(Name == Foo || Name == Bar)
364             << "Discard of unexpected symbol?";
365       },
366       [&]() { DestructorRun = true; });
367 
368   auto &V = ES.createVSO("V");
369 
370   cantFail(V.define(MU));
371 
372   auto FooSym = JITEvaluatedSymbol(1, JITSymbolFlags::Exported);
373   auto BarSym = JITEvaluatedSymbol(2, JITSymbolFlags::Exported);
374   cantFail(V.define(absoluteSymbols({{Foo, FooSym}})));
375 
376   EXPECT_FALSE(DestructorRun)
377       << "MaterializationUnit should not have been destroyed yet";
378 
379   cantFail(V.define(absoluteSymbols({{Bar, BarSym}})));
380 
381   EXPECT_TRUE(DestructorRun)
382       << "MaterializationUnit should have been destroyed";
383 }
384 
385 TEST(CoreAPIsTest, AddAndMaterializeLazySymbol) {
386 
387   constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef;
388   constexpr JITTargetAddress FakeBarAddr = 0xcafef00d;
389 
390   ExecutionSession ES;
391   auto Foo = ES.getSymbolStringPool().intern("foo");
392   auto Bar = ES.getSymbolStringPool().intern("bar");
393 
394   bool FooMaterialized = false;
395   bool BarDiscarded = false;
396 
397   auto &V = ES.createVSO("V");
398 
399   auto MU = llvm::make_unique<SimpleMaterializationUnit>(
400       SymbolFlagsMap(
401           {{Foo, JITSymbolFlags::Exported},
402            {Bar, static_cast<JITSymbolFlags::FlagNames>(
403                      JITSymbolFlags::Exported | JITSymbolFlags::Weak)}}),
404       [&](MaterializationResponsibility R) {
405         assert(BarDiscarded && "Bar should have been discarded by this point");
406         SymbolMap SymbolsToResolve;
407         SymbolsToResolve[Foo] =
408             JITEvaluatedSymbol(FakeFooAddr, JITSymbolFlags::Exported);
409         R.resolve(std::move(SymbolsToResolve));
410         R.finalize();
411         FooMaterialized = true;
412       },
413       [&](const VSO &V, SymbolStringPtr Name) {
414         EXPECT_EQ(Name, Bar) << "Expected Name to be Bar";
415         BarDiscarded = true;
416       });
417 
418   cantFail(V.define(MU));
419 
420   ;
421   cantFail(V.define(absoluteSymbols(
422       {{Bar, JITEvaluatedSymbol(FakeBarAddr, JITSymbolFlags::Exported)}})));
423 
424   SymbolNameSet Names({Foo});
425 
426   bool OnResolutionRun = false;
427   bool OnReadyRun = false;
428 
429   auto OnResolution =
430       [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) {
431         EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error";
432         auto I = Result->Symbols.find(Foo);
433         EXPECT_NE(I, Result->Symbols.end())
434             << "Could not find symbol definition";
435         EXPECT_EQ(I->second.getAddress(), FakeFooAddr)
436             << "Resolution returned incorrect result";
437         OnResolutionRun = true;
438       };
439 
440   auto OnReady = [&](Error Err) {
441     cantFail(std::move(Err));
442     OnReadyRun = true;
443   };
444 
445   auto Q =
446       std::make_shared<AsynchronousSymbolQuery>(Names, OnResolution, OnReady);
447 
448   auto Unresolved = V.lookup(std::move(Q), Names);
449 
450   EXPECT_TRUE(Unresolved.empty()) << "Could not find Foo in dylib";
451   EXPECT_TRUE(FooMaterialized) << "Foo was not materialized";
452   EXPECT_TRUE(BarDiscarded) << "Bar was not discarded";
453   EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run";
454   EXPECT_TRUE(OnReadyRun) << "OnReady was not run";
455 }
456 
457 TEST(CoreAPIsTest, DefineMaterializingSymbol) {
458   ExecutionSession ES;
459   auto Foo = ES.getSymbolStringPool().intern("foo");
460   auto Bar = ES.getSymbolStringPool().intern("bar");
461 
462   auto FooSym = JITEvaluatedSymbol(1, JITSymbolFlags::Exported);
463   auto BarSym = JITEvaluatedSymbol(2, JITSymbolFlags::Exported);
464 
465   bool ExpectNoMoreMaterialization = false;
466   ES.setDispatchMaterialization(
467       [&](VSO &V, std::unique_ptr<MaterializationUnit> MU) {
468         if (ExpectNoMoreMaterialization)
469           ADD_FAILURE() << "Unexpected materialization";
470         MU->doMaterialize(V);
471       });
472 
473   auto MU = llvm::make_unique<SimpleMaterializationUnit>(
474       SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
475       [&](MaterializationResponsibility R) {
476         cantFail(
477             R.defineMaterializing(SymbolFlagsMap({{Bar, BarSym.getFlags()}})));
478         R.resolve(SymbolMap({{Foo, FooSym}, {Bar, BarSym}}));
479         R.finalize();
480       });
481 
482   auto &V = ES.createVSO("V");
483   cantFail(V.define(MU));
484 
485   auto OnResolution1 =
486       [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) {
487         cantFail(std::move(Result));
488       };
489 
490   auto OnReady1 = [](Error Err) { cantFail(std::move(Err)); };
491 
492   auto Q1 = std::make_shared<AsynchronousSymbolQuery>(SymbolNameSet({Foo}),
493                                                       OnResolution1, OnReady1);
494 
495   V.lookup(std::move(Q1), {Foo});
496 
497   bool BarResolved = false;
498   auto OnResolution2 =
499       [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) {
500         auto R = cantFail(std::move(Result));
501         EXPECT_EQ(R.Symbols.size(), 1U) << "Expected to resolve one symbol";
502         EXPECT_EQ(R.Symbols.count(Bar), 1U) << "Expected to resolve 'Bar'";
503         EXPECT_EQ(R.Symbols[Bar].getAddress(), BarSym.getAddress())
504             << "Expected Bar == BarSym";
505         BarResolved = true;
506       };
507 
508   auto OnReady2 = [](Error Err) { cantFail(std::move(Err)); };
509 
510   auto Q2 = std::make_shared<AsynchronousSymbolQuery>(SymbolNameSet({Bar}),
511                                                       OnResolution2, OnReady2);
512 
513   ExpectNoMoreMaterialization = true;
514   V.lookup(std::move(Q2), {Bar});
515 
516   EXPECT_TRUE(BarResolved) << "Bar should have been resolved";
517 }
518 
519 TEST(CoreAPIsTest, FallbackDefinitionGeneratorTest) {
520   constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef;
521   constexpr JITTargetAddress FakeBarAddr = 0xcafef00d;
522 
523   ExecutionSession ES;
524   auto Foo = ES.getSymbolStringPool().intern("foo");
525   auto Bar = ES.getSymbolStringPool().intern("bar");
526 
527   auto FooSym = JITEvaluatedSymbol(FakeFooAddr, JITSymbolFlags::Exported);
528   auto BarSym = JITEvaluatedSymbol(FakeBarAddr, JITSymbolFlags::Exported);
529 
530   auto &V = ES.createVSO("V");
531 
532   cantFail(V.define(absoluteSymbols({{Foo, FooSym}})));
533 
534   V.setFallbackDefinitionGenerator([&](VSO &W, const SymbolNameSet &Names) {
535     cantFail(W.define(absoluteSymbols({{Bar, BarSym}})));
536     return SymbolNameSet({Bar});
537   });
538 
539   auto Result = cantFail(lookup({&V}, {Foo, Bar}));
540 
541   EXPECT_EQ(Result.count(Bar), 1U) << "Expected to find fallback def for 'bar'";
542   EXPECT_EQ(Result[Bar].getAddress(), FakeBarAddr)
543       << "Expected address of fallback def for 'bar' to be " << FakeBarAddr;
544 }
545 
546 TEST(CoreAPIsTest, FailResolution) {
547   ExecutionSession ES;
548   auto Foo = ES.getSymbolStringPool().intern("foo");
549   auto Bar = ES.getSymbolStringPool().intern("bar");
550 
551   SymbolNameSet Names({Foo, Bar});
552 
553   auto MU = llvm::make_unique<SimpleMaterializationUnit>(
554       SymbolFlagsMap(
555           {{Foo, JITSymbolFlags::Weak}, {Bar, JITSymbolFlags::Weak}}),
556       [&](MaterializationResponsibility R) { R.failMaterialization(); });
557 
558   auto &V = ES.createVSO("V");
559 
560   cantFail(V.define(MU));
561 
562   auto OnResolution =
563       [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) {
564         handleAllErrors(Result.takeError(),
565                         [&](FailedToMaterialize &F) {
566                           EXPECT_EQ(F.getSymbols(), Names)
567                               << "Expected to fail on symbols in Names";
568                         },
569                         [](ErrorInfoBase &EIB) {
570                           std::string ErrMsg;
571                           {
572                             raw_string_ostream ErrOut(ErrMsg);
573                             EIB.log(ErrOut);
574                           }
575                           ADD_FAILURE()
576                               << "Expected a FailedToResolve error. Got:\n"
577                               << ErrMsg;
578                         });
579       };
580 
581   auto OnReady = [](Error Err) {
582     cantFail(std::move(Err));
583     ADD_FAILURE() << "OnReady should never be called";
584   };
585 
586   auto Q =
587       std::make_shared<AsynchronousSymbolQuery>(Names, OnResolution, OnReady);
588 
589   V.lookup(std::move(Q), Names);
590 }
591 
592 TEST(CoreAPIsTest, TestLambdaSymbolResolver) {
593   JITEvaluatedSymbol FooSym(0xdeadbeef, JITSymbolFlags::Exported);
594   JITEvaluatedSymbol BarSym(0xcafef00d, JITSymbolFlags::Exported);
595 
596   ExecutionSession ES;
597 
598   auto Foo = ES.getSymbolStringPool().intern("foo");
599   auto Bar = ES.getSymbolStringPool().intern("bar");
600   auto Baz = ES.getSymbolStringPool().intern("baz");
601 
602   auto &V = ES.createVSO("V");
603   cantFail(V.define(absoluteSymbols({{Foo, FooSym}, {Bar, BarSym}})));
604 
605   auto Resolver = createSymbolResolver(
606       [&](SymbolFlagsMap &SymbolFlags, const SymbolNameSet &Symbols) {
607         return V.lookupFlags(SymbolFlags, Symbols);
608       },
609       [&](std::shared_ptr<AsynchronousSymbolQuery> Q, SymbolNameSet Symbols) {
610         return V.lookup(std::move(Q), Symbols);
611       });
612 
613   SymbolNameSet Symbols({Foo, Bar, Baz});
614 
615   SymbolFlagsMap SymbolFlags;
616   SymbolNameSet SymbolsNotFound = Resolver->lookupFlags(SymbolFlags, Symbols);
617 
618   EXPECT_EQ(SymbolFlags.size(), 2U)
619       << "lookupFlags returned the wrong number of results";
620   EXPECT_EQ(SymbolFlags.count(Foo), 1U) << "Missing lookupFlags result for foo";
621   EXPECT_EQ(SymbolFlags.count(Bar), 1U) << "Missing lookupFlags result for bar";
622   EXPECT_EQ(SymbolFlags[Foo], FooSym.getFlags())
623       << "Incorrect lookupFlags result for Foo";
624   EXPECT_EQ(SymbolFlags[Bar], BarSym.getFlags())
625       << "Incorrect lookupFlags result for Bar";
626   EXPECT_EQ(SymbolsNotFound.size(), 1U)
627       << "Expected one symbol not found in lookupFlags";
628   EXPECT_EQ(SymbolsNotFound.count(Baz), 1U)
629       << "Expected baz not to be found in lookupFlags";
630 
631   bool OnResolvedRun = false;
632 
633   auto OnResolved =
634       [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) {
635         OnResolvedRun = true;
636         EXPECT_TRUE(!!Result) << "Unexpected error";
637         EXPECT_EQ(Result->Symbols.size(), 2U)
638             << "Unexpected number of resolved symbols";
639         EXPECT_EQ(Result->Symbols.count(Foo), 1U)
640             << "Missing lookup result for foo";
641         EXPECT_EQ(Result->Symbols.count(Bar), 1U)
642             << "Missing lookup result for bar";
643         EXPECT_EQ(Result->Symbols[Foo].getAddress(), FooSym.getAddress())
644             << "Incorrect address for foo";
645         EXPECT_EQ(Result->Symbols[Bar].getAddress(), BarSym.getAddress())
646             << "Incorrect address for bar";
647       };
648   auto OnReady = [&](Error Err) {
649     EXPECT_FALSE(!!Err) << "Finalization should never fail in this test";
650   };
651 
652   auto Q = std::make_shared<AsynchronousSymbolQuery>(SymbolNameSet({Foo, Bar}),
653                                                      OnResolved, OnReady);
654   auto Unresolved = Resolver->lookup(std::move(Q), Symbols);
655 
656   EXPECT_EQ(Unresolved.size(), 1U) << "Expected one unresolved symbol";
657   EXPECT_EQ(Unresolved.count(Baz), 1U) << "Expected baz to not be resolved";
658   EXPECT_TRUE(OnResolvedRun) << "OnResolved was never run";
659 }
660 
661 TEST(CoreAPIsTest, TestLookupWithUnthreadedMaterialization) {
662   constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef;
663   JITEvaluatedSymbol FooSym(FakeFooAddr, JITSymbolFlags::Exported);
664 
665   ExecutionSession ES(std::make_shared<SymbolStringPool>());
666   auto Foo = ES.getSymbolStringPool().intern("foo");
667 
668   auto MU = llvm::make_unique<SimpleMaterializationUnit>(
669       SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}}),
670       [&](MaterializationResponsibility R) {
671         R.resolve({{Foo, FooSym}});
672         R.finalize();
673       });
674 
675   auto &V = ES.createVSO("V");
676 
677   cantFail(V.define(MU));
678 
679   auto FooLookupResult = cantFail(lookup({&V}, Foo));
680 
681   EXPECT_EQ(FooLookupResult.getAddress(), FooSym.getAddress())
682       << "lookup returned an incorrect address";
683   EXPECT_EQ(FooLookupResult.getFlags(), FooSym.getFlags())
684       << "lookup returned incorrect flags";
685 }
686 
687 TEST(CoreAPIsTest, TestLookupWithThreadedMaterialization) {
688 #if LLVM_ENABLE_THREADS
689   constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef;
690   JITEvaluatedSymbol FooSym(FakeFooAddr, JITSymbolFlags::Exported);
691 
692   ExecutionSession ES(std::make_shared<SymbolStringPool>());
693 
694   std::thread MaterializationThread;
695   ES.setDispatchMaterialization(
696       [&](VSO &V, std::unique_ptr<MaterializationUnit> MU) {
697         auto SharedMU = std::shared_ptr<MaterializationUnit>(std::move(MU));
698         MaterializationThread =
699             std::thread([SharedMU, &V]() { SharedMU->doMaterialize(V); });
700       });
701   auto Foo = ES.getSymbolStringPool().intern("foo");
702 
703   auto &V = ES.createVSO("V");
704   cantFail(V.define(absoluteSymbols({{Foo, FooSym}})));
705 
706   auto FooLookupResult = cantFail(lookup({&V}, Foo));
707 
708   EXPECT_EQ(FooLookupResult.getAddress(), FooSym.getAddress())
709       << "lookup returned an incorrect address";
710   EXPECT_EQ(FooLookupResult.getFlags(), FooSym.getFlags())
711       << "lookup returned incorrect flags";
712   MaterializationThread.join();
713 #endif
714 }
715 
716 TEST(CoreAPIsTest, TestGetRequestedSymbolsAndDelegate) {
717   ExecutionSession ES;
718   auto Foo = ES.getSymbolStringPool().intern("foo");
719   auto Bar = ES.getSymbolStringPool().intern("bar");
720 
721   JITEvaluatedSymbol FooSym(0xdeadbeef, JITSymbolFlags::Exported);
722   JITEvaluatedSymbol BarSym(0xcafef00d, JITSymbolFlags::Exported);
723 
724   SymbolNameSet Names({Foo, Bar});
725 
726   bool FooMaterialized = false;
727   bool BarMaterialized = false;
728 
729   auto MU = llvm::make_unique<SimpleMaterializationUnit>(
730       SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}),
731       [&](MaterializationResponsibility R) {
732         auto Requested = R.getRequestedSymbols();
733         EXPECT_EQ(Requested.size(), 1U) << "Expected one symbol requested";
734         EXPECT_EQ(*Requested.begin(), Foo) << "Expected \"Foo\" requested";
735 
736         auto NewMU = llvm::make_unique<SimpleMaterializationUnit>(
737             SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
738             [&](MaterializationResponsibility R2) {
739               R2.resolve(SymbolMap({{Bar, BarSym}}));
740               R2.finalize();
741               BarMaterialized = true;
742             });
743 
744         R.delegate(std::move(NewMU));
745 
746         R.resolve(SymbolMap({{Foo, FooSym}}));
747         R.finalize();
748 
749         FooMaterialized = true;
750       });
751 
752   auto &V = ES.createVSO("V");
753 
754   cantFail(V.define(MU));
755 
756   EXPECT_FALSE(FooMaterialized) << "Foo should not be materialized yet";
757   EXPECT_FALSE(BarMaterialized) << "Bar should not be materialized yet";
758 
759   auto FooSymResult = cantFail(lookup({&V}, Foo));
760   EXPECT_EQ(FooSymResult.getAddress(), FooSym.getAddress())
761       << "Address mismatch for Foo";
762 
763   EXPECT_TRUE(FooMaterialized) << "Foo should be materialized now";
764   EXPECT_FALSE(BarMaterialized) << "Bar still should not be materialized";
765 
766   auto BarSymResult = cantFail(lookup({&V}, Bar));
767   EXPECT_EQ(BarSymResult.getAddress(), BarSym.getAddress())
768       << "Address mismatch for Bar";
769   EXPECT_TRUE(BarMaterialized) << "Bar should be materialized now";
770 }
771 
772 TEST(CoreAPIsTest, TestMaterializeWeakSymbol) {
773   // Confirm that once a weak definition is selected for materialization it is
774   // treated as strong.
775 
776   constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef;
777   JITSymbolFlags FooFlags = JITSymbolFlags::Exported;
778   FooFlags &= JITSymbolFlags::Weak;
779   auto FooSym = JITEvaluatedSymbol(FakeFooAddr, FooFlags);
780 
781   ExecutionSession ES;
782   auto Foo = ES.getSymbolStringPool().intern("foo");
783 
784   auto &V = ES.createVSO("V");
785 
786   std::unique_ptr<MaterializationResponsibility> FooResponsibility;
787   auto MU = llvm::make_unique<SimpleMaterializationUnit>(
788       SymbolFlagsMap({{Foo, FooFlags}}), [&](MaterializationResponsibility R) {
789         FooResponsibility =
790             llvm::make_unique<MaterializationResponsibility>(std::move(R));
791       });
792 
793   cantFail(V.define(MU));
794   auto Q = std::make_shared<AsynchronousSymbolQuery>(
795       SymbolNameSet({Foo}),
796       [](Expected<AsynchronousSymbolQuery::ResolutionResult> R) {
797         cantFail(std::move(R));
798       },
799       [](Error Err) { cantFail(std::move(Err)); });
800   V.lookup(std::move(Q), SymbolNameSet({Foo}));
801 
802   auto MU2 = llvm::make_unique<SimpleMaterializationUnit>(
803       SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}}),
804       [](MaterializationResponsibility R) {
805         llvm_unreachable("This unit should never be materialized");
806       });
807 
808   auto Err = V.define(MU2);
809   EXPECT_TRUE(!!Err) << "Expected failure value";
810   EXPECT_TRUE(Err.isA<DuplicateDefinition>())
811       << "Expected a duplicate definition error";
812   consumeError(std::move(Err));
813 
814   FooResponsibility->resolve(SymbolMap({{Foo, FooSym}}));
815   FooResponsibility->finalize();
816 }
817 
818 } // namespace
819