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