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 //===----------------------------------------------------------------------===// 8 9 #include "OrcTestCommon.h" 10 #include "llvm/Config/llvm-config.h" 11 #include "llvm/ExecutionEngine/Orc/Core.h" 12 #include "llvm/ExecutionEngine/Orc/Shared/OrcError.h" 13 #include "llvm/Testing/Support/Error.h" 14 15 #include <set> 16 #include <thread> 17 18 using namespace llvm; 19 using namespace llvm::orc; 20 21 class CoreAPIsStandardTest : public CoreAPIsBasedStandardTest {}; 22 23 namespace { 24 25 TEST_F(CoreAPIsStandardTest, BasicSuccessfulLookup) { 26 bool OnCompletionRun = false; 27 28 auto OnCompletion = [&](Expected<SymbolMap> Result) { 29 EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error"; 30 auto &Resolved = *Result; 31 auto I = Resolved.find(Foo); 32 EXPECT_NE(I, Resolved.end()) << "Could not find symbol definition"; 33 EXPECT_EQ(I->second.getAddress(), FooAddr) 34 << "Resolution returned incorrect result"; 35 OnCompletionRun = true; 36 }; 37 38 std::unique_ptr<MaterializationResponsibility> FooMR; 39 40 cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>( 41 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 42 [&](std::unique_ptr<MaterializationResponsibility> R) { 43 FooMR = std::move(R); 44 }))); 45 46 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 47 SymbolLookupSet(Foo), SymbolState::Ready, OnCompletion, 48 NoDependenciesToRegister); 49 50 EXPECT_FALSE(OnCompletionRun) << "Should not have been resolved yet"; 51 52 cantFail(FooMR->notifyResolved({{Foo, FooSym}})); 53 54 EXPECT_FALSE(OnCompletionRun) << "Should not be ready yet"; 55 56 cantFail(FooMR->notifyEmitted()); 57 58 EXPECT_TRUE(OnCompletionRun) << "Should have been marked ready"; 59 } 60 61 TEST_F(CoreAPIsStandardTest, EmptyLookup) { 62 bool OnCompletionRun = false; 63 64 auto OnCompletion = [&](Expected<SymbolMap> Result) { 65 cantFail(std::move(Result)); 66 OnCompletionRun = true; 67 }; 68 69 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), SymbolLookupSet(), 70 SymbolState::Ready, OnCompletion, NoDependenciesToRegister); 71 72 EXPECT_TRUE(OnCompletionRun) << "OnCompletion was not run for empty query"; 73 } 74 75 TEST_F(CoreAPIsStandardTest, ResolveUnrequestedSymbol) { 76 // Test that all symbols in a MaterializationUnit materialize corretly when 77 // only a subset of symbols is looked up. 78 // The aim here is to ensure that we're not relying on the query to set up 79 // state needed to materialize the unrequested symbols. 80 81 cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>( 82 SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}), 83 [this](std::unique_ptr<MaterializationResponsibility> R) { 84 cantFail(R->notifyResolved({{Foo, FooSym}, {Bar, BarSym}})); 85 cantFail(R->notifyEmitted()); 86 }))); 87 88 auto Result = 89 cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Foo}))); 90 EXPECT_EQ(Result.size(), 1U) << "Unexpected number of results"; 91 EXPECT_TRUE(Result.count(Foo)) << "Expected result for \"Foo\""; 92 } 93 94 TEST_F(CoreAPIsStandardTest, MaterializationSideEffctsOnlyBasic) { 95 // Test that basic materialization-side-effects-only symbols work as expected: 96 // that they can be emitted without being resolved, that queries for them 97 // don't return until they're emitted, and that they don't appear in query 98 // results. 99 100 std::unique_ptr<MaterializationResponsibility> FooR; 101 Optional<SymbolMap> Result; 102 103 cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>( 104 SymbolFlagsMap( 105 {{Foo, JITSymbolFlags::Exported | 106 JITSymbolFlags::MaterializationSideEffectsOnly}}), 107 [&](std::unique_ptr<MaterializationResponsibility> R) { 108 FooR = std::move(R); 109 }))); 110 111 ES.lookup( 112 LookupKind::Static, makeJITDylibSearchOrder(&JD), 113 SymbolLookupSet(Foo, SymbolLookupFlags::WeaklyReferencedSymbol), 114 SymbolState::Ready, 115 [&](Expected<SymbolMap> LookupResult) { 116 if (LookupResult) 117 Result = std::move(*LookupResult); 118 else 119 ADD_FAILURE() << "Unexpected lookup error: " 120 << toString(LookupResult.takeError()); 121 }, 122 NoDependenciesToRegister); 123 124 EXPECT_FALSE(Result) << "Lookup returned unexpectedly"; 125 EXPECT_TRUE(FooR) << "Lookup failed to trigger materialization"; 126 EXPECT_THAT_ERROR(FooR->notifyEmitted(), Succeeded()) 127 << "Emission of materialization-side-effects-only symbol failed"; 128 129 EXPECT_TRUE(Result) << "Lookup failed to return"; 130 EXPECT_TRUE(Result->empty()) << "Lookup result contained unexpected value"; 131 } 132 133 TEST_F(CoreAPIsStandardTest, MaterializationSideEffectsOnlyFailuresPersist) { 134 // Test that when a MaterializationSideEffectsOnly symbol is failed it 135 // remains in the failure state rather than vanishing. 136 137 cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>( 138 SymbolFlagsMap( 139 {{Foo, JITSymbolFlags::Exported | 140 JITSymbolFlags::MaterializationSideEffectsOnly}}), 141 [&](std::unique_ptr<MaterializationResponsibility> R) { 142 R->failMaterialization(); 143 }))); 144 145 EXPECT_THAT_EXPECTED( 146 ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Foo})), 147 Failed()); 148 EXPECT_THAT_EXPECTED( 149 ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Foo})), 150 Failed()); 151 } 152 153 TEST_F(CoreAPIsStandardTest, RemoveSymbolsTest) { 154 // Test that: 155 // (1) Missing symbols generate a SymbolsNotFound error. 156 // (2) Materializing symbols generate a SymbolCouldNotBeRemoved error. 157 // (3) Removal of unmaterialized symbols triggers discard on the 158 // materialization unit. 159 // (4) Removal of symbols destroys empty materialization units. 160 // (5) Removal of materialized symbols works. 161 162 // Foo will be fully materialized. 163 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 164 165 // Bar will be unmaterialized. 166 bool BarDiscarded = false; 167 bool BarMaterializerDestructed = false; 168 cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>( 169 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 170 [this](std::unique_ptr<MaterializationResponsibility> R) { 171 ADD_FAILURE() << "Unexpected materialization of \"Bar\""; 172 cantFail(R->notifyResolved({{Bar, BarSym}})); 173 cantFail(R->notifyEmitted()); 174 }, 175 nullptr, 176 [&](const JITDylib &JD, const SymbolStringPtr &Name) { 177 EXPECT_EQ(Name, Bar) << "Expected \"Bar\" to be discarded"; 178 if (Name == Bar) 179 BarDiscarded = true; 180 }, 181 [&]() { BarMaterializerDestructed = true; }))); 182 183 // Baz will be in the materializing state initially, then 184 // materialized for the final removal attempt. 185 std::unique_ptr<MaterializationResponsibility> BazR; 186 cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>( 187 SymbolFlagsMap({{Baz, BazSym.getFlags()}}), 188 [&](std::unique_ptr<MaterializationResponsibility> R) { 189 BazR = std::move(R); 190 }, 191 nullptr, 192 [](const JITDylib &JD, const SymbolStringPtr &Name) { 193 ADD_FAILURE() << "\"Baz\" discarded unexpectedly"; 194 }))); 195 196 bool OnCompletionRun = false; 197 ES.lookup( 198 LookupKind::Static, makeJITDylibSearchOrder(&JD), 199 SymbolLookupSet({Foo, Baz}), SymbolState::Ready, 200 [&](Expected<SymbolMap> Result) { 201 cantFail(Result.takeError()); 202 OnCompletionRun = true; 203 }, 204 NoDependenciesToRegister); 205 206 { 207 // Attempt 1: Search for a missing symbol, Qux. 208 auto Err = JD.remove({Foo, Bar, Baz, Qux}); 209 EXPECT_TRUE(!!Err) << "Expected failure"; 210 EXPECT_TRUE(Err.isA<SymbolsNotFound>()) 211 << "Expected a SymbolsNotFound error"; 212 consumeError(std::move(Err)); 213 } 214 215 { 216 // Attempt 2: Search for a symbol that is still materializing, Baz. 217 auto Err = JD.remove({Foo, Bar, Baz}); 218 EXPECT_TRUE(!!Err) << "Expected failure"; 219 EXPECT_TRUE(Err.isA<SymbolsCouldNotBeRemoved>()) 220 << "Expected a SymbolsNotFound error"; 221 consumeError(std::move(Err)); 222 } 223 224 cantFail(BazR->notifyResolved({{Baz, BazSym}})); 225 cantFail(BazR->notifyEmitted()); 226 { 227 // Attempt 3: Search now that all symbols are fully materialized 228 // (Foo, Baz), or not yet materialized (Bar). 229 auto Err = JD.remove({Foo, Bar, Baz}); 230 EXPECT_FALSE(!!Err) << "Expected success"; 231 } 232 233 EXPECT_TRUE(BarDiscarded) << "\"Bar\" should have been discarded"; 234 EXPECT_TRUE(BarMaterializerDestructed) 235 << "\"Bar\"'s materializer should have been destructed"; 236 EXPECT_TRUE(OnCompletionRun) << "OnCompletion should have been run"; 237 } 238 239 TEST_F(CoreAPIsStandardTest, LookupWithHiddenSymbols) { 240 auto BarHiddenFlags = BarSym.getFlags() & ~JITSymbolFlags::Exported; 241 auto BarHiddenSym = JITEvaluatedSymbol(BarSym.getAddress(), BarHiddenFlags); 242 243 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}, {Bar, BarHiddenSym}}))); 244 245 auto &JD2 = ES.createBareJITDylib("JD2"); 246 cantFail(JD2.define(absoluteSymbols({{Bar, QuxSym}}))); 247 248 /// Try a blocking lookup. 249 auto Result = cantFail(ES.lookup(makeJITDylibSearchOrder({&JD, &JD2}), 250 SymbolLookupSet({Foo, Bar}))); 251 252 EXPECT_EQ(Result.size(), 2U) << "Unexpected number of results"; 253 EXPECT_EQ(Result.count(Foo), 1U) << "Missing result for \"Foo\""; 254 EXPECT_EQ(Result.count(Bar), 1U) << "Missing result for \"Bar\""; 255 EXPECT_EQ(Result[Bar].getAddress(), QuxSym.getAddress()) 256 << "Wrong result for \"Bar\""; 257 } 258 259 TEST_F(CoreAPIsStandardTest, LookupFlagsTest) { 260 // Test that lookupFlags works on a predefined symbol, and does not trigger 261 // materialization of a lazy symbol. Make the lazy symbol weak to test that 262 // the weak flag is propagated correctly. 263 264 BarSym.setFlags(static_cast<JITSymbolFlags::FlagNames>( 265 JITSymbolFlags::Exported | JITSymbolFlags::Weak)); 266 auto MU = std::make_unique<SimpleMaterializationUnit>( 267 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 268 [](std::unique_ptr<MaterializationResponsibility> R) { 269 llvm_unreachable("Symbol materialized on flags lookup"); 270 }); 271 272 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 273 cantFail(JD.define(std::move(MU))); 274 275 auto SymbolFlags = cantFail(ES.lookupFlags( 276 LookupKind::Static, 277 {{&JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}}, 278 SymbolLookupSet({Foo, Bar, Baz}, 279 SymbolLookupFlags::WeaklyReferencedSymbol))); 280 281 EXPECT_EQ(SymbolFlags.size(), 2U) 282 << "Returned symbol flags contains unexpected results"; 283 EXPECT_EQ(SymbolFlags.count(Foo), 1U) << "Missing lookupFlags result for Foo"; 284 EXPECT_EQ(SymbolFlags[Foo], FooSym.getFlags()) 285 << "Incorrect flags returned for Foo"; 286 EXPECT_EQ(SymbolFlags.count(Bar), 1U) 287 << "Missing lookupFlags result for Bar"; 288 EXPECT_EQ(SymbolFlags[Bar], BarSym.getFlags()) 289 << "Incorrect flags returned for Bar"; 290 } 291 292 TEST_F(CoreAPIsStandardTest, LookupWithGeneratorFailure) { 293 294 class BadGenerator : public DefinitionGenerator { 295 public: 296 Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &, 297 JITDylibLookupFlags, const SymbolLookupSet &) override { 298 return make_error<StringError>("BadGenerator", inconvertibleErrorCode()); 299 } 300 }; 301 302 JD.addGenerator(std::make_unique<BadGenerator>()); 303 304 EXPECT_THAT_ERROR( 305 ES.lookupFlags(LookupKind::Static, 306 {{&JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}}, 307 SymbolLookupSet(Foo)) 308 .takeError(), 309 Failed<StringError>()) 310 << "Generator failure did not propagate through lookupFlags"; 311 312 EXPECT_THAT_ERROR( 313 ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet(Foo)).takeError(), 314 Failed<StringError>()) 315 << "Generator failure did not propagate through lookup"; 316 } 317 318 TEST_F(CoreAPIsStandardTest, TestBasicAliases) { 319 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}, {Bar, BarSym}}))); 320 cantFail(JD.define(symbolAliases({{Baz, {Foo, JITSymbolFlags::Exported}}, 321 {Qux, {Bar, JITSymbolFlags::Weak}}}))); 322 cantFail(JD.define(absoluteSymbols({{Qux, QuxSym}}))); 323 324 auto Result = 325 ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Baz, Qux})); 326 EXPECT_TRUE(!!Result) << "Unexpected lookup failure"; 327 EXPECT_EQ(Result->count(Baz), 1U) << "No result for \"baz\""; 328 EXPECT_EQ(Result->count(Qux), 1U) << "No result for \"qux\""; 329 EXPECT_EQ((*Result)[Baz].getAddress(), FooSym.getAddress()) 330 << "\"Baz\"'s address should match \"Foo\"'s"; 331 EXPECT_EQ((*Result)[Qux].getAddress(), QuxSym.getAddress()) 332 << "The \"Qux\" alias should have been overriden"; 333 } 334 335 TEST_F(CoreAPIsStandardTest, TestChainedAliases) { 336 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 337 cantFail(JD.define(symbolAliases( 338 {{Baz, {Bar, BazSym.getFlags()}}, {Bar, {Foo, BarSym.getFlags()}}}))); 339 340 auto Result = 341 ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Bar, Baz})); 342 EXPECT_TRUE(!!Result) << "Unexpected lookup failure"; 343 EXPECT_EQ(Result->count(Bar), 1U) << "No result for \"bar\""; 344 EXPECT_EQ(Result->count(Baz), 1U) << "No result for \"baz\""; 345 EXPECT_EQ((*Result)[Bar].getAddress(), FooSym.getAddress()) 346 << "\"Bar\"'s address should match \"Foo\"'s"; 347 EXPECT_EQ((*Result)[Baz].getAddress(), FooSym.getAddress()) 348 << "\"Baz\"'s address should match \"Foo\"'s"; 349 } 350 351 TEST_F(CoreAPIsStandardTest, TestBasicReExports) { 352 // Test that the basic use case of re-exporting a single symbol from another 353 // JITDylib works. 354 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 355 356 auto &JD2 = ES.createBareJITDylib("JD2"); 357 358 cantFail(JD2.define(reexports(JD, {{Bar, {Foo, BarSym.getFlags()}}}))); 359 360 auto Result = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD2), Bar)); 361 EXPECT_EQ(Result.getAddress(), FooSym.getAddress()) 362 << "Re-export Bar for symbol Foo should match FooSym's address"; 363 } 364 365 TEST_F(CoreAPIsStandardTest, TestThatReExportsDontUnnecessarilyMaterialize) { 366 // Test that re-exports do not materialize symbols that have not been queried 367 // for. 368 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 369 370 bool BarMaterialized = false; 371 auto BarMU = std::make_unique<SimpleMaterializationUnit>( 372 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 373 [&](std::unique_ptr<MaterializationResponsibility> R) { 374 BarMaterialized = true; 375 cantFail(R->notifyResolved({{Bar, BarSym}})); 376 cantFail(R->notifyEmitted()); 377 }); 378 379 cantFail(JD.define(BarMU)); 380 381 auto &JD2 = ES.createBareJITDylib("JD2"); 382 383 cantFail(JD2.define(reexports( 384 JD, {{Baz, {Foo, BazSym.getFlags()}}, {Qux, {Bar, QuxSym.getFlags()}}}))); 385 386 auto Result = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD2), Baz)); 387 EXPECT_EQ(Result.getAddress(), FooSym.getAddress()) 388 << "Re-export Baz for symbol Foo should match FooSym's address"; 389 390 EXPECT_FALSE(BarMaterialized) << "Bar should not have been materialized"; 391 } 392 393 TEST_F(CoreAPIsStandardTest, TestReexportsGenerator) { 394 // Test that a re-exports generator can dynamically generate reexports. 395 396 auto &JD2 = ES.createBareJITDylib("JD2"); 397 cantFail(JD2.define(absoluteSymbols({{Foo, FooSym}, {Bar, BarSym}}))); 398 399 auto Filter = [this](SymbolStringPtr Name) { return Name != Bar; }; 400 401 JD.addGenerator(std::make_unique<ReexportsGenerator>( 402 JD2, JITDylibLookupFlags::MatchExportedSymbolsOnly, Filter)); 403 404 auto Flags = cantFail(ES.lookupFlags( 405 LookupKind::Static, 406 {{&JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}}, 407 SymbolLookupSet({Foo, Bar, Baz}, 408 SymbolLookupFlags::WeaklyReferencedSymbol))); 409 EXPECT_EQ(Flags.size(), 1U) << "Unexpected number of results"; 410 EXPECT_EQ(Flags[Foo], FooSym.getFlags()) << "Unexpected flags for Foo"; 411 412 auto Result = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Foo)); 413 414 EXPECT_EQ(Result.getAddress(), FooSym.getAddress()) 415 << "Incorrect reexported symbol address"; 416 } 417 418 TEST_F(CoreAPIsStandardTest, TestTrivialCircularDependency) { 419 std::unique_ptr<MaterializationResponsibility> FooR; 420 auto FooMU = std::make_unique<SimpleMaterializationUnit>( 421 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 422 [&](std::unique_ptr<MaterializationResponsibility> R) { 423 FooR = std::move(R); 424 }); 425 426 cantFail(JD.define(FooMU)); 427 428 bool FooReady = false; 429 auto OnCompletion = [&](Expected<SymbolMap> Result) { 430 cantFail(std::move(Result)); 431 FooReady = true; 432 }; 433 434 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 435 SymbolLookupSet({Foo}), SymbolState::Ready, OnCompletion, 436 NoDependenciesToRegister); 437 438 FooR->addDependenciesForAll({{&JD, SymbolNameSet({Foo})}}); 439 EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Succeeded()) 440 << "No symbols marked failed, but Foo failed to resolve"; 441 EXPECT_THAT_ERROR(FooR->notifyEmitted(), Succeeded()) 442 << "No symbols marked failed, but Foo failed to emit"; 443 444 EXPECT_TRUE(FooReady) 445 << "Self-dependency prevented symbol from being marked ready"; 446 } 447 448 TEST_F(CoreAPIsStandardTest, TestCircularDependenceInOneJITDylib) { 449 // Test that a circular symbol dependency between three symbols in a JITDylib 450 // does not prevent any symbol from becoming 'ready' once all symbols are 451 // emitted. 452 453 std::unique_ptr<MaterializationResponsibility> FooR; 454 std::unique_ptr<MaterializationResponsibility> BarR; 455 std::unique_ptr<MaterializationResponsibility> BazR; 456 457 // Create a MaterializationUnit for each symbol that moves the 458 // MaterializationResponsibility into one of the locals above. 459 auto FooMU = std::make_unique<SimpleMaterializationUnit>( 460 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 461 [&](std::unique_ptr<MaterializationResponsibility> R) { 462 FooR = std::move(R); 463 }); 464 465 auto BarMU = std::make_unique<SimpleMaterializationUnit>( 466 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 467 [&](std::unique_ptr<MaterializationResponsibility> R) { 468 BarR = std::move(R); 469 }); 470 471 auto BazMU = std::make_unique<SimpleMaterializationUnit>( 472 SymbolFlagsMap({{Baz, BazSym.getFlags()}}), 473 [&](std::unique_ptr<MaterializationResponsibility> R) { 474 BazR = std::move(R); 475 }); 476 477 // Define the symbols. 478 cantFail(JD.define(FooMU)); 479 cantFail(JD.define(BarMU)); 480 cantFail(JD.define(BazMU)); 481 482 // Query each of the symbols to trigger materialization. 483 bool FooResolved = false; 484 bool FooReady = false; 485 486 auto OnFooResolution = [&](Expected<SymbolMap> Result) { 487 cantFail(std::move(Result)); 488 FooResolved = true; 489 }; 490 491 auto OnFooReady = [&](Expected<SymbolMap> Result) { 492 cantFail(std::move(Result)); 493 FooReady = true; 494 }; 495 496 // Issue lookups for Foo. Use NoDependenciesToRegister: We're going to add 497 // the dependencies manually below. 498 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 499 SymbolLookupSet(Foo), SymbolState::Resolved, 500 std::move(OnFooResolution), NoDependenciesToRegister); 501 502 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 503 SymbolLookupSet(Foo), SymbolState::Ready, std::move(OnFooReady), 504 NoDependenciesToRegister); 505 506 bool BarResolved = false; 507 bool BarReady = false; 508 auto OnBarResolution = [&](Expected<SymbolMap> Result) { 509 cantFail(std::move(Result)); 510 BarResolved = true; 511 }; 512 513 auto OnBarReady = [&](Expected<SymbolMap> Result) { 514 cantFail(std::move(Result)); 515 BarReady = true; 516 }; 517 518 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 519 SymbolLookupSet(Bar), SymbolState::Resolved, 520 std::move(OnBarResolution), NoDependenciesToRegister); 521 522 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 523 SymbolLookupSet(Bar), SymbolState::Ready, std::move(OnBarReady), 524 NoDependenciesToRegister); 525 526 bool BazResolved = false; 527 bool BazReady = false; 528 529 auto OnBazResolution = [&](Expected<SymbolMap> Result) { 530 cantFail(std::move(Result)); 531 BazResolved = true; 532 }; 533 534 auto OnBazReady = [&](Expected<SymbolMap> Result) { 535 cantFail(std::move(Result)); 536 BazReady = true; 537 }; 538 539 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 540 SymbolLookupSet(Baz), SymbolState::Resolved, 541 std::move(OnBazResolution), NoDependenciesToRegister); 542 543 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 544 SymbolLookupSet(Baz), SymbolState::Ready, std::move(OnBazReady), 545 NoDependenciesToRegister); 546 547 // Add a circular dependency: Foo -> Bar, Bar -> Baz, Baz -> Foo. 548 FooR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}}); 549 BarR->addDependenciesForAll({{&JD, SymbolNameSet({Baz})}}); 550 BazR->addDependenciesForAll({{&JD, SymbolNameSet({Foo})}}); 551 552 // Add self-dependencies for good measure. This tests that the implementation 553 // of addDependencies filters these out. 554 FooR->addDependenciesForAll({{&JD, SymbolNameSet({Foo})}}); 555 BarR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}}); 556 BazR->addDependenciesForAll({{&JD, SymbolNameSet({Baz})}}); 557 558 // Check that nothing has been resolved yet. 559 EXPECT_FALSE(FooResolved) << "\"Foo\" should not be resolved yet"; 560 EXPECT_FALSE(BarResolved) << "\"Bar\" should not be resolved yet"; 561 EXPECT_FALSE(BazResolved) << "\"Baz\" should not be resolved yet"; 562 563 // Resolve the symbols (but do not emit them). 564 EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Succeeded()) 565 << "No symbols failed, but Foo failed to resolve"; 566 EXPECT_THAT_ERROR(BarR->notifyResolved({{Bar, BarSym}}), Succeeded()) 567 << "No symbols failed, but Bar failed to resolve"; 568 EXPECT_THAT_ERROR(BazR->notifyResolved({{Baz, BazSym}}), Succeeded()) 569 << "No symbols failed, but Baz failed to resolve"; 570 571 // Verify that the symbols have been resolved, but are not ready yet. 572 EXPECT_TRUE(FooResolved) << "\"Foo\" should be resolved now"; 573 EXPECT_TRUE(BarResolved) << "\"Bar\" should be resolved now"; 574 EXPECT_TRUE(BazResolved) << "\"Baz\" should be resolved now"; 575 576 EXPECT_FALSE(FooReady) << "\"Foo\" should not be ready yet"; 577 EXPECT_FALSE(BarReady) << "\"Bar\" should not be ready yet"; 578 EXPECT_FALSE(BazReady) << "\"Baz\" should not be ready yet"; 579 580 // Emit two of the symbols. 581 EXPECT_THAT_ERROR(FooR->notifyEmitted(), Succeeded()) 582 << "No symbols failed, but Foo failed to emit"; 583 EXPECT_THAT_ERROR(BarR->notifyEmitted(), Succeeded()) 584 << "No symbols failed, but Bar failed to emit"; 585 586 // Verify that nothing is ready until the circular dependence is resolved. 587 EXPECT_FALSE(FooReady) << "\"Foo\" still should not be ready"; 588 EXPECT_FALSE(BarReady) << "\"Bar\" still should not be ready"; 589 EXPECT_FALSE(BazReady) << "\"Baz\" still should not be ready"; 590 591 // Emit the last symbol. 592 EXPECT_THAT_ERROR(BazR->notifyEmitted(), Succeeded()) 593 << "No symbols failed, but Baz failed to emit"; 594 595 // Verify that everything becomes ready once the circular dependence resolved. 596 EXPECT_TRUE(FooReady) << "\"Foo\" should be ready now"; 597 EXPECT_TRUE(BarReady) << "\"Bar\" should be ready now"; 598 EXPECT_TRUE(BazReady) << "\"Baz\" should be ready now"; 599 } 600 601 TEST_F(CoreAPIsStandardTest, FailureInDependency) { 602 std::unique_ptr<MaterializationResponsibility> FooR; 603 std::unique_ptr<MaterializationResponsibility> BarR; 604 605 // Create a MaterializationUnit for each symbol that moves the 606 // MaterializationResponsibility into one of the locals above. 607 auto FooMU = std::make_unique<SimpleMaterializationUnit>( 608 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 609 [&](std::unique_ptr<MaterializationResponsibility> R) { 610 FooR = std::move(R); 611 }); 612 613 auto BarMU = std::make_unique<SimpleMaterializationUnit>( 614 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 615 [&](std::unique_ptr<MaterializationResponsibility> R) { 616 BarR = std::move(R); 617 }); 618 619 // Define the symbols. 620 cantFail(JD.define(FooMU)); 621 cantFail(JD.define(BarMU)); 622 623 bool OnFooReadyRun = false; 624 auto OnFooReady = [&](Expected<SymbolMap> Result) { 625 EXPECT_THAT_EXPECTED(std::move(Result), Failed()); 626 OnFooReadyRun = true; 627 }; 628 629 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 630 SymbolLookupSet(Foo), SymbolState::Ready, std::move(OnFooReady), 631 NoDependenciesToRegister); 632 633 bool OnBarReadyRun = false; 634 auto OnBarReady = [&](Expected<SymbolMap> Result) { 635 EXPECT_THAT_EXPECTED(std::move(Result), Failed()); 636 OnBarReadyRun = true; 637 }; 638 639 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 640 SymbolLookupSet(Bar), SymbolState::Ready, std::move(OnBarReady), 641 NoDependenciesToRegister); 642 643 // Add a dependency by Foo on Bar. 644 FooR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}}); 645 646 // Fail bar. 647 BarR->failMaterialization(); 648 649 // Verify that queries on Bar failed, but queries on Foo have not yet. 650 EXPECT_TRUE(OnBarReadyRun) << "Query for \"Bar\" was not run"; 651 EXPECT_FALSE(OnFooReadyRun) << "Query for \"Foo\" was run unexpectedly"; 652 653 // Check that we can still resolve Foo (even though it has been failed). 654 EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Failed()) 655 << "Expected resolution for \"Foo\" to fail."; 656 657 FooR->failMaterialization(); 658 659 // Verify that queries on Foo have now failed. 660 EXPECT_TRUE(OnFooReadyRun) << "Query for \"Foo\" was not run"; 661 662 // Verify that subsequent lookups on Bar and Foo fail. 663 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Bar}), Failed()) 664 << "Lookup on failed symbol should fail"; 665 666 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Foo}), Failed()) 667 << "Lookup on failed symbol should fail"; 668 } 669 670 TEST_F(CoreAPIsStandardTest, FailureInCircularDependency) { 671 std::unique_ptr<MaterializationResponsibility> FooR; 672 std::unique_ptr<MaterializationResponsibility> BarR; 673 674 // Create a MaterializationUnit for each symbol that moves the 675 // MaterializationResponsibility into one of the locals above. 676 auto FooMU = std::make_unique<SimpleMaterializationUnit>( 677 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 678 [&](std::unique_ptr<MaterializationResponsibility> R) { 679 FooR = std::move(R); 680 }); 681 682 auto BarMU = std::make_unique<SimpleMaterializationUnit>( 683 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 684 [&](std::unique_ptr<MaterializationResponsibility> R) { 685 BarR = std::move(R); 686 }); 687 688 // Define the symbols. 689 cantFail(JD.define(FooMU)); 690 cantFail(JD.define(BarMU)); 691 692 bool OnFooReadyRun = false; 693 auto OnFooReady = [&](Expected<SymbolMap> Result) { 694 EXPECT_THAT_EXPECTED(std::move(Result), Failed()); 695 OnFooReadyRun = true; 696 }; 697 698 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 699 SymbolLookupSet(Foo), SymbolState::Ready, std::move(OnFooReady), 700 NoDependenciesToRegister); 701 702 bool OnBarReadyRun = false; 703 auto OnBarReady = [&](Expected<SymbolMap> Result) { 704 EXPECT_THAT_EXPECTED(std::move(Result), Failed()); 705 OnBarReadyRun = true; 706 }; 707 708 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 709 SymbolLookupSet(Bar), SymbolState::Ready, std::move(OnBarReady), 710 NoDependenciesToRegister); 711 712 // Add a dependency by Foo on Bar and vice-versa. 713 FooR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}}); 714 BarR->addDependenciesForAll({{&JD, SymbolNameSet({Foo})}}); 715 716 // Fail bar. 717 BarR->failMaterialization(); 718 719 // Verify that queries on Bar failed, but queries on Foo have not yet. 720 EXPECT_TRUE(OnBarReadyRun) << "Query for \"Bar\" was not run"; 721 EXPECT_FALSE(OnFooReadyRun) << "Query for \"Foo\" was run unexpectedly"; 722 723 // Verify that trying to resolve Foo fails. 724 EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Failed()) 725 << "Expected resolution for \"Foo\" to fail."; 726 727 FooR->failMaterialization(); 728 729 // Verify that queries on Foo have now failed. 730 EXPECT_TRUE(OnFooReadyRun) << "Query for \"Foo\" was not run"; 731 732 // Verify that subsequent lookups on Bar and Foo fail. 733 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Bar}), Failed()) 734 << "Lookup on failed symbol should fail"; 735 736 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Foo}), Failed()) 737 << "Lookup on failed symbol should fail"; 738 } 739 740 TEST_F(CoreAPIsStandardTest, AddDependencyOnFailedSymbol) { 741 std::unique_ptr<MaterializationResponsibility> FooR; 742 std::unique_ptr<MaterializationResponsibility> BarR; 743 744 // Create a MaterializationUnit for each symbol that moves the 745 // MaterializationResponsibility into one of the locals above. 746 auto FooMU = std::make_unique<SimpleMaterializationUnit>( 747 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 748 [&](std::unique_ptr<MaterializationResponsibility> R) { 749 FooR = std::move(R); 750 }); 751 752 auto BarMU = std::make_unique<SimpleMaterializationUnit>( 753 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 754 [&](std::unique_ptr<MaterializationResponsibility> R) { 755 BarR = std::move(R); 756 }); 757 758 // Define the symbols. 759 cantFail(JD.define(FooMU)); 760 cantFail(JD.define(BarMU)); 761 762 bool OnFooReadyRun = false; 763 auto OnFooReady = [&](Expected<SymbolMap> Result) { 764 EXPECT_THAT_EXPECTED(std::move(Result), Failed()); 765 OnFooReadyRun = true; 766 }; 767 768 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 769 SymbolLookupSet(Foo), SymbolState::Ready, std::move(OnFooReady), 770 NoDependenciesToRegister); 771 772 bool OnBarReadyRun = false; 773 auto OnBarReady = [&](Expected<SymbolMap> Result) { 774 EXPECT_THAT_EXPECTED(std::move(Result), Failed()); 775 OnBarReadyRun = true; 776 }; 777 778 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 779 SymbolLookupSet(Bar), SymbolState::Ready, std::move(OnBarReady), 780 NoDependenciesToRegister); 781 782 // Fail bar. 783 BarR->failMaterialization(); 784 785 // We expect Bar's query to fail immediately, but Foo's query not to have run 786 // yet. 787 EXPECT_TRUE(OnBarReadyRun) << "Query for \"Bar\" was not run"; 788 EXPECT_FALSE(OnFooReadyRun) << "Query for \"Foo\" should not have run yet"; 789 790 // Add dependency of Foo on Bar. 791 FooR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}}); 792 793 // Check that we can still resolve Foo (even though it has been failed). 794 EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Failed()) 795 << "Expected resolution for \"Foo\" to fail."; 796 797 FooR->failMaterialization(); 798 799 // Foo's query should have failed before we return from addDependencies. 800 EXPECT_TRUE(OnFooReadyRun) << "Query for \"Foo\" was not run"; 801 802 // Verify that subsequent lookups on Bar and Foo fail. 803 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Bar}), Failed()) 804 << "Lookup on failed symbol should fail"; 805 806 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Foo}), Failed()) 807 << "Lookup on failed symbol should fail"; 808 } 809 810 TEST_F(CoreAPIsStandardTest, FailAfterMaterialization) { 811 std::unique_ptr<MaterializationResponsibility> FooR; 812 std::unique_ptr<MaterializationResponsibility> BarR; 813 814 // Create a MaterializationUnit for each symbol that moves the 815 // MaterializationResponsibility into one of the locals above. 816 auto FooMU = std::make_unique<SimpleMaterializationUnit>( 817 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 818 [&](std::unique_ptr<MaterializationResponsibility> R) { 819 FooR = std::move(R); 820 }); 821 822 auto BarMU = std::make_unique<SimpleMaterializationUnit>( 823 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 824 [&](std::unique_ptr<MaterializationResponsibility> R) { 825 BarR = std::move(R); 826 }); 827 828 // Define the symbols. 829 cantFail(JD.define(FooMU)); 830 cantFail(JD.define(BarMU)); 831 832 bool OnFooReadyRun = false; 833 auto OnFooReady = [&](Expected<SymbolMap> Result) { 834 EXPECT_THAT_EXPECTED(std::move(Result), Failed()); 835 OnFooReadyRun = true; 836 }; 837 838 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 839 SymbolLookupSet(Foo), SymbolState::Ready, std::move(OnFooReady), 840 NoDependenciesToRegister); 841 842 bool OnBarReadyRun = false; 843 auto OnBarReady = [&](Expected<SymbolMap> Result) { 844 EXPECT_THAT_EXPECTED(std::move(Result), Failed()); 845 OnBarReadyRun = true; 846 }; 847 848 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 849 SymbolLookupSet(Bar), SymbolState::Ready, std::move(OnBarReady), 850 NoDependenciesToRegister); 851 852 // Add a dependency by Foo on Bar and vice-versa. 853 FooR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}}); 854 BarR->addDependenciesForAll({{&JD, SymbolNameSet({Foo})}}); 855 856 // Materialize Foo. 857 EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Succeeded()) 858 << "Expected resolution for \"Foo\" to succeed."; 859 EXPECT_THAT_ERROR(FooR->notifyEmitted(), Succeeded()) 860 << "Expected emission for \"Foo\" to succeed."; 861 862 // Fail bar. 863 BarR->failMaterialization(); 864 865 // Verify that both queries failed. 866 EXPECT_TRUE(OnFooReadyRun) << "Query for Foo did not run"; 867 EXPECT_TRUE(OnBarReadyRun) << "Query for Bar did not run"; 868 } 869 870 TEST_F(CoreAPIsStandardTest, FailMaterializerWithUnqueriedSymbols) { 871 // Make sure that symbols with no queries aganist them still 872 // fail correctly. 873 874 bool MaterializerRun = false; 875 auto MU = std::make_unique<SimpleMaterializationUnit>( 876 SymbolFlagsMap( 877 {{Foo, JITSymbolFlags::Exported}, {Bar, JITSymbolFlags::Exported}}), 878 [&](std::unique_ptr<MaterializationResponsibility> R) { 879 MaterializerRun = true; 880 R->failMaterialization(); 881 }); 882 883 cantFail(JD.define(std::move(MU))); 884 885 // Issue a query for Foo, but not bar. 886 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Foo}), Failed()) 887 << "Expected lookup to fail."; 888 889 // Check that the materializer (and therefore failMaterialization) ran. 890 EXPECT_TRUE(MaterializerRun) << "Expected materializer to have run by now"; 891 892 // Check that subsequent queries against both symbols fail. 893 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Foo}), Failed()) 894 << "Expected lookup for Foo to fail."; 895 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Bar}), Failed()) 896 << "Expected lookup for Bar to fail."; 897 } 898 899 TEST_F(CoreAPIsStandardTest, DropMaterializerWhenEmpty) { 900 bool DestructorRun = false; 901 902 JITSymbolFlags WeakExported(JITSymbolFlags::Exported); 903 WeakExported |= JITSymbolFlags::Weak; 904 905 auto MU = std::make_unique<SimpleMaterializationUnit>( 906 SymbolFlagsMap({{Foo, WeakExported}, {Bar, WeakExported}}), 907 [](std::unique_ptr<MaterializationResponsibility> R) { 908 llvm_unreachable("Unexpected call to materialize"); 909 }, 910 nullptr, 911 [&](const JITDylib &JD, SymbolStringPtr Name) { 912 EXPECT_TRUE(Name == Foo || Name == Bar) 913 << "Discard of unexpected symbol?"; 914 }, 915 [&]() { DestructorRun = true; }); 916 917 cantFail(JD.define(MU)); 918 919 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 920 921 EXPECT_FALSE(DestructorRun) 922 << "MaterializationUnit should not have been destroyed yet"; 923 924 cantFail(JD.define(absoluteSymbols({{Bar, BarSym}}))); 925 926 EXPECT_TRUE(DestructorRun) 927 << "MaterializationUnit should have been destroyed"; 928 } 929 930 TEST_F(CoreAPIsStandardTest, AddAndMaterializeLazySymbol) { 931 bool FooMaterialized = false; 932 bool BarDiscarded = false; 933 934 JITSymbolFlags WeakExported(JITSymbolFlags::Exported); 935 WeakExported |= JITSymbolFlags::Weak; 936 937 auto MU = std::make_unique<SimpleMaterializationUnit>( 938 SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}, {Bar, WeakExported}}), 939 [&](std::unique_ptr<MaterializationResponsibility> R) { 940 assert(BarDiscarded && "Bar should have been discarded by this point"); 941 cantFail(R->notifyResolved(SymbolMap({{Foo, FooSym}}))); 942 cantFail(R->notifyEmitted()); 943 FooMaterialized = true; 944 }, 945 nullptr, 946 [&](const JITDylib &JD, SymbolStringPtr Name) { 947 EXPECT_EQ(Name, Bar) << "Expected Name to be Bar"; 948 BarDiscarded = true; 949 }); 950 951 cantFail(JD.define(MU)); 952 cantFail(JD.define(absoluteSymbols({{Bar, BarSym}}))); 953 954 bool OnCompletionRun = false; 955 956 auto OnCompletion = [&](Expected<SymbolMap> Result) { 957 EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error"; 958 auto I = Result->find(Foo); 959 EXPECT_NE(I, Result->end()) << "Could not find symbol definition"; 960 EXPECT_EQ(I->second.getAddress(), FooSym.getAddress()) 961 << "Resolution returned incorrect result"; 962 OnCompletionRun = true; 963 }; 964 965 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 966 SymbolLookupSet(Foo), SymbolState::Ready, std::move(OnCompletion), 967 NoDependenciesToRegister); 968 969 EXPECT_TRUE(FooMaterialized) << "Foo was not materialized"; 970 EXPECT_TRUE(BarDiscarded) << "Bar was not discarded"; 971 EXPECT_TRUE(OnCompletionRun) << "OnResolutionCallback was not run"; 972 } 973 974 TEST_F(CoreAPIsStandardTest, TestBasicWeakSymbolMaterialization) { 975 // Test that weak symbols are materialized correctly when we look them up. 976 BarSym.setFlags(BarSym.getFlags() | JITSymbolFlags::Weak); 977 978 bool BarMaterialized = false; 979 auto MU1 = std::make_unique<SimpleMaterializationUnit>( 980 SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}), 981 [&](std::unique_ptr<MaterializationResponsibility> R) { 982 cantFail(R->notifyResolved(SymbolMap({{Foo, FooSym}, {Bar, BarSym}}))); 983 cantFail(R->notifyEmitted()); 984 BarMaterialized = true; 985 }); 986 987 bool DuplicateBarDiscarded = false; 988 auto MU2 = std::make_unique<SimpleMaterializationUnit>( 989 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 990 [&](std::unique_ptr<MaterializationResponsibility> R) { 991 ADD_FAILURE() << "Attempt to materialize Bar from the wrong unit"; 992 R->failMaterialization(); 993 }, 994 nullptr, 995 [&](const JITDylib &JD, SymbolStringPtr Name) { 996 EXPECT_EQ(Name, Bar) << "Expected \"Bar\" to be discarded"; 997 DuplicateBarDiscarded = true; 998 }); 999 1000 cantFail(JD.define(MU1)); 1001 cantFail(JD.define(MU2)); 1002 1003 bool OnCompletionRun = false; 1004 1005 auto OnCompletion = [&](Expected<SymbolMap> Result) { 1006 cantFail(std::move(Result)); 1007 OnCompletionRun = true; 1008 }; 1009 1010 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 1011 SymbolLookupSet(Bar), SymbolState::Ready, std::move(OnCompletion), 1012 NoDependenciesToRegister); 1013 1014 EXPECT_TRUE(OnCompletionRun) << "OnCompletion not run"; 1015 EXPECT_TRUE(BarMaterialized) << "Bar was not materialized at all"; 1016 EXPECT_TRUE(DuplicateBarDiscarded) 1017 << "Duplicate bar definition not discarded"; 1018 } 1019 1020 TEST_F(CoreAPIsStandardTest, DefineMaterializingSymbol) { 1021 bool ExpectNoMoreMaterialization = false; 1022 ES.setDispatchTask([&](std::unique_ptr<Task> T) { 1023 if (ExpectNoMoreMaterialization && isa<MaterializationTask>(*T)) 1024 ADD_FAILURE() << "Unexpected materialization"; 1025 T->run(); 1026 }); 1027 1028 auto MU = std::make_unique<SimpleMaterializationUnit>( 1029 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 1030 [&](std::unique_ptr<MaterializationResponsibility> R) { 1031 cantFail( 1032 R->defineMaterializing(SymbolFlagsMap({{Bar, BarSym.getFlags()}}))); 1033 cantFail(R->notifyResolved(SymbolMap({{Foo, FooSym}, {Bar, BarSym}}))); 1034 cantFail(R->notifyEmitted()); 1035 }); 1036 1037 cantFail(JD.define(MU)); 1038 cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Foo)); 1039 1040 // Assert that materialization is complete by now. 1041 ExpectNoMoreMaterialization = true; 1042 1043 // Look up bar to verify that no further materialization happens. 1044 auto BarResult = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Bar)); 1045 EXPECT_EQ(BarResult.getAddress(), BarSym.getAddress()) 1046 << "Expected Bar == BarSym"; 1047 } 1048 1049 TEST_F(CoreAPIsStandardTest, GeneratorTest) { 1050 JITEvaluatedSymbol BazHiddenSym( 1051 BazSym.getAddress(), BazSym.getFlags() & ~JITSymbolFlags::Exported); 1052 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}, {Baz, BazHiddenSym}}))); 1053 1054 class TestGenerator : public DefinitionGenerator { 1055 public: 1056 TestGenerator(SymbolMap Symbols) : Symbols(std::move(Symbols)) {} 1057 Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD, 1058 JITDylibLookupFlags JDLookupFlags, 1059 const SymbolLookupSet &Names) override { 1060 SymbolMap NewDefs; 1061 1062 for (const auto &KV : Names) { 1063 const auto &Name = KV.first; 1064 if (Symbols.count(Name)) 1065 NewDefs[Name] = Symbols[Name]; 1066 } 1067 1068 cantFail(JD.define(absoluteSymbols(std::move(NewDefs)))); 1069 return Error::success(); 1070 }; 1071 1072 private: 1073 SymbolMap Symbols; 1074 }; 1075 1076 JD.addGenerator(std::make_unique<TestGenerator>( 1077 SymbolMap({{Bar, BarSym}, {Baz, BazSym}}))); 1078 1079 auto Result = cantFail( 1080 ES.lookup(makeJITDylibSearchOrder(&JD), 1081 SymbolLookupSet({Foo, Bar}) 1082 .add(Baz, SymbolLookupFlags::WeaklyReferencedSymbol))); 1083 1084 EXPECT_EQ(Result.count(Bar), 1U) << "Expected to find fallback def for 'bar'"; 1085 EXPECT_EQ(Result[Bar].getAddress(), BarSym.getAddress()) 1086 << "Expected fallback def for Bar to be equal to BarSym"; 1087 } 1088 1089 TEST_F(CoreAPIsStandardTest, AsynchronousGeneratorTest) { 1090 class TestGenerator : public DefinitionGenerator { 1091 public: 1092 TestGenerator(LookupState &TLS) : TLS(TLS) {} 1093 Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD, 1094 JITDylibLookupFlags JDLookupFlags, 1095 const SymbolLookupSet &Name) override { 1096 TLS = std::move(LS); 1097 return Error::success(); 1098 } 1099 1100 private: 1101 LookupState &TLS; 1102 }; 1103 1104 LookupState LS; 1105 JD.addGenerator(std::make_unique<TestGenerator>(LS)); 1106 1107 bool LookupCompleted = false; 1108 1109 ES.lookup( 1110 LookupKind::Static, makeJITDylibSearchOrder(&JD), SymbolLookupSet(Foo), 1111 SymbolState::Ready, 1112 [&](Expected<SymbolMap> Result) { 1113 LookupCompleted = true; 1114 if (!Result) { 1115 ADD_FAILURE() << "Lookup failed unexpected"; 1116 logAllUnhandledErrors(Result.takeError(), errs(), ""); 1117 return; 1118 } 1119 1120 EXPECT_EQ(Result->size(), 1U) << "Unexpected number of results"; 1121 EXPECT_EQ(Result->count(Foo), 1U) << "Expected result for Foo"; 1122 EXPECT_EQ((*Result)[Foo].getAddress(), FooSym.getAddress()) 1123 << "Bad result for Foo"; 1124 }, 1125 NoDependenciesToRegister); 1126 1127 EXPECT_FALSE(LookupCompleted); 1128 1129 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 1130 1131 LS.continueLookup(Error::success()); 1132 1133 EXPECT_TRUE(LookupCompleted); 1134 } 1135 1136 TEST_F(CoreAPIsStandardTest, FailResolution) { 1137 auto MU = std::make_unique<SimpleMaterializationUnit>( 1138 SymbolFlagsMap({{Foo, JITSymbolFlags::Exported | JITSymbolFlags::Weak}, 1139 {Bar, JITSymbolFlags::Exported | JITSymbolFlags::Weak}}), 1140 [&](std::unique_ptr<MaterializationResponsibility> R) { 1141 R->failMaterialization(); 1142 }); 1143 1144 cantFail(JD.define(MU)); 1145 1146 SymbolNameSet Names({Foo, Bar}); 1147 auto Result = ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet(Names)); 1148 1149 EXPECT_FALSE(!!Result) << "Expected failure"; 1150 if (!Result) { 1151 handleAllErrors( 1152 Result.takeError(), 1153 [&](FailedToMaterialize &F) { 1154 EXPECT_TRUE(F.getSymbols().count(&JD)) 1155 << "Expected to fail on JITDylib JD"; 1156 EXPECT_EQ(F.getSymbols().find(&JD)->second, Names) 1157 << "Expected to fail on symbols in Names"; 1158 }, 1159 [](ErrorInfoBase &EIB) { 1160 std::string ErrMsg; 1161 { 1162 raw_string_ostream ErrOut(ErrMsg); 1163 EIB.log(ErrOut); 1164 } 1165 ADD_FAILURE() << "Expected a FailedToResolve error. Got:\n" << ErrMsg; 1166 }); 1167 } 1168 } 1169 1170 TEST_F(CoreAPIsStandardTest, FailEmissionAfterResolution) { 1171 1172 cantFail(JD.define(absoluteSymbols({{Baz, BazSym}}))); 1173 1174 auto MU = std::make_unique<SimpleMaterializationUnit>( 1175 SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}), 1176 [&](std::unique_ptr<MaterializationResponsibility> R) { 1177 cantFail(R->notifyResolved(SymbolMap({{Foo, FooSym}, {Bar, BarSym}}))); 1178 1179 ES.lookup( 1180 LookupKind::Static, makeJITDylibSearchOrder(&JD), 1181 SymbolLookupSet({Baz}), SymbolState::Resolved, 1182 [&](Expected<SymbolMap> Result) { 1183 // Called when "baz" is resolved. We don't actually depend 1184 // on or care about baz, but use it to trigger failure of 1185 // this materialization before Baz has been finalized in 1186 // order to test that error propagation is correct in this 1187 // scenario. 1188 cantFail(std::move(Result)); 1189 R->failMaterialization(); 1190 }, 1191 [&](const SymbolDependenceMap &Deps) { 1192 R->addDependenciesForAll(Deps); 1193 }); 1194 }); 1195 1196 cantFail(JD.define(MU)); 1197 1198 auto Result = 1199 ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Foo, Bar})); 1200 1201 EXPECT_THAT_EXPECTED(std::move(Result), Failed()) 1202 << "Unexpected success while trying to test error propagation"; 1203 } 1204 1205 TEST_F(CoreAPIsStandardTest, FailAfterPartialResolution) { 1206 1207 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 1208 1209 // Fail materialization of bar. 1210 auto BarMU = std::make_unique<SimpleMaterializationUnit>( 1211 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 1212 [&](std::unique_ptr<MaterializationResponsibility> R) { 1213 R->failMaterialization(); 1214 }); 1215 1216 cantFail(JD.define(std::move(BarMU))); 1217 1218 bool QueryHandlerRun = false; 1219 ES.lookup( 1220 LookupKind::Static, makeJITDylibSearchOrder(&JD), 1221 SymbolLookupSet({Foo, Bar}), SymbolState::Resolved, 1222 [&](Expected<SymbolMap> Result) { 1223 EXPECT_THAT_EXPECTED(std::move(Result), Failed()) 1224 << "Expected query to fail"; 1225 QueryHandlerRun = true; 1226 }, 1227 NoDependenciesToRegister); 1228 EXPECT_TRUE(QueryHandlerRun) << "Query handler never ran"; 1229 } 1230 1231 TEST_F(CoreAPIsStandardTest, TestLookupWithUnthreadedMaterialization) { 1232 auto MU = std::make_unique<SimpleMaterializationUnit>( 1233 SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}}), 1234 [&](std::unique_ptr<MaterializationResponsibility> R) { 1235 cantFail(R->notifyResolved({{Foo, FooSym}})); 1236 cantFail(R->notifyEmitted()); 1237 }); 1238 1239 cantFail(JD.define(MU)); 1240 1241 auto FooLookupResult = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Foo)); 1242 1243 EXPECT_EQ(FooLookupResult.getAddress(), FooSym.getAddress()) 1244 << "lookup returned an incorrect address"; 1245 EXPECT_EQ(FooLookupResult.getFlags(), FooSym.getFlags()) 1246 << "lookup returned incorrect flags"; 1247 } 1248 1249 TEST_F(CoreAPIsStandardTest, TestLookupWithThreadedMaterialization) { 1250 #if LLVM_ENABLE_THREADS 1251 1252 std::mutex WorkThreadsMutex; 1253 std::vector<std::thread> WorkThreads; 1254 ES.setDispatchTask([&](std::unique_ptr<Task> T) { 1255 std::promise<void> WaitP; 1256 std::lock_guard<std::mutex> Lock(WorkThreadsMutex); 1257 WorkThreads.push_back( 1258 std::thread([T = std::move(T), WaitF = WaitP.get_future()]() mutable { 1259 WaitF.get(); 1260 T->run(); 1261 })); 1262 WaitP.set_value(); 1263 }); 1264 1265 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 1266 1267 auto FooLookupResult = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Foo)); 1268 1269 EXPECT_EQ(FooLookupResult.getAddress(), FooSym.getAddress()) 1270 << "lookup returned an incorrect address"; 1271 EXPECT_EQ(FooLookupResult.getFlags(), FooSym.getFlags()) 1272 << "lookup returned incorrect flags"; 1273 1274 for (auto &WT : WorkThreads) 1275 WT.join(); 1276 #endif 1277 } 1278 1279 TEST_F(CoreAPIsStandardTest, TestGetRequestedSymbolsAndReplace) { 1280 // Test that GetRequestedSymbols returns the set of symbols that currently 1281 // have pending queries, and test that MaterializationResponsibility's 1282 // replace method can be used to return definitions to the JITDylib in a new 1283 // MaterializationUnit. 1284 SymbolNameSet Names({Foo, Bar}); 1285 1286 bool FooMaterialized = false; 1287 bool BarMaterialized = false; 1288 1289 auto MU = std::make_unique<SimpleMaterializationUnit>( 1290 SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}), 1291 [&](std::unique_ptr<MaterializationResponsibility> R) { 1292 auto Requested = R->getRequestedSymbols(); 1293 EXPECT_EQ(Requested.size(), 1U) << "Expected one symbol requested"; 1294 EXPECT_EQ(*Requested.begin(), Foo) << "Expected \"Foo\" requested"; 1295 1296 auto NewMU = std::make_unique<SimpleMaterializationUnit>( 1297 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 1298 [&](std::unique_ptr<MaterializationResponsibility> R2) { 1299 cantFail(R2->notifyResolved(SymbolMap({{Bar, BarSym}}))); 1300 cantFail(R2->notifyEmitted()); 1301 BarMaterialized = true; 1302 }); 1303 1304 cantFail(R->replace(std::move(NewMU))); 1305 1306 cantFail(R->notifyResolved(SymbolMap({{Foo, FooSym}}))); 1307 cantFail(R->notifyEmitted()); 1308 1309 FooMaterialized = true; 1310 }); 1311 1312 cantFail(JD.define(MU)); 1313 1314 EXPECT_FALSE(FooMaterialized) << "Foo should not be materialized yet"; 1315 EXPECT_FALSE(BarMaterialized) << "Bar should not be materialized yet"; 1316 1317 auto FooSymResult = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Foo)); 1318 EXPECT_EQ(FooSymResult.getAddress(), FooSym.getAddress()) 1319 << "Address mismatch for Foo"; 1320 1321 EXPECT_TRUE(FooMaterialized) << "Foo should be materialized now"; 1322 EXPECT_FALSE(BarMaterialized) << "Bar still should not be materialized"; 1323 1324 auto BarSymResult = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Bar)); 1325 EXPECT_EQ(BarSymResult.getAddress(), BarSym.getAddress()) 1326 << "Address mismatch for Bar"; 1327 EXPECT_TRUE(BarMaterialized) << "Bar should be materialized now"; 1328 } 1329 1330 TEST_F(CoreAPIsStandardTest, TestMaterializationResponsibilityDelegation) { 1331 auto MU = std::make_unique<SimpleMaterializationUnit>( 1332 SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}), 1333 [&](std::unique_ptr<MaterializationResponsibility> R) { 1334 auto R2 = cantFail(R->delegate({Bar})); 1335 1336 cantFail(R->notifyResolved({{Foo, FooSym}})); 1337 cantFail(R->notifyEmitted()); 1338 cantFail(R2->notifyResolved({{Bar, BarSym}})); 1339 cantFail(R2->notifyEmitted()); 1340 }); 1341 1342 cantFail(JD.define(MU)); 1343 1344 auto Result = 1345 ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Foo, Bar})); 1346 1347 EXPECT_TRUE(!!Result) << "Result should be a success value"; 1348 EXPECT_EQ(Result->count(Foo), 1U) << "\"Foo\" entry missing"; 1349 EXPECT_EQ(Result->count(Bar), 1U) << "\"Bar\" entry missing"; 1350 EXPECT_EQ((*Result)[Foo].getAddress(), FooSym.getAddress()) 1351 << "Address mismatch for \"Foo\""; 1352 EXPECT_EQ((*Result)[Bar].getAddress(), BarSym.getAddress()) 1353 << "Address mismatch for \"Bar\""; 1354 } 1355 1356 TEST_F(CoreAPIsStandardTest, TestMaterializeWeakSymbol) { 1357 // Confirm that once a weak definition is selected for materialization it is 1358 // treated as strong. 1359 JITSymbolFlags WeakExported = JITSymbolFlags::Exported; 1360 WeakExported &= JITSymbolFlags::Weak; 1361 1362 std::unique_ptr<MaterializationResponsibility> FooR; 1363 auto MU = std::make_unique<SimpleMaterializationUnit>( 1364 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 1365 [&](std::unique_ptr<MaterializationResponsibility> R) { 1366 FooR = std::move(R); 1367 }); 1368 1369 cantFail(JD.define(MU)); 1370 auto OnCompletion = [](Expected<SymbolMap> Result) { 1371 cantFail(std::move(Result)); 1372 }; 1373 1374 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 1375 SymbolLookupSet({Foo}), SymbolState::Ready, std::move(OnCompletion), 1376 NoDependenciesToRegister); 1377 1378 auto MU2 = std::make_unique<SimpleMaterializationUnit>( 1379 SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}}), 1380 [](std::unique_ptr<MaterializationResponsibility> R) { 1381 llvm_unreachable("This unit should never be materialized"); 1382 }); 1383 1384 auto Err = JD.define(MU2); 1385 EXPECT_TRUE(!!Err) << "Expected failure value"; 1386 EXPECT_TRUE(Err.isA<DuplicateDefinition>()) 1387 << "Expected a duplicate definition error"; 1388 consumeError(std::move(Err)); 1389 1390 // No dependencies registered, can't fail: 1391 cantFail(FooR->notifyResolved(SymbolMap({{Foo, FooSym}}))); 1392 cantFail(FooR->notifyEmitted()); 1393 } 1394 1395 static bool linkOrdersEqual(const std::vector<JITDylibSP> &LHS, 1396 ArrayRef<JITDylib *> RHS) { 1397 if (LHS.size() != RHS.size()) 1398 return false; 1399 auto *RHSE = RHS.begin(); 1400 for (auto &LHSE : LHS) 1401 if (LHSE.get() != *RHSE) 1402 return false; 1403 else 1404 ++RHSE; 1405 return true; 1406 } 1407 1408 TEST(JITDylibTest, GetDFSLinkOrderTree) { 1409 // Test that DFS ordering behaves as expected when the linkage relationships 1410 // form a tree. 1411 1412 ExecutionSession ES{std::make_unique<UnsupportedExecutorProcessControl>()}; 1413 1414 auto &LibA = ES.createBareJITDylib("A"); 1415 auto &LibB = ES.createBareJITDylib("B"); 1416 auto &LibC = ES.createBareJITDylib("C"); 1417 auto &LibD = ES.createBareJITDylib("D"); 1418 auto &LibE = ES.createBareJITDylib("E"); 1419 auto &LibF = ES.createBareJITDylib("F"); 1420 1421 // Linkage relationships: 1422 // A --- B -- D 1423 // \ \- E 1424 // \- C -- F 1425 LibA.setLinkOrder(makeJITDylibSearchOrder({&LibB, &LibC})); 1426 LibB.setLinkOrder(makeJITDylibSearchOrder({&LibD, &LibE})); 1427 LibC.setLinkOrder(makeJITDylibSearchOrder({&LibF})); 1428 1429 auto DFSOrderFromB = JITDylib::getDFSLinkOrder({&LibB}); 1430 EXPECT_TRUE(linkOrdersEqual(DFSOrderFromB, {&LibB, &LibD, &LibE})) 1431 << "Incorrect DFS link order for LibB"; 1432 1433 auto DFSOrderFromA = JITDylib::getDFSLinkOrder({&LibA}); 1434 EXPECT_TRUE(linkOrdersEqual(DFSOrderFromA, 1435 {&LibA, &LibB, &LibD, &LibE, &LibC, &LibF})) 1436 << "Incorrect DFS link order for libA"; 1437 1438 auto DFSOrderFromAB = JITDylib::getDFSLinkOrder({&LibA, &LibB}); 1439 EXPECT_TRUE(linkOrdersEqual(DFSOrderFromAB, 1440 {&LibA, &LibB, &LibD, &LibE, &LibC, &LibF})) 1441 << "Incorrect DFS link order for { libA, libB }"; 1442 1443 auto DFSOrderFromBA = JITDylib::getDFSLinkOrder({&LibB, &LibA}); 1444 EXPECT_TRUE(linkOrdersEqual(DFSOrderFromBA, 1445 {&LibB, &LibD, &LibE, &LibA, &LibC, &LibF})) 1446 << "Incorrect DFS link order for { libB, libA }"; 1447 } 1448 1449 TEST(JITDylibTest, GetDFSLinkOrderDiamond) { 1450 // Test that DFS ordering behaves as expected when the linkage relationships 1451 // contain a diamond. 1452 1453 ExecutionSession ES{std::make_unique<UnsupportedExecutorProcessControl>()}; 1454 auto &LibA = ES.createBareJITDylib("A"); 1455 auto &LibB = ES.createBareJITDylib("B"); 1456 auto &LibC = ES.createBareJITDylib("C"); 1457 auto &LibD = ES.createBareJITDylib("D"); 1458 1459 // Linkage relationships: 1460 // A -- B --- D 1461 // \-- C --/ 1462 LibA.setLinkOrder(makeJITDylibSearchOrder({&LibB, &LibC})); 1463 LibB.setLinkOrder(makeJITDylibSearchOrder({&LibD})); 1464 LibC.setLinkOrder(makeJITDylibSearchOrder({&LibD})); 1465 1466 auto DFSOrderFromA = JITDylib::getDFSLinkOrder({&LibA}); 1467 EXPECT_TRUE(linkOrdersEqual(DFSOrderFromA, {&LibA, &LibB, &LibD, &LibC})) 1468 << "Incorrect DFS link order for libA"; 1469 } 1470 1471 TEST(JITDylibTest, GetDFSLinkOrderCycle) { 1472 // Test that DFS ordering behaves as expected when the linkage relationships 1473 // contain a cycle. 1474 1475 ExecutionSession ES{std::make_unique<UnsupportedExecutorProcessControl>()}; 1476 auto &LibA = ES.createBareJITDylib("A"); 1477 auto &LibB = ES.createBareJITDylib("B"); 1478 auto &LibC = ES.createBareJITDylib("C"); 1479 1480 // Linkage relationships: 1481 // A -- B --- C -- A 1482 LibA.setLinkOrder(makeJITDylibSearchOrder({&LibB})); 1483 LibB.setLinkOrder(makeJITDylibSearchOrder({&LibC})); 1484 LibC.setLinkOrder(makeJITDylibSearchOrder({&LibA})); 1485 1486 auto DFSOrderFromA = JITDylib::getDFSLinkOrder({&LibA}); 1487 EXPECT_TRUE(linkOrdersEqual(DFSOrderFromA, {&LibA, &LibB, &LibC})) 1488 << "Incorrect DFS link order for libA"; 1489 1490 auto DFSOrderFromB = JITDylib::getDFSLinkOrder({&LibB}); 1491 EXPECT_TRUE(linkOrdersEqual(DFSOrderFromB, {&LibB, &LibC, &LibA})) 1492 << "Incorrect DFS link order for libB"; 1493 1494 auto DFSOrderFromC = JITDylib::getDFSLinkOrder({&LibC}); 1495 EXPECT_TRUE(linkOrdersEqual(DFSOrderFromC, {&LibC, &LibA, &LibB})) 1496 << "Incorrect DFS link order for libC"; 1497 } 1498 1499 TEST_F(CoreAPIsStandardTest, RemoveJITDylibs) { 1500 // Foo will be fully materialized. 1501 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 1502 1503 // Bar should not be materialized at all. 1504 bool BarMaterializerDestroyed = false; 1505 cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>( 1506 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 1507 [&](std::unique_ptr<MaterializationResponsibility> MR) { 1508 llvm_unreachable("Unexpected call to materialize"); 1509 }, 1510 nullptr, 1511 [](const JITDylib &, SymbolStringPtr Name) { 1512 llvm_unreachable("Unexpected call to discard"); 1513 }, 1514 [&]() { BarMaterializerDestroyed = true; }))); 1515 1516 // Baz will be in the materializing state. 1517 std::unique_ptr<MaterializationResponsibility> BazMR; 1518 cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>( 1519 SymbolFlagsMap({{Baz, BazSym.getFlags()}}), 1520 [&](std::unique_ptr<MaterializationResponsibility> MR) { 1521 BazMR = std::move(MR); 1522 }))); 1523 1524 // Lookup to force materialization of Foo. 1525 cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Foo}))); 1526 1527 // Start a lookup to force materialization of Baz. 1528 bool BazLookupFailed = false; 1529 ES.lookup( 1530 LookupKind::Static, makeJITDylibSearchOrder(&JD), SymbolLookupSet({Baz}), 1531 SymbolState::Ready, 1532 [&](Expected<SymbolMap> Result) { 1533 if (!Result) { 1534 BazLookupFailed = true; 1535 consumeError(Result.takeError()); 1536 } 1537 }, 1538 NoDependenciesToRegister); 1539 1540 // Remove the JITDylib. 1541 auto Err = ES.removeJITDylib(JD); 1542 EXPECT_THAT_ERROR(std::move(Err), Succeeded()); 1543 1544 EXPECT_TRUE(BarMaterializerDestroyed); 1545 EXPECT_TRUE(BazLookupFailed); 1546 1547 EXPECT_THAT_ERROR(BazMR->notifyResolved({{Baz, BazSym}}), Failed()); 1548 1549 BazMR->failMaterialization(); 1550 } 1551 1552 } // namespace 1553