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