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, TestCircularDependenceInOneJITDylib) { 522 // Test that a circular symbol dependency between three symbols in a JITDylib 523 // does not prevent any symbol from becoming 'ready' once all symbols are 524 // emitted. 525 526 std::unique_ptr<MaterializationResponsibility> FooR; 527 std::unique_ptr<MaterializationResponsibility> BarR; 528 std::unique_ptr<MaterializationResponsibility> BazR; 529 530 // Create a MaterializationUnit for each symbol that moves the 531 // MaterializationResponsibility into one of the locals above. 532 auto FooMU = std::make_unique<SimpleMaterializationUnit>( 533 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 534 [&](std::unique_ptr<MaterializationResponsibility> R) { 535 FooR = std::move(R); 536 }); 537 538 auto BarMU = std::make_unique<SimpleMaterializationUnit>( 539 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 540 [&](std::unique_ptr<MaterializationResponsibility> R) { 541 BarR = std::move(R); 542 }); 543 544 auto BazMU = std::make_unique<SimpleMaterializationUnit>( 545 SymbolFlagsMap({{Baz, BazSym.getFlags()}}), 546 [&](std::unique_ptr<MaterializationResponsibility> R) { 547 BazR = std::move(R); 548 }); 549 550 // Define the symbols. 551 cantFail(JD.define(FooMU)); 552 cantFail(JD.define(BarMU)); 553 cantFail(JD.define(BazMU)); 554 555 // Query each of the symbols to trigger materialization. 556 bool FooResolved = false; 557 bool FooReady = false; 558 559 auto OnFooResolution = [&](Expected<SymbolMap> Result) { 560 cantFail(std::move(Result)); 561 FooResolved = true; 562 }; 563 564 auto OnFooReady = [&](Expected<SymbolMap> Result) { 565 cantFail(std::move(Result)); 566 FooReady = true; 567 }; 568 569 // Issue lookups for Foo. Use NoDependenciesToRegister: We're going to add 570 // the dependencies manually below. 571 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 572 SymbolLookupSet(Foo), SymbolState::Resolved, 573 std::move(OnFooResolution), NoDependenciesToRegister); 574 575 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 576 SymbolLookupSet(Foo), SymbolState::Ready, std::move(OnFooReady), 577 NoDependenciesToRegister); 578 579 bool BarResolved = false; 580 bool BarReady = false; 581 auto OnBarResolution = [&](Expected<SymbolMap> Result) { 582 cantFail(std::move(Result)); 583 BarResolved = true; 584 }; 585 586 auto OnBarReady = [&](Expected<SymbolMap> Result) { 587 cantFail(std::move(Result)); 588 BarReady = true; 589 }; 590 591 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 592 SymbolLookupSet(Bar), SymbolState::Resolved, 593 std::move(OnBarResolution), NoDependenciesToRegister); 594 595 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 596 SymbolLookupSet(Bar), SymbolState::Ready, std::move(OnBarReady), 597 NoDependenciesToRegister); 598 599 bool BazResolved = false; 600 bool BazReady = false; 601 602 auto OnBazResolution = [&](Expected<SymbolMap> Result) { 603 cantFail(std::move(Result)); 604 BazResolved = true; 605 }; 606 607 auto OnBazReady = [&](Expected<SymbolMap> Result) { 608 cantFail(std::move(Result)); 609 BazReady = true; 610 }; 611 612 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 613 SymbolLookupSet(Baz), SymbolState::Resolved, 614 std::move(OnBazResolution), NoDependenciesToRegister); 615 616 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 617 SymbolLookupSet(Baz), SymbolState::Ready, std::move(OnBazReady), 618 NoDependenciesToRegister); 619 620 // Check that nothing has been resolved yet. 621 EXPECT_FALSE(FooResolved) << "\"Foo\" should not be resolved yet"; 622 EXPECT_FALSE(BarResolved) << "\"Bar\" should not be resolved yet"; 623 EXPECT_FALSE(BazResolved) << "\"Baz\" should not be resolved yet"; 624 625 // Resolve the symbols (but do not emit them). 626 EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Succeeded()) 627 << "No symbols failed, but Foo failed to resolve"; 628 EXPECT_THAT_ERROR(BarR->notifyResolved({{Bar, BarSym}}), Succeeded()) 629 << "No symbols failed, but Bar failed to resolve"; 630 EXPECT_THAT_ERROR(BazR->notifyResolved({{Baz, BazSym}}), Succeeded()) 631 << "No symbols failed, but Baz failed to resolve"; 632 633 // Verify that the symbols have been resolved, but are not ready yet. 634 EXPECT_TRUE(FooResolved) << "\"Foo\" should be resolved now"; 635 EXPECT_TRUE(BarResolved) << "\"Bar\" should be resolved now"; 636 EXPECT_TRUE(BazResolved) << "\"Baz\" should be resolved now"; 637 638 EXPECT_FALSE(FooReady) << "\"Foo\" should not be ready yet"; 639 EXPECT_FALSE(BarReady) << "\"Bar\" should not be ready yet"; 640 EXPECT_FALSE(BazReady) << "\"Baz\" should not be ready yet"; 641 642 // Emit two of the symbols. 643 { 644 SymbolDependenceGroup FooDeps({{Foo}, {{&JD, {Foo, Bar}}}}); 645 EXPECT_THAT_ERROR(FooR->notifyEmitted(FooDeps), Succeeded()) 646 << "No symbols failed, but Foo failed to emit"; 647 648 SymbolDependenceGroup BarDeps({{Bar}, {{&JD, {Bar, Baz}}}}); 649 EXPECT_THAT_ERROR(BarR->notifyEmitted(BarDeps), Succeeded()) 650 << "No symbols failed, but Bar failed to emit"; 651 } 652 653 // Verify that nothing is ready until the circular dependence is resolved. 654 EXPECT_FALSE(FooReady) << "\"Foo\" still should not be ready"; 655 EXPECT_FALSE(BarReady) << "\"Bar\" still should not be ready"; 656 EXPECT_FALSE(BazReady) << "\"Baz\" still should not be ready"; 657 658 // Emit the last symbol. 659 { 660 SymbolDependenceGroup BazDeps({{Baz}, {{&JD, {Baz, Foo}}}}); 661 EXPECT_THAT_ERROR(BazR->notifyEmitted(BazDeps), Succeeded()) 662 << "No symbols failed, but Baz failed to emit"; 663 } 664 665 // Verify that everything becomes ready once the circular dependence resolved. 666 EXPECT_TRUE(FooReady) << "\"Foo\" should be ready now"; 667 EXPECT_TRUE(BarReady) << "\"Bar\" should be ready now"; 668 EXPECT_TRUE(BazReady) << "\"Baz\" should be ready now"; 669 } 670 671 TEST_F(CoreAPIsStandardTest, FailureInDependency) { 672 std::unique_ptr<MaterializationResponsibility> FooR; 673 std::unique_ptr<MaterializationResponsibility> BarR; 674 675 // Create a MaterializationUnit for each symbol that moves the 676 // MaterializationResponsibility into one of the locals above. 677 auto FooMU = std::make_unique<SimpleMaterializationUnit>( 678 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 679 [&](std::unique_ptr<MaterializationResponsibility> R) { 680 FooR = std::move(R); 681 }); 682 683 auto BarMU = std::make_unique<SimpleMaterializationUnit>( 684 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 685 [&](std::unique_ptr<MaterializationResponsibility> R) { 686 BarR = std::move(R); 687 }); 688 689 // Define the symbols. 690 cantFail(JD.define(FooMU)); 691 cantFail(JD.define(BarMU)); 692 693 bool OnFooReadyRun = false; 694 auto OnFooReady = [&](Expected<SymbolMap> Result) { 695 EXPECT_THAT_EXPECTED(std::move(Result), Failed()); 696 OnFooReadyRun = true; 697 }; 698 699 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 700 SymbolLookupSet(Foo), SymbolState::Ready, std::move(OnFooReady), 701 NoDependenciesToRegister); 702 703 bool OnBarReadyRun = false; 704 auto OnBarReady = [&](Expected<SymbolMap> Result) { 705 EXPECT_THAT_EXPECTED(std::move(Result), Failed()); 706 OnBarReadyRun = true; 707 }; 708 709 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 710 SymbolLookupSet(Bar), SymbolState::Ready, std::move(OnBarReady), 711 NoDependenciesToRegister); 712 713 // Fail bar. 714 BarR->failMaterialization(); 715 716 // Verify that queries on Bar failed, but queries on Foo have not yet. 717 EXPECT_TRUE(OnBarReadyRun) << "Query for \"Bar\" was not run"; 718 EXPECT_FALSE(OnFooReadyRun) << "Query for \"Foo\" was run unexpectedly"; 719 720 // Check that we can still resolve Foo (even though it has been failed). 721 EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Succeeded()) 722 << "Expected resolution for \"Foo\" to succeed despite error state."; 723 724 FooR->failMaterialization(); 725 726 // Verify that queries on Foo have now failed. 727 EXPECT_TRUE(OnFooReadyRun) << "Query for \"Foo\" was not run"; 728 729 // Verify that subsequent lookups on Bar and Foo fail. 730 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Bar}), Failed()) 731 << "Lookup on failed symbol should fail"; 732 733 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Foo}), Failed()) 734 << "Lookup on failed symbol should fail"; 735 } 736 737 TEST_F(CoreAPIsStandardTest, AddDependencyOnFailedSymbol) { 738 std::unique_ptr<MaterializationResponsibility> FooR; 739 std::unique_ptr<MaterializationResponsibility> BarR; 740 741 // Create a MaterializationUnit for each symbol that moves the 742 // MaterializationResponsibility into one of the locals above. 743 auto FooMU = std::make_unique<SimpleMaterializationUnit>( 744 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 745 [&](std::unique_ptr<MaterializationResponsibility> R) { 746 FooR = std::move(R); 747 }); 748 749 auto BarMU = std::make_unique<SimpleMaterializationUnit>( 750 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 751 [&](std::unique_ptr<MaterializationResponsibility> R) { 752 BarR = std::move(R); 753 }); 754 755 // Define the symbols. 756 cantFail(JD.define(FooMU)); 757 cantFail(JD.define(BarMU)); 758 759 bool OnFooReadyRun = false; 760 auto OnFooReady = [&](Expected<SymbolMap> Result) { 761 EXPECT_THAT_EXPECTED(std::move(Result), Failed()); 762 OnFooReadyRun = true; 763 }; 764 765 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 766 SymbolLookupSet(Foo), SymbolState::Ready, std::move(OnFooReady), 767 NoDependenciesToRegister); 768 769 bool OnBarReadyRun = false; 770 auto OnBarReady = [&](Expected<SymbolMap> Result) { 771 EXPECT_THAT_EXPECTED(std::move(Result), Failed()); 772 OnBarReadyRun = true; 773 }; 774 775 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 776 SymbolLookupSet(Bar), SymbolState::Ready, std::move(OnBarReady), 777 NoDependenciesToRegister); 778 779 // Fail bar. 780 BarR->failMaterialization(); 781 782 // We expect Bar's query to fail immediately, but Foo's query not to have run 783 // yet. 784 EXPECT_TRUE(OnBarReadyRun) << "Query for \"Bar\" was not run"; 785 EXPECT_FALSE(OnFooReadyRun) << "Query for \"Foo\" should not have run yet"; 786 787 EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Succeeded()) 788 << "Expected resolution for \"Foo\" to succeed."; 789 790 // Check that emission of Foo fails. 791 { 792 SymbolDependenceGroup FooDeps({{Foo}, {{&JD, {Bar}}}}); 793 EXPECT_THAT_ERROR(FooR->notifyEmitted(FooDeps), Failed()); 794 } 795 796 FooR->failMaterialization(); 797 798 // Foo's query should have failed before we return from addDependencies. 799 EXPECT_TRUE(OnFooReadyRun) << "Query for \"Foo\" was not run"; 800 801 // Verify that subsequent lookups on Bar and Foo fail. 802 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Bar}), Failed()) 803 << "Lookup on failed symbol should fail"; 804 805 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Foo}), Failed()) 806 << "Lookup on failed symbol should fail"; 807 } 808 809 TEST_F(CoreAPIsStandardTest, FailAfterMaterialization) { 810 std::unique_ptr<MaterializationResponsibility> FooR; 811 std::unique_ptr<MaterializationResponsibility> BarR; 812 813 // Create a MaterializationUnit for each symbol that moves the 814 // MaterializationResponsibility into one of the locals above. 815 auto FooMU = std::make_unique<SimpleMaterializationUnit>( 816 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 817 [&](std::unique_ptr<MaterializationResponsibility> R) { 818 FooR = std::move(R); 819 }); 820 821 auto BarMU = std::make_unique<SimpleMaterializationUnit>( 822 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 823 [&](std::unique_ptr<MaterializationResponsibility> R) { 824 BarR = std::move(R); 825 }); 826 827 // Define the symbols. 828 cantFail(JD.define(FooMU)); 829 cantFail(JD.define(BarMU)); 830 831 bool OnFooReadyRun = false; 832 auto OnFooReady = [&](Expected<SymbolMap> Result) { 833 EXPECT_THAT_EXPECTED(std::move(Result), Failed()); 834 OnFooReadyRun = true; 835 }; 836 837 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 838 SymbolLookupSet(Foo), SymbolState::Ready, std::move(OnFooReady), 839 NoDependenciesToRegister); 840 841 bool OnBarReadyRun = false; 842 auto OnBarReady = [&](Expected<SymbolMap> Result) { 843 EXPECT_THAT_EXPECTED(std::move(Result), Failed()); 844 OnBarReadyRun = true; 845 }; 846 847 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 848 SymbolLookupSet(Bar), SymbolState::Ready, std::move(OnBarReady), 849 NoDependenciesToRegister); 850 851 // Materialize Foo. 852 EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Succeeded()) 853 << "Expected resolution for \"Foo\" to succeed."; 854 { 855 SymbolDependenceGroup FooDeps({{Foo}, {{&JD, {Bar}}}}); 856 EXPECT_THAT_ERROR(FooR->notifyEmitted(FooDeps), Succeeded()) 857 << "Expected emission for \"Foo\" to succeed."; 858 } 859 860 // Fail bar. 861 BarR->failMaterialization(); 862 863 // Verify that both queries failed. 864 EXPECT_TRUE(OnFooReadyRun) << "Query for Foo did not run"; 865 EXPECT_TRUE(OnBarReadyRun) << "Query for Bar did not run"; 866 } 867 868 TEST_F(CoreAPIsStandardTest, FailMaterializerWithUnqueriedSymbols) { 869 // Make sure that symbols with no queries aganist them still 870 // fail correctly. 871 872 bool MaterializerRun = false; 873 auto MU = std::make_unique<SimpleMaterializationUnit>( 874 SymbolFlagsMap( 875 {{Foo, JITSymbolFlags::Exported}, {Bar, JITSymbolFlags::Exported}}), 876 [&](std::unique_ptr<MaterializationResponsibility> R) { 877 MaterializerRun = true; 878 R->failMaterialization(); 879 }); 880 881 cantFail(JD.define(std::move(MU))); 882 883 // Issue a query for Foo, but not bar. 884 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Foo}), Failed()) 885 << "Expected lookup to fail."; 886 887 // Check that the materializer (and therefore failMaterialization) ran. 888 EXPECT_TRUE(MaterializerRun) << "Expected materializer to have run by now"; 889 890 // Check that subsequent queries against both symbols fail. 891 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Foo}), Failed()) 892 << "Expected lookup for Foo to fail."; 893 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Bar}), Failed()) 894 << "Expected lookup for Bar to fail."; 895 } 896 897 TEST_F(CoreAPIsStandardTest, DropMaterializerWhenEmpty) { 898 bool DestructorRun = false; 899 900 JITSymbolFlags WeakExported(JITSymbolFlags::Exported); 901 WeakExported |= JITSymbolFlags::Weak; 902 903 auto MU = std::make_unique<SimpleMaterializationUnit>( 904 SymbolFlagsMap({{Foo, WeakExported}, {Bar, WeakExported}}), 905 [](std::unique_ptr<MaterializationResponsibility> R) { 906 llvm_unreachable("Unexpected call to materialize"); 907 }, 908 nullptr, 909 [&](const JITDylib &JD, SymbolStringPtr Name) { 910 EXPECT_TRUE(Name == Foo || Name == Bar) 911 << "Discard of unexpected symbol?"; 912 }, 913 [&]() { DestructorRun = true; }); 914 915 cantFail(JD.define(MU)); 916 917 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 918 919 EXPECT_FALSE(DestructorRun) 920 << "MaterializationUnit should not have been destroyed yet"; 921 922 cantFail(JD.define(absoluteSymbols({{Bar, BarSym}}))); 923 924 EXPECT_TRUE(DestructorRun) 925 << "MaterializationUnit should have been destroyed"; 926 } 927 928 TEST_F(CoreAPIsStandardTest, AddAndMaterializeLazySymbol) { 929 bool FooMaterialized = false; 930 bool BarDiscarded = false; 931 932 JITSymbolFlags WeakExported(JITSymbolFlags::Exported); 933 WeakExported |= JITSymbolFlags::Weak; 934 935 auto MU = std::make_unique<SimpleMaterializationUnit>( 936 SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}, {Bar, WeakExported}}), 937 [&](std::unique_ptr<MaterializationResponsibility> R) { 938 assert(BarDiscarded && "Bar should have been discarded by this point"); 939 cantFail(R->notifyResolved(SymbolMap({{Foo, FooSym}}))); 940 cantFail(R->notifyEmitted({})); 941 FooMaterialized = true; 942 }, 943 nullptr, 944 [&](const JITDylib &JD, SymbolStringPtr Name) { 945 EXPECT_EQ(Name, Bar) << "Expected Name to be Bar"; 946 BarDiscarded = true; 947 }); 948 949 cantFail(JD.define(MU)); 950 cantFail(JD.define(absoluteSymbols({{Bar, BarSym}}))); 951 952 bool OnCompletionRun = false; 953 954 auto OnCompletion = [&](Expected<SymbolMap> Result) { 955 EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error"; 956 auto I = Result->find(Foo); 957 EXPECT_NE(I, Result->end()) << "Could not find symbol definition"; 958 EXPECT_EQ(I->second.getAddress(), FooSym.getAddress()) 959 << "Resolution returned incorrect result"; 960 OnCompletionRun = true; 961 }; 962 963 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 964 SymbolLookupSet(Foo), SymbolState::Ready, std::move(OnCompletion), 965 NoDependenciesToRegister); 966 967 EXPECT_TRUE(FooMaterialized) << "Foo was not materialized"; 968 EXPECT_TRUE(BarDiscarded) << "Bar was not discarded"; 969 EXPECT_TRUE(OnCompletionRun) << "OnResolutionCallback was not run"; 970 } 971 972 TEST_F(CoreAPIsStandardTest, TestBasicWeakSymbolMaterialization) { 973 // Test that weak symbols are materialized correctly when we look them up. 974 BarSym.setFlags(BarSym.getFlags() | JITSymbolFlags::Weak); 975 976 bool BarMaterialized = false; 977 auto MU1 = std::make_unique<SimpleMaterializationUnit>( 978 SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}), 979 [&](std::unique_ptr<MaterializationResponsibility> R) { 980 cantFail(R->notifyResolved(SymbolMap({{Foo, FooSym}, {Bar, BarSym}}))); 981 cantFail(R->notifyEmitted({})); 982 BarMaterialized = true; 983 }); 984 985 bool DuplicateBarDiscarded = false; 986 auto MU2 = std::make_unique<SimpleMaterializationUnit>( 987 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 988 [&](std::unique_ptr<MaterializationResponsibility> R) { 989 ADD_FAILURE() << "Attempt to materialize Bar from the wrong unit"; 990 R->failMaterialization(); 991 }, 992 nullptr, 993 [&](const JITDylib &JD, SymbolStringPtr Name) { 994 EXPECT_EQ(Name, Bar) << "Expected \"Bar\" to be discarded"; 995 DuplicateBarDiscarded = true; 996 }); 997 998 cantFail(JD.define(MU1)); 999 cantFail(JD.define(MU2)); 1000 1001 bool OnCompletionRun = false; 1002 1003 auto OnCompletion = [&](Expected<SymbolMap> Result) { 1004 cantFail(std::move(Result)); 1005 OnCompletionRun = true; 1006 }; 1007 1008 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 1009 SymbolLookupSet(Bar), SymbolState::Ready, std::move(OnCompletion), 1010 NoDependenciesToRegister); 1011 1012 EXPECT_TRUE(OnCompletionRun) << "OnCompletion not run"; 1013 EXPECT_TRUE(BarMaterialized) << "Bar was not materialized at all"; 1014 EXPECT_TRUE(DuplicateBarDiscarded) 1015 << "Duplicate bar definition not discarded"; 1016 } 1017 1018 TEST_F(CoreAPIsStandardTest, RedefineBoundWeakSymbol) { 1019 // Check that redefinition of a bound weak symbol fails. 1020 1021 JITSymbolFlags WeakExported(JITSymbolFlags::Exported); 1022 WeakExported |= JITSymbolFlags::Weak; 1023 1024 // Define "Foo" as weak, force materialization. 1025 cantFail(JD.define(absoluteSymbols({{Foo, {FooAddr, WeakExported}}}))); 1026 cantFail(ES.lookup({&JD}, Foo)); 1027 1028 // Attempt to redefine "Foo". Expect failure, despite "Foo" being weak, 1029 // since it has already been bound. 1030 EXPECT_THAT_ERROR(JD.define(absoluteSymbols({{Foo, FooSym}})), Failed()); 1031 } 1032 1033 TEST_F(CoreAPIsStandardTest, DefineMaterializingSymbol) { 1034 bool ExpectNoMoreMaterialization = false; 1035 DispatchOverride = [&](std::unique_ptr<Task> T) { 1036 if (ExpectNoMoreMaterialization && isa<MaterializationTask>(*T)) 1037 ADD_FAILURE() << "Unexpected materialization"; 1038 T->run(); 1039 }; 1040 1041 auto MU = std::make_unique<SimpleMaterializationUnit>( 1042 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 1043 [&](std::unique_ptr<MaterializationResponsibility> R) { 1044 cantFail( 1045 R->defineMaterializing(SymbolFlagsMap({{Bar, BarSym.getFlags()}}))); 1046 cantFail(R->notifyResolved(SymbolMap({{Foo, FooSym}, {Bar, BarSym}}))); 1047 cantFail(R->notifyEmitted({})); 1048 }); 1049 1050 cantFail(JD.define(MU)); 1051 cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Foo)); 1052 1053 // Assert that materialization is complete by now. 1054 ExpectNoMoreMaterialization = true; 1055 1056 // Look up bar to verify that no further materialization happens. 1057 auto BarResult = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Bar)); 1058 EXPECT_EQ(BarResult.getAddress(), BarSym.getAddress()) 1059 << "Expected Bar == BarSym"; 1060 } 1061 1062 TEST_F(CoreAPIsStandardTest, GeneratorTest) { 1063 ExecutorSymbolDef BazHiddenSym(BazSym.getAddress(), 1064 BazSym.getFlags() & ~JITSymbolFlags::Exported); 1065 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}, {Baz, BazHiddenSym}}))); 1066 1067 class TestGenerator : public DefinitionGenerator { 1068 public: 1069 TestGenerator(SymbolMap Symbols) : Symbols(std::move(Symbols)) {} 1070 Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD, 1071 JITDylibLookupFlags JDLookupFlags, 1072 const SymbolLookupSet &Names) override { 1073 SymbolMap NewDefs; 1074 1075 for (const auto &KV : Names) { 1076 const auto &Name = KV.first; 1077 if (Symbols.count(Name)) 1078 NewDefs[Name] = Symbols[Name]; 1079 } 1080 1081 cantFail(JD.define(absoluteSymbols(std::move(NewDefs)))); 1082 return Error::success(); 1083 }; 1084 1085 private: 1086 SymbolMap Symbols; 1087 }; 1088 1089 JD.addGenerator(std::make_unique<TestGenerator>( 1090 SymbolMap({{Bar, BarSym}, {Baz, BazSym}}))); 1091 1092 auto Result = cantFail( 1093 ES.lookup(makeJITDylibSearchOrder(&JD), 1094 SymbolLookupSet({Foo, Bar}) 1095 .add(Baz, SymbolLookupFlags::WeaklyReferencedSymbol))); 1096 1097 EXPECT_EQ(Result.count(Bar), 1U) << "Expected to find fallback def for 'bar'"; 1098 EXPECT_EQ(Result[Bar].getAddress(), BarSym.getAddress()) 1099 << "Expected fallback def for Bar to be equal to BarSym"; 1100 } 1101 1102 /// By default appends LookupStates to a queue. 1103 /// Behavior can be overridden by setting TryToGenerateOverride. 1104 class SimpleAsyncGenerator : public DefinitionGenerator { 1105 public: 1106 struct SuspendedLookupInfo { 1107 LookupState LS; 1108 LookupKind K; 1109 JITDylibSP JD; 1110 JITDylibLookupFlags JDLookupFlags; 1111 SymbolLookupSet Names; 1112 }; 1113 1114 unique_function<Error(LookupState &, LookupKind, JITDylib &, 1115 JITDylibLookupFlags, const SymbolLookupSet &)> 1116 TryToGenerateOverride; 1117 1118 Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD, 1119 JITDylibLookupFlags JDLookupFlags, 1120 const SymbolLookupSet &Names) override { 1121 if (TryToGenerateOverride) 1122 return TryToGenerateOverride(LS, K, JD, JDLookupFlags, Names); 1123 Lookup = SuspendedLookupInfo{std::move(LS), K, &JD, JDLookupFlags, Names}; 1124 return Error::success(); 1125 } 1126 1127 SuspendedLookupInfo takeLookup() { 1128 std::optional<SuspendedLookupInfo> Tmp; 1129 std::swap(Tmp, Lookup); 1130 return std::move(*Tmp); 1131 } 1132 1133 std::optional<SuspendedLookupInfo> Lookup; 1134 }; 1135 1136 TEST_F(CoreAPIsStandardTest, SimpleAsynchronousGeneratorTest) { 1137 1138 auto &G = JD.addGenerator(std::make_unique<SimpleAsyncGenerator>()); 1139 1140 bool LookupCompleted = false; 1141 1142 ES.lookup( 1143 LookupKind::Static, makeJITDylibSearchOrder(&JD), SymbolLookupSet(Foo), 1144 SymbolState::Ready, 1145 [&](Expected<SymbolMap> Result) { 1146 LookupCompleted = true; 1147 EXPECT_THAT_EXPECTED(Result, Succeeded()); 1148 if (Result) { 1149 EXPECT_EQ(*Result, SymbolMap({{Foo, FooSym}})); 1150 } 1151 }, 1152 NoDependenciesToRegister); 1153 1154 EXPECT_FALSE(LookupCompleted); 1155 1156 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 1157 G.takeLookup().LS.continueLookup(Error::success()); 1158 1159 EXPECT_TRUE(LookupCompleted); 1160 } 1161 1162 TEST_F(CoreAPIsStandardTest, ErrorFromSuspendedAsynchronousGeneratorTest) { 1163 1164 auto &G = JD.addGenerator(std::make_unique<SimpleAsyncGenerator>()); 1165 1166 bool LookupCompleted = false; 1167 1168 ES.lookup( 1169 LookupKind::Static, makeJITDylibSearchOrder(&JD), SymbolLookupSet(Foo), 1170 SymbolState::Ready, 1171 [&](Expected<SymbolMap> Result) { 1172 LookupCompleted = true; 1173 EXPECT_THAT_EXPECTED(Result, Failed()); 1174 }, 1175 NoDependenciesToRegister); 1176 1177 EXPECT_FALSE(LookupCompleted); 1178 1179 G.takeLookup().LS.continueLookup( 1180 make_error<StringError>("boom", inconvertibleErrorCode())); 1181 1182 EXPECT_TRUE(LookupCompleted); 1183 } 1184 1185 TEST_F(CoreAPIsStandardTest, ErrorFromAutoSuspendedAsynchronousGeneratorTest) { 1186 1187 auto &G = JD.addGenerator(std::make_unique<SimpleAsyncGenerator>()); 1188 1189 std::atomic_size_t LookupsCompleted = 0; 1190 1191 ES.lookup( 1192 LookupKind::Static, makeJITDylibSearchOrder(&JD), SymbolLookupSet(Foo), 1193 SymbolState::Ready, 1194 [&](Expected<SymbolMap> Result) { 1195 ++LookupsCompleted; 1196 EXPECT_THAT_EXPECTED(Result, Failed()); 1197 }, 1198 NoDependenciesToRegister); 1199 1200 EXPECT_EQ(LookupsCompleted, 0U); 1201 1202 // Suspend the first lookup. 1203 auto LS1 = std::move(G.takeLookup().LS); 1204 1205 // Start a second lookup that should be auto-suspended. 1206 ES.lookup( 1207 LookupKind::Static, makeJITDylibSearchOrder(&JD), SymbolLookupSet(Foo), 1208 SymbolState::Ready, 1209 [&](Expected<SymbolMap> Result) { 1210 ++LookupsCompleted; 1211 EXPECT_THAT_EXPECTED(Result, Failed()); 1212 }, 1213 NoDependenciesToRegister); 1214 1215 EXPECT_EQ(LookupsCompleted, 0U); 1216 1217 // Unsuspend the first lookup. 1218 LS1.continueLookup(make_error<StringError>("boom", inconvertibleErrorCode())); 1219 1220 // Unsuspend the second. 1221 G.takeLookup().LS.continueLookup( 1222 make_error<StringError>("boom", inconvertibleErrorCode())); 1223 1224 EXPECT_EQ(LookupsCompleted, 2U); 1225 } 1226 1227 TEST_F(CoreAPIsStandardTest, BlockedGeneratorAutoSuspensionTest) { 1228 // Test that repeated lookups while a generator is in use cause automatic 1229 // lookup suspension / resumption. 1230 1231 auto &G = JD.addGenerator(std::make_unique<SimpleAsyncGenerator>()); 1232 1233 bool Lookup1Completed = false; 1234 bool Lookup2Completed = false; 1235 bool Lookup3Completed = false; 1236 bool Lookup4Completed = false; 1237 1238 // Add lookup 1. 1239 // 1240 // Tests that tryToGenerate-suspended lookups resume auto-suspended lookups 1241 // when the tryToGenerate-suspended lookup continues (i.e. the call to 1242 // OL_resumeLookupAfterGeneration at the top of OL_applyQueryPhase1). 1243 ES.lookup( 1244 LookupKind::Static, makeJITDylibSearchOrder(&JD), SymbolLookupSet(Foo), 1245 SymbolState::Ready, 1246 [&](Expected<SymbolMap> Result) { 1247 Lookup1Completed = true; 1248 EXPECT_THAT_EXPECTED(Result, Succeeded()); 1249 if (Result) { 1250 EXPECT_EQ(*Result, SymbolMap({{Foo, FooSym}})); 1251 } 1252 }, 1253 NoDependenciesToRegister); 1254 1255 // The generator should immediately see the first lookup. 1256 EXPECT_NE(G.Lookup, std::nullopt); 1257 1258 // Add lookup 2. 1259 // 1260 // Tests that lookups that pass through tryToGenerate without being captured 1261 // resume auto-suspended lookups. We set a one-shot TryToGenerateOverride to 1262 // prevent capture of lookup 2 by tryToGenerate. This tests the call to 1263 // OL_resumeLookupAfterGeneration inside the generator loop. 1264 G.TryToGenerateOverride = [&](LookupState &LS, LookupKind K, JITDylib &JD, 1265 JITDylibLookupFlags JDLookupFlags, 1266 const SymbolLookupSet &Names) -> Error { 1267 cantFail(JD.define(absoluteSymbols({{Bar, BarSym}}))); 1268 G.TryToGenerateOverride = nullptr; 1269 return Error::success(); 1270 }; 1271 1272 ES.lookup( 1273 LookupKind::Static, makeJITDylibSearchOrder(&JD), SymbolLookupSet(Bar), 1274 SymbolState::Ready, 1275 [&](Expected<SymbolMap> Result) { 1276 Lookup2Completed = true; 1277 EXPECT_THAT_EXPECTED(Result, Succeeded()); 1278 if (Result) { 1279 EXPECT_EQ(*Result, SymbolMap({{Bar, BarSym}})); 1280 } 1281 }, 1282 NoDependenciesToRegister); 1283 1284 // Add lookup 3. 1285 // 1286 // Test that if a lookup's symbols have already been generated (and it 1287 // consequently skips the generator loop entirely) it still resumes the next 1288 // suspended lookup. This tests the call to OL_resumeLookupAfterGeneration 1289 // just above the generator loop. 1290 ES.lookup( 1291 LookupKind::Static, makeJITDylibSearchOrder(&JD), SymbolLookupSet(Bar), 1292 SymbolState::Ready, 1293 [&](Expected<SymbolMap> Result) { 1294 Lookup3Completed = true; 1295 EXPECT_THAT_EXPECTED(Result, Succeeded()); 1296 if (Result) { 1297 EXPECT_EQ(*Result, SymbolMap({{Bar, BarSym}})); 1298 } 1299 }, 1300 NoDependenciesToRegister); 1301 1302 // Add lookup 4. 1303 // 1304 // This is just used to verify that lookup 3 triggered resumption of the next 1305 // lookup as expected. 1306 ES.lookup( 1307 LookupKind::Static, makeJITDylibSearchOrder(&JD), SymbolLookupSet(Baz), 1308 SymbolState::Ready, 1309 [&](Expected<SymbolMap> Result) { 1310 Lookup4Completed = true; 1311 EXPECT_THAT_EXPECTED(Result, Succeeded()); 1312 if (Result) { 1313 EXPECT_EQ(*Result, SymbolMap({{Baz, BazSym}})); 1314 } 1315 }, 1316 NoDependenciesToRegister); 1317 1318 // All lookups have been started, but none should have been completed yet. 1319 EXPECT_FALSE(Lookup1Completed); 1320 EXPECT_FALSE(Lookup2Completed); 1321 EXPECT_FALSE(Lookup3Completed); 1322 EXPECT_FALSE(Lookup4Completed); 1323 1324 // Start continuing lookups. 1325 1326 // First Define foo and continue lookup 1. We expect this to complete lookups 1327 // 1, 2 and 3: the TryToGenerateOverride set above will define bar, which will 1328 // allow both 2 and 3 to complete. 1329 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 1330 G.takeLookup().LS.continueLookup(Error::success()); 1331 1332 EXPECT_TRUE(Lookup1Completed); 1333 EXPECT_TRUE(Lookup2Completed); 1334 EXPECT_TRUE(Lookup3Completed); 1335 EXPECT_FALSE(Lookup4Completed); 1336 EXPECT_NE(G.Lookup, std::nullopt); 1337 1338 // Check that the most recently captured lookup is lookup 4 (for baz). 1339 if (G.Lookup) { 1340 EXPECT_EQ(G.Lookup->Names.begin()->first, Baz); 1341 } 1342 1343 cantFail(JD.define(absoluteSymbols({{Baz, BazSym}}))); 1344 G.takeLookup().LS.continueLookup(Error::success()); 1345 1346 EXPECT_TRUE(Lookup4Completed); 1347 } 1348 1349 TEST_F(CoreAPIsStandardTest, FailResolution) { 1350 auto MU = std::make_unique<SimpleMaterializationUnit>( 1351 SymbolFlagsMap({{Foo, JITSymbolFlags::Exported | JITSymbolFlags::Weak}, 1352 {Bar, JITSymbolFlags::Exported | JITSymbolFlags::Weak}}), 1353 [&](std::unique_ptr<MaterializationResponsibility> R) { 1354 R->failMaterialization(); 1355 }); 1356 1357 cantFail(JD.define(MU)); 1358 1359 SymbolNameSet Names({Foo, Bar}); 1360 auto Result = ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet(Names)); 1361 1362 EXPECT_FALSE(!!Result) << "Expected failure"; 1363 if (!Result) { 1364 handleAllErrors( 1365 Result.takeError(), 1366 [&](FailedToMaterialize &F) { 1367 EXPECT_TRUE(F.getSymbols().count(&JD)) 1368 << "Expected to fail on JITDylib JD"; 1369 EXPECT_EQ(F.getSymbols().find(&JD)->second, Names) 1370 << "Expected to fail on symbols in Names"; 1371 }, 1372 [](ErrorInfoBase &EIB) { 1373 std::string ErrMsg; 1374 { 1375 raw_string_ostream ErrOut(ErrMsg); 1376 EIB.log(ErrOut); 1377 } 1378 ADD_FAILURE() << "Expected a FailedToResolve error. Got:\n" << ErrMsg; 1379 }); 1380 } 1381 } 1382 1383 TEST_F(CoreAPIsStandardTest, FailEmissionAfterResolution) { 1384 1385 cantFail(JD.define(absoluteSymbols({{Baz, BazSym}}))); 1386 1387 auto MU = std::make_unique<SimpleMaterializationUnit>( 1388 SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}), 1389 [&](std::unique_ptr<MaterializationResponsibility> R) { 1390 cantFail(R->notifyResolved(SymbolMap({{Foo, FooSym}, {Bar, BarSym}}))); 1391 ES.lookup( 1392 LookupKind::Static, makeJITDylibSearchOrder(&JD), 1393 SymbolLookupSet({Baz}), SymbolState::Resolved, 1394 [&](Expected<SymbolMap> Result) { 1395 // Called when "baz" is resolved. We don't actually depend 1396 // on or care about baz, but use it to trigger failure of 1397 // this materialization before Baz has been finalized in 1398 // order to test that error propagation is correct in this 1399 // scenario. 1400 cantFail(std::move(Result)); 1401 R->failMaterialization(); 1402 }, 1403 NoDependenciesToRegister); 1404 }); 1405 1406 cantFail(JD.define(MU)); 1407 1408 auto Result = 1409 ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Foo, Bar})); 1410 1411 EXPECT_THAT_EXPECTED(std::move(Result), Failed()) 1412 << "Unexpected success while trying to test error propagation"; 1413 } 1414 1415 TEST_F(CoreAPIsStandardTest, FailAfterPartialResolution) { 1416 1417 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 1418 1419 // Fail materialization of bar. 1420 auto BarMU = std::make_unique<SimpleMaterializationUnit>( 1421 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 1422 [&](std::unique_ptr<MaterializationResponsibility> R) { 1423 R->failMaterialization(); 1424 }); 1425 1426 cantFail(JD.define(std::move(BarMU))); 1427 1428 bool QueryHandlerRun = false; 1429 ES.lookup( 1430 LookupKind::Static, makeJITDylibSearchOrder(&JD), 1431 SymbolLookupSet({Foo, Bar}), SymbolState::Resolved, 1432 [&](Expected<SymbolMap> Result) { 1433 EXPECT_THAT_EXPECTED(std::move(Result), Failed()) 1434 << "Expected query to fail"; 1435 QueryHandlerRun = true; 1436 }, 1437 NoDependenciesToRegister); 1438 EXPECT_TRUE(QueryHandlerRun) << "Query handler never ran"; 1439 } 1440 1441 TEST_F(CoreAPIsStandardTest, FailDefineMaterializingDueToDefunctTracker) { 1442 // Check that a defunct resource tracker causes defineMaterializing to error 1443 // immediately. 1444 1445 std::unique_ptr<MaterializationResponsibility> FooMR; 1446 auto MU = std::make_unique<SimpleMaterializationUnit>( 1447 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 1448 [&](std::unique_ptr<MaterializationResponsibility> R) { 1449 FooMR = std::move(R); 1450 }); 1451 1452 auto RT = JD.createResourceTracker(); 1453 cantFail(JD.define(std::move(MU), RT)); 1454 1455 bool OnCompletionRan = false; 1456 auto OnCompletion = [&](Expected<SymbolMap> Result) { 1457 EXPECT_THAT_EXPECTED(Result, Failed()); 1458 OnCompletionRan = true; 1459 }; 1460 1461 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 1462 SymbolLookupSet(Foo), SymbolState::Ready, OnCompletion, 1463 NoDependenciesToRegister); 1464 1465 cantFail(RT->remove()); 1466 1467 EXPECT_THAT_ERROR(FooMR->defineMaterializing(SymbolFlagsMap()), Failed()) 1468 << "defineMaterializing should have failed due to a defunct tracker"; 1469 1470 FooMR->failMaterialization(); 1471 1472 EXPECT_TRUE(OnCompletionRan) << "OnCompletion handler did not run."; 1473 } 1474 1475 TEST_F(CoreAPIsStandardTest, TestLookupWithUnthreadedMaterialization) { 1476 auto MU = std::make_unique<SimpleMaterializationUnit>( 1477 SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}}), 1478 [&](std::unique_ptr<MaterializationResponsibility> R) { 1479 cantFail(R->notifyResolved({{Foo, FooSym}})); 1480 cantFail(R->notifyEmitted({})); 1481 }); 1482 1483 cantFail(JD.define(MU)); 1484 1485 auto FooLookupResult = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Foo)); 1486 1487 EXPECT_EQ(FooLookupResult.getAddress(), FooSym.getAddress()) 1488 << "lookup returned an incorrect address"; 1489 EXPECT_EQ(FooLookupResult.getFlags(), FooSym.getFlags()) 1490 << "lookup returned incorrect flags"; 1491 } 1492 1493 TEST_F(CoreAPIsStandardTest, TestLookupWithThreadedMaterialization) { 1494 #if LLVM_ENABLE_THREADS 1495 1496 std::mutex WorkThreadsMutex; 1497 std::vector<std::thread> WorkThreads; 1498 DispatchOverride = [&](std::unique_ptr<Task> T) { 1499 std::promise<void> WaitP; 1500 std::lock_guard<std::mutex> Lock(WorkThreadsMutex); 1501 WorkThreads.push_back( 1502 std::thread([T = std::move(T), WaitF = WaitP.get_future()]() mutable { 1503 WaitF.get(); 1504 T->run(); 1505 })); 1506 WaitP.set_value(); 1507 }; 1508 1509 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 1510 1511 auto FooLookupResult = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Foo)); 1512 1513 EXPECT_EQ(FooLookupResult.getAddress(), FooSym.getAddress()) 1514 << "lookup returned an incorrect address"; 1515 EXPECT_EQ(FooLookupResult.getFlags(), FooSym.getFlags()) 1516 << "lookup returned incorrect flags"; 1517 1518 for (auto &WT : WorkThreads) 1519 WT.join(); 1520 #endif 1521 } 1522 1523 TEST_F(CoreAPIsStandardTest, TestGetRequestedSymbolsAndReplace) { 1524 // Test that GetRequestedSymbols returns the set of symbols that currently 1525 // have pending queries, and test that MaterializationResponsibility's 1526 // replace method can be used to return definitions to the JITDylib in a new 1527 // MaterializationUnit. 1528 SymbolNameSet Names({Foo, Bar}); 1529 1530 bool FooMaterialized = false; 1531 bool BarMaterialized = false; 1532 1533 auto MU = std::make_unique<SimpleMaterializationUnit>( 1534 SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}), 1535 [&](std::unique_ptr<MaterializationResponsibility> R) { 1536 auto Requested = R->getRequestedSymbols(); 1537 EXPECT_EQ(Requested.size(), 1U) << "Expected one symbol requested"; 1538 EXPECT_EQ(*Requested.begin(), Foo) << "Expected \"Foo\" requested"; 1539 1540 auto NewMU = std::make_unique<SimpleMaterializationUnit>( 1541 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 1542 [&](std::unique_ptr<MaterializationResponsibility> R2) { 1543 cantFail(R2->notifyResolved(SymbolMap({{Bar, BarSym}}))); 1544 cantFail(R2->notifyEmitted({})); 1545 BarMaterialized = true; 1546 }); 1547 1548 cantFail(R->replace(std::move(NewMU))); 1549 1550 cantFail(R->notifyResolved(SymbolMap({{Foo, FooSym}}))); 1551 cantFail(R->notifyEmitted({})); 1552 1553 FooMaterialized = true; 1554 }); 1555 1556 cantFail(JD.define(MU)); 1557 1558 EXPECT_FALSE(FooMaterialized) << "Foo should not be materialized yet"; 1559 EXPECT_FALSE(BarMaterialized) << "Bar should not be materialized yet"; 1560 1561 auto FooSymResult = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Foo)); 1562 EXPECT_EQ(FooSymResult.getAddress(), FooSym.getAddress()) 1563 << "Address mismatch for Foo"; 1564 1565 EXPECT_TRUE(FooMaterialized) << "Foo should be materialized now"; 1566 EXPECT_FALSE(BarMaterialized) << "Bar still should not be materialized"; 1567 1568 auto BarSymResult = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Bar)); 1569 EXPECT_EQ(BarSymResult.getAddress(), BarSym.getAddress()) 1570 << "Address mismatch for Bar"; 1571 EXPECT_TRUE(BarMaterialized) << "Bar should be materialized now"; 1572 } 1573 1574 TEST_F(CoreAPIsStandardTest, TestMaterializationResponsibilityDelegation) { 1575 auto MU = std::make_unique<SimpleMaterializationUnit>( 1576 SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}), 1577 [&](std::unique_ptr<MaterializationResponsibility> R) { 1578 auto R2 = cantFail(R->delegate({Bar})); 1579 1580 cantFail(R->notifyResolved({{Foo, FooSym}})); 1581 cantFail(R->notifyEmitted({})); 1582 cantFail(R2->notifyResolved({{Bar, BarSym}})); 1583 cantFail(R2->notifyEmitted({})); 1584 }); 1585 1586 cantFail(JD.define(MU)); 1587 1588 auto Result = 1589 ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Foo, Bar})); 1590 1591 EXPECT_TRUE(!!Result) << "Result should be a success value"; 1592 EXPECT_EQ(Result->count(Foo), 1U) << "\"Foo\" entry missing"; 1593 EXPECT_EQ(Result->count(Bar), 1U) << "\"Bar\" entry missing"; 1594 EXPECT_EQ((*Result)[Foo].getAddress(), FooSym.getAddress()) 1595 << "Address mismatch for \"Foo\""; 1596 EXPECT_EQ((*Result)[Bar].getAddress(), BarSym.getAddress()) 1597 << "Address mismatch for \"Bar\""; 1598 } 1599 1600 TEST_F(CoreAPIsStandardTest, TestMaterializeWeakSymbol) { 1601 // Confirm that once a weak definition is selected for materialization it is 1602 // treated as strong. 1603 JITSymbolFlags WeakExported = JITSymbolFlags::Exported; 1604 WeakExported &= JITSymbolFlags::Weak; 1605 1606 std::unique_ptr<MaterializationResponsibility> FooR; 1607 auto MU = std::make_unique<SimpleMaterializationUnit>( 1608 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 1609 [&](std::unique_ptr<MaterializationResponsibility> R) { 1610 FooR = std::move(R); 1611 }); 1612 1613 cantFail(JD.define(MU)); 1614 auto OnCompletion = [](Expected<SymbolMap> Result) { 1615 cantFail(std::move(Result)); 1616 }; 1617 1618 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 1619 SymbolLookupSet({Foo}), SymbolState::Ready, std::move(OnCompletion), 1620 NoDependenciesToRegister); 1621 1622 auto MU2 = std::make_unique<SimpleMaterializationUnit>( 1623 SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}}), 1624 [](std::unique_ptr<MaterializationResponsibility> R) { 1625 llvm_unreachable("This unit should never be materialized"); 1626 }); 1627 1628 auto Err = JD.define(MU2); 1629 EXPECT_TRUE(!!Err) << "Expected failure value"; 1630 EXPECT_TRUE(Err.isA<DuplicateDefinition>()) 1631 << "Expected a duplicate definition error"; 1632 consumeError(std::move(Err)); 1633 1634 // No dependencies registered, can't fail: 1635 cantFail(FooR->notifyResolved(SymbolMap({{Foo, FooSym}}))); 1636 cantFail(FooR->notifyEmitted({})); 1637 } 1638 1639 static bool linkOrdersEqual(const std::vector<JITDylibSP> &LHS, 1640 ArrayRef<JITDylib *> RHS) { 1641 if (LHS.size() != RHS.size()) 1642 return false; 1643 auto *RHSE = RHS.begin(); 1644 for (auto &LHSE : LHS) 1645 if (LHSE.get() != *RHSE) 1646 return false; 1647 else 1648 ++RHSE; 1649 return true; 1650 } 1651 1652 TEST(JITDylibTest, GetDFSLinkOrderTree) { 1653 // Test that DFS ordering behaves as expected when the linkage relationships 1654 // form a tree. 1655 1656 ExecutionSession ES{std::make_unique<UnsupportedExecutorProcessControl>()}; 1657 auto _ = make_scope_exit([&]() { cantFail(ES.endSession()); }); 1658 1659 auto &LibA = ES.createBareJITDylib("A"); 1660 auto &LibB = ES.createBareJITDylib("B"); 1661 auto &LibC = ES.createBareJITDylib("C"); 1662 auto &LibD = ES.createBareJITDylib("D"); 1663 auto &LibE = ES.createBareJITDylib("E"); 1664 auto &LibF = ES.createBareJITDylib("F"); 1665 1666 // Linkage relationships: 1667 // A --- B -- D 1668 // \ \- E 1669 // \- C -- F 1670 LibA.setLinkOrder(makeJITDylibSearchOrder({&LibB, &LibC})); 1671 LibB.setLinkOrder(makeJITDylibSearchOrder({&LibD, &LibE})); 1672 LibC.setLinkOrder(makeJITDylibSearchOrder({&LibF})); 1673 1674 auto DFSOrderFromB = cantFail(JITDylib::getDFSLinkOrder({&LibB})); 1675 EXPECT_TRUE(linkOrdersEqual(DFSOrderFromB, {&LibB, &LibD, &LibE})) 1676 << "Incorrect DFS link order for LibB"; 1677 1678 auto DFSOrderFromA = cantFail(JITDylib::getDFSLinkOrder({&LibA})); 1679 EXPECT_TRUE(linkOrdersEqual(DFSOrderFromA, 1680 {&LibA, &LibB, &LibD, &LibE, &LibC, &LibF})) 1681 << "Incorrect DFS link order for libA"; 1682 1683 auto DFSOrderFromAB = cantFail(JITDylib::getDFSLinkOrder({&LibA, &LibB})); 1684 EXPECT_TRUE(linkOrdersEqual(DFSOrderFromAB, 1685 {&LibA, &LibB, &LibD, &LibE, &LibC, &LibF})) 1686 << "Incorrect DFS link order for { libA, libB }"; 1687 1688 auto DFSOrderFromBA = cantFail(JITDylib::getDFSLinkOrder({&LibB, &LibA})); 1689 EXPECT_TRUE(linkOrdersEqual(DFSOrderFromBA, 1690 {&LibB, &LibD, &LibE, &LibA, &LibC, &LibF})) 1691 << "Incorrect DFS link order for { libB, libA }"; 1692 } 1693 1694 TEST(JITDylibTest, GetDFSLinkOrderDiamond) { 1695 // Test that DFS ordering behaves as expected when the linkage relationships 1696 // contain a diamond. 1697 1698 ExecutionSession ES{std::make_unique<UnsupportedExecutorProcessControl>()}; 1699 auto _ = make_scope_exit([&]() { cantFail(ES.endSession()); }); 1700 1701 auto &LibA = ES.createBareJITDylib("A"); 1702 auto &LibB = ES.createBareJITDylib("B"); 1703 auto &LibC = ES.createBareJITDylib("C"); 1704 auto &LibD = ES.createBareJITDylib("D"); 1705 1706 // Linkage relationships: 1707 // A -- B --- D 1708 // \-- C --/ 1709 LibA.setLinkOrder(makeJITDylibSearchOrder({&LibB, &LibC})); 1710 LibB.setLinkOrder(makeJITDylibSearchOrder({&LibD})); 1711 LibC.setLinkOrder(makeJITDylibSearchOrder({&LibD})); 1712 1713 auto DFSOrderFromA = cantFail(JITDylib::getDFSLinkOrder({&LibA})); 1714 EXPECT_TRUE(linkOrdersEqual(DFSOrderFromA, {&LibA, &LibB, &LibD, &LibC})) 1715 << "Incorrect DFS link order for libA"; 1716 } 1717 1718 TEST(JITDylibTest, GetDFSLinkOrderCycle) { 1719 // Test that DFS ordering behaves as expected when the linkage relationships 1720 // contain a cycle. 1721 1722 ExecutionSession ES{std::make_unique<UnsupportedExecutorProcessControl>()}; 1723 auto _ = make_scope_exit([&]() { cantFail(ES.endSession()); }); 1724 1725 auto &LibA = ES.createBareJITDylib("A"); 1726 auto &LibB = ES.createBareJITDylib("B"); 1727 auto &LibC = ES.createBareJITDylib("C"); 1728 1729 // Linkage relationships: 1730 // A -- B --- C -- A 1731 LibA.setLinkOrder(makeJITDylibSearchOrder({&LibB})); 1732 LibB.setLinkOrder(makeJITDylibSearchOrder({&LibC})); 1733 LibC.setLinkOrder(makeJITDylibSearchOrder({&LibA})); 1734 1735 auto DFSOrderFromA = cantFail(JITDylib::getDFSLinkOrder({&LibA})); 1736 EXPECT_TRUE(linkOrdersEqual(DFSOrderFromA, {&LibA, &LibB, &LibC})) 1737 << "Incorrect DFS link order for libA"; 1738 1739 auto DFSOrderFromB = cantFail(JITDylib::getDFSLinkOrder({&LibB})); 1740 EXPECT_TRUE(linkOrdersEqual(DFSOrderFromB, {&LibB, &LibC, &LibA})) 1741 << "Incorrect DFS link order for libB"; 1742 1743 auto DFSOrderFromC = cantFail(JITDylib::getDFSLinkOrder({&LibC})); 1744 EXPECT_TRUE(linkOrdersEqual(DFSOrderFromC, {&LibC, &LibA, &LibB})) 1745 << "Incorrect DFS link order for libC"; 1746 } 1747 1748 TEST_F(CoreAPIsStandardTest, RemoveJITDylibs) { 1749 // Foo will be fully materialized. 1750 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 1751 1752 // Bar should not be materialized at all. 1753 bool BarMaterializerDestroyed = false; 1754 cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>( 1755 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 1756 [&](std::unique_ptr<MaterializationResponsibility> MR) { 1757 llvm_unreachable("Unexpected call to materialize"); 1758 }, 1759 nullptr, 1760 [](const JITDylib &, SymbolStringPtr Name) { 1761 llvm_unreachable("Unexpected call to discard"); 1762 }, 1763 [&]() { BarMaterializerDestroyed = true; }))); 1764 1765 // Baz will be in the materializing state. 1766 std::unique_ptr<MaterializationResponsibility> BazMR; 1767 cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>( 1768 SymbolFlagsMap({{Baz, BazSym.getFlags()}}), 1769 [&](std::unique_ptr<MaterializationResponsibility> MR) { 1770 BazMR = std::move(MR); 1771 }))); 1772 1773 // Lookup to force materialization of Foo. 1774 cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Foo}))); 1775 1776 // Start a lookup to force materialization of Baz. 1777 bool BazLookupFailed = false; 1778 ES.lookup( 1779 LookupKind::Static, makeJITDylibSearchOrder(&JD), SymbolLookupSet({Baz}), 1780 SymbolState::Ready, 1781 [&](Expected<SymbolMap> Result) { 1782 if (!Result) { 1783 BazLookupFailed = true; 1784 consumeError(Result.takeError()); 1785 } 1786 }, 1787 NoDependenciesToRegister); 1788 1789 // Remove the JITDylib. 1790 auto Err = ES.removeJITDylib(JD); 1791 EXPECT_THAT_ERROR(std::move(Err), Succeeded()); 1792 1793 EXPECT_TRUE(BarMaterializerDestroyed); 1794 EXPECT_TRUE(BazLookupFailed); 1795 1796 EXPECT_THAT_ERROR(BazMR->notifyResolved({{Baz, BazSym}}), Failed()); 1797 1798 EXPECT_THAT_EXPECTED(JD.getDFSLinkOrder(), Failed()); 1799 1800 BazMR->failMaterialization(); 1801 } 1802 1803 TEST(CoreAPIsExtraTest, SessionTeardownByFailedToMaterialize) { 1804 1805 auto RunTestCase = []() -> Error { 1806 ExecutionSession ES{std::make_unique<UnsupportedExecutorProcessControl>( 1807 std::make_shared<SymbolStringPool>())}; 1808 auto Foo = ES.intern("foo"); 1809 auto FooFlags = JITSymbolFlags::Exported; 1810 1811 auto &JD = ES.createBareJITDylib("Foo"); 1812 cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>( 1813 SymbolFlagsMap({{Foo, FooFlags}}), 1814 [&](std::unique_ptr<MaterializationResponsibility> R) { 1815 R->failMaterialization(); 1816 }))); 1817 1818 auto Sym = ES.lookup({&JD}, Foo); 1819 assert(!Sym && "Query should have failed"); 1820 cantFail(ES.endSession()); 1821 return Sym.takeError(); 1822 }; 1823 1824 auto Err = RunTestCase(); 1825 EXPECT_TRUE(!!Err); // Expect that error occurred. 1826 EXPECT_TRUE( 1827 Err.isA<FailedToMaterialize>()); // Expect FailedToMaterialize error. 1828 1829 // Make sure that we can log errors, even though the session has been 1830 // destroyed. 1831 logAllUnhandledErrors(std::move(Err), nulls(), ""); 1832 } 1833 1834 } // namespace 1835