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