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, EmptyVSOAndQueryLookup) {
167   ExecutionSession ES;
168   auto &V = ES.createVSO("V");
169 
170   bool OnResolvedRun = false;
171   bool OnReadyRun = false;
172 
173   auto Q = std::make_shared<AsynchronousSymbolQuery>(
174       SymbolNameSet(),
175       [&](Expected<AsynchronousSymbolQuery::ResolutionResult> RR) {
176         cantFail(std::move(RR));
177         OnResolvedRun = true;
178       },
179       [&](Error Err) {
180         cantFail(std::move(Err));
181         OnReadyRun = true;
182       });
183 
184   V.lookup(std::move(Q), {});
185 
186   EXPECT_TRUE(OnResolvedRun) << "OnResolved was not run for empty query";
187   EXPECT_TRUE(OnReadyRun) << "OnReady was not run for empty query";
188 }
189 
190 TEST(CoreAPIsTest, ChainedVSOLookup) {
191   ExecutionSession ES;
192   auto Foo = ES.getSymbolStringPool().intern("foo");
193   auto FooSym = JITEvaluatedSymbol(1U, JITSymbolFlags::Exported);
194 
195   auto &V1 = ES.createVSO("V1");
196   cantFail(V1.define(absoluteSymbols({{Foo, FooSym}})));
197 
198   auto &V2 = ES.createVSO("V2");
199 
200   bool OnResolvedRun = false;
201   bool OnReadyRun = false;
202 
203   auto Q = std::make_shared<AsynchronousSymbolQuery>(
204       SymbolNameSet({Foo}),
205       [&](Expected<AsynchronousSymbolQuery::ResolutionResult> RR) {
206         cantFail(std::move(RR));
207         OnResolvedRun = true;
208       },
209       [&](Error Err) {
210         cantFail(std::move(Err));
211         OnReadyRun = true;
212       });
213 
214   V2.lookup(Q, V1.lookup(Q, {Foo}));
215 
216   EXPECT_TRUE(OnResolvedRun) << "OnResolved was not run for empty query";
217   EXPECT_TRUE(OnReadyRun) << "OnReady was not run for empty query";
218 }
219 
220 TEST(CoreAPIsTest, LookupFlagsTest) {
221 
222   // Test that lookupFlags works on a predefined symbol, and does not trigger
223   // materialization of a lazy symbol.
224 
225   ExecutionSession ES;
226   auto Foo = ES.getSymbolStringPool().intern("foo");
227   auto Bar = ES.getSymbolStringPool().intern("bar");
228   auto Baz = ES.getSymbolStringPool().intern("baz");
229 
230   JITSymbolFlags FooFlags = JITSymbolFlags::Exported;
231   JITSymbolFlags BarFlags = static_cast<JITSymbolFlags::FlagNames>(
232       JITSymbolFlags::Exported | JITSymbolFlags::Weak);
233 
234   VSO &V = ES.createVSO("V");
235 
236   auto MU = llvm::make_unique<SimpleMaterializationUnit>(
237       SymbolFlagsMap({{Bar, BarFlags}}),
238       [](MaterializationResponsibility R) {
239         llvm_unreachable("Symbol materialized on flags lookup");
240       });
241 
242   cantFail(V.define(
243       absoluteSymbols({{Foo, JITEvaluatedSymbol(0xdeadbeef, FooFlags)}})));
244   cantFail(V.define(std::move(MU)));
245 
246   SymbolNameSet Names({Foo, Bar, Baz});
247 
248   SymbolFlagsMap SymbolFlags;
249   auto SymbolsNotFound = V.lookupFlags(SymbolFlags, Names);
250 
251   EXPECT_EQ(SymbolsNotFound.size(), 1U) << "Expected one not-found symbol";
252   EXPECT_EQ(SymbolsNotFound.count(Baz), 1U) << "Expected Baz to be not-found";
253   EXPECT_EQ(SymbolFlags.size(), 2U)
254       << "Returned symbol flags contains unexpected results";
255   EXPECT_EQ(SymbolFlags.count(Foo), 1U) << "Missing lookupFlags result for Foo";
256   EXPECT_EQ(SymbolFlags[Foo], FooFlags) << "Incorrect flags returned for Foo";
257   EXPECT_EQ(SymbolFlags.count(Bar), 1U)
258       << "Missing  lookupFlags result for Bar";
259   EXPECT_EQ(SymbolFlags[Bar], BarFlags) << "Incorrect flags returned for Bar";
260 }
261 
262 TEST(CoreAPIsTest, TestAliases) {
263   ExecutionSession ES;
264   auto &V = ES.createVSO("V");
265 
266   auto Foo = ES.getSymbolStringPool().intern("foo");
267   auto FooSym = JITEvaluatedSymbol(1U, JITSymbolFlags::Exported);
268   auto Bar = ES.getSymbolStringPool().intern("bar");
269   auto BarSym = JITEvaluatedSymbol(2U, JITSymbolFlags::Exported);
270 
271   auto Baz = ES.getSymbolStringPool().intern("baz");
272   auto Qux = ES.getSymbolStringPool().intern("qux");
273 
274   auto QuxSym = JITEvaluatedSymbol(3U, JITSymbolFlags::Exported);
275 
276   cantFail(V.define(absoluteSymbols({{Foo, FooSym}, {Bar, BarSym}})));
277   cantFail(V.define(symbolAliases({{Baz, {Foo, JITSymbolFlags::Exported}},
278                                    {Qux, {Bar, JITSymbolFlags::Weak}}})));
279   cantFail(V.define(absoluteSymbols({{Qux, QuxSym}})));
280 
281   auto Result = lookup({&V}, {Baz, Qux});
282   EXPECT_TRUE(!!Result) << "Unexpected lookup failure";
283   EXPECT_EQ(Result->count(Baz), 1U) << "No result for \"baz\"";
284   EXPECT_EQ(Result->count(Qux), 1U) << "No result for \"qux\"";
285   EXPECT_EQ((*Result)[Baz].getAddress(), FooSym.getAddress())
286       << "\"Baz\"'s address should match \"Foo\"'s";
287   EXPECT_EQ((*Result)[Qux].getAddress(), QuxSym.getAddress())
288       << "The \"Qux\" alias should have been overriden";
289 }
290 
291 TEST(CoreAPIsTest, TestTrivialCircularDependency) {
292   ExecutionSession ES;
293 
294   auto &V = ES.createVSO("V");
295 
296   auto Foo = ES.getSymbolStringPool().intern("foo");
297   auto FooFlags = JITSymbolFlags::Exported;
298   auto FooSym = JITEvaluatedSymbol(1U, FooFlags);
299 
300   Optional<MaterializationResponsibility> FooR;
301   auto FooMU = llvm::make_unique<SimpleMaterializationUnit>(
302       SymbolFlagsMap({{Foo, FooFlags}}),
303       [&](MaterializationResponsibility R) { FooR.emplace(std::move(R)); });
304 
305   cantFail(V.define(FooMU));
306 
307   bool FooReady = false;
308   auto Q =
309     std::make_shared<AsynchronousSymbolQuery>(
310       SymbolNameSet({ Foo }),
311       [](Expected<AsynchronousSymbolQuery::ResolutionResult> R) {
312         cantFail(std::move(R));
313       },
314       [&](Error Err) {
315         cantFail(std::move(Err));
316         FooReady = true;
317       });
318 
319   V.lookup(std::move(Q), { Foo });
320 
321   FooR->addDependencies({{&V, {Foo}}});
322   FooR->resolve({{Foo, FooSym}});
323   FooR->finalize();
324 
325   EXPECT_TRUE(FooReady)
326     << "Self-dependency prevented symbol from being marked ready";
327 }
328 
329 TEST(CoreAPIsTest, TestCircularDependenceInOneVSO) {
330 
331   ExecutionSession ES;
332 
333   auto &V = ES.createVSO("V");
334 
335   // Create three symbols: Foo, Bar and Baz.
336   auto Foo = ES.getSymbolStringPool().intern("foo");
337   auto FooFlags = JITSymbolFlags::Exported;
338   auto FooSym = JITEvaluatedSymbol(1U, FooFlags);
339 
340   auto Bar = ES.getSymbolStringPool().intern("bar");
341   auto BarFlags = JITSymbolFlags::Exported;
342   auto BarSym = JITEvaluatedSymbol(2U, BarFlags);
343 
344   auto Baz = ES.getSymbolStringPool().intern("baz");
345   auto BazFlags = JITSymbolFlags::Exported;
346   auto BazSym = JITEvaluatedSymbol(3U, BazFlags);
347 
348   // Create three MaterializationResponsibility objects: one for each symbol
349   // (these are optional because MaterializationResponsibility does not have
350   // a default constructor).
351   Optional<MaterializationResponsibility> FooR;
352   Optional<MaterializationResponsibility> BarR;
353   Optional<MaterializationResponsibility> BazR;
354 
355   // Create a MaterializationUnit for each symbol that moves the
356   // MaterializationResponsibility into one of the locals above.
357   auto FooMU = llvm::make_unique<SimpleMaterializationUnit>(
358       SymbolFlagsMap({{Foo, FooFlags}}),
359       [&](MaterializationResponsibility R) { FooR.emplace(std::move(R)); });
360 
361   auto BarMU = llvm::make_unique<SimpleMaterializationUnit>(
362       SymbolFlagsMap({{Bar, BarFlags}}),
363       [&](MaterializationResponsibility R) { BarR.emplace(std::move(R)); });
364 
365   auto BazMU = llvm::make_unique<SimpleMaterializationUnit>(
366       SymbolFlagsMap({{Baz, BazFlags}}),
367       [&](MaterializationResponsibility R) { BazR.emplace(std::move(R)); });
368 
369   // Define the symbols.
370   cantFail(V.define(FooMU));
371   cantFail(V.define(BarMU));
372   cantFail(V.define(BazMU));
373 
374   // Query each of the symbols to trigger materialization.
375   bool FooResolved = false;
376   bool FooReady = false;
377   auto FooQ = std::make_shared<AsynchronousSymbolQuery>(
378       SymbolNameSet({Foo}),
379       [&](Expected<AsynchronousSymbolQuery::ResolutionResult> RR) {
380         cantFail(std::move(RR));
381         FooResolved = true;
382       },
383       [&](Error Err) {
384         cantFail(std::move(Err));
385         FooReady = true;
386       });
387   {
388     auto Unresolved = V.lookup(FooQ, {Foo});
389     EXPECT_TRUE(Unresolved.empty()) << "Failed to resolve \"Foo\"";
390   }
391 
392   bool BarResolved = false;
393   bool BarReady = false;
394   auto BarQ = std::make_shared<AsynchronousSymbolQuery>(
395       SymbolNameSet({Bar}),
396       [&](Expected<AsynchronousSymbolQuery::ResolutionResult> RR) {
397         cantFail(std::move(RR));
398         BarResolved = true;
399       },
400       [&](Error Err) {
401         cantFail(std::move(Err));
402         BarReady = true;
403       });
404   {
405     auto Unresolved = V.lookup(BarQ, {Bar});
406     EXPECT_TRUE(Unresolved.empty()) << "Failed to resolve \"Bar\"";
407   }
408 
409   bool BazResolved = false;
410   bool BazReady = false;
411   auto BazQ = std::make_shared<AsynchronousSymbolQuery>(
412       SymbolNameSet({Baz}),
413       [&](Expected<AsynchronousSymbolQuery::ResolutionResult> RR) {
414         cantFail(std::move(RR));
415         BazResolved = true;
416       },
417       [&](Error Err) {
418         cantFail(std::move(Err));
419         BazReady = true;
420       });
421   {
422     auto Unresolved = V.lookup(BazQ, {Baz});
423     EXPECT_TRUE(Unresolved.empty()) << "Failed to resolve \"Baz\"";
424   }
425 
426   // Add a circular dependency: Foo -> Bar, Bar -> Baz, Baz -> Foo.
427   FooR->addDependencies({{&V, SymbolNameSet({Bar})}});
428   BarR->addDependencies({{&V, SymbolNameSet({Baz})}});
429   BazR->addDependencies({{&V, SymbolNameSet({Foo})}});
430 
431   // Add self-dependencies for good measure. This tests that the implementation
432   // of addDependencies filters these out.
433   FooR->addDependencies({{&V, SymbolNameSet({Foo})}});
434   BarR->addDependencies({{&V, SymbolNameSet({Bar})}});
435   BazR->addDependencies({{&V, SymbolNameSet({Baz})}});
436 
437   EXPECT_FALSE(FooResolved) << "\"Foo\" should not be resolved yet";
438   EXPECT_FALSE(BarResolved) << "\"Bar\" should not be resolved yet";
439   EXPECT_FALSE(BazResolved) << "\"Baz\" should not be resolved yet";
440 
441   FooR->resolve({{Foo, FooSym}});
442   BarR->resolve({{Bar, BarSym}});
443   BazR->resolve({{Baz, BazSym}});
444 
445   EXPECT_TRUE(FooResolved) << "\"Foo\" should be resolved now";
446   EXPECT_TRUE(BarResolved) << "\"Bar\" should be resolved now";
447   EXPECT_TRUE(BazResolved) << "\"Baz\" should be resolved now";
448 
449   EXPECT_FALSE(FooReady) << "\"Foo\" should not be ready yet";
450   EXPECT_FALSE(BarReady) << "\"Bar\" should not be ready yet";
451   EXPECT_FALSE(BazReady) << "\"Baz\" should not be ready yet";
452 
453   FooR->finalize();
454   BarR->finalize();
455 
456   // Verify that nothing is ready until the circular dependence is resolved.
457 
458   EXPECT_FALSE(FooReady) << "\"Foo\" still should not be ready";
459   EXPECT_FALSE(BarReady) << "\"Bar\" still should not be ready";
460   EXPECT_FALSE(BazReady) << "\"Baz\" still should not be ready";
461 
462   BazR->finalize();
463 
464   // Verify that everything becomes ready once the circular dependence resolved.
465   EXPECT_TRUE(FooReady) << "\"Foo\" should be ready now";
466   EXPECT_TRUE(BarReady) << "\"Bar\" should be ready now";
467   EXPECT_TRUE(BazReady) << "\"Baz\" should be ready now";
468 }
469 
470 TEST(CoreAPIsTest, DropMaterializerWhenEmpty) {
471   ExecutionSession ES;
472   auto Foo = ES.getSymbolStringPool().intern("foo");
473   auto Bar = ES.getSymbolStringPool().intern("bar");
474 
475   bool DestructorRun = false;
476 
477   auto MU = llvm::make_unique<SimpleMaterializationUnit>(
478       SymbolFlagsMap(
479           {{Foo, JITSymbolFlags::Weak}, {Bar, JITSymbolFlags::Weak}}),
480       [](MaterializationResponsibility R) {
481         llvm_unreachable("Unexpected call to materialize");
482       },
483       [&](const VSO &V, SymbolStringPtr Name) {
484         EXPECT_TRUE(Name == Foo || Name == Bar)
485             << "Discard of unexpected symbol?";
486       },
487       [&]() { DestructorRun = true; });
488 
489   auto &V = ES.createVSO("V");
490 
491   cantFail(V.define(MU));
492 
493   auto FooSym = JITEvaluatedSymbol(1, JITSymbolFlags::Exported);
494   auto BarSym = JITEvaluatedSymbol(2, JITSymbolFlags::Exported);
495   cantFail(V.define(absoluteSymbols({{Foo, FooSym}})));
496 
497   EXPECT_FALSE(DestructorRun)
498       << "MaterializationUnit should not have been destroyed yet";
499 
500   cantFail(V.define(absoluteSymbols({{Bar, BarSym}})));
501 
502   EXPECT_TRUE(DestructorRun)
503       << "MaterializationUnit should have been destroyed";
504 }
505 
506 TEST(CoreAPIsTest, AddAndMaterializeLazySymbol) {
507 
508   constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef;
509   constexpr JITTargetAddress FakeBarAddr = 0xcafef00d;
510 
511   ExecutionSession ES;
512   auto Foo = ES.getSymbolStringPool().intern("foo");
513   auto Bar = ES.getSymbolStringPool().intern("bar");
514 
515   bool FooMaterialized = false;
516   bool BarDiscarded = false;
517 
518   auto &V = ES.createVSO("V");
519 
520   auto MU = llvm::make_unique<SimpleMaterializationUnit>(
521       SymbolFlagsMap(
522           {{Foo, JITSymbolFlags::Exported},
523            {Bar, static_cast<JITSymbolFlags::FlagNames>(
524                      JITSymbolFlags::Exported | JITSymbolFlags::Weak)}}),
525       [&](MaterializationResponsibility R) {
526         assert(BarDiscarded && "Bar should have been discarded by this point");
527         SymbolMap SymbolsToResolve;
528         SymbolsToResolve[Foo] =
529             JITEvaluatedSymbol(FakeFooAddr, JITSymbolFlags::Exported);
530         R.resolve(std::move(SymbolsToResolve));
531         R.finalize();
532         FooMaterialized = true;
533       },
534       [&](const VSO &V, SymbolStringPtr Name) {
535         EXPECT_EQ(Name, Bar) << "Expected Name to be Bar";
536         BarDiscarded = true;
537       });
538 
539   cantFail(V.define(MU));
540 
541   ;
542   cantFail(V.define(absoluteSymbols(
543       {{Bar, JITEvaluatedSymbol(FakeBarAddr, JITSymbolFlags::Exported)}})));
544 
545   SymbolNameSet Names({Foo});
546 
547   bool OnResolutionRun = false;
548   bool OnReadyRun = false;
549 
550   auto OnResolution =
551       [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) {
552         EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error";
553         auto I = Result->Symbols.find(Foo);
554         EXPECT_NE(I, Result->Symbols.end())
555             << "Could not find symbol definition";
556         EXPECT_EQ(I->second.getAddress(), FakeFooAddr)
557             << "Resolution returned incorrect result";
558         OnResolutionRun = true;
559       };
560 
561   auto OnReady = [&](Error Err) {
562     cantFail(std::move(Err));
563     OnReadyRun = true;
564   };
565 
566   auto Q =
567       std::make_shared<AsynchronousSymbolQuery>(Names, OnResolution, OnReady);
568 
569   auto Unresolved = V.lookup(std::move(Q), Names);
570 
571   EXPECT_TRUE(Unresolved.empty()) << "Could not find Foo in dylib";
572   EXPECT_TRUE(FooMaterialized) << "Foo was not materialized";
573   EXPECT_TRUE(BarDiscarded) << "Bar was not discarded";
574   EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run";
575   EXPECT_TRUE(OnReadyRun) << "OnReady was not run";
576 }
577 
578 TEST(CoreAPIsTest, DefineMaterializingSymbol) {
579   ExecutionSession ES;
580   auto Foo = ES.getSymbolStringPool().intern("foo");
581   auto Bar = ES.getSymbolStringPool().intern("bar");
582 
583   auto FooSym = JITEvaluatedSymbol(1, JITSymbolFlags::Exported);
584   auto BarSym = JITEvaluatedSymbol(2, JITSymbolFlags::Exported);
585 
586   bool ExpectNoMoreMaterialization = false;
587   ES.setDispatchMaterialization(
588       [&](VSO &V, std::unique_ptr<MaterializationUnit> MU) {
589         if (ExpectNoMoreMaterialization)
590           ADD_FAILURE() << "Unexpected materialization";
591         MU->doMaterialize(V);
592       });
593 
594   auto MU = llvm::make_unique<SimpleMaterializationUnit>(
595       SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
596       [&](MaterializationResponsibility R) {
597         cantFail(
598             R.defineMaterializing(SymbolFlagsMap({{Bar, BarSym.getFlags()}})));
599         R.resolve(SymbolMap({{Foo, FooSym}, {Bar, BarSym}}));
600         R.finalize();
601       });
602 
603   auto &V = ES.createVSO("V");
604   cantFail(V.define(MU));
605 
606   auto OnResolution1 =
607       [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) {
608         cantFail(std::move(Result));
609       };
610 
611   auto OnReady1 = [](Error Err) { cantFail(std::move(Err)); };
612 
613   auto Q1 = std::make_shared<AsynchronousSymbolQuery>(SymbolNameSet({Foo}),
614                                                       OnResolution1, OnReady1);
615 
616   V.lookup(std::move(Q1), {Foo});
617 
618   bool BarResolved = false;
619   auto OnResolution2 =
620       [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) {
621         auto R = cantFail(std::move(Result));
622         EXPECT_EQ(R.Symbols.size(), 1U) << "Expected to resolve one symbol";
623         EXPECT_EQ(R.Symbols.count(Bar), 1U) << "Expected to resolve 'Bar'";
624         EXPECT_EQ(R.Symbols[Bar].getAddress(), BarSym.getAddress())
625             << "Expected Bar == BarSym";
626         BarResolved = true;
627       };
628 
629   auto OnReady2 = [](Error Err) { cantFail(std::move(Err)); };
630 
631   auto Q2 = std::make_shared<AsynchronousSymbolQuery>(SymbolNameSet({Bar}),
632                                                       OnResolution2, OnReady2);
633 
634   ExpectNoMoreMaterialization = true;
635   V.lookup(std::move(Q2), {Bar});
636 
637   EXPECT_TRUE(BarResolved) << "Bar should have been resolved";
638 }
639 
640 TEST(CoreAPIsTest, FallbackDefinitionGeneratorTest) {
641   constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef;
642   constexpr JITTargetAddress FakeBarAddr = 0xcafef00d;
643 
644   ExecutionSession ES;
645   auto Foo = ES.getSymbolStringPool().intern("foo");
646   auto Bar = ES.getSymbolStringPool().intern("bar");
647 
648   auto FooSym = JITEvaluatedSymbol(FakeFooAddr, JITSymbolFlags::Exported);
649   auto BarSym = JITEvaluatedSymbol(FakeBarAddr, JITSymbolFlags::Exported);
650 
651   auto &V = ES.createVSO("V");
652 
653   cantFail(V.define(absoluteSymbols({{Foo, FooSym}})));
654 
655   V.setFallbackDefinitionGenerator([&](VSO &W, const SymbolNameSet &Names) {
656     cantFail(W.define(absoluteSymbols({{Bar, BarSym}})));
657     return SymbolNameSet({Bar});
658   });
659 
660   auto Result = cantFail(lookup({&V}, {Foo, Bar}));
661 
662   EXPECT_EQ(Result.count(Bar), 1U) << "Expected to find fallback def for 'bar'";
663   EXPECT_EQ(Result[Bar].getAddress(), FakeBarAddr)
664       << "Expected address of fallback def for 'bar' to be " << FakeBarAddr;
665 }
666 
667 TEST(CoreAPIsTest, FailResolution) {
668   ExecutionSession ES;
669   auto Foo = ES.getSymbolStringPool().intern("foo");
670   auto Bar = ES.getSymbolStringPool().intern("bar");
671 
672   SymbolNameSet Names({Foo, Bar});
673 
674   auto MU = llvm::make_unique<SimpleMaterializationUnit>(
675       SymbolFlagsMap(
676           {{Foo, JITSymbolFlags::Weak}, {Bar, JITSymbolFlags::Weak}}),
677       [&](MaterializationResponsibility R) { R.failMaterialization(); });
678 
679   auto &V = ES.createVSO("V");
680 
681   cantFail(V.define(MU));
682 
683   auto OnResolution =
684       [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) {
685         handleAllErrors(Result.takeError(),
686                         [&](FailedToMaterialize &F) {
687                           EXPECT_EQ(F.getSymbols(), Names)
688                               << "Expected to fail on symbols in Names";
689                         },
690                         [](ErrorInfoBase &EIB) {
691                           std::string ErrMsg;
692                           {
693                             raw_string_ostream ErrOut(ErrMsg);
694                             EIB.log(ErrOut);
695                           }
696                           ADD_FAILURE()
697                               << "Expected a FailedToResolve error. Got:\n"
698                               << ErrMsg;
699                         });
700       };
701 
702   auto OnReady = [](Error Err) {
703     cantFail(std::move(Err));
704     ADD_FAILURE() << "OnReady should never be called";
705   };
706 
707   auto Q =
708       std::make_shared<AsynchronousSymbolQuery>(Names, OnResolution, OnReady);
709 
710   V.lookup(std::move(Q), Names);
711 }
712 
713 TEST(CoreAPIsTest, TestLambdaSymbolResolver) {
714   JITEvaluatedSymbol FooSym(0xdeadbeef, JITSymbolFlags::Exported);
715   JITEvaluatedSymbol BarSym(0xcafef00d, JITSymbolFlags::Exported);
716 
717   ExecutionSession ES;
718 
719   auto Foo = ES.getSymbolStringPool().intern("foo");
720   auto Bar = ES.getSymbolStringPool().intern("bar");
721   auto Baz = ES.getSymbolStringPool().intern("baz");
722 
723   auto &V = ES.createVSO("V");
724   cantFail(V.define(absoluteSymbols({{Foo, FooSym}, {Bar, BarSym}})));
725 
726   auto Resolver = createSymbolResolver(
727       [&](SymbolFlagsMap &SymbolFlags, const SymbolNameSet &Symbols) {
728         return V.lookupFlags(SymbolFlags, Symbols);
729       },
730       [&](std::shared_ptr<AsynchronousSymbolQuery> Q, SymbolNameSet Symbols) {
731         return V.lookup(std::move(Q), Symbols);
732       });
733 
734   SymbolNameSet Symbols({Foo, Bar, Baz});
735 
736   SymbolFlagsMap SymbolFlags;
737   SymbolNameSet SymbolsNotFound = Resolver->lookupFlags(SymbolFlags, Symbols);
738 
739   EXPECT_EQ(SymbolFlags.size(), 2U)
740       << "lookupFlags returned the wrong number of results";
741   EXPECT_EQ(SymbolFlags.count(Foo), 1U) << "Missing lookupFlags result for foo";
742   EXPECT_EQ(SymbolFlags.count(Bar), 1U) << "Missing lookupFlags result for bar";
743   EXPECT_EQ(SymbolFlags[Foo], FooSym.getFlags())
744       << "Incorrect lookupFlags result for Foo";
745   EXPECT_EQ(SymbolFlags[Bar], BarSym.getFlags())
746       << "Incorrect lookupFlags result for Bar";
747   EXPECT_EQ(SymbolsNotFound.size(), 1U)
748       << "Expected one symbol not found in lookupFlags";
749   EXPECT_EQ(SymbolsNotFound.count(Baz), 1U)
750       << "Expected baz not to be found in lookupFlags";
751 
752   bool OnResolvedRun = false;
753 
754   auto OnResolved =
755       [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) {
756         OnResolvedRun = true;
757         EXPECT_TRUE(!!Result) << "Unexpected error";
758         EXPECT_EQ(Result->Symbols.size(), 2U)
759             << "Unexpected number of resolved symbols";
760         EXPECT_EQ(Result->Symbols.count(Foo), 1U)
761             << "Missing lookup result for foo";
762         EXPECT_EQ(Result->Symbols.count(Bar), 1U)
763             << "Missing lookup result for bar";
764         EXPECT_EQ(Result->Symbols[Foo].getAddress(), FooSym.getAddress())
765             << "Incorrect address for foo";
766         EXPECT_EQ(Result->Symbols[Bar].getAddress(), BarSym.getAddress())
767             << "Incorrect address for bar";
768       };
769   auto OnReady = [&](Error Err) {
770     EXPECT_FALSE(!!Err) << "Finalization should never fail in this test";
771   };
772 
773   auto Q = std::make_shared<AsynchronousSymbolQuery>(SymbolNameSet({Foo, Bar}),
774                                                      OnResolved, OnReady);
775   auto Unresolved = Resolver->lookup(std::move(Q), Symbols);
776 
777   EXPECT_EQ(Unresolved.size(), 1U) << "Expected one unresolved symbol";
778   EXPECT_EQ(Unresolved.count(Baz), 1U) << "Expected baz to not be resolved";
779   EXPECT_TRUE(OnResolvedRun) << "OnResolved was never run";
780 }
781 
782 TEST(CoreAPIsTest, TestLookupWithUnthreadedMaterialization) {
783   constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef;
784   JITEvaluatedSymbol FooSym(FakeFooAddr, JITSymbolFlags::Exported);
785 
786   ExecutionSession ES(std::make_shared<SymbolStringPool>());
787   auto Foo = ES.getSymbolStringPool().intern("foo");
788 
789   auto MU = llvm::make_unique<SimpleMaterializationUnit>(
790       SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}}),
791       [&](MaterializationResponsibility R) {
792         R.resolve({{Foo, FooSym}});
793         R.finalize();
794       });
795 
796   auto &V = ES.createVSO("V");
797 
798   cantFail(V.define(MU));
799 
800   auto FooLookupResult = cantFail(lookup({&V}, Foo));
801 
802   EXPECT_EQ(FooLookupResult.getAddress(), FooSym.getAddress())
803       << "lookup returned an incorrect address";
804   EXPECT_EQ(FooLookupResult.getFlags(), FooSym.getFlags())
805       << "lookup returned incorrect flags";
806 }
807 
808 TEST(CoreAPIsTest, TestLookupWithThreadedMaterialization) {
809 #if LLVM_ENABLE_THREADS
810   constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef;
811   JITEvaluatedSymbol FooSym(FakeFooAddr, JITSymbolFlags::Exported);
812 
813   ExecutionSession ES(std::make_shared<SymbolStringPool>());
814 
815   std::thread MaterializationThread;
816   ES.setDispatchMaterialization(
817       [&](VSO &V, std::unique_ptr<MaterializationUnit> MU) {
818         auto SharedMU = std::shared_ptr<MaterializationUnit>(std::move(MU));
819         MaterializationThread =
820             std::thread([SharedMU, &V]() { SharedMU->doMaterialize(V); });
821       });
822   auto Foo = ES.getSymbolStringPool().intern("foo");
823 
824   auto &V = ES.createVSO("V");
825   cantFail(V.define(absoluteSymbols({{Foo, FooSym}})));
826 
827   auto FooLookupResult = cantFail(lookup({&V}, Foo));
828 
829   EXPECT_EQ(FooLookupResult.getAddress(), FooSym.getAddress())
830       << "lookup returned an incorrect address";
831   EXPECT_EQ(FooLookupResult.getFlags(), FooSym.getFlags())
832       << "lookup returned incorrect flags";
833   MaterializationThread.join();
834 #endif
835 }
836 
837 TEST(CoreAPIsTest, TestGetRequestedSymbolsAndDelegate) {
838   ExecutionSession ES;
839   auto Foo = ES.getSymbolStringPool().intern("foo");
840   auto Bar = ES.getSymbolStringPool().intern("bar");
841 
842   JITEvaluatedSymbol FooSym(0xdeadbeef, JITSymbolFlags::Exported);
843   JITEvaluatedSymbol BarSym(0xcafef00d, JITSymbolFlags::Exported);
844 
845   SymbolNameSet Names({Foo, Bar});
846 
847   bool FooMaterialized = false;
848   bool BarMaterialized = false;
849 
850   auto MU = llvm::make_unique<SimpleMaterializationUnit>(
851       SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}),
852       [&](MaterializationResponsibility R) {
853         auto Requested = R.getRequestedSymbols();
854         EXPECT_EQ(Requested.size(), 1U) << "Expected one symbol requested";
855         EXPECT_EQ(*Requested.begin(), Foo) << "Expected \"Foo\" requested";
856 
857         auto NewMU = llvm::make_unique<SimpleMaterializationUnit>(
858             SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
859             [&](MaterializationResponsibility R2) {
860               R2.resolve(SymbolMap({{Bar, BarSym}}));
861               R2.finalize();
862               BarMaterialized = true;
863             });
864 
865         R.delegate(std::move(NewMU));
866 
867         R.resolve(SymbolMap({{Foo, FooSym}}));
868         R.finalize();
869 
870         FooMaterialized = true;
871       });
872 
873   auto &V = ES.createVSO("V");
874 
875   cantFail(V.define(MU));
876 
877   EXPECT_FALSE(FooMaterialized) << "Foo should not be materialized yet";
878   EXPECT_FALSE(BarMaterialized) << "Bar should not be materialized yet";
879 
880   auto FooSymResult = cantFail(lookup({&V}, Foo));
881   EXPECT_EQ(FooSymResult.getAddress(), FooSym.getAddress())
882       << "Address mismatch for Foo";
883 
884   EXPECT_TRUE(FooMaterialized) << "Foo should be materialized now";
885   EXPECT_FALSE(BarMaterialized) << "Bar still should not be materialized";
886 
887   auto BarSymResult = cantFail(lookup({&V}, Bar));
888   EXPECT_EQ(BarSymResult.getAddress(), BarSym.getAddress())
889       << "Address mismatch for Bar";
890   EXPECT_TRUE(BarMaterialized) << "Bar should be materialized now";
891 }
892 
893 TEST(CoreAPIsTest, TestMaterializeWeakSymbol) {
894   // Confirm that once a weak definition is selected for materialization it is
895   // treated as strong.
896 
897   constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef;
898   JITSymbolFlags FooFlags = JITSymbolFlags::Exported;
899   FooFlags &= JITSymbolFlags::Weak;
900   auto FooSym = JITEvaluatedSymbol(FakeFooAddr, FooFlags);
901 
902   ExecutionSession ES;
903   auto Foo = ES.getSymbolStringPool().intern("foo");
904 
905   auto &V = ES.createVSO("V");
906 
907   std::unique_ptr<MaterializationResponsibility> FooResponsibility;
908   auto MU = llvm::make_unique<SimpleMaterializationUnit>(
909       SymbolFlagsMap({{Foo, FooFlags}}), [&](MaterializationResponsibility R) {
910         FooResponsibility =
911             llvm::make_unique<MaterializationResponsibility>(std::move(R));
912       });
913 
914   cantFail(V.define(MU));
915   auto Q = std::make_shared<AsynchronousSymbolQuery>(
916       SymbolNameSet({Foo}),
917       [](Expected<AsynchronousSymbolQuery::ResolutionResult> R) {
918         cantFail(std::move(R));
919       },
920       [](Error Err) { cantFail(std::move(Err)); });
921   V.lookup(std::move(Q), SymbolNameSet({Foo}));
922 
923   auto MU2 = llvm::make_unique<SimpleMaterializationUnit>(
924       SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}}),
925       [](MaterializationResponsibility R) {
926         llvm_unreachable("This unit should never be materialized");
927       });
928 
929   auto Err = V.define(MU2);
930   EXPECT_TRUE(!!Err) << "Expected failure value";
931   EXPECT_TRUE(Err.isA<DuplicateDefinition>())
932       << "Expected a duplicate definition error";
933   consumeError(std::move(Err));
934 
935   FooResponsibility->resolve(SymbolMap({{Foo, FooSym}}));
936   FooResponsibility->finalize();
937 }
938 
939 } // namespace
940