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