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