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