[docs] Fix build-docs.sh
[llvm-project.git] / llvm / unittests / ExecutionEngine / Orc / CoreAPIsTest.cpp
blob7ef20cdc49d5b91bc6746c0e48184bc6618a6849
1 //===----------- CoreAPIsTest.cpp - Unit tests for Core ORC APIs ----------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include "OrcTestCommon.h"
10 #include "llvm/ADT/ScopeExit.h"
11 #include "llvm/Config/llvm-config.h"
12 #include "llvm/ExecutionEngine/Orc/Core.h"
13 #include "llvm/ExecutionEngine/Orc/Shared/OrcError.h"
14 #include "llvm/Testing/Support/Error.h"
16 #include <set>
17 #include <thread>
19 using namespace llvm;
20 using namespace llvm::orc;
22 class CoreAPIsStandardTest : public CoreAPIsBasedStandardTest {};
24 namespace {
26 TEST_F(CoreAPIsStandardTest, BasicSuccessfulLookup) {
27 bool OnCompletionRun = false;
29 auto OnCompletion = [&](Expected<SymbolMap> Result) {
30 EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error";
31 auto &Resolved = *Result;
32 auto I = Resolved.find(Foo);
33 EXPECT_NE(I, Resolved.end()) << "Could not find symbol definition";
34 EXPECT_EQ(I->second.getAddress(), FooAddr)
35 << "Resolution returned incorrect result";
36 OnCompletionRun = true;
39 std::unique_ptr<MaterializationResponsibility> FooMR;
41 cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(
42 SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
43 [&](std::unique_ptr<MaterializationResponsibility> R) {
44 FooMR = std::move(R);
45 })));
47 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
48 SymbolLookupSet(Foo), SymbolState::Ready, OnCompletion,
49 NoDependenciesToRegister);
51 EXPECT_FALSE(OnCompletionRun) << "Should not have been resolved yet";
53 cantFail(FooMR->notifyResolved({{Foo, FooSym}}));
55 EXPECT_FALSE(OnCompletionRun) << "Should not be ready yet";
57 cantFail(FooMR->notifyEmitted());
59 EXPECT_TRUE(OnCompletionRun) << "Should have been marked ready";
62 TEST_F(CoreAPIsStandardTest, EmptyLookup) {
63 bool OnCompletionRun = false;
65 auto OnCompletion = [&](Expected<SymbolMap> Result) {
66 cantFail(std::move(Result));
67 OnCompletionRun = true;
70 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), SymbolLookupSet(),
71 SymbolState::Ready, OnCompletion, NoDependenciesToRegister);
73 EXPECT_TRUE(OnCompletionRun) << "OnCompletion was not run for empty query";
76 TEST_F(CoreAPIsStandardTest, ResolveUnrequestedSymbol) {
77 // Test that all symbols in a MaterializationUnit materialize corretly when
78 // only a subset of symbols is looked up.
79 // The aim here is to ensure that we're not relying on the query to set up
80 // state needed to materialize the unrequested symbols.
82 cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(
83 SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}),
84 [this](std::unique_ptr<MaterializationResponsibility> R) {
85 cantFail(R->notifyResolved({{Foo, FooSym}, {Bar, BarSym}}));
86 cantFail(R->notifyEmitted());
87 })));
89 auto Result =
90 cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Foo})));
91 EXPECT_EQ(Result.size(), 1U) << "Unexpected number of results";
92 EXPECT_TRUE(Result.count(Foo)) << "Expected result for \"Foo\"";
95 TEST_F(CoreAPIsStandardTest, MaterializationSideEffctsOnlyBasic) {
96 // Test that basic materialization-side-effects-only symbols work as expected:
97 // that they can be emitted without being resolved, that queries for them
98 // don't return until they're emitted, and that they don't appear in query
99 // results.
101 std::unique_ptr<MaterializationResponsibility> FooR;
102 Optional<SymbolMap> Result;
104 cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(
105 SymbolFlagsMap(
106 {{Foo, JITSymbolFlags::Exported |
107 JITSymbolFlags::MaterializationSideEffectsOnly}}),
108 [&](std::unique_ptr<MaterializationResponsibility> R) {
109 FooR = std::move(R);
110 })));
112 ES.lookup(
113 LookupKind::Static, makeJITDylibSearchOrder(&JD),
114 SymbolLookupSet(Foo, SymbolLookupFlags::WeaklyReferencedSymbol),
115 SymbolState::Ready,
116 [&](Expected<SymbolMap> LookupResult) {
117 if (LookupResult)
118 Result = std::move(*LookupResult);
119 else
120 ADD_FAILURE() << "Unexpected lookup error: "
121 << toString(LookupResult.takeError());
123 NoDependenciesToRegister);
125 EXPECT_FALSE(Result) << "Lookup returned unexpectedly";
126 EXPECT_TRUE(FooR) << "Lookup failed to trigger materialization";
127 EXPECT_THAT_ERROR(FooR->notifyEmitted(), Succeeded())
128 << "Emission of materialization-side-effects-only symbol failed";
130 EXPECT_TRUE(Result) << "Lookup failed to return";
131 EXPECT_TRUE(Result->empty()) << "Lookup result contained unexpected value";
134 TEST_F(CoreAPIsStandardTest, MaterializationSideEffectsOnlyFailuresPersist) {
135 // Test that when a MaterializationSideEffectsOnly symbol is failed it
136 // remains in the failure state rather than vanishing.
138 cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(
139 SymbolFlagsMap(
140 {{Foo, JITSymbolFlags::Exported |
141 JITSymbolFlags::MaterializationSideEffectsOnly}}),
142 [&](std::unique_ptr<MaterializationResponsibility> R) {
143 R->failMaterialization();
144 })));
146 EXPECT_THAT_EXPECTED(
147 ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Foo})),
148 Failed());
149 EXPECT_THAT_EXPECTED(
150 ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Foo})),
151 Failed());
154 TEST_F(CoreAPIsStandardTest, RemoveSymbolsTest) {
155 // Test that:
156 // (1) Missing symbols generate a SymbolsNotFound error.
157 // (2) Materializing symbols generate a SymbolCouldNotBeRemoved error.
158 // (3) Removal of unmaterialized symbols triggers discard on the
159 // materialization unit.
160 // (4) Removal of symbols destroys empty materialization units.
161 // (5) Removal of materialized symbols works.
163 // Foo will be fully materialized.
164 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}})));
166 // Bar will be unmaterialized.
167 bool BarDiscarded = false;
168 bool BarMaterializerDestructed = false;
169 cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(
170 SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
171 [this](std::unique_ptr<MaterializationResponsibility> R) {
172 ADD_FAILURE() << "Unexpected materialization of \"Bar\"";
173 cantFail(R->notifyResolved({{Bar, BarSym}}));
174 cantFail(R->notifyEmitted());
176 nullptr,
177 [&](const JITDylib &JD, const SymbolStringPtr &Name) {
178 EXPECT_EQ(Name, Bar) << "Expected \"Bar\" to be discarded";
179 if (Name == Bar)
180 BarDiscarded = true;
182 [&]() { BarMaterializerDestructed = true; })));
184 // Baz will be in the materializing state initially, then
185 // materialized for the final removal attempt.
186 std::unique_ptr<MaterializationResponsibility> BazR;
187 cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(
188 SymbolFlagsMap({{Baz, BazSym.getFlags()}}),
189 [&](std::unique_ptr<MaterializationResponsibility> R) {
190 BazR = std::move(R);
192 nullptr,
193 [](const JITDylib &JD, const SymbolStringPtr &Name) {
194 ADD_FAILURE() << "\"Baz\" discarded unexpectedly";
195 })));
197 bool OnCompletionRun = false;
198 ES.lookup(
199 LookupKind::Static, makeJITDylibSearchOrder(&JD),
200 SymbolLookupSet({Foo, Baz}), SymbolState::Ready,
201 [&](Expected<SymbolMap> Result) {
202 cantFail(Result.takeError());
203 OnCompletionRun = true;
205 NoDependenciesToRegister);
208 // Attempt 1: Search for a missing symbol, Qux.
209 auto Err = JD.remove({Foo, Bar, Baz, Qux});
210 EXPECT_TRUE(!!Err) << "Expected failure";
211 EXPECT_TRUE(Err.isA<SymbolsNotFound>())
212 << "Expected a SymbolsNotFound error";
213 consumeError(std::move(Err));
217 // Attempt 2: Search for a symbol that is still materializing, Baz.
218 auto Err = JD.remove({Foo, Bar, Baz});
219 EXPECT_TRUE(!!Err) << "Expected failure";
220 EXPECT_TRUE(Err.isA<SymbolsCouldNotBeRemoved>())
221 << "Expected a SymbolsNotFound error";
222 consumeError(std::move(Err));
225 cantFail(BazR->notifyResolved({{Baz, BazSym}}));
226 cantFail(BazR->notifyEmitted());
228 // Attempt 3: Search now that all symbols are fully materialized
229 // (Foo, Baz), or not yet materialized (Bar).
230 auto Err = JD.remove({Foo, Bar, Baz});
231 EXPECT_FALSE(!!Err) << "Expected success";
234 EXPECT_TRUE(BarDiscarded) << "\"Bar\" should have been discarded";
235 EXPECT_TRUE(BarMaterializerDestructed)
236 << "\"Bar\"'s materializer should have been destructed";
237 EXPECT_TRUE(OnCompletionRun) << "OnCompletion should have been run";
240 TEST_F(CoreAPIsStandardTest, LookupWithHiddenSymbols) {
241 auto BarHiddenFlags = BarSym.getFlags() & ~JITSymbolFlags::Exported;
242 auto BarHiddenSym = JITEvaluatedSymbol(BarSym.getAddress(), BarHiddenFlags);
244 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}, {Bar, BarHiddenSym}})));
246 auto &JD2 = ES.createBareJITDylib("JD2");
247 cantFail(JD2.define(absoluteSymbols({{Bar, QuxSym}})));
249 /// Try a blocking lookup.
250 auto Result = cantFail(ES.lookup(makeJITDylibSearchOrder({&JD, &JD2}),
251 SymbolLookupSet({Foo, Bar})));
253 EXPECT_EQ(Result.size(), 2U) << "Unexpected number of results";
254 EXPECT_EQ(Result.count(Foo), 1U) << "Missing result for \"Foo\"";
255 EXPECT_EQ(Result.count(Bar), 1U) << "Missing result for \"Bar\"";
256 EXPECT_EQ(Result[Bar].getAddress(), QuxSym.getAddress())
257 << "Wrong result for \"Bar\"";
260 TEST_F(CoreAPIsStandardTest, LookupFlagsTest) {
261 // Test that lookupFlags works on a predefined symbol, and does not trigger
262 // materialization of a lazy symbol. Make the lazy symbol weak to test that
263 // the weak flag is propagated correctly.
265 BarSym.setFlags(static_cast<JITSymbolFlags::FlagNames>(
266 JITSymbolFlags::Exported | JITSymbolFlags::Weak));
267 auto MU = std::make_unique<SimpleMaterializationUnit>(
268 SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
269 [](std::unique_ptr<MaterializationResponsibility> R) {
270 llvm_unreachable("Symbol materialized on flags lookup");
273 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}})));
274 cantFail(JD.define(std::move(MU)));
276 auto SymbolFlags = cantFail(ES.lookupFlags(
277 LookupKind::Static,
278 {{&JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}},
279 SymbolLookupSet({Foo, Bar, Baz},
280 SymbolLookupFlags::WeaklyReferencedSymbol)));
282 EXPECT_EQ(SymbolFlags.size(), 2U)
283 << "Returned symbol flags contains unexpected results";
284 EXPECT_EQ(SymbolFlags.count(Foo), 1U) << "Missing lookupFlags result for Foo";
285 EXPECT_EQ(SymbolFlags[Foo], FooSym.getFlags())
286 << "Incorrect flags returned for Foo";
287 EXPECT_EQ(SymbolFlags.count(Bar), 1U)
288 << "Missing lookupFlags result for Bar";
289 EXPECT_EQ(SymbolFlags[Bar], BarSym.getFlags())
290 << "Incorrect flags returned for Bar";
293 TEST_F(CoreAPIsStandardTest, LookupWithGeneratorFailure) {
295 class BadGenerator : public DefinitionGenerator {
296 public:
297 Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &,
298 JITDylibLookupFlags, const SymbolLookupSet &) override {
299 return make_error<StringError>("BadGenerator", inconvertibleErrorCode());
303 JD.addGenerator(std::make_unique<BadGenerator>());
305 EXPECT_THAT_ERROR(
306 ES.lookupFlags(LookupKind::Static,
307 {{&JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}},
308 SymbolLookupSet(Foo))
309 .takeError(),
310 Failed<StringError>())
311 << "Generator failure did not propagate through lookupFlags";
313 EXPECT_THAT_ERROR(
314 ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet(Foo)).takeError(),
315 Failed<StringError>())
316 << "Generator failure did not propagate through lookup";
319 TEST_F(CoreAPIsStandardTest, TestBasicAliases) {
320 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}, {Bar, BarSym}})));
321 cantFail(JD.define(symbolAliases({{Baz, {Foo, JITSymbolFlags::Exported}},
322 {Qux, {Bar, JITSymbolFlags::Weak}}})));
323 cantFail(JD.define(absoluteSymbols({{Qux, QuxSym}})));
325 auto Result =
326 ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Baz, Qux}));
327 EXPECT_TRUE(!!Result) << "Unexpected lookup failure";
328 EXPECT_EQ(Result->count(Baz), 1U) << "No result for \"baz\"";
329 EXPECT_EQ(Result->count(Qux), 1U) << "No result for \"qux\"";
330 EXPECT_EQ((*Result)[Baz].getAddress(), FooSym.getAddress())
331 << "\"Baz\"'s address should match \"Foo\"'s";
332 EXPECT_EQ((*Result)[Qux].getAddress(), QuxSym.getAddress())
333 << "The \"Qux\" alias should have been overriden";
336 TEST_F(CoreAPIsStandardTest, TestChainedAliases) {
337 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}})));
338 cantFail(JD.define(symbolAliases(
339 {{Baz, {Bar, BazSym.getFlags()}}, {Bar, {Foo, BarSym.getFlags()}}})));
341 auto Result =
342 ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Bar, Baz}));
343 EXPECT_TRUE(!!Result) << "Unexpected lookup failure";
344 EXPECT_EQ(Result->count(Bar), 1U) << "No result for \"bar\"";
345 EXPECT_EQ(Result->count(Baz), 1U) << "No result for \"baz\"";
346 EXPECT_EQ((*Result)[Bar].getAddress(), FooSym.getAddress())
347 << "\"Bar\"'s address should match \"Foo\"'s";
348 EXPECT_EQ((*Result)[Baz].getAddress(), FooSym.getAddress())
349 << "\"Baz\"'s address should match \"Foo\"'s";
352 TEST_F(CoreAPIsStandardTest, TestBasicReExports) {
353 // Test that the basic use case of re-exporting a single symbol from another
354 // JITDylib works.
355 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}})));
357 auto &JD2 = ES.createBareJITDylib("JD2");
359 cantFail(JD2.define(reexports(JD, {{Bar, {Foo, BarSym.getFlags()}}})));
361 auto Result = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD2), Bar));
362 EXPECT_EQ(Result.getAddress(), FooSym.getAddress())
363 << "Re-export Bar for symbol Foo should match FooSym's address";
366 TEST_F(CoreAPIsStandardTest, TestThatReExportsDontUnnecessarilyMaterialize) {
367 // Test that re-exports do not materialize symbols that have not been queried
368 // for.
369 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}})));
371 bool BarMaterialized = false;
372 auto BarMU = std::make_unique<SimpleMaterializationUnit>(
373 SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
374 [&](std::unique_ptr<MaterializationResponsibility> R) {
375 BarMaterialized = true;
376 cantFail(R->notifyResolved({{Bar, BarSym}}));
377 cantFail(R->notifyEmitted());
380 cantFail(JD.define(BarMU));
382 auto &JD2 = ES.createBareJITDylib("JD2");
384 cantFail(JD2.define(reexports(
385 JD, {{Baz, {Foo, BazSym.getFlags()}}, {Qux, {Bar, QuxSym.getFlags()}}})));
387 auto Result = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD2), Baz));
388 EXPECT_EQ(Result.getAddress(), FooSym.getAddress())
389 << "Re-export Baz for symbol Foo should match FooSym's address";
391 EXPECT_FALSE(BarMaterialized) << "Bar should not have been materialized";
394 TEST_F(CoreAPIsStandardTest, TestReexportsGenerator) {
395 // Test that a re-exports generator can dynamically generate reexports.
397 auto &JD2 = ES.createBareJITDylib("JD2");
398 cantFail(JD2.define(absoluteSymbols({{Foo, FooSym}, {Bar, BarSym}})));
400 auto Filter = [this](SymbolStringPtr Name) { return Name != Bar; };
402 JD.addGenerator(std::make_unique<ReexportsGenerator>(
403 JD2, JITDylibLookupFlags::MatchExportedSymbolsOnly, Filter));
405 auto Flags = cantFail(ES.lookupFlags(
406 LookupKind::Static,
407 {{&JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}},
408 SymbolLookupSet({Foo, Bar, Baz},
409 SymbolLookupFlags::WeaklyReferencedSymbol)));
410 EXPECT_EQ(Flags.size(), 1U) << "Unexpected number of results";
411 EXPECT_EQ(Flags[Foo], FooSym.getFlags()) << "Unexpected flags for Foo";
413 auto Result = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Foo));
415 EXPECT_EQ(Result.getAddress(), FooSym.getAddress())
416 << "Incorrect reexported symbol address";
419 TEST_F(CoreAPIsStandardTest, TestTrivialCircularDependency) {
420 std::unique_ptr<MaterializationResponsibility> FooR;
421 auto FooMU = std::make_unique<SimpleMaterializationUnit>(
422 SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
423 [&](std::unique_ptr<MaterializationResponsibility> R) {
424 FooR = std::move(R);
427 cantFail(JD.define(FooMU));
429 bool FooReady = false;
430 auto OnCompletion = [&](Expected<SymbolMap> Result) {
431 cantFail(std::move(Result));
432 FooReady = true;
435 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
436 SymbolLookupSet({Foo}), SymbolState::Ready, OnCompletion,
437 NoDependenciesToRegister);
439 FooR->addDependenciesForAll({{&JD, SymbolNameSet({Foo})}});
440 EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Succeeded())
441 << "No symbols marked failed, but Foo failed to resolve";
442 EXPECT_THAT_ERROR(FooR->notifyEmitted(), Succeeded())
443 << "No symbols marked failed, but Foo failed to emit";
445 EXPECT_TRUE(FooReady)
446 << "Self-dependency prevented symbol from being marked ready";
449 TEST_F(CoreAPIsStandardTest, TestCircularDependenceInOneJITDylib) {
450 // Test that a circular symbol dependency between three symbols in a JITDylib
451 // does not prevent any symbol from becoming 'ready' once all symbols are
452 // emitted.
454 std::unique_ptr<MaterializationResponsibility> FooR;
455 std::unique_ptr<MaterializationResponsibility> BarR;
456 std::unique_ptr<MaterializationResponsibility> BazR;
458 // Create a MaterializationUnit for each symbol that moves the
459 // MaterializationResponsibility into one of the locals above.
460 auto FooMU = std::make_unique<SimpleMaterializationUnit>(
461 SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
462 [&](std::unique_ptr<MaterializationResponsibility> R) {
463 FooR = std::move(R);
466 auto BarMU = std::make_unique<SimpleMaterializationUnit>(
467 SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
468 [&](std::unique_ptr<MaterializationResponsibility> R) {
469 BarR = std::move(R);
472 auto BazMU = std::make_unique<SimpleMaterializationUnit>(
473 SymbolFlagsMap({{Baz, BazSym.getFlags()}}),
474 [&](std::unique_ptr<MaterializationResponsibility> R) {
475 BazR = std::move(R);
478 // Define the symbols.
479 cantFail(JD.define(FooMU));
480 cantFail(JD.define(BarMU));
481 cantFail(JD.define(BazMU));
483 // Query each of the symbols to trigger materialization.
484 bool FooResolved = false;
485 bool FooReady = false;
487 auto OnFooResolution = [&](Expected<SymbolMap> Result) {
488 cantFail(std::move(Result));
489 FooResolved = true;
492 auto OnFooReady = [&](Expected<SymbolMap> Result) {
493 cantFail(std::move(Result));
494 FooReady = true;
497 // Issue lookups for Foo. Use NoDependenciesToRegister: We're going to add
498 // the dependencies manually below.
499 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
500 SymbolLookupSet(Foo), SymbolState::Resolved,
501 std::move(OnFooResolution), NoDependenciesToRegister);
503 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
504 SymbolLookupSet(Foo), SymbolState::Ready, std::move(OnFooReady),
505 NoDependenciesToRegister);
507 bool BarResolved = false;
508 bool BarReady = false;
509 auto OnBarResolution = [&](Expected<SymbolMap> Result) {
510 cantFail(std::move(Result));
511 BarResolved = true;
514 auto OnBarReady = [&](Expected<SymbolMap> Result) {
515 cantFail(std::move(Result));
516 BarReady = true;
519 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
520 SymbolLookupSet(Bar), SymbolState::Resolved,
521 std::move(OnBarResolution), NoDependenciesToRegister);
523 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
524 SymbolLookupSet(Bar), SymbolState::Ready, std::move(OnBarReady),
525 NoDependenciesToRegister);
527 bool BazResolved = false;
528 bool BazReady = false;
530 auto OnBazResolution = [&](Expected<SymbolMap> Result) {
531 cantFail(std::move(Result));
532 BazResolved = true;
535 auto OnBazReady = [&](Expected<SymbolMap> Result) {
536 cantFail(std::move(Result));
537 BazReady = true;
540 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
541 SymbolLookupSet(Baz), SymbolState::Resolved,
542 std::move(OnBazResolution), NoDependenciesToRegister);
544 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
545 SymbolLookupSet(Baz), SymbolState::Ready, std::move(OnBazReady),
546 NoDependenciesToRegister);
548 // Add a circular dependency: Foo -> Bar, Bar -> Baz, Baz -> Foo.
549 FooR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}});
550 BarR->addDependenciesForAll({{&JD, SymbolNameSet({Baz})}});
551 BazR->addDependenciesForAll({{&JD, SymbolNameSet({Foo})}});
553 // Add self-dependencies for good measure. This tests that the implementation
554 // of addDependencies filters these out.
555 FooR->addDependenciesForAll({{&JD, SymbolNameSet({Foo})}});
556 BarR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}});
557 BazR->addDependenciesForAll({{&JD, SymbolNameSet({Baz})}});
559 // Check that nothing has been resolved yet.
560 EXPECT_FALSE(FooResolved) << "\"Foo\" should not be resolved yet";
561 EXPECT_FALSE(BarResolved) << "\"Bar\" should not be resolved yet";
562 EXPECT_FALSE(BazResolved) << "\"Baz\" should not be resolved yet";
564 // Resolve the symbols (but do not emit them).
565 EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Succeeded())
566 << "No symbols failed, but Foo failed to resolve";
567 EXPECT_THAT_ERROR(BarR->notifyResolved({{Bar, BarSym}}), Succeeded())
568 << "No symbols failed, but Bar failed to resolve";
569 EXPECT_THAT_ERROR(BazR->notifyResolved({{Baz, BazSym}}), Succeeded())
570 << "No symbols failed, but Baz failed to resolve";
572 // Verify that the symbols have been resolved, but are not ready yet.
573 EXPECT_TRUE(FooResolved) << "\"Foo\" should be resolved now";
574 EXPECT_TRUE(BarResolved) << "\"Bar\" should be resolved now";
575 EXPECT_TRUE(BazResolved) << "\"Baz\" should be resolved now";
577 EXPECT_FALSE(FooReady) << "\"Foo\" should not be ready yet";
578 EXPECT_FALSE(BarReady) << "\"Bar\" should not be ready yet";
579 EXPECT_FALSE(BazReady) << "\"Baz\" should not be ready yet";
581 // Emit two of the symbols.
582 EXPECT_THAT_ERROR(FooR->notifyEmitted(), Succeeded())
583 << "No symbols failed, but Foo failed to emit";
584 EXPECT_THAT_ERROR(BarR->notifyEmitted(), Succeeded())
585 << "No symbols failed, but Bar failed to emit";
587 // Verify that nothing is ready until the circular dependence is resolved.
588 EXPECT_FALSE(FooReady) << "\"Foo\" still should not be ready";
589 EXPECT_FALSE(BarReady) << "\"Bar\" still should not be ready";
590 EXPECT_FALSE(BazReady) << "\"Baz\" still should not be ready";
592 // Emit the last symbol.
593 EXPECT_THAT_ERROR(BazR->notifyEmitted(), Succeeded())
594 << "No symbols failed, but Baz failed to emit";
596 // Verify that everything becomes ready once the circular dependence resolved.
597 EXPECT_TRUE(FooReady) << "\"Foo\" should be ready now";
598 EXPECT_TRUE(BarReady) << "\"Bar\" should be ready now";
599 EXPECT_TRUE(BazReady) << "\"Baz\" should be ready now";
602 TEST_F(CoreAPIsStandardTest, FailureInDependency) {
603 std::unique_ptr<MaterializationResponsibility> FooR;
604 std::unique_ptr<MaterializationResponsibility> BarR;
606 // Create a MaterializationUnit for each symbol that moves the
607 // MaterializationResponsibility into one of the locals above.
608 auto FooMU = std::make_unique<SimpleMaterializationUnit>(
609 SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
610 [&](std::unique_ptr<MaterializationResponsibility> R) {
611 FooR = std::move(R);
614 auto BarMU = std::make_unique<SimpleMaterializationUnit>(
615 SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
616 [&](std::unique_ptr<MaterializationResponsibility> R) {
617 BarR = std::move(R);
620 // Define the symbols.
621 cantFail(JD.define(FooMU));
622 cantFail(JD.define(BarMU));
624 bool OnFooReadyRun = false;
625 auto OnFooReady = [&](Expected<SymbolMap> Result) {
626 EXPECT_THAT_EXPECTED(std::move(Result), Failed());
627 OnFooReadyRun = true;
630 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
631 SymbolLookupSet(Foo), SymbolState::Ready, std::move(OnFooReady),
632 NoDependenciesToRegister);
634 bool OnBarReadyRun = false;
635 auto OnBarReady = [&](Expected<SymbolMap> Result) {
636 EXPECT_THAT_EXPECTED(std::move(Result), Failed());
637 OnBarReadyRun = true;
640 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
641 SymbolLookupSet(Bar), SymbolState::Ready, std::move(OnBarReady),
642 NoDependenciesToRegister);
644 // Add a dependency by Foo on Bar.
645 FooR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}});
647 // Fail bar.
648 BarR->failMaterialization();
650 // Verify that queries on Bar failed, but queries on Foo have not yet.
651 EXPECT_TRUE(OnBarReadyRun) << "Query for \"Bar\" was not run";
652 EXPECT_FALSE(OnFooReadyRun) << "Query for \"Foo\" was run unexpectedly";
654 // Check that we can still resolve Foo (even though it has been failed).
655 EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Failed())
656 << "Expected resolution for \"Foo\" to fail.";
658 FooR->failMaterialization();
660 // Verify that queries on Foo have now failed.
661 EXPECT_TRUE(OnFooReadyRun) << "Query for \"Foo\" was not run";
663 // Verify that subsequent lookups on Bar and Foo fail.
664 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Bar}), Failed())
665 << "Lookup on failed symbol should fail";
667 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Foo}), Failed())
668 << "Lookup on failed symbol should fail";
671 TEST_F(CoreAPIsStandardTest, FailureInCircularDependency) {
672 std::unique_ptr<MaterializationResponsibility> FooR;
673 std::unique_ptr<MaterializationResponsibility> BarR;
675 // Create a MaterializationUnit for each symbol that moves the
676 // MaterializationResponsibility into one of the locals above.
677 auto FooMU = std::make_unique<SimpleMaterializationUnit>(
678 SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
679 [&](std::unique_ptr<MaterializationResponsibility> R) {
680 FooR = std::move(R);
683 auto BarMU = std::make_unique<SimpleMaterializationUnit>(
684 SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
685 [&](std::unique_ptr<MaterializationResponsibility> R) {
686 BarR = std::move(R);
689 // Define the symbols.
690 cantFail(JD.define(FooMU));
691 cantFail(JD.define(BarMU));
693 bool OnFooReadyRun = false;
694 auto OnFooReady = [&](Expected<SymbolMap> Result) {
695 EXPECT_THAT_EXPECTED(std::move(Result), Failed());
696 OnFooReadyRun = true;
699 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
700 SymbolLookupSet(Foo), SymbolState::Ready, std::move(OnFooReady),
701 NoDependenciesToRegister);
703 bool OnBarReadyRun = false;
704 auto OnBarReady = [&](Expected<SymbolMap> Result) {
705 EXPECT_THAT_EXPECTED(std::move(Result), Failed());
706 OnBarReadyRun = true;
709 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
710 SymbolLookupSet(Bar), SymbolState::Ready, std::move(OnBarReady),
711 NoDependenciesToRegister);
713 // Add a dependency by Foo on Bar and vice-versa.
714 FooR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}});
715 BarR->addDependenciesForAll({{&JD, SymbolNameSet({Foo})}});
717 // Fail bar.
718 BarR->failMaterialization();
720 // Verify that queries on Bar failed, but queries on Foo have not yet.
721 EXPECT_TRUE(OnBarReadyRun) << "Query for \"Bar\" was not run";
722 EXPECT_FALSE(OnFooReadyRun) << "Query for \"Foo\" was run unexpectedly";
724 // Verify that trying to resolve Foo fails.
725 EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Failed())
726 << "Expected resolution for \"Foo\" to fail.";
728 FooR->failMaterialization();
730 // Verify that queries on Foo have now failed.
731 EXPECT_TRUE(OnFooReadyRun) << "Query for \"Foo\" was not run";
733 // Verify that subsequent lookups on Bar and Foo fail.
734 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Bar}), Failed())
735 << "Lookup on failed symbol should fail";
737 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Foo}), Failed())
738 << "Lookup on failed symbol should fail";
741 TEST_F(CoreAPIsStandardTest, AddDependencyOnFailedSymbol) {
742 std::unique_ptr<MaterializationResponsibility> FooR;
743 std::unique_ptr<MaterializationResponsibility> BarR;
745 // Create a MaterializationUnit for each symbol that moves the
746 // MaterializationResponsibility into one of the locals above.
747 auto FooMU = std::make_unique<SimpleMaterializationUnit>(
748 SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
749 [&](std::unique_ptr<MaterializationResponsibility> R) {
750 FooR = std::move(R);
753 auto BarMU = std::make_unique<SimpleMaterializationUnit>(
754 SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
755 [&](std::unique_ptr<MaterializationResponsibility> R) {
756 BarR = std::move(R);
759 // Define the symbols.
760 cantFail(JD.define(FooMU));
761 cantFail(JD.define(BarMU));
763 bool OnFooReadyRun = false;
764 auto OnFooReady = [&](Expected<SymbolMap> Result) {
765 EXPECT_THAT_EXPECTED(std::move(Result), Failed());
766 OnFooReadyRun = true;
769 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
770 SymbolLookupSet(Foo), SymbolState::Ready, std::move(OnFooReady),
771 NoDependenciesToRegister);
773 bool OnBarReadyRun = false;
774 auto OnBarReady = [&](Expected<SymbolMap> Result) {
775 EXPECT_THAT_EXPECTED(std::move(Result), Failed());
776 OnBarReadyRun = true;
779 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
780 SymbolLookupSet(Bar), SymbolState::Ready, std::move(OnBarReady),
781 NoDependenciesToRegister);
783 // Fail bar.
784 BarR->failMaterialization();
786 // We expect Bar's query to fail immediately, but Foo's query not to have run
787 // yet.
788 EXPECT_TRUE(OnBarReadyRun) << "Query for \"Bar\" was not run";
789 EXPECT_FALSE(OnFooReadyRun) << "Query for \"Foo\" should not have run yet";
791 // Add dependency of Foo on Bar.
792 FooR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}});
794 // Check that we can still resolve Foo (even though it has been failed).
795 EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Failed())
796 << "Expected resolution for \"Foo\" to fail.";
798 FooR->failMaterialization();
800 // Foo's query should have failed before we return from addDependencies.
801 EXPECT_TRUE(OnFooReadyRun) << "Query for \"Foo\" was not run";
803 // Verify that subsequent lookups on Bar and Foo fail.
804 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Bar}), Failed())
805 << "Lookup on failed symbol should fail";
807 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Foo}), Failed())
808 << "Lookup on failed symbol should fail";
811 TEST_F(CoreAPIsStandardTest, FailAfterMaterialization) {
812 std::unique_ptr<MaterializationResponsibility> FooR;
813 std::unique_ptr<MaterializationResponsibility> BarR;
815 // Create a MaterializationUnit for each symbol that moves the
816 // MaterializationResponsibility into one of the locals above.
817 auto FooMU = std::make_unique<SimpleMaterializationUnit>(
818 SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
819 [&](std::unique_ptr<MaterializationResponsibility> R) {
820 FooR = std::move(R);
823 auto BarMU = std::make_unique<SimpleMaterializationUnit>(
824 SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
825 [&](std::unique_ptr<MaterializationResponsibility> R) {
826 BarR = std::move(R);
829 // Define the symbols.
830 cantFail(JD.define(FooMU));
831 cantFail(JD.define(BarMU));
833 bool OnFooReadyRun = false;
834 auto OnFooReady = [&](Expected<SymbolMap> Result) {
835 EXPECT_THAT_EXPECTED(std::move(Result), Failed());
836 OnFooReadyRun = true;
839 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
840 SymbolLookupSet(Foo), SymbolState::Ready, std::move(OnFooReady),
841 NoDependenciesToRegister);
843 bool OnBarReadyRun = false;
844 auto OnBarReady = [&](Expected<SymbolMap> Result) {
845 EXPECT_THAT_EXPECTED(std::move(Result), Failed());
846 OnBarReadyRun = true;
849 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
850 SymbolLookupSet(Bar), SymbolState::Ready, std::move(OnBarReady),
851 NoDependenciesToRegister);
853 // Add a dependency by Foo on Bar and vice-versa.
854 FooR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}});
855 BarR->addDependenciesForAll({{&JD, SymbolNameSet({Foo})}});
857 // Materialize Foo.
858 EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Succeeded())
859 << "Expected resolution for \"Foo\" to succeed.";
860 EXPECT_THAT_ERROR(FooR->notifyEmitted(), Succeeded())
861 << "Expected emission for \"Foo\" to succeed.";
863 // Fail bar.
864 BarR->failMaterialization();
866 // Verify that both queries failed.
867 EXPECT_TRUE(OnFooReadyRun) << "Query for Foo did not run";
868 EXPECT_TRUE(OnBarReadyRun) << "Query for Bar did not run";
871 TEST_F(CoreAPIsStandardTest, FailMaterializerWithUnqueriedSymbols) {
872 // Make sure that symbols with no queries aganist them still
873 // fail correctly.
875 bool MaterializerRun = false;
876 auto MU = std::make_unique<SimpleMaterializationUnit>(
877 SymbolFlagsMap(
878 {{Foo, JITSymbolFlags::Exported}, {Bar, JITSymbolFlags::Exported}}),
879 [&](std::unique_ptr<MaterializationResponsibility> R) {
880 MaterializerRun = true;
881 R->failMaterialization();
884 cantFail(JD.define(std::move(MU)));
886 // Issue a query for Foo, but not bar.
887 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Foo}), Failed())
888 << "Expected lookup to fail.";
890 // Check that the materializer (and therefore failMaterialization) ran.
891 EXPECT_TRUE(MaterializerRun) << "Expected materializer to have run by now";
893 // Check that subsequent queries against both symbols fail.
894 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Foo}), Failed())
895 << "Expected lookup for Foo to fail.";
896 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Bar}), Failed())
897 << "Expected lookup for Bar to fail.";
900 TEST_F(CoreAPIsStandardTest, DropMaterializerWhenEmpty) {
901 bool DestructorRun = false;
903 JITSymbolFlags WeakExported(JITSymbolFlags::Exported);
904 WeakExported |= JITSymbolFlags::Weak;
906 auto MU = std::make_unique<SimpleMaterializationUnit>(
907 SymbolFlagsMap({{Foo, WeakExported}, {Bar, WeakExported}}),
908 [](std::unique_ptr<MaterializationResponsibility> R) {
909 llvm_unreachable("Unexpected call to materialize");
911 nullptr,
912 [&](const JITDylib &JD, SymbolStringPtr Name) {
913 EXPECT_TRUE(Name == Foo || Name == Bar)
914 << "Discard of unexpected symbol?";
916 [&]() { DestructorRun = true; });
918 cantFail(JD.define(MU));
920 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}})));
922 EXPECT_FALSE(DestructorRun)
923 << "MaterializationUnit should not have been destroyed yet";
925 cantFail(JD.define(absoluteSymbols({{Bar, BarSym}})));
927 EXPECT_TRUE(DestructorRun)
928 << "MaterializationUnit should have been destroyed";
931 TEST_F(CoreAPIsStandardTest, AddAndMaterializeLazySymbol) {
932 bool FooMaterialized = false;
933 bool BarDiscarded = false;
935 JITSymbolFlags WeakExported(JITSymbolFlags::Exported);
936 WeakExported |= JITSymbolFlags::Weak;
938 auto MU = std::make_unique<SimpleMaterializationUnit>(
939 SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}, {Bar, WeakExported}}),
940 [&](std::unique_ptr<MaterializationResponsibility> R) {
941 assert(BarDiscarded && "Bar should have been discarded by this point");
942 cantFail(R->notifyResolved(SymbolMap({{Foo, FooSym}})));
943 cantFail(R->notifyEmitted());
944 FooMaterialized = true;
946 nullptr,
947 [&](const JITDylib &JD, SymbolStringPtr Name) {
948 EXPECT_EQ(Name, Bar) << "Expected Name to be Bar";
949 BarDiscarded = true;
952 cantFail(JD.define(MU));
953 cantFail(JD.define(absoluteSymbols({{Bar, BarSym}})));
955 bool OnCompletionRun = false;
957 auto OnCompletion = [&](Expected<SymbolMap> Result) {
958 EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error";
959 auto I = Result->find(Foo);
960 EXPECT_NE(I, Result->end()) << "Could not find symbol definition";
961 EXPECT_EQ(I->second.getAddress(), FooSym.getAddress())
962 << "Resolution returned incorrect result";
963 OnCompletionRun = true;
966 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
967 SymbolLookupSet(Foo), SymbolState::Ready, std::move(OnCompletion),
968 NoDependenciesToRegister);
970 EXPECT_TRUE(FooMaterialized) << "Foo was not materialized";
971 EXPECT_TRUE(BarDiscarded) << "Bar was not discarded";
972 EXPECT_TRUE(OnCompletionRun) << "OnResolutionCallback was not run";
975 TEST_F(CoreAPIsStandardTest, TestBasicWeakSymbolMaterialization) {
976 // Test that weak symbols are materialized correctly when we look them up.
977 BarSym.setFlags(BarSym.getFlags() | JITSymbolFlags::Weak);
979 bool BarMaterialized = false;
980 auto MU1 = std::make_unique<SimpleMaterializationUnit>(
981 SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}),
982 [&](std::unique_ptr<MaterializationResponsibility> R) {
983 cantFail(R->notifyResolved(SymbolMap({{Foo, FooSym}, {Bar, BarSym}})));
984 cantFail(R->notifyEmitted());
985 BarMaterialized = true;
988 bool DuplicateBarDiscarded = false;
989 auto MU2 = std::make_unique<SimpleMaterializationUnit>(
990 SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
991 [&](std::unique_ptr<MaterializationResponsibility> R) {
992 ADD_FAILURE() << "Attempt to materialize Bar from the wrong unit";
993 R->failMaterialization();
995 nullptr,
996 [&](const JITDylib &JD, SymbolStringPtr Name) {
997 EXPECT_EQ(Name, Bar) << "Expected \"Bar\" to be discarded";
998 DuplicateBarDiscarded = true;
1001 cantFail(JD.define(MU1));
1002 cantFail(JD.define(MU2));
1004 bool OnCompletionRun = false;
1006 auto OnCompletion = [&](Expected<SymbolMap> Result) {
1007 cantFail(std::move(Result));
1008 OnCompletionRun = true;
1011 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
1012 SymbolLookupSet(Bar), SymbolState::Ready, std::move(OnCompletion),
1013 NoDependenciesToRegister);
1015 EXPECT_TRUE(OnCompletionRun) << "OnCompletion not run";
1016 EXPECT_TRUE(BarMaterialized) << "Bar was not materialized at all";
1017 EXPECT_TRUE(DuplicateBarDiscarded)
1018 << "Duplicate bar definition not discarded";
1021 TEST_F(CoreAPIsStandardTest, DefineMaterializingSymbol) {
1022 bool ExpectNoMoreMaterialization = false;
1023 ES.setDispatchTask([&](std::unique_ptr<Task> T) {
1024 if (ExpectNoMoreMaterialization && isa<MaterializationTask>(*T))
1025 ADD_FAILURE() << "Unexpected materialization";
1026 T->run();
1029 auto MU = std::make_unique<SimpleMaterializationUnit>(
1030 SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
1031 [&](std::unique_ptr<MaterializationResponsibility> R) {
1032 cantFail(
1033 R->defineMaterializing(SymbolFlagsMap({{Bar, BarSym.getFlags()}})));
1034 cantFail(R->notifyResolved(SymbolMap({{Foo, FooSym}, {Bar, BarSym}})));
1035 cantFail(R->notifyEmitted());
1038 cantFail(JD.define(MU));
1039 cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Foo));
1041 // Assert that materialization is complete by now.
1042 ExpectNoMoreMaterialization = true;
1044 // Look up bar to verify that no further materialization happens.
1045 auto BarResult = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Bar));
1046 EXPECT_EQ(BarResult.getAddress(), BarSym.getAddress())
1047 << "Expected Bar == BarSym";
1050 TEST_F(CoreAPIsStandardTest, GeneratorTest) {
1051 JITEvaluatedSymbol BazHiddenSym(
1052 BazSym.getAddress(), BazSym.getFlags() & ~JITSymbolFlags::Exported);
1053 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}, {Baz, BazHiddenSym}})));
1055 class TestGenerator : public DefinitionGenerator {
1056 public:
1057 TestGenerator(SymbolMap Symbols) : Symbols(std::move(Symbols)) {}
1058 Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD,
1059 JITDylibLookupFlags JDLookupFlags,
1060 const SymbolLookupSet &Names) override {
1061 SymbolMap NewDefs;
1063 for (const auto &KV : Names) {
1064 const auto &Name = KV.first;
1065 if (Symbols.count(Name))
1066 NewDefs[Name] = Symbols[Name];
1069 cantFail(JD.define(absoluteSymbols(std::move(NewDefs))));
1070 return Error::success();
1073 private:
1074 SymbolMap Symbols;
1077 JD.addGenerator(std::make_unique<TestGenerator>(
1078 SymbolMap({{Bar, BarSym}, {Baz, BazSym}})));
1080 auto Result = cantFail(
1081 ES.lookup(makeJITDylibSearchOrder(&JD),
1082 SymbolLookupSet({Foo, Bar})
1083 .add(Baz, SymbolLookupFlags::WeaklyReferencedSymbol)));
1085 EXPECT_EQ(Result.count(Bar), 1U) << "Expected to find fallback def for 'bar'";
1086 EXPECT_EQ(Result[Bar].getAddress(), BarSym.getAddress())
1087 << "Expected fallback def for Bar to be equal to BarSym";
1090 TEST_F(CoreAPIsStandardTest, AsynchronousGeneratorTest) {
1091 class TestGenerator : public DefinitionGenerator {
1092 public:
1093 TestGenerator(LookupState &TLS) : TLS(TLS) {}
1094 Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD,
1095 JITDylibLookupFlags JDLookupFlags,
1096 const SymbolLookupSet &Name) override {
1097 TLS = std::move(LS);
1098 return Error::success();
1101 private:
1102 LookupState &TLS;
1105 LookupState LS;
1106 JD.addGenerator(std::make_unique<TestGenerator>(LS));
1108 bool LookupCompleted = false;
1110 ES.lookup(
1111 LookupKind::Static, makeJITDylibSearchOrder(&JD), SymbolLookupSet(Foo),
1112 SymbolState::Ready,
1113 [&](Expected<SymbolMap> Result) {
1114 LookupCompleted = true;
1115 if (!Result) {
1116 ADD_FAILURE() << "Lookup failed unexpected";
1117 logAllUnhandledErrors(Result.takeError(), errs(), "");
1118 return;
1121 EXPECT_EQ(Result->size(), 1U) << "Unexpected number of results";
1122 EXPECT_EQ(Result->count(Foo), 1U) << "Expected result for Foo";
1123 EXPECT_EQ((*Result)[Foo].getAddress(), FooSym.getAddress())
1124 << "Bad result for Foo";
1126 NoDependenciesToRegister);
1128 EXPECT_FALSE(LookupCompleted);
1130 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}})));
1132 LS.continueLookup(Error::success());
1134 EXPECT_TRUE(LookupCompleted);
1137 TEST_F(CoreAPIsStandardTest, FailResolution) {
1138 auto MU = std::make_unique<SimpleMaterializationUnit>(
1139 SymbolFlagsMap({{Foo, JITSymbolFlags::Exported | JITSymbolFlags::Weak},
1140 {Bar, JITSymbolFlags::Exported | JITSymbolFlags::Weak}}),
1141 [&](std::unique_ptr<MaterializationResponsibility> R) {
1142 R->failMaterialization();
1145 cantFail(JD.define(MU));
1147 SymbolNameSet Names({Foo, Bar});
1148 auto Result = ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet(Names));
1150 EXPECT_FALSE(!!Result) << "Expected failure";
1151 if (!Result) {
1152 handleAllErrors(
1153 Result.takeError(),
1154 [&](FailedToMaterialize &F) {
1155 EXPECT_TRUE(F.getSymbols().count(&JD))
1156 << "Expected to fail on JITDylib JD";
1157 EXPECT_EQ(F.getSymbols().find(&JD)->second, Names)
1158 << "Expected to fail on symbols in Names";
1160 [](ErrorInfoBase &EIB) {
1161 std::string ErrMsg;
1163 raw_string_ostream ErrOut(ErrMsg);
1164 EIB.log(ErrOut);
1166 ADD_FAILURE() << "Expected a FailedToResolve error. Got:\n" << ErrMsg;
1171 TEST_F(CoreAPIsStandardTest, FailEmissionAfterResolution) {
1173 cantFail(JD.define(absoluteSymbols({{Baz, BazSym}})));
1175 auto MU = std::make_unique<SimpleMaterializationUnit>(
1176 SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}),
1177 [&](std::unique_ptr<MaterializationResponsibility> R) {
1178 cantFail(R->notifyResolved(SymbolMap({{Foo, FooSym}, {Bar, BarSym}})));
1180 ES.lookup(
1181 LookupKind::Static, makeJITDylibSearchOrder(&JD),
1182 SymbolLookupSet({Baz}), SymbolState::Resolved,
1183 [&](Expected<SymbolMap> Result) {
1184 // Called when "baz" is resolved. We don't actually depend
1185 // on or care about baz, but use it to trigger failure of
1186 // this materialization before Baz has been finalized in
1187 // order to test that error propagation is correct in this
1188 // scenario.
1189 cantFail(std::move(Result));
1190 R->failMaterialization();
1192 [&](const SymbolDependenceMap &Deps) {
1193 R->addDependenciesForAll(Deps);
1197 cantFail(JD.define(MU));
1199 auto Result =
1200 ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Foo, Bar}));
1202 EXPECT_THAT_EXPECTED(std::move(Result), Failed())
1203 << "Unexpected success while trying to test error propagation";
1206 TEST_F(CoreAPIsStandardTest, FailAfterPartialResolution) {
1208 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}})));
1210 // Fail materialization of bar.
1211 auto BarMU = std::make_unique<SimpleMaterializationUnit>(
1212 SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
1213 [&](std::unique_ptr<MaterializationResponsibility> R) {
1214 R->failMaterialization();
1217 cantFail(JD.define(std::move(BarMU)));
1219 bool QueryHandlerRun = false;
1220 ES.lookup(
1221 LookupKind::Static, makeJITDylibSearchOrder(&JD),
1222 SymbolLookupSet({Foo, Bar}), SymbolState::Resolved,
1223 [&](Expected<SymbolMap> Result) {
1224 EXPECT_THAT_EXPECTED(std::move(Result), Failed())
1225 << "Expected query to fail";
1226 QueryHandlerRun = true;
1228 NoDependenciesToRegister);
1229 EXPECT_TRUE(QueryHandlerRun) << "Query handler never ran";
1232 TEST_F(CoreAPIsStandardTest, TestLookupWithUnthreadedMaterialization) {
1233 auto MU = std::make_unique<SimpleMaterializationUnit>(
1234 SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}}),
1235 [&](std::unique_ptr<MaterializationResponsibility> R) {
1236 cantFail(R->notifyResolved({{Foo, FooSym}}));
1237 cantFail(R->notifyEmitted());
1240 cantFail(JD.define(MU));
1242 auto FooLookupResult = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Foo));
1244 EXPECT_EQ(FooLookupResult.getAddress(), FooSym.getAddress())
1245 << "lookup returned an incorrect address";
1246 EXPECT_EQ(FooLookupResult.getFlags(), FooSym.getFlags())
1247 << "lookup returned incorrect flags";
1250 TEST_F(CoreAPIsStandardTest, TestLookupWithThreadedMaterialization) {
1251 #if LLVM_ENABLE_THREADS
1253 std::mutex WorkThreadsMutex;
1254 std::vector<std::thread> WorkThreads;
1255 ES.setDispatchTask([&](std::unique_ptr<Task> T) {
1256 std::promise<void> WaitP;
1257 std::lock_guard<std::mutex> Lock(WorkThreadsMutex);
1258 WorkThreads.push_back(
1259 std::thread([T = std::move(T), WaitF = WaitP.get_future()]() mutable {
1260 WaitF.get();
1261 T->run();
1262 }));
1263 WaitP.set_value();
1266 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}})));
1268 auto FooLookupResult = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Foo));
1270 EXPECT_EQ(FooLookupResult.getAddress(), FooSym.getAddress())
1271 << "lookup returned an incorrect address";
1272 EXPECT_EQ(FooLookupResult.getFlags(), FooSym.getFlags())
1273 << "lookup returned incorrect flags";
1275 for (auto &WT : WorkThreads)
1276 WT.join();
1277 #endif
1280 TEST_F(CoreAPIsStandardTest, TestGetRequestedSymbolsAndReplace) {
1281 // Test that GetRequestedSymbols returns the set of symbols that currently
1282 // have pending queries, and test that MaterializationResponsibility's
1283 // replace method can be used to return definitions to the JITDylib in a new
1284 // MaterializationUnit.
1285 SymbolNameSet Names({Foo, Bar});
1287 bool FooMaterialized = false;
1288 bool BarMaterialized = false;
1290 auto MU = std::make_unique<SimpleMaterializationUnit>(
1291 SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}),
1292 [&](std::unique_ptr<MaterializationResponsibility> R) {
1293 auto Requested = R->getRequestedSymbols();
1294 EXPECT_EQ(Requested.size(), 1U) << "Expected one symbol requested";
1295 EXPECT_EQ(*Requested.begin(), Foo) << "Expected \"Foo\" requested";
1297 auto NewMU = std::make_unique<SimpleMaterializationUnit>(
1298 SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
1299 [&](std::unique_ptr<MaterializationResponsibility> R2) {
1300 cantFail(R2->notifyResolved(SymbolMap({{Bar, BarSym}})));
1301 cantFail(R2->notifyEmitted());
1302 BarMaterialized = true;
1305 cantFail(R->replace(std::move(NewMU)));
1307 cantFail(R->notifyResolved(SymbolMap({{Foo, FooSym}})));
1308 cantFail(R->notifyEmitted());
1310 FooMaterialized = true;
1313 cantFail(JD.define(MU));
1315 EXPECT_FALSE(FooMaterialized) << "Foo should not be materialized yet";
1316 EXPECT_FALSE(BarMaterialized) << "Bar should not be materialized yet";
1318 auto FooSymResult = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Foo));
1319 EXPECT_EQ(FooSymResult.getAddress(), FooSym.getAddress())
1320 << "Address mismatch for Foo";
1322 EXPECT_TRUE(FooMaterialized) << "Foo should be materialized now";
1323 EXPECT_FALSE(BarMaterialized) << "Bar still should not be materialized";
1325 auto BarSymResult = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Bar));
1326 EXPECT_EQ(BarSymResult.getAddress(), BarSym.getAddress())
1327 << "Address mismatch for Bar";
1328 EXPECT_TRUE(BarMaterialized) << "Bar should be materialized now";
1331 TEST_F(CoreAPIsStandardTest, TestMaterializationResponsibilityDelegation) {
1332 auto MU = std::make_unique<SimpleMaterializationUnit>(
1333 SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}),
1334 [&](std::unique_ptr<MaterializationResponsibility> R) {
1335 auto R2 = cantFail(R->delegate({Bar}));
1337 cantFail(R->notifyResolved({{Foo, FooSym}}));
1338 cantFail(R->notifyEmitted());
1339 cantFail(R2->notifyResolved({{Bar, BarSym}}));
1340 cantFail(R2->notifyEmitted());
1343 cantFail(JD.define(MU));
1345 auto Result =
1346 ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Foo, Bar}));
1348 EXPECT_TRUE(!!Result) << "Result should be a success value";
1349 EXPECT_EQ(Result->count(Foo), 1U) << "\"Foo\" entry missing";
1350 EXPECT_EQ(Result->count(Bar), 1U) << "\"Bar\" entry missing";
1351 EXPECT_EQ((*Result)[Foo].getAddress(), FooSym.getAddress())
1352 << "Address mismatch for \"Foo\"";
1353 EXPECT_EQ((*Result)[Bar].getAddress(), BarSym.getAddress())
1354 << "Address mismatch for \"Bar\"";
1357 TEST_F(CoreAPIsStandardTest, TestMaterializeWeakSymbol) {
1358 // Confirm that once a weak definition is selected for materialization it is
1359 // treated as strong.
1360 JITSymbolFlags WeakExported = JITSymbolFlags::Exported;
1361 WeakExported &= JITSymbolFlags::Weak;
1363 std::unique_ptr<MaterializationResponsibility> FooR;
1364 auto MU = std::make_unique<SimpleMaterializationUnit>(
1365 SymbolFlagsMap({{Foo, FooSym.getFlags()}}),
1366 [&](std::unique_ptr<MaterializationResponsibility> R) {
1367 FooR = std::move(R);
1370 cantFail(JD.define(MU));
1371 auto OnCompletion = [](Expected<SymbolMap> Result) {
1372 cantFail(std::move(Result));
1375 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD),
1376 SymbolLookupSet({Foo}), SymbolState::Ready, std::move(OnCompletion),
1377 NoDependenciesToRegister);
1379 auto MU2 = std::make_unique<SimpleMaterializationUnit>(
1380 SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}}),
1381 [](std::unique_ptr<MaterializationResponsibility> R) {
1382 llvm_unreachable("This unit should never be materialized");
1385 auto Err = JD.define(MU2);
1386 EXPECT_TRUE(!!Err) << "Expected failure value";
1387 EXPECT_TRUE(Err.isA<DuplicateDefinition>())
1388 << "Expected a duplicate definition error";
1389 consumeError(std::move(Err));
1391 // No dependencies registered, can't fail:
1392 cantFail(FooR->notifyResolved(SymbolMap({{Foo, FooSym}})));
1393 cantFail(FooR->notifyEmitted());
1396 static bool linkOrdersEqual(const std::vector<JITDylibSP> &LHS,
1397 ArrayRef<JITDylib *> RHS) {
1398 if (LHS.size() != RHS.size())
1399 return false;
1400 auto *RHSE = RHS.begin();
1401 for (auto &LHSE : LHS)
1402 if (LHSE.get() != *RHSE)
1403 return false;
1404 else
1405 ++RHSE;
1406 return true;
1409 TEST(JITDylibTest, GetDFSLinkOrderTree) {
1410 // Test that DFS ordering behaves as expected when the linkage relationships
1411 // form a tree.
1413 ExecutionSession ES{std::make_unique<UnsupportedExecutorProcessControl>()};
1414 auto _ = make_scope_exit([&]() { cantFail(ES.endSession()); });
1416 auto &LibA = ES.createBareJITDylib("A");
1417 auto &LibB = ES.createBareJITDylib("B");
1418 auto &LibC = ES.createBareJITDylib("C");
1419 auto &LibD = ES.createBareJITDylib("D");
1420 auto &LibE = ES.createBareJITDylib("E");
1421 auto &LibF = ES.createBareJITDylib("F");
1423 // Linkage relationships:
1424 // A --- B -- D
1425 // \ \- E
1426 // \- C -- F
1427 LibA.setLinkOrder(makeJITDylibSearchOrder({&LibB, &LibC}));
1428 LibB.setLinkOrder(makeJITDylibSearchOrder({&LibD, &LibE}));
1429 LibC.setLinkOrder(makeJITDylibSearchOrder({&LibF}));
1431 auto DFSOrderFromB = cantFail(JITDylib::getDFSLinkOrder({&LibB}));
1432 EXPECT_TRUE(linkOrdersEqual(DFSOrderFromB, {&LibB, &LibD, &LibE}))
1433 << "Incorrect DFS link order for LibB";
1435 auto DFSOrderFromA = cantFail(JITDylib::getDFSLinkOrder({&LibA}));
1436 EXPECT_TRUE(linkOrdersEqual(DFSOrderFromA,
1437 {&LibA, &LibB, &LibD, &LibE, &LibC, &LibF}))
1438 << "Incorrect DFS link order for libA";
1440 auto DFSOrderFromAB = cantFail(JITDylib::getDFSLinkOrder({&LibA, &LibB}));
1441 EXPECT_TRUE(linkOrdersEqual(DFSOrderFromAB,
1442 {&LibA, &LibB, &LibD, &LibE, &LibC, &LibF}))
1443 << "Incorrect DFS link order for { libA, libB }";
1445 auto DFSOrderFromBA = cantFail(JITDylib::getDFSLinkOrder({&LibB, &LibA}));
1446 EXPECT_TRUE(linkOrdersEqual(DFSOrderFromBA,
1447 {&LibB, &LibD, &LibE, &LibA, &LibC, &LibF}))
1448 << "Incorrect DFS link order for { libB, libA }";
1451 TEST(JITDylibTest, GetDFSLinkOrderDiamond) {
1452 // Test that DFS ordering behaves as expected when the linkage relationships
1453 // contain a diamond.
1455 ExecutionSession ES{std::make_unique<UnsupportedExecutorProcessControl>()};
1456 auto _ = make_scope_exit([&]() { cantFail(ES.endSession()); });
1458 auto &LibA = ES.createBareJITDylib("A");
1459 auto &LibB = ES.createBareJITDylib("B");
1460 auto &LibC = ES.createBareJITDylib("C");
1461 auto &LibD = ES.createBareJITDylib("D");
1463 // Linkage relationships:
1464 // A -- B --- D
1465 // \-- C --/
1466 LibA.setLinkOrder(makeJITDylibSearchOrder({&LibB, &LibC}));
1467 LibB.setLinkOrder(makeJITDylibSearchOrder({&LibD}));
1468 LibC.setLinkOrder(makeJITDylibSearchOrder({&LibD}));
1470 auto DFSOrderFromA = cantFail(JITDylib::getDFSLinkOrder({&LibA}));
1471 EXPECT_TRUE(linkOrdersEqual(DFSOrderFromA, {&LibA, &LibB, &LibD, &LibC}))
1472 << "Incorrect DFS link order for libA";
1475 TEST(JITDylibTest, GetDFSLinkOrderCycle) {
1476 // Test that DFS ordering behaves as expected when the linkage relationships
1477 // contain a cycle.
1479 ExecutionSession ES{std::make_unique<UnsupportedExecutorProcessControl>()};
1480 auto _ = make_scope_exit([&]() { cantFail(ES.endSession()); });
1482 auto &LibA = ES.createBareJITDylib("A");
1483 auto &LibB = ES.createBareJITDylib("B");
1484 auto &LibC = ES.createBareJITDylib("C");
1486 // Linkage relationships:
1487 // A -- B --- C -- A
1488 LibA.setLinkOrder(makeJITDylibSearchOrder({&LibB}));
1489 LibB.setLinkOrder(makeJITDylibSearchOrder({&LibC}));
1490 LibC.setLinkOrder(makeJITDylibSearchOrder({&LibA}));
1492 auto DFSOrderFromA = cantFail(JITDylib::getDFSLinkOrder({&LibA}));
1493 EXPECT_TRUE(linkOrdersEqual(DFSOrderFromA, {&LibA, &LibB, &LibC}))
1494 << "Incorrect DFS link order for libA";
1496 auto DFSOrderFromB = cantFail(JITDylib::getDFSLinkOrder({&LibB}));
1497 EXPECT_TRUE(linkOrdersEqual(DFSOrderFromB, {&LibB, &LibC, &LibA}))
1498 << "Incorrect DFS link order for libB";
1500 auto DFSOrderFromC = cantFail(JITDylib::getDFSLinkOrder({&LibC}));
1501 EXPECT_TRUE(linkOrdersEqual(DFSOrderFromC, {&LibC, &LibA, &LibB}))
1502 << "Incorrect DFS link order for libC";
1505 TEST_F(CoreAPIsStandardTest, RemoveJITDylibs) {
1506 // Foo will be fully materialized.
1507 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}})));
1509 // Bar should not be materialized at all.
1510 bool BarMaterializerDestroyed = false;
1511 cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(
1512 SymbolFlagsMap({{Bar, BarSym.getFlags()}}),
1513 [&](std::unique_ptr<MaterializationResponsibility> MR) {
1514 llvm_unreachable("Unexpected call to materialize");
1516 nullptr,
1517 [](const JITDylib &, SymbolStringPtr Name) {
1518 llvm_unreachable("Unexpected call to discard");
1520 [&]() { BarMaterializerDestroyed = true; })));
1522 // Baz will be in the materializing state.
1523 std::unique_ptr<MaterializationResponsibility> BazMR;
1524 cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(
1525 SymbolFlagsMap({{Baz, BazSym.getFlags()}}),
1526 [&](std::unique_ptr<MaterializationResponsibility> MR) {
1527 BazMR = std::move(MR);
1528 })));
1530 // Lookup to force materialization of Foo.
1531 cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Foo})));
1533 // Start a lookup to force materialization of Baz.
1534 bool BazLookupFailed = false;
1535 ES.lookup(
1536 LookupKind::Static, makeJITDylibSearchOrder(&JD), SymbolLookupSet({Baz}),
1537 SymbolState::Ready,
1538 [&](Expected<SymbolMap> Result) {
1539 if (!Result) {
1540 BazLookupFailed = true;
1541 consumeError(Result.takeError());
1544 NoDependenciesToRegister);
1546 // Remove the JITDylib.
1547 auto Err = ES.removeJITDylib(JD);
1548 EXPECT_THAT_ERROR(std::move(Err), Succeeded());
1550 EXPECT_TRUE(BarMaterializerDestroyed);
1551 EXPECT_TRUE(BazLookupFailed);
1553 EXPECT_THAT_ERROR(BazMR->notifyResolved({{Baz, BazSym}}), Failed());
1555 EXPECT_THAT_EXPECTED(JD.getDFSLinkOrder(), Failed());
1557 BazMR->failMaterialization();
1560 TEST(CoreAPIsExtraTest, SessionTeardownByFailedToMaterialize) {
1562 auto RunTestCase = []() -> Error {
1563 ExecutionSession ES{std::make_unique<UnsupportedExecutorProcessControl>(
1564 std::make_shared<SymbolStringPool>())};
1565 auto Foo = ES.intern("foo");
1566 auto FooFlags = JITSymbolFlags::Exported;
1568 auto &JD = ES.createBareJITDylib("Foo");
1569 cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>(
1570 SymbolFlagsMap({{Foo, FooFlags}}),
1571 [&](std::unique_ptr<MaterializationResponsibility> R) {
1572 R->failMaterialization();
1573 })));
1575 auto Sym = ES.lookup({&JD}, Foo);
1576 assert(!Sym && "Query should have failed");
1577 cantFail(ES.endSession());
1578 return Sym.takeError();
1581 auto Err = RunTestCase();
1582 EXPECT_TRUE(!!Err); // Expect that error occurred.
1583 EXPECT_TRUE(
1584 Err.isA<FailedToMaterialize>()); // Expect FailedToMaterialize error.
1586 // Make sure that we can log errors, even though the session has been
1587 // destroyed.
1588 logAllUnhandledErrors(std::move(Err), nulls(), "");
1591 } // namespace