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