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