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