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