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