1 //===----------- CoreAPIsTest.cpp - Unit tests for Core ORC APIs ----------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "OrcTestCommon.h" 11 #include "llvm/Config/llvm-config.h" 12 #include "llvm/ExecutionEngine/Orc/Core.h" 13 #include "llvm/ExecutionEngine/Orc/OrcError.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 class SimpleMaterializationUnit : public MaterializationUnit { 26 public: 27 using MaterializeFunction = 28 std::function<void(MaterializationResponsibility)>; 29 using DiscardFunction = 30 std::function<void(const JITDylib &, SymbolStringPtr)>; 31 using DestructorFunction = std::function<void()>; 32 33 SimpleMaterializationUnit( 34 SymbolFlagsMap SymbolFlags, MaterializeFunction Materialize, 35 DiscardFunction Discard = DiscardFunction(), 36 DestructorFunction Destructor = DestructorFunction()) 37 : MaterializationUnit(std::move(SymbolFlags)), 38 Materialize(std::move(Materialize)), Discard(std::move(Discard)), 39 Destructor(std::move(Destructor)) {} 40 41 ~SimpleMaterializationUnit() override { 42 if (Destructor) 43 Destructor(); 44 } 45 46 void materialize(MaterializationResponsibility R) override { 47 Materialize(std::move(R)); 48 } 49 50 void discard(const JITDylib &JD, SymbolStringPtr Name) override { 51 if (Discard) 52 Discard(JD, std::move(Name)); 53 else 54 llvm_unreachable("Discard not supported"); 55 } 56 57 private: 58 MaterializeFunction Materialize; 59 DiscardFunction Discard; 60 DestructorFunction Destructor; 61 }; 62 63 TEST_F(CoreAPIsStandardTest, BasicSuccessfulLookup) { 64 bool OnResolutionRun = false; 65 bool OnReadyRun = false; 66 67 auto OnResolution = [&](Expected<SymbolMap> Result) { 68 EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error"; 69 auto &Resolved = *Result; 70 auto I = Resolved.find(Foo); 71 EXPECT_NE(I, Resolved.end()) << "Could not find symbol definition"; 72 EXPECT_EQ(I->second.getAddress(), FooAddr) 73 << "Resolution returned incorrect result"; 74 OnResolutionRun = true; 75 }; 76 auto OnReady = [&](Error Err) { 77 cantFail(std::move(Err)); 78 OnReadyRun = true; 79 }; 80 81 std::shared_ptr<MaterializationResponsibility> FooMR; 82 83 cantFail(JD.define(llvm::make_unique<SimpleMaterializationUnit>( 84 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 85 [&](MaterializationResponsibility R) { 86 FooMR = std::make_shared<MaterializationResponsibility>(std::move(R)); 87 }))); 88 89 ES.lookup({&JD}, {Foo}, OnResolution, OnReady, NoDependenciesToRegister); 90 91 EXPECT_FALSE(OnResolutionRun) << "Should not have been resolved yet"; 92 EXPECT_FALSE(OnReadyRun) << "Should not have been marked ready yet"; 93 94 FooMR->resolve({{Foo, FooSym}}); 95 96 EXPECT_TRUE(OnResolutionRun) << "Should have been resolved"; 97 EXPECT_FALSE(OnReadyRun) << "Should not have been marked ready yet"; 98 99 FooMR->emit(); 100 101 EXPECT_TRUE(OnReadyRun) << "Should have been marked ready"; 102 } 103 104 TEST_F(CoreAPIsStandardTest, ExecutionSessionFailQuery) { 105 bool OnResolutionRun = false; 106 bool OnReadyRun = false; 107 108 auto OnResolution = [&](Expected<SymbolMap> Result) { 109 EXPECT_FALSE(!!Result) << "Resolution unexpectedly returned success"; 110 auto Msg = toString(Result.takeError()); 111 EXPECT_EQ(Msg, "xyz") << "Resolution returned incorrect result"; 112 OnResolutionRun = true; 113 }; 114 auto OnReady = [&](Error Err) { 115 cantFail(std::move(Err)); 116 OnReadyRun = true; 117 }; 118 119 AsynchronousSymbolQuery Q(SymbolNameSet({Foo}), OnResolution, OnReady); 120 121 ES.legacyFailQuery(Q, 122 make_error<StringError>("xyz", inconvertibleErrorCode())); 123 124 EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run"; 125 EXPECT_FALSE(OnReadyRun) << "OnReady unexpectedly run"; 126 } 127 128 TEST_F(CoreAPIsStandardTest, EmptyLookup) { 129 bool OnResolvedRun = false; 130 bool OnReadyRun = false; 131 132 auto OnResolution = [&](Expected<SymbolMap> Result) { 133 cantFail(std::move(Result)); 134 OnResolvedRun = true; 135 }; 136 137 auto OnReady = [&](Error Err) { 138 cantFail(std::move(Err)); 139 OnReadyRun = true; 140 }; 141 142 ES.lookup({&JD}, {}, OnResolution, OnReady, NoDependenciesToRegister); 143 144 EXPECT_TRUE(OnResolvedRun) << "OnResolved was not run for empty query"; 145 EXPECT_TRUE(OnReadyRun) << "OnReady was not run for empty query"; 146 } 147 148 TEST_F(CoreAPIsStandardTest, ChainedJITDylibLookup) { 149 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 150 151 auto &JD2 = ES.createJITDylib("JD2"); 152 153 bool OnResolvedRun = false; 154 bool OnReadyRun = false; 155 156 auto Q = std::make_shared<AsynchronousSymbolQuery>( 157 SymbolNameSet({Foo}), 158 [&](Expected<SymbolMap> Result) { 159 cantFail(std::move(Result)); 160 OnResolvedRun = true; 161 }, 162 [&](Error Err) { 163 cantFail(std::move(Err)); 164 OnReadyRun = true; 165 }); 166 167 JD2.legacyLookup(Q, JD.legacyLookup(Q, {Foo})); 168 169 EXPECT_TRUE(OnResolvedRun) << "OnResolved was not run for empty query"; 170 EXPECT_TRUE(OnReadyRun) << "OnReady was not run for empty query"; 171 } 172 173 TEST_F(CoreAPIsStandardTest, LookupFlagsTest) { 174 // Test that lookupFlags works on a predefined symbol, and does not trigger 175 // materialization of a lazy symbol. Make the lazy symbol weak to test that 176 // the weak flag is propagated correctly. 177 178 BarSym.setFlags(static_cast<JITSymbolFlags::FlagNames>( 179 JITSymbolFlags::Exported | JITSymbolFlags::Weak)); 180 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 181 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 182 [](MaterializationResponsibility R) { 183 llvm_unreachable("Symbol materialized on flags lookup"); 184 }); 185 186 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 187 cantFail(JD.define(std::move(MU))); 188 189 SymbolNameSet Names({Foo, Bar, Baz}); 190 191 auto SymbolFlags = JD.lookupFlags(Names); 192 193 EXPECT_EQ(SymbolFlags.size(), 2U) 194 << "Returned symbol flags contains unexpected results"; 195 EXPECT_EQ(SymbolFlags.count(Foo), 1U) << "Missing lookupFlags result for Foo"; 196 EXPECT_EQ(SymbolFlags[Foo], FooSym.getFlags()) 197 << "Incorrect flags returned for Foo"; 198 EXPECT_EQ(SymbolFlags.count(Bar), 1U) 199 << "Missing lookupFlags result for Bar"; 200 EXPECT_EQ(SymbolFlags[Bar], BarSym.getFlags()) 201 << "Incorrect flags returned for Bar"; 202 } 203 204 TEST_F(CoreAPIsStandardTest, TestBasicAliases) { 205 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}, {Bar, BarSym}}))); 206 cantFail(JD.define(symbolAliases({{Baz, {Foo, JITSymbolFlags::Exported}}, 207 {Qux, {Bar, JITSymbolFlags::Weak}}}))); 208 cantFail(JD.define(absoluteSymbols({{Qux, QuxSym}}))); 209 210 auto Result = lookup({&JD}, {Baz, Qux}); 211 EXPECT_TRUE(!!Result) << "Unexpected lookup failure"; 212 EXPECT_EQ(Result->count(Baz), 1U) << "No result for \"baz\""; 213 EXPECT_EQ(Result->count(Qux), 1U) << "No result for \"qux\""; 214 EXPECT_EQ((*Result)[Baz].getAddress(), FooSym.getAddress()) 215 << "\"Baz\"'s address should match \"Foo\"'s"; 216 EXPECT_EQ((*Result)[Qux].getAddress(), QuxSym.getAddress()) 217 << "The \"Qux\" alias should have been overriden"; 218 } 219 220 TEST_F(CoreAPIsStandardTest, TestChainedAliases) { 221 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 222 cantFail(JD.define(symbolAliases( 223 {{Baz, {Bar, BazSym.getFlags()}}, {Bar, {Foo, BarSym.getFlags()}}}))); 224 225 auto Result = lookup({&JD}, {Bar, Baz}); 226 EXPECT_TRUE(!!Result) << "Unexpected lookup failure"; 227 EXPECT_EQ(Result->count(Bar), 1U) << "No result for \"bar\""; 228 EXPECT_EQ(Result->count(Baz), 1U) << "No result for \"baz\""; 229 EXPECT_EQ((*Result)[Bar].getAddress(), FooSym.getAddress()) 230 << "\"Bar\"'s address should match \"Foo\"'s"; 231 EXPECT_EQ((*Result)[Baz].getAddress(), FooSym.getAddress()) 232 << "\"Baz\"'s address should match \"Foo\"'s"; 233 } 234 235 TEST_F(CoreAPIsStandardTest, TestBasicReExports) { 236 // Test that the basic use case of re-exporting a single symbol from another 237 // JITDylib works. 238 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 239 240 auto &JD2 = ES.createJITDylib("JD2"); 241 242 cantFail(JD2.define(reexports(JD, {{Bar, {Foo, BarSym.getFlags()}}}))); 243 244 auto Result = cantFail(lookup({&JD2}, Bar)); 245 EXPECT_EQ(Result.getAddress(), FooSym.getAddress()) 246 << "Re-export Bar for symbol Foo should match FooSym's address"; 247 } 248 249 TEST_F(CoreAPIsStandardTest, TestThatReExportsDontUnnecessarilyMaterialize) { 250 // Test that re-exports do not materialize symbols that have not been queried 251 // for. 252 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 253 254 bool BarMaterialized = false; 255 auto BarMU = llvm::make_unique<SimpleMaterializationUnit>( 256 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 257 [&](MaterializationResponsibility R) { 258 BarMaterialized = true; 259 R.resolve({{Bar, BarSym}}); 260 R.emit(); 261 }); 262 263 cantFail(JD.define(BarMU)); 264 265 auto &JD2 = ES.createJITDylib("JD2"); 266 267 cantFail(JD2.define(reexports( 268 JD, {{Baz, {Foo, BazSym.getFlags()}}, {Qux, {Bar, QuxSym.getFlags()}}}))); 269 270 auto Result = cantFail(lookup({&JD2}, Baz)); 271 EXPECT_EQ(Result.getAddress(), FooSym.getAddress()) 272 << "Re-export Baz for symbol Foo should match FooSym's address"; 273 274 EXPECT_FALSE(BarMaterialized) << "Bar should not have been materialized"; 275 } 276 277 TEST_F(CoreAPIsStandardTest, TestReexportsFallbackGenerator) { 278 // Test that a re-exports fallback generator can dynamically generate 279 // reexports. 280 281 auto &JD2 = ES.createJITDylib("JD2"); 282 cantFail(JD2.define(absoluteSymbols({{Foo, FooSym}, {Bar, BarSym}}))); 283 284 auto Filter = [this](SymbolStringPtr Name) { return Name != Bar; }; 285 286 JD.setFallbackDefinitionGenerator( 287 ReexportsFallbackDefinitionGenerator(JD2, Filter)); 288 289 auto Flags = JD.lookupFlags({Foo, Bar, Baz}); 290 EXPECT_EQ(Flags.size(), 1U) << "Unexpected number of results"; 291 EXPECT_EQ(Flags[Foo], FooSym.getFlags()) << "Unexpected flags for Foo"; 292 293 auto Result = cantFail(lookup({&JD}, Foo)); 294 295 EXPECT_EQ(Result.getAddress(), FooSym.getAddress()) 296 << "Incorrect reexported symbol address"; 297 } 298 299 TEST_F(CoreAPIsStandardTest, TestTrivialCircularDependency) { 300 Optional<MaterializationResponsibility> FooR; 301 auto FooMU = llvm::make_unique<SimpleMaterializationUnit>( 302 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 303 [&](MaterializationResponsibility R) { FooR.emplace(std::move(R)); }); 304 305 cantFail(JD.define(FooMU)); 306 307 bool FooReady = false; 308 auto OnResolution = [](Expected<SymbolMap> R) { cantFail(std::move(R)); }; 309 auto OnReady = [&](Error Err) { 310 cantFail(std::move(Err)); 311 FooReady = true; 312 }; 313 314 ES.lookup({&JD}, {Foo}, std::move(OnResolution), std::move(OnReady), 315 NoDependenciesToRegister); 316 317 FooR->resolve({{Foo, FooSym}}); 318 FooR->emit(); 319 320 EXPECT_TRUE(FooReady) 321 << "Self-dependency prevented symbol from being marked ready"; 322 } 323 324 TEST_F(CoreAPIsStandardTest, TestCircularDependenceInOneJITDylib) { 325 // Test that a circular symbol dependency between three symbols in a JITDylib 326 // does not prevent any symbol from becoming 'ready' once all symbols are 327 // emitted. 328 329 // Create three MaterializationResponsibility objects: one for each of Foo, 330 // Bar and Baz. These are optional because MaterializationResponsibility 331 // does not have a default constructor). 332 Optional<MaterializationResponsibility> FooR; 333 Optional<MaterializationResponsibility> BarR; 334 Optional<MaterializationResponsibility> BazR; 335 336 // Create a MaterializationUnit for each symbol that moves the 337 // MaterializationResponsibility into one of the locals above. 338 auto FooMU = llvm::make_unique<SimpleMaterializationUnit>( 339 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 340 [&](MaterializationResponsibility R) { FooR.emplace(std::move(R)); }); 341 342 auto BarMU = llvm::make_unique<SimpleMaterializationUnit>( 343 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 344 [&](MaterializationResponsibility R) { BarR.emplace(std::move(R)); }); 345 346 auto BazMU = llvm::make_unique<SimpleMaterializationUnit>( 347 SymbolFlagsMap({{Baz, BazSym.getFlags()}}), 348 [&](MaterializationResponsibility R) { BazR.emplace(std::move(R)); }); 349 350 // Define the symbols. 351 cantFail(JD.define(FooMU)); 352 cantFail(JD.define(BarMU)); 353 cantFail(JD.define(BazMU)); 354 355 // Query each of the symbols to trigger materialization. 356 bool FooResolved = false; 357 bool FooReady = false; 358 359 auto OnFooResolution = [&](Expected<SymbolMap> Result) { 360 cantFail(std::move(Result)); 361 FooResolved = true; 362 }; 363 364 auto OnFooReady = [&](Error Err) { 365 cantFail(std::move(Err)); 366 FooReady = true; 367 }; 368 369 // Issue a lookup for Foo. Use NoDependenciesToRegister: We're going to add 370 // the dependencies manually below. 371 ES.lookup({&JD}, {Foo}, std::move(OnFooResolution), std::move(OnFooReady), 372 NoDependenciesToRegister); 373 374 bool BarResolved = false; 375 bool BarReady = false; 376 auto OnBarResolution = [&](Expected<SymbolMap> Result) { 377 cantFail(std::move(Result)); 378 BarResolved = true; 379 }; 380 381 auto OnBarReady = [&](Error Err) { 382 cantFail(std::move(Err)); 383 BarReady = true; 384 }; 385 386 ES.lookup({&JD}, {Bar}, std::move(OnBarResolution), std::move(OnBarReady), 387 NoDependenciesToRegister); 388 389 bool BazResolved = false; 390 bool BazReady = false; 391 392 auto OnBazResolution = [&](Expected<SymbolMap> Result) { 393 cantFail(std::move(Result)); 394 BazResolved = true; 395 }; 396 397 auto OnBazReady = [&](Error Err) { 398 cantFail(std::move(Err)); 399 BazReady = true; 400 }; 401 402 ES.lookup({&JD}, {Baz}, std::move(OnBazResolution), std::move(OnBazReady), 403 NoDependenciesToRegister); 404 405 // Add a circular dependency: Foo -> Bar, Bar -> Baz, Baz -> Foo. 406 FooR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}}); 407 BarR->addDependenciesForAll({{&JD, SymbolNameSet({Baz})}}); 408 BazR->addDependenciesForAll({{&JD, SymbolNameSet({Foo})}}); 409 410 // Add self-dependencies for good measure. This tests that the implementation 411 // of addDependencies filters these out. 412 FooR->addDependenciesForAll({{&JD, SymbolNameSet({Foo})}}); 413 BarR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}}); 414 BazR->addDependenciesForAll({{&JD, SymbolNameSet({Baz})}}); 415 416 // Check that nothing has been resolved yet. 417 EXPECT_FALSE(FooResolved) << "\"Foo\" should not be resolved yet"; 418 EXPECT_FALSE(BarResolved) << "\"Bar\" should not be resolved yet"; 419 EXPECT_FALSE(BazResolved) << "\"Baz\" should not be resolved yet"; 420 421 // Resolve the symbols (but do not emit them). 422 FooR->resolve({{Foo, FooSym}}); 423 BarR->resolve({{Bar, BarSym}}); 424 BazR->resolve({{Baz, BazSym}}); 425 426 // Verify that the symbols have been resolved, but are not ready yet. 427 EXPECT_TRUE(FooResolved) << "\"Foo\" should be resolved now"; 428 EXPECT_TRUE(BarResolved) << "\"Bar\" should be resolved now"; 429 EXPECT_TRUE(BazResolved) << "\"Baz\" should be resolved now"; 430 431 EXPECT_FALSE(FooReady) << "\"Foo\" should not be ready yet"; 432 EXPECT_FALSE(BarReady) << "\"Bar\" should not be ready yet"; 433 EXPECT_FALSE(BazReady) << "\"Baz\" should not be ready yet"; 434 435 // Emit two of the symbols. 436 FooR->emit(); 437 BarR->emit(); 438 439 // Verify that nothing is ready until the circular dependence is resolved. 440 EXPECT_FALSE(FooReady) << "\"Foo\" still should not be ready"; 441 EXPECT_FALSE(BarReady) << "\"Bar\" still should not be ready"; 442 EXPECT_FALSE(BazReady) << "\"Baz\" still should not be ready"; 443 444 // Emit the last symbol. 445 BazR->emit(); 446 447 // Verify that everything becomes ready once the circular dependence resolved. 448 EXPECT_TRUE(FooReady) << "\"Foo\" should be ready now"; 449 EXPECT_TRUE(BarReady) << "\"Bar\" should be ready now"; 450 EXPECT_TRUE(BazReady) << "\"Baz\" should be ready now"; 451 } 452 453 TEST_F(CoreAPIsStandardTest, DropMaterializerWhenEmpty) { 454 bool DestructorRun = false; 455 456 JITSymbolFlags WeakExported(JITSymbolFlags::Exported); 457 WeakExported |= JITSymbolFlags::Weak; 458 459 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 460 SymbolFlagsMap({{Foo, WeakExported}, {Bar, WeakExported}}), 461 [](MaterializationResponsibility R) { 462 llvm_unreachable("Unexpected call to materialize"); 463 }, 464 [&](const JITDylib &JD, SymbolStringPtr Name) { 465 EXPECT_TRUE(Name == Foo || Name == Bar) 466 << "Discard of unexpected symbol?"; 467 }, 468 [&]() { DestructorRun = true; }); 469 470 cantFail(JD.define(MU)); 471 472 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 473 474 EXPECT_FALSE(DestructorRun) 475 << "MaterializationUnit should not have been destroyed yet"; 476 477 cantFail(JD.define(absoluteSymbols({{Bar, BarSym}}))); 478 479 EXPECT_TRUE(DestructorRun) 480 << "MaterializationUnit should have been destroyed"; 481 } 482 483 TEST_F(CoreAPIsStandardTest, AddAndMaterializeLazySymbol) { 484 bool FooMaterialized = false; 485 bool BarDiscarded = false; 486 487 JITSymbolFlags WeakExported(JITSymbolFlags::Exported); 488 WeakExported |= JITSymbolFlags::Weak; 489 490 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 491 SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}, {Bar, WeakExported}}), 492 [&](MaterializationResponsibility R) { 493 assert(BarDiscarded && "Bar should have been discarded by this point"); 494 R.resolve(SymbolMap({{Foo, FooSym}})); 495 R.emit(); 496 FooMaterialized = true; 497 }, 498 [&](const JITDylib &JD, SymbolStringPtr Name) { 499 EXPECT_EQ(Name, Bar) << "Expected Name to be Bar"; 500 BarDiscarded = true; 501 }); 502 503 cantFail(JD.define(MU)); 504 cantFail(JD.define(absoluteSymbols({{Bar, BarSym}}))); 505 506 SymbolNameSet Names({Foo}); 507 508 bool OnResolutionRun = false; 509 bool OnReadyRun = false; 510 511 auto OnResolution = [&](Expected<SymbolMap> Result) { 512 EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error"; 513 auto I = Result->find(Foo); 514 EXPECT_NE(I, Result->end()) << "Could not find symbol definition"; 515 EXPECT_EQ(I->second.getAddress(), FooSym.getAddress()) 516 << "Resolution returned incorrect result"; 517 OnResolutionRun = true; 518 }; 519 520 auto OnReady = [&](Error Err) { 521 cantFail(std::move(Err)); 522 OnReadyRun = true; 523 }; 524 525 ES.lookup({&JD}, Names, std::move(OnResolution), std::move(OnReady), 526 NoDependenciesToRegister); 527 528 EXPECT_TRUE(FooMaterialized) << "Foo was not materialized"; 529 EXPECT_TRUE(BarDiscarded) << "Bar was not discarded"; 530 EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run"; 531 EXPECT_TRUE(OnReadyRun) << "OnReady was not run"; 532 } 533 534 TEST_F(CoreAPIsStandardTest, TestBasicWeakSymbolMaterialization) { 535 // Test that weak symbols are materialized correctly when we look them up. 536 BarSym.setFlags(BarSym.getFlags() | JITSymbolFlags::Weak); 537 538 bool BarMaterialized = false; 539 auto MU1 = llvm::make_unique<SimpleMaterializationUnit>( 540 SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}), 541 [&](MaterializationResponsibility R) { 542 R.resolve(SymbolMap({{Foo, FooSym}, {Bar, BarSym}})), R.emit(); 543 BarMaterialized = true; 544 }); 545 546 bool DuplicateBarDiscarded = false; 547 auto MU2 = llvm::make_unique<SimpleMaterializationUnit>( 548 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 549 [&](MaterializationResponsibility R) { 550 ADD_FAILURE() << "Attempt to materialize Bar from the wrong unit"; 551 R.failMaterialization(); 552 }, 553 [&](const JITDylib &JD, SymbolStringPtr Name) { 554 EXPECT_EQ(Name, Bar) << "Expected \"Bar\" to be discarded"; 555 DuplicateBarDiscarded = true; 556 }); 557 558 cantFail(JD.define(MU1)); 559 cantFail(JD.define(MU2)); 560 561 bool OnResolvedRun = false; 562 bool OnReadyRun = false; 563 564 auto OnResolution = [&](Expected<SymbolMap> Result) { 565 cantFail(std::move(Result)); 566 OnResolvedRun = true; 567 }; 568 569 auto OnReady = [&](Error Err) { 570 cantFail(std::move(Err)); 571 OnReadyRun = true; 572 }; 573 574 ES.lookup({&JD}, {Bar}, std::move(OnResolution), std::move(OnReady), 575 NoDependenciesToRegister); 576 577 EXPECT_TRUE(OnResolvedRun) << "OnResolved not run"; 578 EXPECT_TRUE(OnReadyRun) << "OnReady not run"; 579 EXPECT_TRUE(BarMaterialized) << "Bar was not materialized at all"; 580 EXPECT_TRUE(DuplicateBarDiscarded) 581 << "Duplicate bar definition not discarded"; 582 } 583 584 TEST_F(CoreAPIsStandardTest, DefineMaterializingSymbol) { 585 bool ExpectNoMoreMaterialization = false; 586 ES.setDispatchMaterialization( 587 [&](JITDylib &JD, std::unique_ptr<MaterializationUnit> MU) { 588 if (ExpectNoMoreMaterialization) 589 ADD_FAILURE() << "Unexpected materialization"; 590 MU->doMaterialize(JD); 591 }); 592 593 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 594 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 595 [&](MaterializationResponsibility R) { 596 cantFail( 597 R.defineMaterializing(SymbolFlagsMap({{Bar, BarSym.getFlags()}}))); 598 R.resolve(SymbolMap({{Foo, FooSym}, {Bar, BarSym}})); 599 R.emit(); 600 }); 601 602 cantFail(JD.define(MU)); 603 cantFail(lookup({&JD}, Foo)); 604 605 // Assert that materialization is complete by now. 606 ExpectNoMoreMaterialization = true; 607 608 // Look up bar to verify that no further materialization happens. 609 auto BarResult = cantFail(lookup({&JD}, Bar)); 610 EXPECT_EQ(BarResult.getAddress(), BarSym.getAddress()) 611 << "Expected Bar == BarSym"; 612 } 613 614 TEST_F(CoreAPIsStandardTest, FallbackDefinitionGeneratorTest) { 615 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 616 617 JD.setFallbackDefinitionGenerator( 618 [&](JITDylib &JD2, const SymbolNameSet &Names) { 619 cantFail(JD2.define(absoluteSymbols({{Bar, BarSym}}))); 620 return SymbolNameSet({Bar}); 621 }); 622 623 auto Result = cantFail(lookup({&JD}, {Foo, Bar})); 624 625 EXPECT_EQ(Result.count(Bar), 1U) << "Expected to find fallback def for 'bar'"; 626 EXPECT_EQ(Result[Bar].getAddress(), BarSym.getAddress()) 627 << "Expected fallback def for Bar to be equal to BarSym"; 628 } 629 630 TEST_F(CoreAPIsStandardTest, FailResolution) { 631 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 632 SymbolFlagsMap( 633 {{Foo, JITSymbolFlags::Weak}, {Bar, JITSymbolFlags::Weak}}), 634 [&](MaterializationResponsibility R) { R.failMaterialization(); }); 635 636 cantFail(JD.define(MU)); 637 638 SymbolNameSet Names({Foo, Bar}); 639 auto Result = lookup({&JD}, Names); 640 641 EXPECT_FALSE(!!Result) << "Expected failure"; 642 if (!Result) { 643 handleAllErrors(Result.takeError(), 644 [&](FailedToMaterialize &F) { 645 EXPECT_EQ(F.getSymbols(), Names) 646 << "Expected to fail on symbols in Names"; 647 }, 648 [](ErrorInfoBase &EIB) { 649 std::string ErrMsg; 650 { 651 raw_string_ostream ErrOut(ErrMsg); 652 EIB.log(ErrOut); 653 } 654 ADD_FAILURE() 655 << "Expected a FailedToResolve error. Got:\n" 656 << ErrMsg; 657 }); 658 } 659 } 660 661 TEST_F(CoreAPIsStandardTest, TestLookupWithUnthreadedMaterialization) { 662 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 663 SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}}), 664 [&](MaterializationResponsibility R) { 665 R.resolve({{Foo, FooSym}}); 666 R.emit(); 667 }); 668 669 cantFail(JD.define(MU)); 670 671 auto FooLookupResult = cantFail(lookup({&JD}, Foo)); 672 673 EXPECT_EQ(FooLookupResult.getAddress(), FooSym.getAddress()) 674 << "lookup returned an incorrect address"; 675 EXPECT_EQ(FooLookupResult.getFlags(), FooSym.getFlags()) 676 << "lookup returned incorrect flags"; 677 } 678 679 TEST_F(CoreAPIsStandardTest, TestLookupWithThreadedMaterialization) { 680 #if LLVM_ENABLE_THREADS 681 682 std::thread MaterializationThread; 683 ES.setDispatchMaterialization( 684 [&](JITDylib &JD, std::unique_ptr<MaterializationUnit> MU) { 685 auto SharedMU = std::shared_ptr<MaterializationUnit>(std::move(MU)); 686 MaterializationThread = 687 std::thread([SharedMU, &JD]() { SharedMU->doMaterialize(JD); }); 688 }); 689 690 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 691 692 auto FooLookupResult = cantFail(lookup({&JD}, Foo)); 693 694 EXPECT_EQ(FooLookupResult.getAddress(), FooSym.getAddress()) 695 << "lookup returned an incorrect address"; 696 EXPECT_EQ(FooLookupResult.getFlags(), FooSym.getFlags()) 697 << "lookup returned incorrect flags"; 698 MaterializationThread.join(); 699 #endif 700 } 701 702 TEST_F(CoreAPIsStandardTest, TestGetRequestedSymbolsAndReplace) { 703 // Test that GetRequestedSymbols returns the set of symbols that currently 704 // have pending queries, and test that MaterializationResponsibility's 705 // replace method can be used to return definitions to the JITDylib in a new 706 // MaterializationUnit. 707 SymbolNameSet Names({Foo, Bar}); 708 709 bool FooMaterialized = false; 710 bool BarMaterialized = false; 711 712 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 713 SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}), 714 [&](MaterializationResponsibility R) { 715 auto Requested = R.getRequestedSymbols(); 716 EXPECT_EQ(Requested.size(), 1U) << "Expected one symbol requested"; 717 EXPECT_EQ(*Requested.begin(), Foo) << "Expected \"Foo\" requested"; 718 719 auto NewMU = llvm::make_unique<SimpleMaterializationUnit>( 720 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 721 [&](MaterializationResponsibility R2) { 722 R2.resolve(SymbolMap({{Bar, BarSym}})); 723 R2.emit(); 724 BarMaterialized = true; 725 }); 726 727 R.replace(std::move(NewMU)); 728 729 R.resolve(SymbolMap({{Foo, FooSym}})); 730 R.emit(); 731 732 FooMaterialized = true; 733 }); 734 735 cantFail(JD.define(MU)); 736 737 EXPECT_FALSE(FooMaterialized) << "Foo should not be materialized yet"; 738 EXPECT_FALSE(BarMaterialized) << "Bar should not be materialized yet"; 739 740 auto FooSymResult = cantFail(lookup({&JD}, Foo)); 741 EXPECT_EQ(FooSymResult.getAddress(), FooSym.getAddress()) 742 << "Address mismatch for Foo"; 743 744 EXPECT_TRUE(FooMaterialized) << "Foo should be materialized now"; 745 EXPECT_FALSE(BarMaterialized) << "Bar still should not be materialized"; 746 747 auto BarSymResult = cantFail(lookup({&JD}, Bar)); 748 EXPECT_EQ(BarSymResult.getAddress(), BarSym.getAddress()) 749 << "Address mismatch for Bar"; 750 EXPECT_TRUE(BarMaterialized) << "Bar should be materialized now"; 751 } 752 753 TEST_F(CoreAPIsStandardTest, TestMaterializationResponsibilityDelegation) { 754 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 755 SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}), 756 [&](MaterializationResponsibility R) { 757 auto R2 = R.delegate({Bar}); 758 759 R.resolve({{Foo, FooSym}}); 760 R.emit(); 761 R2.resolve({{Bar, BarSym}}); 762 R2.emit(); 763 }); 764 765 cantFail(JD.define(MU)); 766 767 auto Result = lookup({&JD}, {Foo, Bar}); 768 769 EXPECT_TRUE(!!Result) << "Result should be a success value"; 770 EXPECT_EQ(Result->count(Foo), 1U) << "\"Foo\" entry missing"; 771 EXPECT_EQ(Result->count(Bar), 1U) << "\"Bar\" entry missing"; 772 EXPECT_EQ((*Result)[Foo].getAddress(), FooSym.getAddress()) 773 << "Address mismatch for \"Foo\""; 774 EXPECT_EQ((*Result)[Bar].getAddress(), BarSym.getAddress()) 775 << "Address mismatch for \"Bar\""; 776 } 777 778 TEST_F(CoreAPIsStandardTest, TestMaterializeWeakSymbol) { 779 // Confirm that once a weak definition is selected for materialization it is 780 // treated as strong. 781 JITSymbolFlags WeakExported = JITSymbolFlags::Exported; 782 WeakExported &= JITSymbolFlags::Weak; 783 784 std::unique_ptr<MaterializationResponsibility> FooResponsibility; 785 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 786 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 787 [&](MaterializationResponsibility R) { 788 FooResponsibility = 789 llvm::make_unique<MaterializationResponsibility>(std::move(R)); 790 }); 791 792 cantFail(JD.define(MU)); 793 auto OnResolution = [](Expected<SymbolMap> Result) { 794 cantFail(std::move(Result)); 795 }; 796 797 auto OnReady = [](Error Err) { cantFail(std::move(Err)); }; 798 799 ES.lookup({&JD}, {Foo}, std::move(OnResolution), std::move(OnReady), 800 NoDependenciesToRegister); 801 802 auto MU2 = llvm::make_unique<SimpleMaterializationUnit>( 803 SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}}), 804 [](MaterializationResponsibility R) { 805 llvm_unreachable("This unit should never be materialized"); 806 }); 807 808 auto Err = JD.define(MU2); 809 EXPECT_TRUE(!!Err) << "Expected failure value"; 810 EXPECT_TRUE(Err.isA<DuplicateDefinition>()) 811 << "Expected a duplicate definition error"; 812 consumeError(std::move(Err)); 813 814 FooResponsibility->resolve(SymbolMap({{Foo, FooSym}})); 815 FooResponsibility->emit(); 816 } 817 818 TEST_F(CoreAPIsStandardTest, TestMainJITDylibAndDefaultLookupOrder) { 819 cantFail(ES.getMainJITDylib().define(absoluteSymbols({{Foo, FooSym}}))); 820 auto Results = cantFail(ES.lookup({Foo})); 821 822 EXPECT_EQ(Results.size(), 1U) << "Incorrect number of results"; 823 EXPECT_EQ(Results.count(Foo), 1U) << "Expected result for 'Foo'"; 824 EXPECT_EQ(Results[Foo].getAddress(), FooSym.getAddress()) 825 << "Expected result address to match Foo's address"; 826 } 827 828 } // namespace 829