19510447aSLang Hames //===----------- CoreAPIsTest.cpp - Unit tests for Core ORC APIs ----------===//
29510447aSLang Hames //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
69510447aSLang Hames //
79510447aSLang Hames //===----------------------------------------------------------------------===//
89510447aSLang Hames 
99510447aSLang Hames #include "OrcTestCommon.h"
10f3428dafSLang Hames #include "llvm/ADT/ScopeExit.h"
11432a3883SNico Weber #include "llvm/Config/llvm-config.h"
129510447aSLang Hames #include "llvm/ExecutionEngine/Orc/Core.h"
1324672ddeSLang Hames #include "llvm/ExecutionEngine/Orc/Shared/OrcError.h"
144f71049aSLang Hames #include "llvm/Testing/Support/Error.h"
159510447aSLang Hames 
169510447aSLang Hames #include <set>
17817f1f64SLang Hames #include <thread>
189510447aSLang Hames 
199510447aSLang Hames using namespace llvm;
209510447aSLang Hames using namespace llvm::orc;
219510447aSLang Hames 
22fd0c1e71SLang Hames class CoreAPIsStandardTest : public CoreAPIsBasedStandardTest {};
23fd0c1e71SLang Hames 
249510447aSLang Hames namespace {
259510447aSLang Hames 
TEST_F(CoreAPIsStandardTest,BasicSuccessfulLookup)26a48d1083SLang Hames TEST_F(CoreAPIsStandardTest, BasicSuccessfulLookup) {
27d4a8089fSLang Hames   bool OnCompletionRun = false;
28a48d1083SLang Hames 
29d4a8089fSLang Hames   auto OnCompletion = [&](Expected<SymbolMap> Result) {
309510447aSLang Hames     EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error";
31a48d1083SLang Hames     auto &Resolved = *Result;
32d261e125SLang Hames     auto I = Resolved.find(Foo);
33d261e125SLang Hames     EXPECT_NE(I, Resolved.end()) << "Could not find symbol definition";
3458ba7812SLang Hames     EXPECT_EQ(I->second.getAddress(), FooAddr)
359510447aSLang Hames         << "Resolution returned incorrect result";
36d4a8089fSLang Hames     OnCompletionRun = true;
379510447aSLang Hames   };
389510447aSLang Hames 
397dcd0042SLang Hames   std::unique_ptr<MaterializationResponsibility> FooMR;
409510447aSLang Hames 
410eaee545SJonas Devlieghere   cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(
42a48d1083SLang Hames       SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
437dcd0042SLang Hames       [&](std::unique_ptr<MaterializationResponsibility> R) {
447dcd0042SLang Hames         FooMR = std::move(R);
45a48d1083SLang Hames       })));
469510447aSLang Hames 
47674df13bSLang Hames   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
48674df13bSLang Hames             SymbolLookupSet(Foo), SymbolState::Ready, OnCompletion,
49674df13bSLang Hames             NoDependenciesToRegister);
50d261e125SLang Hames 
51d4a8089fSLang Hames   EXPECT_FALSE(OnCompletionRun) << "Should not have been resolved yet";
52d261e125SLang Hames 
53e00585c7SLang Hames   cantFail(FooMR->notifyResolved({{Foo, FooSym}}));
54d261e125SLang Hames 
55d4a8089fSLang Hames   EXPECT_FALSE(OnCompletionRun) << "Should not be ready yet";
56a48d1083SLang Hames 
57e00585c7SLang Hames   cantFail(FooMR->notifyEmitted());
58a48d1083SLang Hames 
59d4a8089fSLang Hames   EXPECT_TRUE(OnCompletionRun) << "Should have been marked ready";
609510447aSLang Hames }
619510447aSLang Hames 
TEST_F(CoreAPIsStandardTest,EmptyLookup)62a48d1083SLang Hames TEST_F(CoreAPIsStandardTest, EmptyLookup) {
63d4a8089fSLang Hames   bool OnCompletionRun = false;
649510447aSLang Hames 
65d4a8089fSLang Hames   auto OnCompletion = [&](Expected<SymbolMap> Result) {
66a48d1083SLang Hames     cantFail(std::move(Result));
67d4a8089fSLang Hames     OnCompletionRun = true;
689510447aSLang Hames   };
699510447aSLang Hames 
70674df13bSLang Hames   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), SymbolLookupSet(),
71674df13bSLang Hames             SymbolState::Ready, OnCompletion, NoDependenciesToRegister);
729510447aSLang Hames 
73d4a8089fSLang Hames   EXPECT_TRUE(OnCompletionRun) << "OnCompletion was not run for empty query";
74a5247cc5SLang Hames }
75a5247cc5SLang Hames 
TEST_F(CoreAPIsStandardTest,ResolveUnrequestedSymbol)76d38d06e6SLang Hames TEST_F(CoreAPIsStandardTest, ResolveUnrequestedSymbol) {
77d38d06e6SLang Hames   // Test that all symbols in a MaterializationUnit materialize corretly when
78d38d06e6SLang Hames   // only a subset of symbols is looked up.
79d38d06e6SLang Hames   // The aim here is to ensure that we're not relying on the query to set up
80d38d06e6SLang Hames   // state needed to materialize the unrequested symbols.
81d38d06e6SLang Hames 
82d38d06e6SLang Hames   cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(
83d38d06e6SLang Hames       SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}),
847dcd0042SLang Hames       [this](std::unique_ptr<MaterializationResponsibility> R) {
857dcd0042SLang Hames         cantFail(R->notifyResolved({{Foo, FooSym}, {Bar, BarSym}}));
867dcd0042SLang Hames         cantFail(R->notifyEmitted());
87d38d06e6SLang Hames       })));
88d38d06e6SLang Hames 
89d38d06e6SLang Hames   auto Result =
90d38d06e6SLang Hames       cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Foo})));
91d38d06e6SLang Hames   EXPECT_EQ(Result.size(), 1U) << "Unexpected number of results";
92d38d06e6SLang Hames   EXPECT_TRUE(Result.count(Foo)) << "Expected result for \"Foo\"";
93d38d06e6SLang Hames }
94d38d06e6SLang Hames 
TEST_F(CoreAPIsStandardTest,MaterializationSideEffctsOnlyBasic)953e753ce1SLang Hames TEST_F(CoreAPIsStandardTest, MaterializationSideEffctsOnlyBasic) {
96cb84e482SLang Hames   // Test that basic materialization-side-effects-only symbols work as expected:
97cb84e482SLang Hames   // that they can be emitted without being resolved, that queries for them
98cb84e482SLang Hames   // don't return until they're emitted, and that they don't appear in query
99cb84e482SLang Hames   // results.
100cb84e482SLang Hames 
1017dcd0042SLang Hames   std::unique_ptr<MaterializationResponsibility> FooR;
102cb84e482SLang Hames   Optional<SymbolMap> Result;
103cb84e482SLang Hames 
104cb84e482SLang Hames   cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(
105cb84e482SLang Hames       SymbolFlagsMap(
106cb84e482SLang Hames           {{Foo, JITSymbolFlags::Exported |
107cb84e482SLang Hames                      JITSymbolFlags::MaterializationSideEffectsOnly}}),
1087dcd0042SLang Hames       [&](std::unique_ptr<MaterializationResponsibility> R) {
1097dcd0042SLang Hames         FooR = std::move(R);
1107dcd0042SLang Hames       })));
111cb84e482SLang Hames 
112cb84e482SLang Hames   ES.lookup(
113cb84e482SLang Hames       LookupKind::Static, makeJITDylibSearchOrder(&JD),
114cd8a80deSLang Hames       SymbolLookupSet(Foo, SymbolLookupFlags::WeaklyReferencedSymbol),
115cb84e482SLang Hames       SymbolState::Ready,
116cb84e482SLang Hames       [&](Expected<SymbolMap> LookupResult) {
117cb84e482SLang Hames         if (LookupResult)
118cb84e482SLang Hames           Result = std::move(*LookupResult);
119cb84e482SLang Hames         else
120cb84e482SLang Hames           ADD_FAILURE() << "Unexpected lookup error: "
121cb84e482SLang Hames                         << toString(LookupResult.takeError());
122cb84e482SLang Hames       },
123cb84e482SLang Hames       NoDependenciesToRegister);
124cb84e482SLang Hames 
125cb84e482SLang Hames   EXPECT_FALSE(Result) << "Lookup returned unexpectedly";
126cb84e482SLang Hames   EXPECT_TRUE(FooR) << "Lookup failed to trigger materialization";
127cb84e482SLang Hames   EXPECT_THAT_ERROR(FooR->notifyEmitted(), Succeeded())
128cb84e482SLang Hames       << "Emission of materialization-side-effects-only symbol failed";
129cb84e482SLang Hames 
130cb84e482SLang Hames   EXPECT_TRUE(Result) << "Lookup failed to return";
131cb84e482SLang Hames   EXPECT_TRUE(Result->empty()) << "Lookup result contained unexpected value";
132cb84e482SLang Hames }
133cb84e482SLang Hames 
TEST_F(CoreAPIsStandardTest,MaterializationSideEffectsOnlyFailuresPersist)1343e753ce1SLang Hames TEST_F(CoreAPIsStandardTest, MaterializationSideEffectsOnlyFailuresPersist) {
1353e753ce1SLang Hames   // Test that when a MaterializationSideEffectsOnly symbol is failed it
1363e753ce1SLang Hames   // remains in the failure state rather than vanishing.
1373e753ce1SLang Hames 
1383e753ce1SLang Hames   cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(
1393e753ce1SLang Hames       SymbolFlagsMap(
1403e753ce1SLang Hames           {{Foo, JITSymbolFlags::Exported |
1413e753ce1SLang Hames                      JITSymbolFlags::MaterializationSideEffectsOnly}}),
1427dcd0042SLang Hames       [&](std::unique_ptr<MaterializationResponsibility> R) {
1437dcd0042SLang Hames         R->failMaterialization();
1447dcd0042SLang Hames       })));
1453e753ce1SLang Hames 
1463e753ce1SLang Hames   EXPECT_THAT_EXPECTED(
1473e753ce1SLang Hames       ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Foo})),
1483e753ce1SLang Hames       Failed());
1493e753ce1SLang Hames   EXPECT_THAT_EXPECTED(
1503e753ce1SLang Hames       ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Foo})),
1513e753ce1SLang Hames       Failed());
1523e753ce1SLang Hames }
1533e753ce1SLang Hames 
TEST_F(CoreAPIsStandardTest,RemoveSymbolsTest)154535448e0SLang Hames TEST_F(CoreAPIsStandardTest, RemoveSymbolsTest) {
155535448e0SLang Hames   // Test that:
156535448e0SLang Hames   // (1) Missing symbols generate a SymbolsNotFound error.
157535448e0SLang Hames   // (2) Materializing symbols generate a SymbolCouldNotBeRemoved error.
158535448e0SLang Hames   // (3) Removal of unmaterialized symbols triggers discard on the
159535448e0SLang Hames   //     materialization unit.
160535448e0SLang Hames   // (4) Removal of symbols destroys empty materialization units.
161535448e0SLang Hames   // (5) Removal of materialized symbols works.
162535448e0SLang Hames 
163535448e0SLang Hames   // Foo will be fully materialized.
164535448e0SLang Hames   cantFail(JD.define(absoluteSymbols({{Foo, FooSym}})));
165535448e0SLang Hames 
166535448e0SLang Hames   // Bar will be unmaterialized.
167535448e0SLang Hames   bool BarDiscarded = false;
168535448e0SLang Hames   bool BarMaterializerDestructed = false;
1690eaee545SJonas Devlieghere   cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(
170535448e0SLang Hames       SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
1717dcd0042SLang Hames       [this](std::unique_ptr<MaterializationResponsibility> R) {
172535448e0SLang Hames         ADD_FAILURE() << "Unexpected materialization of \"Bar\"";
1737dcd0042SLang Hames         cantFail(R->notifyResolved({{Bar, BarSym}}));
1747dcd0042SLang Hames         cantFail(R->notifyEmitted());
175535448e0SLang Hames       },
17685fb9976SLang Hames       nullptr,
177535448e0SLang Hames       [&](const JITDylib &JD, const SymbolStringPtr &Name) {
178535448e0SLang Hames         EXPECT_EQ(Name, Bar) << "Expected \"Bar\" to be discarded";
179535448e0SLang Hames         if (Name == Bar)
180535448e0SLang Hames           BarDiscarded = true;
181535448e0SLang Hames       },
182535448e0SLang Hames       [&]() { BarMaterializerDestructed = true; })));
183535448e0SLang Hames 
184535448e0SLang Hames   // Baz will be in the materializing state initially, then
185535448e0SLang Hames   // materialized for the final removal attempt.
1867dcd0042SLang Hames   std::unique_ptr<MaterializationResponsibility> BazR;
1870eaee545SJonas Devlieghere   cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(
188535448e0SLang Hames       SymbolFlagsMap({{Baz, BazSym.getFlags()}}),
1897dcd0042SLang Hames       [&](std::unique_ptr<MaterializationResponsibility> R) {
1907dcd0042SLang Hames         BazR = std::move(R);
1917dcd0042SLang Hames       },
19285fb9976SLang Hames       nullptr,
193535448e0SLang Hames       [](const JITDylib &JD, const SymbolStringPtr &Name) {
194535448e0SLang Hames         ADD_FAILURE() << "\"Baz\" discarded unexpectedly";
195535448e0SLang Hames       })));
196535448e0SLang Hames 
197d4a8089fSLang Hames   bool OnCompletionRun = false;
198d4a8089fSLang Hames   ES.lookup(
199674df13bSLang Hames       LookupKind::Static, makeJITDylibSearchOrder(&JD),
200674df13bSLang Hames       SymbolLookupSet({Foo, Baz}), SymbolState::Ready,
201535448e0SLang Hames       [&](Expected<SymbolMap> Result) {
202d4a8089fSLang Hames         cantFail(Result.takeError());
203d4a8089fSLang Hames         OnCompletionRun = true;
204535448e0SLang Hames       },
205535448e0SLang Hames       NoDependenciesToRegister);
206535448e0SLang Hames 
207535448e0SLang Hames   {
208535448e0SLang Hames     // Attempt 1: Search for a missing symbol, Qux.
209535448e0SLang Hames     auto Err = JD.remove({Foo, Bar, Baz, Qux});
210535448e0SLang Hames     EXPECT_TRUE(!!Err) << "Expected failure";
211535448e0SLang Hames     EXPECT_TRUE(Err.isA<SymbolsNotFound>())
212535448e0SLang Hames         << "Expected a SymbolsNotFound error";
213cd0e5990SLang Hames     consumeError(std::move(Err));
214535448e0SLang Hames   }
215535448e0SLang Hames 
216535448e0SLang Hames   {
217535448e0SLang Hames     // Attempt 2: Search for a symbol that is still materializing, Baz.
218535448e0SLang Hames     auto Err = JD.remove({Foo, Bar, Baz});
219535448e0SLang Hames     EXPECT_TRUE(!!Err) << "Expected failure";
220535448e0SLang Hames     EXPECT_TRUE(Err.isA<SymbolsCouldNotBeRemoved>())
221535448e0SLang Hames         << "Expected a SymbolsNotFound error";
222cd0e5990SLang Hames     consumeError(std::move(Err));
223535448e0SLang Hames   }
224535448e0SLang Hames 
225e00585c7SLang Hames   cantFail(BazR->notifyResolved({{Baz, BazSym}}));
226e00585c7SLang Hames   cantFail(BazR->notifyEmitted());
227535448e0SLang Hames   {
228535448e0SLang Hames     // Attempt 3: Search now that all symbols are fully materialized
229535448e0SLang Hames     // (Foo, Baz), or not yet materialized (Bar).
230535448e0SLang Hames     auto Err = JD.remove({Foo, Bar, Baz});
231b7aa1cc3SLang Hames     EXPECT_FALSE(!!Err) << "Expected success";
232535448e0SLang Hames   }
233535448e0SLang Hames 
234535448e0SLang Hames   EXPECT_TRUE(BarDiscarded) << "\"Bar\" should have been discarded";
235535448e0SLang Hames   EXPECT_TRUE(BarMaterializerDestructed)
236535448e0SLang Hames       << "\"Bar\"'s materializer should have been destructed";
237d4a8089fSLang Hames   EXPECT_TRUE(OnCompletionRun) << "OnCompletion should have been run";
238535448e0SLang Hames }
239535448e0SLang Hames 
TEST_F(CoreAPIsStandardTest,LookupWithHiddenSymbols)2407899ccbcSLang Hames TEST_F(CoreAPIsStandardTest, LookupWithHiddenSymbols) {
2417899ccbcSLang Hames   auto BarHiddenFlags = BarSym.getFlags() & ~JITSymbolFlags::Exported;
2427899ccbcSLang Hames   auto BarHiddenSym = JITEvaluatedSymbol(BarSym.getAddress(), BarHiddenFlags);
2437899ccbcSLang Hames 
2447899ccbcSLang Hames   cantFail(JD.define(absoluteSymbols({{Foo, FooSym}, {Bar, BarHiddenSym}})));
2457899ccbcSLang Hames 
24685fb9976SLang Hames   auto &JD2 = ES.createBareJITDylib("JD2");
2477899ccbcSLang Hames   cantFail(JD2.define(absoluteSymbols({{Bar, QuxSym}})));
2487899ccbcSLang Hames 
24923cb2e7fSLang Hames   /// Try a blocking lookup.
250674df13bSLang Hames   auto Result = cantFail(ES.lookup(makeJITDylibSearchOrder({&JD, &JD2}),
251674df13bSLang Hames                                    SymbolLookupSet({Foo, Bar})));
2527899ccbcSLang Hames 
2537899ccbcSLang Hames   EXPECT_EQ(Result.size(), 2U) << "Unexpected number of results";
2547899ccbcSLang Hames   EXPECT_EQ(Result.count(Foo), 1U) << "Missing result for \"Foo\"";
2557899ccbcSLang Hames   EXPECT_EQ(Result.count(Bar), 1U) << "Missing result for \"Bar\"";
2567899ccbcSLang Hames   EXPECT_EQ(Result[Bar].getAddress(), QuxSym.getAddress())
2577899ccbcSLang Hames       << "Wrong result for \"Bar\"";
2587899ccbcSLang Hames }
2597899ccbcSLang Hames 
TEST_F(CoreAPIsStandardTest,LookupFlagsTest)26058ba7812SLang Hames TEST_F(CoreAPIsStandardTest, LookupFlagsTest) {
2615ff5a30bSLang Hames   // Test that lookupFlags works on a predefined symbol, and does not trigger
26258ba7812SLang Hames   // materialization of a lazy symbol. Make the lazy symbol weak to test that
26358ba7812SLang Hames   // the weak flag is propagated correctly.
2645ff5a30bSLang Hames 
26558ba7812SLang Hames   BarSym.setFlags(static_cast<JITSymbolFlags::FlagNames>(
26658ba7812SLang Hames       JITSymbolFlags::Exported | JITSymbolFlags::Weak));
2670eaee545SJonas Devlieghere   auto MU = std::make_unique<SimpleMaterializationUnit>(
26858ba7812SLang Hames       SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
2697dcd0042SLang Hames       [](std::unique_ptr<MaterializationResponsibility> R) {
2705ff5a30bSLang Hames         llvm_unreachable("Symbol materialized on flags lookup");
2715ff5a30bSLang Hames       });
2725ff5a30bSLang Hames 
273d5f56c59SLang Hames   cantFail(JD.define(absoluteSymbols({{Foo, FooSym}})));
274d5f56c59SLang Hames   cantFail(JD.define(std::move(MU)));
2755ff5a30bSLang Hames 
276069919c9SLang Hames   auto SymbolFlags = cantFail(ES.lookupFlags(
277069919c9SLang Hames       LookupKind::Static,
278069919c9SLang Hames       {{&JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}},
279069919c9SLang Hames       SymbolLookupSet({Foo, Bar, Baz},
280069919c9SLang Hames                       SymbolLookupFlags::WeaklyReferencedSymbol)));
2815ff5a30bSLang Hames 
282c8a74a04SLang Hames   EXPECT_EQ(SymbolFlags.size(), 2U)
2835ff5a30bSLang Hames       << "Returned symbol flags contains unexpected results";
284c8a74a04SLang Hames   EXPECT_EQ(SymbolFlags.count(Foo), 1U) << "Missing lookupFlags result for Foo";
28558ba7812SLang Hames   EXPECT_EQ(SymbolFlags[Foo], FooSym.getFlags())
28658ba7812SLang Hames       << "Incorrect flags returned for Foo";
287c8a74a04SLang Hames   EXPECT_EQ(SymbolFlags.count(Bar), 1U)
2885ff5a30bSLang Hames       << "Missing  lookupFlags result for Bar";
28958ba7812SLang Hames   EXPECT_EQ(SymbolFlags[Bar], BarSym.getFlags())
29058ba7812SLang Hames       << "Incorrect flags returned for Bar";
2915ff5a30bSLang Hames }
2925ff5a30bSLang Hames 
TEST_F(CoreAPIsStandardTest,LookupWithGeneratorFailure)293b1286723SLang Hames TEST_F(CoreAPIsStandardTest, LookupWithGeneratorFailure) {
294b1286723SLang Hames 
2955d2e359cSLang Hames   class BadGenerator : public DefinitionGenerator {
296b1286723SLang Hames   public:
297069919c9SLang Hames     Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &,
298069919c9SLang Hames                         JITDylibLookupFlags, const SymbolLookupSet &) override {
299b1286723SLang Hames       return make_error<StringError>("BadGenerator", inconvertibleErrorCode());
300b1286723SLang Hames     }
301b1286723SLang Hames   };
302b1286723SLang Hames 
3030eaee545SJonas Devlieghere   JD.addGenerator(std::make_unique<BadGenerator>());
304b1286723SLang Hames 
305674df13bSLang Hames   EXPECT_THAT_ERROR(
306069919c9SLang Hames       ES.lookupFlags(LookupKind::Static,
307069919c9SLang Hames                      {{&JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}},
308674df13bSLang Hames                      SymbolLookupSet(Foo))
309674df13bSLang Hames           .takeError(),
310674df13bSLang Hames       Failed<StringError>())
311b1286723SLang Hames       << "Generator failure did not propagate through lookupFlags";
312b1286723SLang Hames 
313b1286723SLang Hames   EXPECT_THAT_ERROR(
314674df13bSLang Hames       ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet(Foo)).takeError(),
315b1286723SLang Hames       Failed<StringError>())
316b1286723SLang Hames       << "Generator failure did not propagate through lookup";
317b1286723SLang Hames }
318b1286723SLang Hames 
TEST_F(CoreAPIsStandardTest,TestBasicAliases)31958ba7812SLang Hames TEST_F(CoreAPIsStandardTest, TestBasicAliases) {
320d5f56c59SLang Hames   cantFail(JD.define(absoluteSymbols({{Foo, FooSym}, {Bar, BarSym}})));
321d5f56c59SLang Hames   cantFail(JD.define(symbolAliases({{Baz, {Foo, JITSymbolFlags::Exported}},
322ce72161dSLang Hames                                     {Qux, {Bar, JITSymbolFlags::Weak}}})));
323d5f56c59SLang Hames   cantFail(JD.define(absoluteSymbols({{Qux, QuxSym}})));
324ce72161dSLang Hames 
325674df13bSLang Hames   auto Result =
326674df13bSLang Hames       ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Baz, Qux}));
327ce72161dSLang Hames   EXPECT_TRUE(!!Result) << "Unexpected lookup failure";
328ce72161dSLang Hames   EXPECT_EQ(Result->count(Baz), 1U) << "No result for \"baz\"";
329ce72161dSLang Hames   EXPECT_EQ(Result->count(Qux), 1U) << "No result for \"qux\"";
330ce72161dSLang Hames   EXPECT_EQ((*Result)[Baz].getAddress(), FooSym.getAddress())
331ce72161dSLang Hames       << "\"Baz\"'s address should match \"Foo\"'s";
332ce72161dSLang Hames   EXPECT_EQ((*Result)[Qux].getAddress(), QuxSym.getAddress())
333ce72161dSLang Hames       << "The \"Qux\" alias should have been overriden";
334ce72161dSLang Hames }
335ce72161dSLang Hames 
TEST_F(CoreAPIsStandardTest,TestChainedAliases)33658ba7812SLang Hames TEST_F(CoreAPIsStandardTest, TestChainedAliases) {
337d5f56c59SLang Hames   cantFail(JD.define(absoluteSymbols({{Foo, FooSym}})));
338d5f56c59SLang Hames   cantFail(JD.define(symbolAliases(
33958ba7812SLang Hames       {{Baz, {Bar, BazSym.getFlags()}}, {Bar, {Foo, BarSym.getFlags()}}})));
340a3c473e6SLang Hames 
341674df13bSLang Hames   auto Result =
342674df13bSLang Hames       ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Bar, Baz}));
343a3c473e6SLang Hames   EXPECT_TRUE(!!Result) << "Unexpected lookup failure";
344a3c473e6SLang Hames   EXPECT_EQ(Result->count(Bar), 1U) << "No result for \"bar\"";
345a3c473e6SLang Hames   EXPECT_EQ(Result->count(Baz), 1U) << "No result for \"baz\"";
346a3c473e6SLang Hames   EXPECT_EQ((*Result)[Bar].getAddress(), FooSym.getAddress())
347a3c473e6SLang Hames       << "\"Bar\"'s address should match \"Foo\"'s";
348a3c473e6SLang Hames   EXPECT_EQ((*Result)[Baz].getAddress(), FooSym.getAddress())
349a3c473e6SLang Hames       << "\"Baz\"'s address should match \"Foo\"'s";
350a3c473e6SLang Hames }
351a3c473e6SLang Hames 
TEST_F(CoreAPIsStandardTest,TestBasicReExports)352960246dbSLang Hames TEST_F(CoreAPIsStandardTest, TestBasicReExports) {
353960246dbSLang Hames   // Test that the basic use case of re-exporting a single symbol from another
354d5f56c59SLang Hames   // JITDylib works.
355d5f56c59SLang Hames   cantFail(JD.define(absoluteSymbols({{Foo, FooSym}})));
356960246dbSLang Hames 
35785fb9976SLang Hames   auto &JD2 = ES.createBareJITDylib("JD2");
358960246dbSLang Hames 
359d5f56c59SLang Hames   cantFail(JD2.define(reexports(JD, {{Bar, {Foo, BarSym.getFlags()}}})));
360960246dbSLang Hames 
361674df13bSLang Hames   auto Result = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD2), Bar));
362960246dbSLang Hames   EXPECT_EQ(Result.getAddress(), FooSym.getAddress())
363960246dbSLang Hames       << "Re-export Bar for symbol Foo should match FooSym's address";
364960246dbSLang Hames }
365960246dbSLang Hames 
TEST_F(CoreAPIsStandardTest,TestThatReExportsDontUnnecessarilyMaterialize)366960246dbSLang Hames TEST_F(CoreAPIsStandardTest, TestThatReExportsDontUnnecessarilyMaterialize) {
367960246dbSLang Hames   // Test that re-exports do not materialize symbols that have not been queried
368960246dbSLang Hames   // for.
369d5f56c59SLang Hames   cantFail(JD.define(absoluteSymbols({{Foo, FooSym}})));
370960246dbSLang Hames 
371960246dbSLang Hames   bool BarMaterialized = false;
3720eaee545SJonas Devlieghere   auto BarMU = std::make_unique<SimpleMaterializationUnit>(
373960246dbSLang Hames       SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
3747dcd0042SLang Hames       [&](std::unique_ptr<MaterializationResponsibility> R) {
375960246dbSLang Hames         BarMaterialized = true;
3767dcd0042SLang Hames         cantFail(R->notifyResolved({{Bar, BarSym}}));
3777dcd0042SLang Hames         cantFail(R->notifyEmitted());
378960246dbSLang Hames       });
379960246dbSLang Hames 
380d5f56c59SLang Hames   cantFail(JD.define(BarMU));
381960246dbSLang Hames 
38285fb9976SLang Hames   auto &JD2 = ES.createBareJITDylib("JD2");
383960246dbSLang Hames 
384d5f56c59SLang Hames   cantFail(JD2.define(reexports(
385d5f56c59SLang Hames       JD, {{Baz, {Foo, BazSym.getFlags()}}, {Qux, {Bar, QuxSym.getFlags()}}})));
386960246dbSLang Hames 
387674df13bSLang Hames   auto Result = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD2), Baz));
388960246dbSLang Hames   EXPECT_EQ(Result.getAddress(), FooSym.getAddress())
389960246dbSLang Hames       << "Re-export Baz for symbol Foo should match FooSym's address";
390960246dbSLang Hames 
391960246dbSLang Hames   EXPECT_FALSE(BarMaterialized) << "Bar should not have been materialized";
392960246dbSLang Hames }
393960246dbSLang Hames 
TEST_F(CoreAPIsStandardTest,TestReexportsGenerator)394a5157d6fSLang Hames TEST_F(CoreAPIsStandardTest, TestReexportsGenerator) {
395a5157d6fSLang Hames   // Test that a re-exports generator can dynamically generate reexports.
396be1066deSLang Hames 
39785fb9976SLang Hames   auto &JD2 = ES.createBareJITDylib("JD2");
398d5f56c59SLang Hames   cantFail(JD2.define(absoluteSymbols({{Foo, FooSym}, {Bar, BarSym}})));
399be1066deSLang Hames 
400be1066deSLang Hames   auto Filter = [this](SymbolStringPtr Name) { return Name != Bar; };
401be1066deSLang Hames 
402674df13bSLang Hames   JD.addGenerator(std::make_unique<ReexportsGenerator>(
403674df13bSLang Hames       JD2, JITDylibLookupFlags::MatchExportedSymbolsOnly, Filter));
404be1066deSLang Hames 
405069919c9SLang Hames   auto Flags = cantFail(ES.lookupFlags(
406069919c9SLang Hames       LookupKind::Static,
407069919c9SLang Hames       {{&JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}},
408069919c9SLang Hames       SymbolLookupSet({Foo, Bar, Baz},
409069919c9SLang Hames                       SymbolLookupFlags::WeaklyReferencedSymbol)));
410be1066deSLang Hames   EXPECT_EQ(Flags.size(), 1U) << "Unexpected number of results";
411be1066deSLang Hames   EXPECT_EQ(Flags[Foo], FooSym.getFlags()) << "Unexpected flags for Foo";
412be1066deSLang Hames 
413674df13bSLang Hames   auto Result = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Foo));
414be1066deSLang Hames 
415be1066deSLang Hames   EXPECT_EQ(Result.getAddress(), FooSym.getAddress())
416be1066deSLang Hames       << "Incorrect reexported symbol address";
417be1066deSLang Hames }
418be1066deSLang Hames 
TEST_F(CoreAPIsStandardTest,TestTrivialCircularDependency)41958ba7812SLang Hames TEST_F(CoreAPIsStandardTest, TestTrivialCircularDependency) {
4207dcd0042SLang Hames   std::unique_ptr<MaterializationResponsibility> FooR;
4210eaee545SJonas Devlieghere   auto FooMU = std::make_unique<SimpleMaterializationUnit>(
42258ba7812SLang Hames       SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
4237dcd0042SLang Hames       [&](std::unique_ptr<MaterializationResponsibility> R) {
4247dcd0042SLang Hames         FooR = std::move(R);
4257dcd0042SLang Hames       });
426df5776b1SLang Hames 
427d5f56c59SLang Hames   cantFail(JD.define(FooMU));
428df5776b1SLang Hames 
429df5776b1SLang Hames   bool FooReady = false;
430d4a8089fSLang Hames   auto OnCompletion = [&](Expected<SymbolMap> Result) {
431d4a8089fSLang Hames     cantFail(std::move(Result));
432df5776b1SLang Hames     FooReady = true;
433a48d1083SLang Hames   };
434df5776b1SLang Hames 
435674df13bSLang Hames   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
436674df13bSLang Hames             SymbolLookupSet({Foo}), SymbolState::Ready, OnCompletion,
437674df13bSLang Hames             NoDependenciesToRegister);
438df5776b1SLang Hames 
4398e2837e5SLang Hames   FooR->addDependenciesForAll({{&JD, SymbolNameSet({Foo})}});
440e00585c7SLang Hames   EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Succeeded())
441e00585c7SLang Hames       << "No symbols marked failed, but Foo failed to resolve";
442e00585c7SLang Hames   EXPECT_THAT_ERROR(FooR->notifyEmitted(), Succeeded())
443e00585c7SLang Hames       << "No symbols marked failed, but Foo failed to emit";
444df5776b1SLang Hames 
445df5776b1SLang Hames   EXPECT_TRUE(FooReady)
446df5776b1SLang Hames     << "Self-dependency prevented symbol from being marked ready";
447df5776b1SLang Hames }
448df5776b1SLang Hames 
TEST_F(CoreAPIsStandardTest,TestCircularDependenceInOneJITDylib)449d5f56c59SLang Hames TEST_F(CoreAPIsStandardTest, TestCircularDependenceInOneJITDylib) {
450d5f56c59SLang Hames   // Test that a circular symbol dependency between three symbols in a JITDylib
451d5f56c59SLang Hames   // does not prevent any symbol from becoming 'ready' once all symbols are
45276e21c97SLang Hames   // emitted.
453d261e125SLang Hames 
4547dcd0042SLang Hames   std::unique_ptr<MaterializationResponsibility> FooR;
4557dcd0042SLang Hames   std::unique_ptr<MaterializationResponsibility> BarR;
4567dcd0042SLang Hames   std::unique_ptr<MaterializationResponsibility> BazR;
457d261e125SLang Hames 
458d261e125SLang Hames   // Create a MaterializationUnit for each symbol that moves the
459d261e125SLang Hames   // MaterializationResponsibility into one of the locals above.
4600eaee545SJonas Devlieghere   auto FooMU = std::make_unique<SimpleMaterializationUnit>(
46158ba7812SLang Hames       SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
4627dcd0042SLang Hames       [&](std::unique_ptr<MaterializationResponsibility> R) {
4637dcd0042SLang Hames         FooR = std::move(R);
4647dcd0042SLang Hames       });
465d261e125SLang Hames 
4660eaee545SJonas Devlieghere   auto BarMU = std::make_unique<SimpleMaterializationUnit>(
46758ba7812SLang Hames       SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
4687dcd0042SLang Hames       [&](std::unique_ptr<MaterializationResponsibility> R) {
4697dcd0042SLang Hames         BarR = std::move(R);
4707dcd0042SLang Hames       });
471d261e125SLang Hames 
4720eaee545SJonas Devlieghere   auto BazMU = std::make_unique<SimpleMaterializationUnit>(
47358ba7812SLang Hames       SymbolFlagsMap({{Baz, BazSym.getFlags()}}),
4747dcd0042SLang Hames       [&](std::unique_ptr<MaterializationResponsibility> R) {
4757dcd0042SLang Hames         BazR = std::move(R);
4767dcd0042SLang Hames       });
477d261e125SLang Hames 
478d261e125SLang Hames   // Define the symbols.
479d5f56c59SLang Hames   cantFail(JD.define(FooMU));
480d5f56c59SLang Hames   cantFail(JD.define(BarMU));
481d5f56c59SLang Hames   cantFail(JD.define(BazMU));
482d261e125SLang Hames 
483d261e125SLang Hames   // Query each of the symbols to trigger materialization.
484d261e125SLang Hames   bool FooResolved = false;
485d261e125SLang Hames   bool FooReady = false;
486a48d1083SLang Hames 
487a48d1083SLang Hames   auto OnFooResolution = [&](Expected<SymbolMap> Result) {
488a48d1083SLang Hames     cantFail(std::move(Result));
489d261e125SLang Hames     FooResolved = true;
490a48d1083SLang Hames   };
491a48d1083SLang Hames 
492d4a8089fSLang Hames   auto OnFooReady = [&](Expected<SymbolMap> Result) {
493d4a8089fSLang Hames     cantFail(std::move(Result));
494d261e125SLang Hames     FooReady = true;
495a48d1083SLang Hames   };
496a48d1083SLang Hames 
497d4a8089fSLang Hames   // Issue lookups for Foo. Use NoDependenciesToRegister: We're going to add
498a48d1083SLang Hames   // the dependencies manually below.
499674df13bSLang Hames   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
500674df13bSLang Hames             SymbolLookupSet(Foo), SymbolState::Resolved,
501d4a8089fSLang Hames             std::move(OnFooResolution), NoDependenciesToRegister);
502d4a8089fSLang Hames 
503674df13bSLang Hames   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
504674df13bSLang Hames             SymbolLookupSet(Foo), SymbolState::Ready, std::move(OnFooReady),
505674df13bSLang Hames             NoDependenciesToRegister);
506d261e125SLang Hames 
507d261e125SLang Hames   bool BarResolved = false;
508d261e125SLang Hames   bool BarReady = false;
509a48d1083SLang Hames   auto OnBarResolution = [&](Expected<SymbolMap> Result) {
510a48d1083SLang Hames     cantFail(std::move(Result));
511d261e125SLang Hames     BarResolved = true;
512a48d1083SLang Hames   };
513a48d1083SLang Hames 
514d4a8089fSLang Hames   auto OnBarReady = [&](Expected<SymbolMap> Result) {
515d4a8089fSLang Hames     cantFail(std::move(Result));
516d261e125SLang Hames     BarReady = true;
517a48d1083SLang Hames   };
518a48d1083SLang Hames 
519674df13bSLang Hames   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
520674df13bSLang Hames             SymbolLookupSet(Bar), SymbolState::Resolved,
521d4a8089fSLang Hames             std::move(OnBarResolution), NoDependenciesToRegister);
522d4a8089fSLang Hames 
523674df13bSLang Hames   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
524674df13bSLang Hames             SymbolLookupSet(Bar), SymbolState::Ready, std::move(OnBarReady),
525674df13bSLang Hames             NoDependenciesToRegister);
526d261e125SLang Hames 
527d261e125SLang Hames   bool BazResolved = false;
528d261e125SLang Hames   bool BazReady = false;
529a48d1083SLang Hames 
530a48d1083SLang Hames   auto OnBazResolution = [&](Expected<SymbolMap> Result) {
531a48d1083SLang Hames     cantFail(std::move(Result));
532d261e125SLang Hames     BazResolved = true;
533a48d1083SLang Hames   };
534a48d1083SLang Hames 
535d4a8089fSLang Hames   auto OnBazReady = [&](Expected<SymbolMap> Result) {
536d4a8089fSLang Hames     cantFail(std::move(Result));
537d261e125SLang Hames     BazReady = true;
538a48d1083SLang Hames   };
539a48d1083SLang Hames 
540674df13bSLang Hames   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
541674df13bSLang Hames             SymbolLookupSet(Baz), SymbolState::Resolved,
542d4a8089fSLang Hames             std::move(OnBazResolution), NoDependenciesToRegister);
543d4a8089fSLang Hames 
544674df13bSLang Hames   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
545674df13bSLang Hames             SymbolLookupSet(Baz), SymbolState::Ready, std::move(OnBazReady),
546674df13bSLang Hames             NoDependenciesToRegister);
547d261e125SLang Hames 
548b7788ebbSLang Hames   // Add a circular dependency: Foo -> Bar, Bar -> Baz, Baz -> Foo.
549d5f56c59SLang Hames   FooR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}});
550d5f56c59SLang Hames   BarR->addDependenciesForAll({{&JD, SymbolNameSet({Baz})}});
551d5f56c59SLang Hames   BazR->addDependenciesForAll({{&JD, SymbolNameSet({Foo})}});
552d261e125SLang Hames 
553b7788ebbSLang Hames   // Add self-dependencies for good measure. This tests that the implementation
554b7788ebbSLang Hames   // of addDependencies filters these out.
555d5f56c59SLang Hames   FooR->addDependenciesForAll({{&JD, SymbolNameSet({Foo})}});
556d5f56c59SLang Hames   BarR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}});
557d5f56c59SLang Hames   BazR->addDependenciesForAll({{&JD, SymbolNameSet({Baz})}});
558b7788ebbSLang Hames 
55958ba7812SLang Hames   // Check that nothing has been resolved yet.
560d261e125SLang Hames   EXPECT_FALSE(FooResolved) << "\"Foo\" should not be resolved yet";
561d261e125SLang Hames   EXPECT_FALSE(BarResolved) << "\"Bar\" should not be resolved yet";
562d261e125SLang Hames   EXPECT_FALSE(BazResolved) << "\"Baz\" should not be resolved yet";
563d261e125SLang Hames 
56476e21c97SLang Hames   // Resolve the symbols (but do not emit them).
565e00585c7SLang Hames   EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Succeeded())
566e00585c7SLang Hames       << "No symbols failed, but Foo failed to resolve";
567e00585c7SLang Hames   EXPECT_THAT_ERROR(BarR->notifyResolved({{Bar, BarSym}}), Succeeded())
568e00585c7SLang Hames       << "No symbols failed, but Bar failed to resolve";
569e00585c7SLang Hames   EXPECT_THAT_ERROR(BazR->notifyResolved({{Baz, BazSym}}), Succeeded())
570e00585c7SLang Hames       << "No symbols failed, but Baz failed to resolve";
571d261e125SLang Hames 
57258ba7812SLang Hames   // Verify that the symbols have been resolved, but are not ready yet.
573d261e125SLang Hames   EXPECT_TRUE(FooResolved) << "\"Foo\" should be resolved now";
574d261e125SLang Hames   EXPECT_TRUE(BarResolved) << "\"Bar\" should be resolved now";
575d261e125SLang Hames   EXPECT_TRUE(BazResolved) << "\"Baz\" should be resolved now";
576d261e125SLang Hames 
577d261e125SLang Hames   EXPECT_FALSE(FooReady) << "\"Foo\" should not be ready yet";
578d261e125SLang Hames   EXPECT_FALSE(BarReady) << "\"Bar\" should not be ready yet";
579d261e125SLang Hames   EXPECT_FALSE(BazReady) << "\"Baz\" should not be ready yet";
580d261e125SLang Hames 
58176e21c97SLang Hames   // Emit two of the symbols.
582e00585c7SLang Hames   EXPECT_THAT_ERROR(FooR->notifyEmitted(), Succeeded())
583e00585c7SLang Hames       << "No symbols failed, but Foo failed to emit";
584e00585c7SLang Hames   EXPECT_THAT_ERROR(BarR->notifyEmitted(), Succeeded())
585e00585c7SLang Hames       << "No symbols failed, but Bar failed to emit";
586d261e125SLang Hames 
587d261e125SLang Hames   // Verify that nothing is ready until the circular dependence is resolved.
588d261e125SLang Hames   EXPECT_FALSE(FooReady) << "\"Foo\" still should not be ready";
589d261e125SLang Hames   EXPECT_FALSE(BarReady) << "\"Bar\" still should not be ready";
590d261e125SLang Hames   EXPECT_FALSE(BazReady) << "\"Baz\" still should not be ready";
591d261e125SLang Hames 
59276e21c97SLang Hames   // Emit the last symbol.
593e00585c7SLang Hames   EXPECT_THAT_ERROR(BazR->notifyEmitted(), Succeeded())
594e00585c7SLang Hames       << "No symbols failed, but Baz failed to emit";
595d261e125SLang Hames 
596d261e125SLang Hames   // Verify that everything becomes ready once the circular dependence resolved.
597d261e125SLang Hames   EXPECT_TRUE(FooReady) << "\"Foo\" should be ready now";
598d261e125SLang Hames   EXPECT_TRUE(BarReady) << "\"Bar\" should be ready now";
599d261e125SLang Hames   EXPECT_TRUE(BazReady) << "\"Baz\" should be ready now";
600d261e125SLang Hames }
601d261e125SLang Hames 
TEST_F(CoreAPIsStandardTest,FailureInDependency)602e00585c7SLang Hames TEST_F(CoreAPIsStandardTest, FailureInDependency) {
6037dcd0042SLang Hames   std::unique_ptr<MaterializationResponsibility> FooR;
6047dcd0042SLang Hames   std::unique_ptr<MaterializationResponsibility> BarR;
605e00585c7SLang Hames 
606e00585c7SLang Hames   // Create a MaterializationUnit for each symbol that moves the
607e00585c7SLang Hames   // MaterializationResponsibility into one of the locals above.
608e00585c7SLang Hames   auto FooMU = std::make_unique<SimpleMaterializationUnit>(
609e00585c7SLang Hames       SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
6107dcd0042SLang Hames       [&](std::unique_ptr<MaterializationResponsibility> R) {
6117dcd0042SLang Hames         FooR = std::move(R);
6127dcd0042SLang Hames       });
613e00585c7SLang Hames 
614e00585c7SLang Hames   auto BarMU = std::make_unique<SimpleMaterializationUnit>(
615e00585c7SLang Hames       SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
6167dcd0042SLang Hames       [&](std::unique_ptr<MaterializationResponsibility> R) {
6177dcd0042SLang Hames         BarR = std::move(R);
6187dcd0042SLang Hames       });
619e00585c7SLang Hames 
620e00585c7SLang Hames   // Define the symbols.
621e00585c7SLang Hames   cantFail(JD.define(FooMU));
622e00585c7SLang Hames   cantFail(JD.define(BarMU));
623e00585c7SLang Hames 
624e00585c7SLang Hames   bool OnFooReadyRun = false;
625e00585c7SLang Hames   auto OnFooReady = [&](Expected<SymbolMap> Result) {
626e00585c7SLang Hames     EXPECT_THAT_EXPECTED(std::move(Result), Failed());
627e00585c7SLang Hames     OnFooReadyRun = true;
628e00585c7SLang Hames   };
629e00585c7SLang Hames 
630674df13bSLang Hames   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
631674df13bSLang Hames             SymbolLookupSet(Foo), SymbolState::Ready, std::move(OnFooReady),
632674df13bSLang Hames             NoDependenciesToRegister);
633e00585c7SLang Hames 
634e00585c7SLang Hames   bool OnBarReadyRun = false;
635e00585c7SLang Hames   auto OnBarReady = [&](Expected<SymbolMap> Result) {
636e00585c7SLang Hames     EXPECT_THAT_EXPECTED(std::move(Result), Failed());
637e00585c7SLang Hames     OnBarReadyRun = true;
638e00585c7SLang Hames   };
639e00585c7SLang Hames 
640674df13bSLang Hames   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
641674df13bSLang Hames             SymbolLookupSet(Bar), SymbolState::Ready, std::move(OnBarReady),
642674df13bSLang Hames             NoDependenciesToRegister);
643e00585c7SLang Hames 
644e00585c7SLang Hames   // Add a dependency by Foo on Bar.
645e00585c7SLang Hames   FooR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}});
646e00585c7SLang Hames 
647e00585c7SLang Hames   // Fail bar.
648e00585c7SLang Hames   BarR->failMaterialization();
649e00585c7SLang Hames 
650e00585c7SLang Hames   // Verify that queries on Bar failed, but queries on Foo have not yet.
651e00585c7SLang Hames   EXPECT_TRUE(OnBarReadyRun) << "Query for \"Bar\" was not run";
652e00585c7SLang Hames   EXPECT_FALSE(OnFooReadyRun) << "Query for \"Foo\" was run unexpectedly";
653e00585c7SLang Hames 
654e00585c7SLang Hames   // Check that we can still resolve Foo (even though it has been failed).
655e00585c7SLang Hames   EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Failed())
656e00585c7SLang Hames       << "Expected resolution for \"Foo\" to fail.";
657e00585c7SLang Hames 
658e00585c7SLang Hames   FooR->failMaterialization();
659e00585c7SLang Hames 
660e00585c7SLang Hames   // Verify that queries on Foo have now failed.
661e00585c7SLang Hames   EXPECT_TRUE(OnFooReadyRun) << "Query for \"Foo\" was not run";
662e00585c7SLang Hames 
663e00585c7SLang Hames   // Verify that subsequent lookups on Bar and Foo fail.
664e00585c7SLang Hames   EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Bar}), Failed())
665e00585c7SLang Hames       << "Lookup on failed symbol should fail";
666e00585c7SLang Hames 
667e00585c7SLang Hames   EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Foo}), Failed())
668e00585c7SLang Hames       << "Lookup on failed symbol should fail";
669e00585c7SLang Hames }
670e00585c7SLang Hames 
TEST_F(CoreAPIsStandardTest,FailureInCircularDependency)671e00585c7SLang Hames TEST_F(CoreAPIsStandardTest, FailureInCircularDependency) {
6727dcd0042SLang Hames   std::unique_ptr<MaterializationResponsibility> FooR;
6737dcd0042SLang Hames   std::unique_ptr<MaterializationResponsibility> BarR;
674e00585c7SLang Hames 
675e00585c7SLang Hames   // Create a MaterializationUnit for each symbol that moves the
676e00585c7SLang Hames   // MaterializationResponsibility into one of the locals above.
677e00585c7SLang Hames   auto FooMU = std::make_unique<SimpleMaterializationUnit>(
678e00585c7SLang Hames       SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
6797dcd0042SLang Hames       [&](std::unique_ptr<MaterializationResponsibility> R) {
6807dcd0042SLang Hames         FooR = std::move(R);
6817dcd0042SLang Hames       });
682e00585c7SLang Hames 
683e00585c7SLang Hames   auto BarMU = std::make_unique<SimpleMaterializationUnit>(
684e00585c7SLang Hames       SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
6857dcd0042SLang Hames       [&](std::unique_ptr<MaterializationResponsibility> R) {
6867dcd0042SLang Hames         BarR = std::move(R);
6877dcd0042SLang Hames       });
688e00585c7SLang Hames 
689e00585c7SLang Hames   // Define the symbols.
690e00585c7SLang Hames   cantFail(JD.define(FooMU));
691e00585c7SLang Hames   cantFail(JD.define(BarMU));
692e00585c7SLang Hames 
693e00585c7SLang Hames   bool OnFooReadyRun = false;
694e00585c7SLang Hames   auto OnFooReady = [&](Expected<SymbolMap> Result) {
695e00585c7SLang Hames     EXPECT_THAT_EXPECTED(std::move(Result), Failed());
696e00585c7SLang Hames     OnFooReadyRun = true;
697e00585c7SLang Hames   };
698e00585c7SLang Hames 
699674df13bSLang Hames   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
700674df13bSLang Hames             SymbolLookupSet(Foo), SymbolState::Ready, std::move(OnFooReady),
701674df13bSLang Hames             NoDependenciesToRegister);
702e00585c7SLang Hames 
703e00585c7SLang Hames   bool OnBarReadyRun = false;
704e00585c7SLang Hames   auto OnBarReady = [&](Expected<SymbolMap> Result) {
705e00585c7SLang Hames     EXPECT_THAT_EXPECTED(std::move(Result), Failed());
706e00585c7SLang Hames     OnBarReadyRun = true;
707e00585c7SLang Hames   };
708e00585c7SLang Hames 
709674df13bSLang Hames   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
710674df13bSLang Hames             SymbolLookupSet(Bar), SymbolState::Ready, std::move(OnBarReady),
711674df13bSLang Hames             NoDependenciesToRegister);
712e00585c7SLang Hames 
713e00585c7SLang Hames   // Add a dependency by Foo on Bar and vice-versa.
714e00585c7SLang Hames   FooR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}});
715e00585c7SLang Hames   BarR->addDependenciesForAll({{&JD, SymbolNameSet({Foo})}});
716e00585c7SLang Hames 
717e00585c7SLang Hames   // Fail bar.
718e00585c7SLang Hames   BarR->failMaterialization();
719e00585c7SLang Hames 
720e00585c7SLang Hames   // Verify that queries on Bar failed, but queries on Foo have not yet.
721e00585c7SLang Hames   EXPECT_TRUE(OnBarReadyRun) << "Query for \"Bar\" was not run";
722e00585c7SLang Hames   EXPECT_FALSE(OnFooReadyRun) << "Query for \"Foo\" was run unexpectedly";
723e00585c7SLang Hames 
724e00585c7SLang Hames   // Verify that trying to resolve Foo fails.
725e00585c7SLang Hames   EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Failed())
726e00585c7SLang Hames       << "Expected resolution for \"Foo\" to fail.";
727e00585c7SLang Hames 
728e00585c7SLang Hames   FooR->failMaterialization();
729e00585c7SLang Hames 
730e00585c7SLang Hames   // Verify that queries on Foo have now failed.
731e00585c7SLang Hames   EXPECT_TRUE(OnFooReadyRun) << "Query for \"Foo\" was not run";
732e00585c7SLang Hames 
733e00585c7SLang Hames   // Verify that subsequent lookups on Bar and Foo fail.
734e00585c7SLang Hames   EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Bar}), Failed())
735e00585c7SLang Hames       << "Lookup on failed symbol should fail";
736e00585c7SLang Hames 
737e00585c7SLang Hames   EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Foo}), Failed())
738e00585c7SLang Hames       << "Lookup on failed symbol should fail";
739e00585c7SLang Hames }
740e00585c7SLang Hames 
TEST_F(CoreAPIsStandardTest,AddDependencyOnFailedSymbol)741e00585c7SLang Hames TEST_F(CoreAPIsStandardTest, AddDependencyOnFailedSymbol) {
7427dcd0042SLang Hames   std::unique_ptr<MaterializationResponsibility> FooR;
7437dcd0042SLang Hames   std::unique_ptr<MaterializationResponsibility> BarR;
744e00585c7SLang Hames 
745e00585c7SLang Hames   // Create a MaterializationUnit for each symbol that moves the
746e00585c7SLang Hames   // MaterializationResponsibility into one of the locals above.
747e00585c7SLang Hames   auto FooMU = std::make_unique<SimpleMaterializationUnit>(
748e00585c7SLang Hames       SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
7497dcd0042SLang Hames       [&](std::unique_ptr<MaterializationResponsibility> R) {
7507dcd0042SLang Hames         FooR = std::move(R);
7517dcd0042SLang Hames       });
752e00585c7SLang Hames 
753e00585c7SLang Hames   auto BarMU = std::make_unique<SimpleMaterializationUnit>(
754e00585c7SLang Hames       SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
7557dcd0042SLang Hames       [&](std::unique_ptr<MaterializationResponsibility> R) {
7567dcd0042SLang Hames         BarR = std::move(R);
7577dcd0042SLang Hames       });
758e00585c7SLang Hames 
759e00585c7SLang Hames   // Define the symbols.
760e00585c7SLang Hames   cantFail(JD.define(FooMU));
761e00585c7SLang Hames   cantFail(JD.define(BarMU));
762e00585c7SLang Hames 
763e00585c7SLang Hames   bool OnFooReadyRun = false;
764e00585c7SLang Hames   auto OnFooReady = [&](Expected<SymbolMap> Result) {
765e00585c7SLang Hames     EXPECT_THAT_EXPECTED(std::move(Result), Failed());
766e00585c7SLang Hames     OnFooReadyRun = true;
767e00585c7SLang Hames   };
768e00585c7SLang Hames 
769674df13bSLang Hames   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
770674df13bSLang Hames             SymbolLookupSet(Foo), SymbolState::Ready, std::move(OnFooReady),
771674df13bSLang Hames             NoDependenciesToRegister);
772e00585c7SLang Hames 
773e00585c7SLang Hames   bool OnBarReadyRun = false;
774e00585c7SLang Hames   auto OnBarReady = [&](Expected<SymbolMap> Result) {
775e00585c7SLang Hames     EXPECT_THAT_EXPECTED(std::move(Result), Failed());
776e00585c7SLang Hames     OnBarReadyRun = true;
777e00585c7SLang Hames   };
778e00585c7SLang Hames 
779674df13bSLang Hames   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
780674df13bSLang Hames             SymbolLookupSet(Bar), SymbolState::Ready, std::move(OnBarReady),
781674df13bSLang Hames             NoDependenciesToRegister);
782e00585c7SLang Hames 
783e00585c7SLang Hames   // Fail bar.
784e00585c7SLang Hames   BarR->failMaterialization();
785e00585c7SLang Hames 
786e00585c7SLang Hames   // We expect Bar's query to fail immediately, but Foo's query not to have run
787e00585c7SLang Hames   // yet.
788e00585c7SLang Hames   EXPECT_TRUE(OnBarReadyRun) << "Query for \"Bar\" was not run";
789e00585c7SLang Hames   EXPECT_FALSE(OnFooReadyRun) << "Query for \"Foo\" should not have run yet";
790e00585c7SLang Hames 
791e00585c7SLang Hames   // Add dependency of Foo on Bar.
792e00585c7SLang Hames   FooR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}});
793e00585c7SLang Hames 
794e00585c7SLang Hames   // Check that we can still resolve Foo (even though it has been failed).
795e00585c7SLang Hames   EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Failed())
796e00585c7SLang Hames       << "Expected resolution for \"Foo\" to fail.";
797e00585c7SLang Hames 
798e00585c7SLang Hames   FooR->failMaterialization();
799e00585c7SLang Hames 
800e00585c7SLang Hames   // Foo's query should have failed before we return from addDependencies.
801e00585c7SLang Hames   EXPECT_TRUE(OnFooReadyRun) << "Query for \"Foo\" was not run";
802e00585c7SLang Hames 
803e00585c7SLang Hames   // Verify that subsequent lookups on Bar and Foo fail.
804e00585c7SLang Hames   EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Bar}), Failed())
805e00585c7SLang Hames       << "Lookup on failed symbol should fail";
806e00585c7SLang Hames 
807e00585c7SLang Hames   EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Foo}), Failed())
808e00585c7SLang Hames       << "Lookup on failed symbol should fail";
809e00585c7SLang Hames }
810e00585c7SLang Hames 
TEST_F(CoreAPIsStandardTest,FailAfterMaterialization)8118853ac7eSLang Hames TEST_F(CoreAPIsStandardTest, FailAfterMaterialization) {
8127dcd0042SLang Hames   std::unique_ptr<MaterializationResponsibility> FooR;
8137dcd0042SLang Hames   std::unique_ptr<MaterializationResponsibility> BarR;
8148853ac7eSLang Hames 
8158853ac7eSLang Hames   // Create a MaterializationUnit for each symbol that moves the
8168853ac7eSLang Hames   // MaterializationResponsibility into one of the locals above.
8178853ac7eSLang Hames   auto FooMU = std::make_unique<SimpleMaterializationUnit>(
8188853ac7eSLang Hames       SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
8197dcd0042SLang Hames       [&](std::unique_ptr<MaterializationResponsibility> R) {
8207dcd0042SLang Hames         FooR = std::move(R);
8217dcd0042SLang Hames       });
8228853ac7eSLang Hames 
8238853ac7eSLang Hames   auto BarMU = std::make_unique<SimpleMaterializationUnit>(
8248853ac7eSLang Hames       SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
8257dcd0042SLang Hames       [&](std::unique_ptr<MaterializationResponsibility> R) {
8267dcd0042SLang Hames         BarR = std::move(R);
8277dcd0042SLang Hames       });
8288853ac7eSLang Hames 
8298853ac7eSLang Hames   // Define the symbols.
8308853ac7eSLang Hames   cantFail(JD.define(FooMU));
8318853ac7eSLang Hames   cantFail(JD.define(BarMU));
8328853ac7eSLang Hames 
8338853ac7eSLang Hames   bool OnFooReadyRun = false;
8348853ac7eSLang Hames   auto OnFooReady = [&](Expected<SymbolMap> Result) {
8358853ac7eSLang Hames     EXPECT_THAT_EXPECTED(std::move(Result), Failed());
8368853ac7eSLang Hames     OnFooReadyRun = true;
8378853ac7eSLang Hames   };
8388853ac7eSLang Hames 
839674df13bSLang Hames   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
840674df13bSLang Hames             SymbolLookupSet(Foo), SymbolState::Ready, std::move(OnFooReady),
841674df13bSLang Hames             NoDependenciesToRegister);
8428853ac7eSLang Hames 
8438853ac7eSLang Hames   bool OnBarReadyRun = false;
8448853ac7eSLang Hames   auto OnBarReady = [&](Expected<SymbolMap> Result) {
8458853ac7eSLang Hames     EXPECT_THAT_EXPECTED(std::move(Result), Failed());
8468853ac7eSLang Hames     OnBarReadyRun = true;
8478853ac7eSLang Hames   };
8488853ac7eSLang Hames 
849674df13bSLang Hames   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
850674df13bSLang Hames             SymbolLookupSet(Bar), SymbolState::Ready, std::move(OnBarReady),
851674df13bSLang Hames             NoDependenciesToRegister);
8528853ac7eSLang Hames 
8538853ac7eSLang Hames   // Add a dependency by Foo on Bar and vice-versa.
8548853ac7eSLang Hames   FooR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}});
8558853ac7eSLang Hames   BarR->addDependenciesForAll({{&JD, SymbolNameSet({Foo})}});
8568853ac7eSLang Hames 
8578853ac7eSLang Hames   // Materialize Foo.
8588853ac7eSLang Hames   EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Succeeded())
8598853ac7eSLang Hames       << "Expected resolution for \"Foo\" to succeed.";
8608853ac7eSLang Hames   EXPECT_THAT_ERROR(FooR->notifyEmitted(), Succeeded())
8618853ac7eSLang Hames       << "Expected emission for \"Foo\" to succeed.";
8628853ac7eSLang Hames 
8638853ac7eSLang Hames   // Fail bar.
8648853ac7eSLang Hames   BarR->failMaterialization();
8658853ac7eSLang Hames 
8668853ac7eSLang Hames   // Verify that both queries failed.
8678853ac7eSLang Hames   EXPECT_TRUE(OnFooReadyRun) << "Query for Foo did not run";
8688853ac7eSLang Hames   EXPECT_TRUE(OnBarReadyRun) << "Query for Bar did not run";
8698853ac7eSLang Hames }
8708853ac7eSLang Hames 
TEST_F(CoreAPIsStandardTest,FailMaterializerWithUnqueriedSymbols)8718ec96618SLang Hames TEST_F(CoreAPIsStandardTest, FailMaterializerWithUnqueriedSymbols) {
8728ec96618SLang Hames   // Make sure that symbols with no queries aganist them still
8738ec96618SLang Hames   // fail correctly.
8748ec96618SLang Hames 
8758ec96618SLang Hames   bool MaterializerRun = false;
8768ec96618SLang Hames   auto MU = std::make_unique<SimpleMaterializationUnit>(
8778ec96618SLang Hames       SymbolFlagsMap(
8788ec96618SLang Hames           {{Foo, JITSymbolFlags::Exported}, {Bar, JITSymbolFlags::Exported}}),
8797dcd0042SLang Hames       [&](std::unique_ptr<MaterializationResponsibility> R) {
8808ec96618SLang Hames         MaterializerRun = true;
8817dcd0042SLang Hames         R->failMaterialization();
8828ec96618SLang Hames       });
8838ec96618SLang Hames 
8848ec96618SLang Hames   cantFail(JD.define(std::move(MU)));
8858ec96618SLang Hames 
8868ec96618SLang Hames   // Issue a query for Foo, but not bar.
8878ec96618SLang Hames   EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Foo}), Failed())
8888ec96618SLang Hames       << "Expected lookup to fail.";
8898ec96618SLang Hames 
8908ec96618SLang Hames   // Check that the materializer (and therefore failMaterialization) ran.
8918ec96618SLang Hames   EXPECT_TRUE(MaterializerRun) << "Expected materializer to have run by now";
8928ec96618SLang Hames 
8938ec96618SLang Hames   // Check that subsequent queries against both symbols fail.
8948ec96618SLang Hames   EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Foo}), Failed())
8958ec96618SLang Hames       << "Expected lookup for Foo to fail.";
8968ec96618SLang Hames   EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Bar}), Failed())
8978ec96618SLang Hames       << "Expected lookup for Bar to fail.";
8988ec96618SLang Hames }
8998ec96618SLang Hames 
TEST_F(CoreAPIsStandardTest,DropMaterializerWhenEmpty)90058ba7812SLang Hames TEST_F(CoreAPIsStandardTest, DropMaterializerWhenEmpty) {
9019d8877baSLang Hames   bool DestructorRun = false;
9029d8877baSLang Hames 
90358ba7812SLang Hames   JITSymbolFlags WeakExported(JITSymbolFlags::Exported);
90458ba7812SLang Hames   WeakExported |= JITSymbolFlags::Weak;
90558ba7812SLang Hames 
9060eaee545SJonas Devlieghere   auto MU = std::make_unique<SimpleMaterializationUnit>(
90758ba7812SLang Hames       SymbolFlagsMap({{Foo, WeakExported}, {Bar, WeakExported}}),
9087dcd0042SLang Hames       [](std::unique_ptr<MaterializationResponsibility> R) {
9099d8877baSLang Hames         llvm_unreachable("Unexpected call to materialize");
9109d8877baSLang Hames       },
91185fb9976SLang Hames       nullptr,
912d5f56c59SLang Hames       [&](const JITDylib &JD, SymbolStringPtr Name) {
9139d8877baSLang Hames         EXPECT_TRUE(Name == Foo || Name == Bar)
9149d8877baSLang Hames             << "Discard of unexpected symbol?";
9159d8877baSLang Hames       },
9169d8877baSLang Hames       [&]() { DestructorRun = true; });
9179d8877baSLang Hames 
918d5f56c59SLang Hames   cantFail(JD.define(MU));
9199d8877baSLang Hames 
920d5f56c59SLang Hames   cantFail(JD.define(absoluteSymbols({{Foo, FooSym}})));
9219d8877baSLang Hames 
9229d8877baSLang Hames   EXPECT_FALSE(DestructorRun)
9239d8877baSLang Hames       << "MaterializationUnit should not have been destroyed yet";
9249d8877baSLang Hames 
925d5f56c59SLang Hames   cantFail(JD.define(absoluteSymbols({{Bar, BarSym}})));
9269d8877baSLang Hames 
9279d8877baSLang Hames   EXPECT_TRUE(DestructorRun)
9289d8877baSLang Hames       << "MaterializationUnit should have been destroyed";
9299d8877baSLang Hames }
9309d8877baSLang Hames 
TEST_F(CoreAPIsStandardTest,AddAndMaterializeLazySymbol)93158ba7812SLang Hames TEST_F(CoreAPIsStandardTest, AddAndMaterializeLazySymbol) {
9329510447aSLang Hames   bool FooMaterialized = false;
9339510447aSLang Hames   bool BarDiscarded = false;
9349510447aSLang Hames 
93558ba7812SLang Hames   JITSymbolFlags WeakExported(JITSymbolFlags::Exported);
93658ba7812SLang Hames   WeakExported |= JITSymbolFlags::Weak;
9379510447aSLang Hames 
9380eaee545SJonas Devlieghere   auto MU = std::make_unique<SimpleMaterializationUnit>(
93958ba7812SLang Hames       SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}, {Bar, WeakExported}}),
9407dcd0042SLang Hames       [&](std::unique_ptr<MaterializationResponsibility> R) {
9414cca7d22SLang Hames         assert(BarDiscarded && "Bar should have been discarded by this point");
9427dcd0042SLang Hames         cantFail(R->notifyResolved(SymbolMap({{Foo, FooSym}})));
9437dcd0042SLang Hames         cantFail(R->notifyEmitted());
9449510447aSLang Hames         FooMaterialized = true;
9459510447aSLang Hames       },
94685fb9976SLang Hames       nullptr,
947d5f56c59SLang Hames       [&](const JITDylib &JD, SymbolStringPtr Name) {
9489510447aSLang Hames         EXPECT_EQ(Name, Bar) << "Expected Name to be Bar";
9499510447aSLang Hames         BarDiscarded = true;
9509510447aSLang Hames       });
9519510447aSLang Hames 
952d5f56c59SLang Hames   cantFail(JD.define(MU));
953d5f56c59SLang Hames   cantFail(JD.define(absoluteSymbols({{Bar, BarSym}})));
9549510447aSLang Hames 
955d4a8089fSLang Hames   bool OnCompletionRun = false;
9569510447aSLang Hames 
957d4a8089fSLang Hames   auto OnCompletion = [&](Expected<SymbolMap> Result) {
9589510447aSLang Hames     EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error";
959a48d1083SLang Hames     auto I = Result->find(Foo);
960a48d1083SLang Hames     EXPECT_NE(I, Result->end()) << "Could not find symbol definition";
96158ba7812SLang Hames     EXPECT_EQ(I->second.getAddress(), FooSym.getAddress())
9629510447aSLang Hames         << "Resolution returned incorrect result";
963d4a8089fSLang Hames     OnCompletionRun = true;
9649510447aSLang Hames   };
9659510447aSLang Hames 
966674df13bSLang Hames   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
967674df13bSLang Hames             SymbolLookupSet(Foo), SymbolState::Ready, std::move(OnCompletion),
968674df13bSLang Hames             NoDependenciesToRegister);
9699510447aSLang Hames 
9709510447aSLang Hames   EXPECT_TRUE(FooMaterialized) << "Foo was not materialized";
9719510447aSLang Hames   EXPECT_TRUE(BarDiscarded) << "Bar was not discarded";
972d4a8089fSLang Hames   EXPECT_TRUE(OnCompletionRun) << "OnResolutionCallback was not run";
9739510447aSLang Hames }
9749510447aSLang Hames 
TEST_F(CoreAPIsStandardTest,TestBasicWeakSymbolMaterialization)9756cadc7c0SLang Hames TEST_F(CoreAPIsStandardTest, TestBasicWeakSymbolMaterialization) {
9766cadc7c0SLang Hames   // Test that weak symbols are materialized correctly when we look them up.
9776a2a889bSLang Hames   BarSym.setFlags(BarSym.getFlags() | JITSymbolFlags::Weak);
9786cadc7c0SLang Hames 
9796cadc7c0SLang Hames   bool BarMaterialized = false;
9800eaee545SJonas Devlieghere   auto MU1 = std::make_unique<SimpleMaterializationUnit>(
9816cadc7c0SLang Hames       SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}),
9827dcd0042SLang Hames       [&](std::unique_ptr<MaterializationResponsibility> R) {
9837dcd0042SLang Hames         cantFail(R->notifyResolved(SymbolMap({{Foo, FooSym}, {Bar, BarSym}})));
9847dcd0042SLang Hames         cantFail(R->notifyEmitted());
9856cadc7c0SLang Hames         BarMaterialized = true;
9866cadc7c0SLang Hames       });
9876cadc7c0SLang Hames 
9886cadc7c0SLang Hames   bool DuplicateBarDiscarded = false;
9890eaee545SJonas Devlieghere   auto MU2 = std::make_unique<SimpleMaterializationUnit>(
9906cadc7c0SLang Hames       SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
9917dcd0042SLang Hames       [&](std::unique_ptr<MaterializationResponsibility> R) {
9926cadc7c0SLang Hames         ADD_FAILURE() << "Attempt to materialize Bar from the wrong unit";
9937dcd0042SLang Hames         R->failMaterialization();
9946cadc7c0SLang Hames       },
99585fb9976SLang Hames       nullptr,
9966cadc7c0SLang Hames       [&](const JITDylib &JD, SymbolStringPtr Name) {
9976cadc7c0SLang Hames         EXPECT_EQ(Name, Bar) << "Expected \"Bar\" to be discarded";
9986cadc7c0SLang Hames         DuplicateBarDiscarded = true;
9996cadc7c0SLang Hames       });
10006cadc7c0SLang Hames 
10016cadc7c0SLang Hames   cantFail(JD.define(MU1));
10026cadc7c0SLang Hames   cantFail(JD.define(MU2));
10036cadc7c0SLang Hames 
1004d4a8089fSLang Hames   bool OnCompletionRun = false;
10056cadc7c0SLang Hames 
1006d4a8089fSLang Hames   auto OnCompletion = [&](Expected<SymbolMap> Result) {
10076cadc7c0SLang Hames     cantFail(std::move(Result));
1008d4a8089fSLang Hames     OnCompletionRun = true;
10096cadc7c0SLang Hames   };
10106cadc7c0SLang Hames 
1011674df13bSLang Hames   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
1012674df13bSLang Hames             SymbolLookupSet(Bar), SymbolState::Ready, std::move(OnCompletion),
1013674df13bSLang Hames             NoDependenciesToRegister);
10146cadc7c0SLang Hames 
1015d4a8089fSLang Hames   EXPECT_TRUE(OnCompletionRun) << "OnCompletion not run";
10166cadc7c0SLang Hames   EXPECT_TRUE(BarMaterialized) << "Bar was not materialized at all";
10176cadc7c0SLang Hames   EXPECT_TRUE(DuplicateBarDiscarded)
10186cadc7c0SLang Hames       << "Duplicate bar definition not discarded";
10196cadc7c0SLang Hames }
10206cadc7c0SLang Hames 
TEST_F(CoreAPIsStandardTest,DefineMaterializingSymbol)102158ba7812SLang Hames TEST_F(CoreAPIsStandardTest, DefineMaterializingSymbol) {
1022d261e125SLang Hames   bool ExpectNoMoreMaterialization = false;
10237f9a89f9SLang Hames   ES.setDispatchTask([&](std::unique_ptr<Task> T) {
10247f9a89f9SLang Hames     if (ExpectNoMoreMaterialization && isa<MaterializationTask>(*T))
1025d261e125SLang Hames       ADD_FAILURE() << "Unexpected materialization";
10265344c88dSLang Hames     T->run();
1027d261e125SLang Hames   });
1028d261e125SLang Hames 
10290eaee545SJonas Devlieghere   auto MU = std::make_unique<SimpleMaterializationUnit>(
1030d261e125SLang Hames       SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
10317dcd0042SLang Hames       [&](std::unique_ptr<MaterializationResponsibility> R) {
1032d261e125SLang Hames         cantFail(
10337dcd0042SLang Hames             R->defineMaterializing(SymbolFlagsMap({{Bar, BarSym.getFlags()}})));
10347dcd0042SLang Hames         cantFail(R->notifyResolved(SymbolMap({{Foo, FooSym}, {Bar, BarSym}})));
10357dcd0042SLang Hames         cantFail(R->notifyEmitted());
1036d261e125SLang Hames       });
1037d261e125SLang Hames 
1038d5f56c59SLang Hames   cantFail(JD.define(MU));
1039674df13bSLang Hames   cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Foo));
1040d261e125SLang Hames 
104158ba7812SLang Hames   // Assert that materialization is complete by now.
1042d261e125SLang Hames   ExpectNoMoreMaterialization = true;
1043d261e125SLang Hames 
104458ba7812SLang Hames   // Look up bar to verify that no further materialization happens.
1045674df13bSLang Hames   auto BarResult = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Bar));
104658ba7812SLang Hames   EXPECT_EQ(BarResult.getAddress(), BarSym.getAddress())
104758ba7812SLang Hames       << "Expected Bar == BarSym";
1048d261e125SLang Hames }
1049d261e125SLang Hames 
TEST_F(CoreAPIsStandardTest,GeneratorTest)1050a5157d6fSLang Hames TEST_F(CoreAPIsStandardTest, GeneratorTest) {
1051069919c9SLang Hames   JITEvaluatedSymbol BazHiddenSym(
1052069919c9SLang Hames       BazSym.getAddress(), BazSym.getFlags() & ~JITSymbolFlags::Exported);
1053069919c9SLang Hames   cantFail(JD.define(absoluteSymbols({{Foo, FooSym}, {Baz, BazHiddenSym}})));
10542aae2581SLang Hames 
10555d2e359cSLang Hames   class TestGenerator : public DefinitionGenerator {
105652a34a78SLang Hames   public:
105752a34a78SLang Hames     TestGenerator(SymbolMap Symbols) : Symbols(std::move(Symbols)) {}
1058069919c9SLang Hames     Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD,
1059674df13bSLang Hames                         JITDylibLookupFlags JDLookupFlags,
106031eb8349SLogan Smith                         const SymbolLookupSet &Names) override {
106152a34a78SLang Hames       SymbolMap NewDefs;
106252a34a78SLang Hames 
1063674df13bSLang Hames       for (const auto &KV : Names) {
1064674df13bSLang Hames         const auto &Name = KV.first;
1065674df13bSLang Hames         if (Symbols.count(Name))
106652a34a78SLang Hames           NewDefs[Name] = Symbols[Name];
106752a34a78SLang Hames       }
1068674df13bSLang Hames 
106952a34a78SLang Hames       cantFail(JD.define(absoluteSymbols(std::move(NewDefs))));
1070674df13bSLang Hames       return Error::success();
107152a34a78SLang Hames     };
107252a34a78SLang Hames 
107352a34a78SLang Hames   private:
107452a34a78SLang Hames     SymbolMap Symbols;
107552a34a78SLang Hames   };
107652a34a78SLang Hames 
1077069919c9SLang Hames   JD.addGenerator(std::make_unique<TestGenerator>(
1078069919c9SLang Hames       SymbolMap({{Bar, BarSym}, {Baz, BazSym}})));
10792aae2581SLang Hames 
1080674df13bSLang Hames   auto Result = cantFail(
1081069919c9SLang Hames       ES.lookup(makeJITDylibSearchOrder(&JD),
1082069919c9SLang Hames                 SymbolLookupSet({Foo, Bar})
1083069919c9SLang Hames                     .add(Baz, SymbolLookupFlags::WeaklyReferencedSymbol)));
10842aae2581SLang Hames 
10852aae2581SLang Hames   EXPECT_EQ(Result.count(Bar), 1U) << "Expected to find fallback def for 'bar'";
108658ba7812SLang Hames   EXPECT_EQ(Result[Bar].getAddress(), BarSym.getAddress())
108758ba7812SLang Hames       << "Expected fallback def for Bar to be equal to BarSym";
10882aae2581SLang Hames }
10892aae2581SLang Hames 
TEST_F(CoreAPIsStandardTest,AsynchronousGeneratorTest)1090cd8a80deSLang Hames TEST_F(CoreAPIsStandardTest, AsynchronousGeneratorTest) {
1091cd8a80deSLang Hames   class TestGenerator : public DefinitionGenerator {
1092cd8a80deSLang Hames   public:
1093cd8a80deSLang Hames     TestGenerator(LookupState &TLS) : TLS(TLS) {}
1094cd8a80deSLang Hames     Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD,
1095cd8a80deSLang Hames                         JITDylibLookupFlags JDLookupFlags,
1096cd8a80deSLang Hames                         const SymbolLookupSet &Name) override {
1097cd8a80deSLang Hames       TLS = std::move(LS);
1098cd8a80deSLang Hames       return Error::success();
1099cd8a80deSLang Hames     }
1100cd8a80deSLang Hames 
1101cd8a80deSLang Hames   private:
1102cd8a80deSLang Hames     LookupState &TLS;
1103cd8a80deSLang Hames   };
1104cd8a80deSLang Hames 
1105cd8a80deSLang Hames   LookupState LS;
1106cd8a80deSLang Hames   JD.addGenerator(std::make_unique<TestGenerator>(LS));
1107cd8a80deSLang Hames 
1108cd8a80deSLang Hames   bool LookupCompleted = false;
1109cd8a80deSLang Hames 
1110cd8a80deSLang Hames   ES.lookup(
1111cd8a80deSLang Hames       LookupKind::Static, makeJITDylibSearchOrder(&JD), SymbolLookupSet(Foo),
1112cd8a80deSLang Hames       SymbolState::Ready,
1113cd8a80deSLang Hames       [&](Expected<SymbolMap> Result) {
1114cd8a80deSLang Hames         LookupCompleted = true;
1115cd8a80deSLang Hames         if (!Result) {
1116cd8a80deSLang Hames           ADD_FAILURE() << "Lookup failed unexpected";
1117cd8a80deSLang Hames           logAllUnhandledErrors(Result.takeError(), errs(), "");
1118cd8a80deSLang Hames           return;
1119cd8a80deSLang Hames         }
1120cd8a80deSLang Hames 
1121cd8a80deSLang Hames         EXPECT_EQ(Result->size(), 1U) << "Unexpected number of results";
1122cd8a80deSLang Hames         EXPECT_EQ(Result->count(Foo), 1U) << "Expected result for Foo";
1123cd8a80deSLang Hames         EXPECT_EQ((*Result)[Foo].getAddress(), FooSym.getAddress())
1124cd8a80deSLang Hames             << "Bad result for Foo";
1125cd8a80deSLang Hames       },
1126cd8a80deSLang Hames       NoDependenciesToRegister);
1127cd8a80deSLang Hames 
1128cd8a80deSLang Hames   EXPECT_FALSE(LookupCompleted);
1129cd8a80deSLang Hames 
1130cd8a80deSLang Hames   cantFail(JD.define(absoluteSymbols({{Foo, FooSym}})));
1131cd8a80deSLang Hames 
1132cd8a80deSLang Hames   LS.continueLookup(Error::success());
1133cd8a80deSLang Hames 
1134cd8a80deSLang Hames   EXPECT_TRUE(LookupCompleted);
1135cd8a80deSLang Hames }
1136cd8a80deSLang Hames 
TEST_F(CoreAPIsStandardTest,FailResolution)113758ba7812SLang Hames TEST_F(CoreAPIsStandardTest, FailResolution) {
11380eaee545SJonas Devlieghere   auto MU = std::make_unique<SimpleMaterializationUnit>(
11397899ccbcSLang Hames       SymbolFlagsMap({{Foo, JITSymbolFlags::Exported | JITSymbolFlags::Weak},
11407899ccbcSLang Hames                       {Bar, JITSymbolFlags::Exported | JITSymbolFlags::Weak}}),
11417dcd0042SLang Hames       [&](std::unique_ptr<MaterializationResponsibility> R) {
11427dcd0042SLang Hames         R->failMaterialization();
1143d4a8089fSLang Hames       });
11449d8877baSLang Hames 
1145d5f56c59SLang Hames   cantFail(JD.define(MU));
11469d8877baSLang Hames 
114758ba7812SLang Hames   SymbolNameSet Names({Foo, Bar});
1148674df13bSLang Hames   auto Result = ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet(Names));
114958ba7812SLang Hames 
115058ba7812SLang Hames   EXPECT_FALSE(!!Result) << "Expected failure";
115158ba7812SLang Hames   if (!Result) {
1152e00585c7SLang Hames     handleAllErrors(
1153e00585c7SLang Hames         Result.takeError(),
1154ecb3e500SLang Hames         [&](FailedToMaterialize &F) {
1155e00585c7SLang Hames           EXPECT_TRUE(F.getSymbols().count(&JD))
1156e00585c7SLang Hames               << "Expected to fail on JITDylib JD";
1157e00585c7SLang Hames           EXPECT_EQ(F.getSymbols().find(&JD)->second, Names)
11589d8877baSLang Hames               << "Expected to fail on symbols in Names";
11599d8877baSLang Hames         },
11609d8877baSLang Hames         [](ErrorInfoBase &EIB) {
11619d8877baSLang Hames           std::string ErrMsg;
11629d8877baSLang Hames           {
11639d8877baSLang Hames             raw_string_ostream ErrOut(ErrMsg);
11649d8877baSLang Hames             EIB.log(ErrOut);
11659d8877baSLang Hames           }
1166e00585c7SLang Hames           ADD_FAILURE() << "Expected a FailedToResolve error. Got:\n" << ErrMsg;
11679d8877baSLang Hames         });
116858ba7812SLang Hames   }
11699d8877baSLang Hames }
11709d8877baSLang Hames 
TEST_F(CoreAPIsStandardTest,FailEmissionAfterResolution)11717371fb42SLang Hames TEST_F(CoreAPIsStandardTest, FailEmissionAfterResolution) {
11724f71049aSLang Hames 
11734f71049aSLang Hames   cantFail(JD.define(absoluteSymbols({{Baz, BazSym}})));
11744f71049aSLang Hames 
11750eaee545SJonas Devlieghere   auto MU = std::make_unique<SimpleMaterializationUnit>(
11764f71049aSLang Hames       SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}),
11777dcd0042SLang Hames       [&](std::unique_ptr<MaterializationResponsibility> R) {
11787dcd0042SLang Hames         cantFail(R->notifyResolved(SymbolMap({{Foo, FooSym}, {Bar, BarSym}})));
11794f71049aSLang Hames 
11804f71049aSLang Hames         ES.lookup(
1181674df13bSLang Hames             LookupKind::Static, makeJITDylibSearchOrder(&JD),
1182674df13bSLang Hames             SymbolLookupSet({Baz}), SymbolState::Resolved,
11837dcd0042SLang Hames             [&](Expected<SymbolMap> Result) {
11844f71049aSLang Hames               // Called when "baz" is resolved. We don't actually depend
11854f71049aSLang Hames               // on or care about baz, but use it to trigger failure of
11864f71049aSLang Hames               // this materialization before Baz has been finalized in
11874f71049aSLang Hames               // order to test that error propagation is correct in this
11884f71049aSLang Hames               // scenario.
11894f71049aSLang Hames               cantFail(std::move(Result));
11907dcd0042SLang Hames               R->failMaterialization();
11914f71049aSLang Hames             },
11924f71049aSLang Hames             [&](const SymbolDependenceMap &Deps) {
11937dcd0042SLang Hames               R->addDependenciesForAll(Deps);
11944f71049aSLang Hames             });
11954f71049aSLang Hames       });
11964f71049aSLang Hames 
11974f71049aSLang Hames   cantFail(JD.define(MU));
11984f71049aSLang Hames 
1199674df13bSLang Hames   auto Result =
1200674df13bSLang Hames       ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Foo, Bar}));
12014f71049aSLang Hames 
12024f71049aSLang Hames   EXPECT_THAT_EXPECTED(std::move(Result), Failed())
12034f71049aSLang Hames       << "Unexpected success while trying to test error propagation";
12044f71049aSLang Hames }
12054f71049aSLang Hames 
TEST_F(CoreAPIsStandardTest,FailAfterPartialResolution)12067371fb42SLang Hames TEST_F(CoreAPIsStandardTest, FailAfterPartialResolution) {
12077371fb42SLang Hames 
12087371fb42SLang Hames   cantFail(JD.define(absoluteSymbols({{Foo, FooSym}})));
12097371fb42SLang Hames 
12107371fb42SLang Hames   // Fail materialization of bar.
12117371fb42SLang Hames   auto BarMU = std::make_unique<SimpleMaterializationUnit>(
12127371fb42SLang Hames       SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
12137dcd0042SLang Hames       [&](std::unique_ptr<MaterializationResponsibility> R) {
12147dcd0042SLang Hames         R->failMaterialization();
12157dcd0042SLang Hames       });
12167371fb42SLang Hames 
12177371fb42SLang Hames   cantFail(JD.define(std::move(BarMU)));
12187371fb42SLang Hames 
12197371fb42SLang Hames   bool QueryHandlerRun = false;
12207371fb42SLang Hames   ES.lookup(
1221674df13bSLang Hames       LookupKind::Static, makeJITDylibSearchOrder(&JD),
1222674df13bSLang Hames       SymbolLookupSet({Foo, Bar}), SymbolState::Resolved,
12237371fb42SLang Hames       [&](Expected<SymbolMap> Result) {
12247371fb42SLang Hames         EXPECT_THAT_EXPECTED(std::move(Result), Failed())
12257371fb42SLang Hames             << "Expected query to fail";
12267371fb42SLang Hames         QueryHandlerRun = true;
12277371fb42SLang Hames       },
12287371fb42SLang Hames       NoDependenciesToRegister);
12297371fb42SLang Hames   EXPECT_TRUE(QueryHandlerRun) << "Query handler never ran";
12307371fb42SLang Hames }
12317371fb42SLang Hames 
TEST_F(CoreAPIsStandardTest,TestLookupWithUnthreadedMaterialization)123258ba7812SLang Hames TEST_F(CoreAPIsStandardTest, TestLookupWithUnthreadedMaterialization) {
12330eaee545SJonas Devlieghere   auto MU = std::make_unique<SimpleMaterializationUnit>(
1234d261e125SLang Hames       SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}}),
12357dcd0042SLang Hames       [&](std::unique_ptr<MaterializationResponsibility> R) {
12367dcd0042SLang Hames         cantFail(R->notifyResolved({{Foo, FooSym}}));
12377dcd0042SLang Hames         cantFail(R->notifyEmitted());
1238817f1f64SLang Hames       });
1239817f1f64SLang Hames 
1240d5f56c59SLang Hames   cantFail(JD.define(MU));
1241817f1f64SLang Hames 
1242674df13bSLang Hames   auto FooLookupResult = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Foo));
1243817f1f64SLang Hames 
1244817f1f64SLang Hames   EXPECT_EQ(FooLookupResult.getAddress(), FooSym.getAddress())
1245817f1f64SLang Hames       << "lookup returned an incorrect address";
1246817f1f64SLang Hames   EXPECT_EQ(FooLookupResult.getFlags(), FooSym.getFlags())
1247817f1f64SLang Hames       << "lookup returned incorrect flags";
1248817f1f64SLang Hames }
1249817f1f64SLang Hames 
TEST_F(CoreAPIsStandardTest,TestLookupWithThreadedMaterialization)125058ba7812SLang Hames TEST_F(CoreAPIsStandardTest, TestLookupWithThreadedMaterialization) {
1251817f1f64SLang Hames #if LLVM_ENABLE_THREADS
1252817f1f64SLang Hames 
1253fda4300dSLang Hames   std::mutex WorkThreadsMutex;
12547f9a89f9SLang Hames   std::vector<std::thread> WorkThreads;
12557f9a89f9SLang Hames   ES.setDispatchTask([&](std::unique_ptr<Task> T) {
12561a1d6e6fSLang Hames     std::promise<void> WaitP;
1257fda4300dSLang Hames     std::lock_guard<std::mutex> Lock(WorkThreadsMutex);
12587f9a89f9SLang Hames     WorkThreads.push_back(
12591a1d6e6fSLang Hames         std::thread([T = std::move(T), WaitF = WaitP.get_future()]() mutable {
12601a1d6e6fSLang Hames           WaitF.get();
12611a1d6e6fSLang Hames           T->run();
12621a1d6e6fSLang Hames         }));
12631a1d6e6fSLang Hames     WaitP.set_value();
1264d261e125SLang Hames   });
1265817f1f64SLang Hames 
1266d5f56c59SLang Hames   cantFail(JD.define(absoluteSymbols({{Foo, FooSym}})));
1267d261e125SLang Hames 
1268674df13bSLang Hames   auto FooLookupResult = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Foo));
1269817f1f64SLang Hames 
1270817f1f64SLang Hames   EXPECT_EQ(FooLookupResult.getAddress(), FooSym.getAddress())
1271817f1f64SLang Hames       << "lookup returned an incorrect address";
1272817f1f64SLang Hames   EXPECT_EQ(FooLookupResult.getFlags(), FooSym.getFlags())
1273817f1f64SLang Hames       << "lookup returned incorrect flags";
12747f9a89f9SLang Hames 
12757f9a89f9SLang Hames   for (auto &WT : WorkThreads)
12767f9a89f9SLang Hames     WT.join();
1277817f1f64SLang Hames #endif
1278817f1f64SLang Hames }
1279817f1f64SLang Hames 
TEST_F(CoreAPIsStandardTest,TestGetRequestedSymbolsAndReplace)128058ba7812SLang Hames TEST_F(CoreAPIsStandardTest, TestGetRequestedSymbolsAndReplace) {
128158ba7812SLang Hames   // Test that GetRequestedSymbols returns the set of symbols that currently
128258ba7812SLang Hames   // have pending queries, and test that MaterializationResponsibility's
1283d5f56c59SLang Hames   // replace method can be used to return definitions to the JITDylib in a new
128458ba7812SLang Hames   // MaterializationUnit.
12856fe6616cSLang Hames   SymbolNameSet Names({Foo, Bar});
12866fe6616cSLang Hames 
12876fe6616cSLang Hames   bool FooMaterialized = false;
12886fe6616cSLang Hames   bool BarMaterialized = false;
12896fe6616cSLang Hames 
12900eaee545SJonas Devlieghere   auto MU = std::make_unique<SimpleMaterializationUnit>(
12916fe6616cSLang Hames       SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}),
12927dcd0042SLang Hames       [&](std::unique_ptr<MaterializationResponsibility> R) {
12937dcd0042SLang Hames         auto Requested = R->getRequestedSymbols();
12946fe6616cSLang Hames         EXPECT_EQ(Requested.size(), 1U) << "Expected one symbol requested";
12956fe6616cSLang Hames         EXPECT_EQ(*Requested.begin(), Foo) << "Expected \"Foo\" requested";
12966fe6616cSLang Hames 
12970eaee545SJonas Devlieghere         auto NewMU = std::make_unique<SimpleMaterializationUnit>(
12986fe6616cSLang Hames             SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
12997dcd0042SLang Hames             [&](std::unique_ptr<MaterializationResponsibility> R2) {
13007dcd0042SLang Hames               cantFail(R2->notifyResolved(SymbolMap({{Bar, BarSym}})));
13017dcd0042SLang Hames               cantFail(R2->notifyEmitted());
13026fe6616cSLang Hames               BarMaterialized = true;
13036fe6616cSLang Hames             });
13046fe6616cSLang Hames 
13050aec49c8SLang Hames         cantFail(R->replace(std::move(NewMU)));
13066fe6616cSLang Hames 
13077dcd0042SLang Hames         cantFail(R->notifyResolved(SymbolMap({{Foo, FooSym}})));
13087dcd0042SLang Hames         cantFail(R->notifyEmitted());
13096fe6616cSLang Hames 
13106fe6616cSLang Hames         FooMaterialized = true;
13116fe6616cSLang Hames       });
13126fe6616cSLang Hames 
1313d5f56c59SLang Hames   cantFail(JD.define(MU));
13146fe6616cSLang Hames 
13156fe6616cSLang Hames   EXPECT_FALSE(FooMaterialized) << "Foo should not be materialized yet";
13166fe6616cSLang Hames   EXPECT_FALSE(BarMaterialized) << "Bar should not be materialized yet";
13176fe6616cSLang Hames 
1318674df13bSLang Hames   auto FooSymResult = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Foo));
13196fe6616cSLang Hames   EXPECT_EQ(FooSymResult.getAddress(), FooSym.getAddress())
13206fe6616cSLang Hames       << "Address mismatch for Foo";
13216fe6616cSLang Hames 
13226fe6616cSLang Hames   EXPECT_TRUE(FooMaterialized) << "Foo should be materialized now";
13236fe6616cSLang Hames   EXPECT_FALSE(BarMaterialized) << "Bar still should not be materialized";
13246fe6616cSLang Hames 
1325674df13bSLang Hames   auto BarSymResult = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Bar));
13266fe6616cSLang Hames   EXPECT_EQ(BarSymResult.getAddress(), BarSym.getAddress())
13276fe6616cSLang Hames       << "Address mismatch for Bar";
13286fe6616cSLang Hames   EXPECT_TRUE(BarMaterialized) << "Bar should be materialized now";
13296fe6616cSLang Hames }
13306fe6616cSLang Hames 
TEST_F(CoreAPIsStandardTest,TestMaterializationResponsibilityDelegation)133158ba7812SLang Hames TEST_F(CoreAPIsStandardTest, TestMaterializationResponsibilityDelegation) {
13320eaee545SJonas Devlieghere   auto MU = std::make_unique<SimpleMaterializationUnit>(
1333f07dad3dSLang Hames       SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}),
13347dcd0042SLang Hames       [&](std::unique_ptr<MaterializationResponsibility> R) {
13350aec49c8SLang Hames         auto R2 = cantFail(R->delegate({Bar}));
1336f07dad3dSLang Hames 
13377dcd0042SLang Hames         cantFail(R->notifyResolved({{Foo, FooSym}}));
13387dcd0042SLang Hames         cantFail(R->notifyEmitted());
13397dcd0042SLang Hames         cantFail(R2->notifyResolved({{Bar, BarSym}}));
13407dcd0042SLang Hames         cantFail(R2->notifyEmitted());
1341f07dad3dSLang Hames       });
1342f07dad3dSLang Hames 
1343d5f56c59SLang Hames   cantFail(JD.define(MU));
1344f07dad3dSLang Hames 
1345674df13bSLang Hames   auto Result =
1346674df13bSLang Hames       ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Foo, Bar}));
1347f07dad3dSLang Hames 
1348f07dad3dSLang Hames   EXPECT_TRUE(!!Result) << "Result should be a success value";
1349f07dad3dSLang Hames   EXPECT_EQ(Result->count(Foo), 1U) << "\"Foo\" entry missing";
1350f07dad3dSLang Hames   EXPECT_EQ(Result->count(Bar), 1U) << "\"Bar\" entry missing";
1351f07dad3dSLang Hames   EXPECT_EQ((*Result)[Foo].getAddress(), FooSym.getAddress())
1352f07dad3dSLang Hames       << "Address mismatch for \"Foo\"";
1353f07dad3dSLang Hames   EXPECT_EQ((*Result)[Bar].getAddress(), BarSym.getAddress())
1354f07dad3dSLang Hames       << "Address mismatch for \"Bar\"";
1355f07dad3dSLang Hames }
1356f07dad3dSLang Hames 
TEST_F(CoreAPIsStandardTest,TestMaterializeWeakSymbol)135758ba7812SLang Hames TEST_F(CoreAPIsStandardTest, TestMaterializeWeakSymbol) {
13585d6c5099SLang Hames   // Confirm that once a weak definition is selected for materialization it is
13595d6c5099SLang Hames   // treated as strong.
136058ba7812SLang Hames   JITSymbolFlags WeakExported = JITSymbolFlags::Exported;
136158ba7812SLang Hames   WeakExported &= JITSymbolFlags::Weak;
13625d6c5099SLang Hames 
13637dcd0042SLang Hames   std::unique_ptr<MaterializationResponsibility> FooR;
13640eaee545SJonas Devlieghere   auto MU = std::make_unique<SimpleMaterializationUnit>(
136558ba7812SLang Hames       SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
13667dcd0042SLang Hames       [&](std::unique_ptr<MaterializationResponsibility> R) {
13677dcd0042SLang Hames         FooR = std::move(R);
13685d6c5099SLang Hames       });
13695d6c5099SLang Hames 
1370d5f56c59SLang Hames   cantFail(JD.define(MU));
1371d4a8089fSLang Hames   auto OnCompletion = [](Expected<SymbolMap> Result) {
1372a48d1083SLang Hames     cantFail(std::move(Result));
1373a48d1083SLang Hames   };
1374a48d1083SLang Hames 
1375674df13bSLang Hames   ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
1376674df13bSLang Hames             SymbolLookupSet({Foo}), SymbolState::Ready, std::move(OnCompletion),
1377674df13bSLang Hames             NoDependenciesToRegister);
13785d6c5099SLang Hames 
13790eaee545SJonas Devlieghere   auto MU2 = std::make_unique<SimpleMaterializationUnit>(
13805d6c5099SLang Hames       SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}}),
13817dcd0042SLang Hames       [](std::unique_ptr<MaterializationResponsibility> R) {
13825d6c5099SLang Hames         llvm_unreachable("This unit should never be materialized");
13835d6c5099SLang Hames       });
13845d6c5099SLang Hames 
1385d5f56c59SLang Hames   auto Err = JD.define(MU2);
13865d6c5099SLang Hames   EXPECT_TRUE(!!Err) << "Expected failure value";
13875d6c5099SLang Hames   EXPECT_TRUE(Err.isA<DuplicateDefinition>())
13885d6c5099SLang Hames       << "Expected a duplicate definition error";
13895d6c5099SLang Hames   consumeError(std::move(Err));
13905d6c5099SLang Hames 
1391e00585c7SLang Hames   // No dependencies registered, can't fail:
13927dcd0042SLang Hames   cantFail(FooR->notifyResolved(SymbolMap({{Foo, FooSym}})));
13937dcd0042SLang Hames   cantFail(FooR->notifyEmitted());
13945d6c5099SLang Hames }
13955d6c5099SLang Hames 
linkOrdersEqual(const std::vector<JITDylibSP> & LHS,ArrayRef<JITDylib * > RHS)13960aec49c8SLang Hames static bool linkOrdersEqual(const std::vector<JITDylibSP> &LHS,
1397e1d5f7d0SLang Hames                             ArrayRef<JITDylib *> RHS) {
1398e1d5f7d0SLang Hames   if (LHS.size() != RHS.size())
1399e1d5f7d0SLang Hames     return false;
1400e1d5f7d0SLang Hames   auto *RHSE = RHS.begin();
1401e1d5f7d0SLang Hames   for (auto &LHSE : LHS)
1402e1d5f7d0SLang Hames     if (LHSE.get() != *RHSE)
1403e1d5f7d0SLang Hames       return false;
1404e1d5f7d0SLang Hames     else
1405e1d5f7d0SLang Hames       ++RHSE;
1406e1d5f7d0SLang Hames   return true;
1407b16ac944SMartin Storsjö }
1408e1d5f7d0SLang Hames 
TEST(JITDylibTest,GetDFSLinkOrderTree)1409e1d5f7d0SLang Hames TEST(JITDylibTest, GetDFSLinkOrderTree) {
1410e1d5f7d0SLang Hames   // Test that DFS ordering behaves as expected when the linkage relationships
1411e1d5f7d0SLang Hames   // form a tree.
1412e1d5f7d0SLang Hames 
14132487db1fSLang Hames   ExecutionSession ES{std::make_unique<UnsupportedExecutorProcessControl>()};
1414f3428dafSLang Hames   auto _ = make_scope_exit([&]() { cantFail(ES.endSession()); });
1415e1d5f7d0SLang Hames 
1416e1d5f7d0SLang Hames   auto &LibA = ES.createBareJITDylib("A");
1417e1d5f7d0SLang Hames   auto &LibB = ES.createBareJITDylib("B");
1418e1d5f7d0SLang Hames   auto &LibC = ES.createBareJITDylib("C");
1419e1d5f7d0SLang Hames   auto &LibD = ES.createBareJITDylib("D");
1420e1d5f7d0SLang Hames   auto &LibE = ES.createBareJITDylib("E");
1421e1d5f7d0SLang Hames   auto &LibF = ES.createBareJITDylib("F");
1422e1d5f7d0SLang Hames 
1423e1d5f7d0SLang Hames   // Linkage relationships:
1424e1d5f7d0SLang Hames   // A --- B -- D
1425e1d5f7d0SLang Hames   //  \      \- E
1426e1d5f7d0SLang Hames   //    \- C -- F
1427e1d5f7d0SLang Hames   LibA.setLinkOrder(makeJITDylibSearchOrder({&LibB, &LibC}));
1428e1d5f7d0SLang Hames   LibB.setLinkOrder(makeJITDylibSearchOrder({&LibD, &LibE}));
1429e1d5f7d0SLang Hames   LibC.setLinkOrder(makeJITDylibSearchOrder({&LibF}));
1430e1d5f7d0SLang Hames 
14319eb4939bSLang Hames   auto DFSOrderFromB = cantFail(JITDylib::getDFSLinkOrder({&LibB}));
1432e1d5f7d0SLang Hames   EXPECT_TRUE(linkOrdersEqual(DFSOrderFromB, {&LibB, &LibD, &LibE}))
1433e1d5f7d0SLang Hames       << "Incorrect DFS link order for LibB";
1434e1d5f7d0SLang Hames 
14359eb4939bSLang Hames   auto DFSOrderFromA = cantFail(JITDylib::getDFSLinkOrder({&LibA}));
1436e1d5f7d0SLang Hames   EXPECT_TRUE(linkOrdersEqual(DFSOrderFromA,
1437e1d5f7d0SLang Hames                               {&LibA, &LibB, &LibD, &LibE, &LibC, &LibF}))
1438e1d5f7d0SLang Hames       << "Incorrect DFS link order for libA";
1439e1d5f7d0SLang Hames 
14409eb4939bSLang Hames   auto DFSOrderFromAB = cantFail(JITDylib::getDFSLinkOrder({&LibA, &LibB}));
1441e1d5f7d0SLang Hames   EXPECT_TRUE(linkOrdersEqual(DFSOrderFromAB,
1442e1d5f7d0SLang Hames                               {&LibA, &LibB, &LibD, &LibE, &LibC, &LibF}))
1443e1d5f7d0SLang Hames       << "Incorrect DFS link order for { libA, libB }";
1444e1d5f7d0SLang Hames 
14459eb4939bSLang Hames   auto DFSOrderFromBA = cantFail(JITDylib::getDFSLinkOrder({&LibB, &LibA}));
1446e1d5f7d0SLang Hames   EXPECT_TRUE(linkOrdersEqual(DFSOrderFromBA,
1447e1d5f7d0SLang Hames                               {&LibB, &LibD, &LibE, &LibA, &LibC, &LibF}))
1448e1d5f7d0SLang Hames       << "Incorrect DFS link order for { libB, libA }";
1449e1d5f7d0SLang Hames }
1450e1d5f7d0SLang Hames 
TEST(JITDylibTest,GetDFSLinkOrderDiamond)1451e1d5f7d0SLang Hames TEST(JITDylibTest, GetDFSLinkOrderDiamond) {
1452e1d5f7d0SLang Hames   // Test that DFS ordering behaves as expected when the linkage relationships
1453e1d5f7d0SLang Hames   // contain a diamond.
1454e1d5f7d0SLang Hames 
14552487db1fSLang Hames   ExecutionSession ES{std::make_unique<UnsupportedExecutorProcessControl>()};
1456f3428dafSLang Hames   auto _ = make_scope_exit([&]() { cantFail(ES.endSession()); });
1457f3428dafSLang Hames 
1458e1d5f7d0SLang Hames   auto &LibA = ES.createBareJITDylib("A");
1459e1d5f7d0SLang Hames   auto &LibB = ES.createBareJITDylib("B");
1460e1d5f7d0SLang Hames   auto &LibC = ES.createBareJITDylib("C");
1461e1d5f7d0SLang Hames   auto &LibD = ES.createBareJITDylib("D");
1462e1d5f7d0SLang Hames 
1463e1d5f7d0SLang Hames   // Linkage relationships:
1464e1d5f7d0SLang Hames   // A -- B --- D
1465e1d5f7d0SLang Hames   //  \-- C --/
1466e1d5f7d0SLang Hames   LibA.setLinkOrder(makeJITDylibSearchOrder({&LibB, &LibC}));
1467e1d5f7d0SLang Hames   LibB.setLinkOrder(makeJITDylibSearchOrder({&LibD}));
1468e1d5f7d0SLang Hames   LibC.setLinkOrder(makeJITDylibSearchOrder({&LibD}));
1469e1d5f7d0SLang Hames 
14709eb4939bSLang Hames   auto DFSOrderFromA = cantFail(JITDylib::getDFSLinkOrder({&LibA}));
1471e1d5f7d0SLang Hames   EXPECT_TRUE(linkOrdersEqual(DFSOrderFromA, {&LibA, &LibB, &LibD, &LibC}))
1472e1d5f7d0SLang Hames       << "Incorrect DFS link order for libA";
1473e1d5f7d0SLang Hames }
1474e1d5f7d0SLang Hames 
TEST(JITDylibTest,GetDFSLinkOrderCycle)1475e1d5f7d0SLang Hames TEST(JITDylibTest, GetDFSLinkOrderCycle) {
1476e1d5f7d0SLang Hames   // Test that DFS ordering behaves as expected when the linkage relationships
1477e1d5f7d0SLang Hames   // contain a cycle.
1478e1d5f7d0SLang Hames 
14792487db1fSLang Hames   ExecutionSession ES{std::make_unique<UnsupportedExecutorProcessControl>()};
1480f3428dafSLang Hames   auto _ = make_scope_exit([&]() { cantFail(ES.endSession()); });
1481f3428dafSLang Hames 
1482e1d5f7d0SLang Hames   auto &LibA = ES.createBareJITDylib("A");
1483e1d5f7d0SLang Hames   auto &LibB = ES.createBareJITDylib("B");
1484e1d5f7d0SLang Hames   auto &LibC = ES.createBareJITDylib("C");
1485e1d5f7d0SLang Hames 
1486e1d5f7d0SLang Hames   // Linkage relationships:
1487e1d5f7d0SLang Hames   // A -- B --- C -- A
1488e1d5f7d0SLang Hames   LibA.setLinkOrder(makeJITDylibSearchOrder({&LibB}));
1489e1d5f7d0SLang Hames   LibB.setLinkOrder(makeJITDylibSearchOrder({&LibC}));
1490e1d5f7d0SLang Hames   LibC.setLinkOrder(makeJITDylibSearchOrder({&LibA}));
1491e1d5f7d0SLang Hames 
14929eb4939bSLang Hames   auto DFSOrderFromA = cantFail(JITDylib::getDFSLinkOrder({&LibA}));
1493e1d5f7d0SLang Hames   EXPECT_TRUE(linkOrdersEqual(DFSOrderFromA, {&LibA, &LibB, &LibC}))
1494e1d5f7d0SLang Hames       << "Incorrect DFS link order for libA";
1495e1d5f7d0SLang Hames 
14969eb4939bSLang Hames   auto DFSOrderFromB = cantFail(JITDylib::getDFSLinkOrder({&LibB}));
1497e1d5f7d0SLang Hames   EXPECT_TRUE(linkOrdersEqual(DFSOrderFromB, {&LibB, &LibC, &LibA}))
1498e1d5f7d0SLang Hames       << "Incorrect DFS link order for libB";
1499e1d5f7d0SLang Hames 
15009eb4939bSLang Hames   auto DFSOrderFromC = cantFail(JITDylib::getDFSLinkOrder({&LibC}));
1501e1d5f7d0SLang Hames   EXPECT_TRUE(linkOrdersEqual(DFSOrderFromC, {&LibC, &LibA, &LibB}))
1502e1d5f7d0SLang Hames       << "Incorrect DFS link order for libC";
1503e1d5f7d0SLang Hames }
1504e1d5f7d0SLang Hames 
TEST_F(CoreAPIsStandardTest,RemoveJITDylibs)1505758d54b4SLang Hames TEST_F(CoreAPIsStandardTest, RemoveJITDylibs) {
1506758d54b4SLang Hames   // Foo will be fully materialized.
1507758d54b4SLang Hames   cantFail(JD.define(absoluteSymbols({{Foo, FooSym}})));
1508758d54b4SLang Hames 
1509758d54b4SLang Hames   // Bar should not be materialized at all.
1510758d54b4SLang Hames   bool BarMaterializerDestroyed = false;
1511758d54b4SLang Hames   cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(
1512758d54b4SLang Hames       SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
1513758d54b4SLang Hames       [&](std::unique_ptr<MaterializationResponsibility> MR) {
1514758d54b4SLang Hames         llvm_unreachable("Unexpected call to materialize");
1515758d54b4SLang Hames       },
1516758d54b4SLang Hames       nullptr,
1517758d54b4SLang Hames       [](const JITDylib &, SymbolStringPtr Name) {
1518758d54b4SLang Hames         llvm_unreachable("Unexpected call to discard");
1519758d54b4SLang Hames       },
1520758d54b4SLang Hames       [&]() { BarMaterializerDestroyed = true; })));
1521758d54b4SLang Hames 
1522758d54b4SLang Hames   // Baz will be in the materializing state.
1523758d54b4SLang Hames   std::unique_ptr<MaterializationResponsibility> BazMR;
1524758d54b4SLang Hames   cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(
1525758d54b4SLang Hames       SymbolFlagsMap({{Baz, BazSym.getFlags()}}),
1526758d54b4SLang Hames       [&](std::unique_ptr<MaterializationResponsibility> MR) {
1527758d54b4SLang Hames         BazMR = std::move(MR);
1528758d54b4SLang Hames       })));
1529758d54b4SLang Hames 
1530758d54b4SLang Hames   // Lookup to force materialization of Foo.
1531905381dcSLang Hames   cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Foo})));
1532758d54b4SLang Hames 
1533758d54b4SLang Hames   // Start a lookup to force materialization of Baz.
1534758d54b4SLang Hames   bool BazLookupFailed = false;
1535758d54b4SLang Hames   ES.lookup(
1536758d54b4SLang Hames       LookupKind::Static, makeJITDylibSearchOrder(&JD), SymbolLookupSet({Baz}),
1537758d54b4SLang Hames       SymbolState::Ready,
1538758d54b4SLang Hames       [&](Expected<SymbolMap> Result) {
1539758d54b4SLang Hames         if (!Result) {
1540758d54b4SLang Hames           BazLookupFailed = true;
1541758d54b4SLang Hames           consumeError(Result.takeError());
1542758d54b4SLang Hames         }
1543758d54b4SLang Hames       },
1544758d54b4SLang Hames       NoDependenciesToRegister);
1545758d54b4SLang Hames 
1546758d54b4SLang Hames   // Remove the JITDylib.
1547758d54b4SLang Hames   auto Err = ES.removeJITDylib(JD);
1548758d54b4SLang Hames   EXPECT_THAT_ERROR(std::move(Err), Succeeded());
1549758d54b4SLang Hames 
1550758d54b4SLang Hames   EXPECT_TRUE(BarMaterializerDestroyed);
1551758d54b4SLang Hames   EXPECT_TRUE(BazLookupFailed);
1552758d54b4SLang Hames 
1553758d54b4SLang Hames   EXPECT_THAT_ERROR(BazMR->notifyResolved({{Baz, BazSym}}), Failed());
1554758d54b4SLang Hames 
15559eb4939bSLang Hames   EXPECT_THAT_EXPECTED(JD.getDFSLinkOrder(), Failed());
15569eb4939bSLang Hames 
1557758d54b4SLang Hames   BazMR->failMaterialization();
1558758d54b4SLang Hames }
1559758d54b4SLang Hames 
TEST(CoreAPIsExtraTest,SessionTeardownByFailedToMaterialize)1560*55e8f721SLang Hames TEST(CoreAPIsExtraTest, SessionTeardownByFailedToMaterialize) {
1561*55e8f721SLang Hames 
1562*55e8f721SLang Hames   auto RunTestCase = []() -> Error {
1563*55e8f721SLang Hames     ExecutionSession ES{std::make_unique<UnsupportedExecutorProcessControl>(
1564*55e8f721SLang Hames         std::make_shared<SymbolStringPool>())};
1565*55e8f721SLang Hames     auto Foo = ES.intern("foo");
1566*55e8f721SLang Hames     auto FooFlags = JITSymbolFlags::Exported;
1567*55e8f721SLang Hames 
1568*55e8f721SLang Hames     auto &JD = ES.createBareJITDylib("Foo");
1569*55e8f721SLang Hames     cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(
1570*55e8f721SLang Hames         SymbolFlagsMap({{Foo, FooFlags}}),
1571*55e8f721SLang Hames         [&](std::unique_ptr<MaterializationResponsibility> R) {
1572*55e8f721SLang Hames           R->failMaterialization();
1573*55e8f721SLang Hames         })));
1574*55e8f721SLang Hames 
1575*55e8f721SLang Hames     auto Sym = ES.lookup({&JD}, Foo);
1576*55e8f721SLang Hames     assert(!Sym && "Query should have failed");
1577*55e8f721SLang Hames     cantFail(ES.endSession());
1578*55e8f721SLang Hames     return Sym.takeError();
1579*55e8f721SLang Hames   };
1580*55e8f721SLang Hames 
1581*55e8f721SLang Hames   auto Err = RunTestCase();
1582*55e8f721SLang Hames   EXPECT_TRUE(!!Err); // Expect that error occurred.
1583*55e8f721SLang Hames   EXPECT_TRUE(
1584*55e8f721SLang Hames       Err.isA<FailedToMaterialize>()); // Expect FailedToMaterialize error.
1585*55e8f721SLang Hames 
1586*55e8f721SLang Hames   // Make sure that we can log errors, even though the session has been
1587*55e8f721SLang Hames   // destroyed.
1588*55e8f721SLang Hames   logAllUnhandledErrors(std::move(Err), nulls(), "");
1589*55e8f721SLang Hames }
1590*55e8f721SLang Hames 
15919510447aSLang Hames } // namespace
1592