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 #include "gtest/gtest.h" 15 16 #include <set> 17 #include <thread> 18 19 using namespace llvm; 20 using namespace llvm::orc; 21 22 namespace { 23 24 class SimpleMaterializationUnit : public MaterializationUnit { 25 public: 26 using MaterializeFunction = 27 std::function<void(MaterializationResponsibility)>; 28 using DiscardFunction = std::function<void(const VSO &, SymbolStringPtr)>; 29 using DestructorFunction = std::function<void()>; 30 31 SimpleMaterializationUnit( 32 SymbolFlagsMap SymbolFlags, MaterializeFunction Materialize, 33 DiscardFunction Discard = DiscardFunction(), 34 DestructorFunction Destructor = DestructorFunction()) 35 : MaterializationUnit(std::move(SymbolFlags)), 36 Materialize(std::move(Materialize)), Discard(std::move(Discard)), 37 Destructor(std::move(Destructor)) {} 38 39 ~SimpleMaterializationUnit() override { 40 if (Destructor) 41 Destructor(); 42 } 43 44 void materialize(MaterializationResponsibility R) override { 45 Materialize(std::move(R)); 46 } 47 48 void discard(const VSO &V, SymbolStringPtr Name) override { 49 if (Discard) 50 Discard(V, std::move(Name)); 51 else 52 llvm_unreachable("Discard not supported"); 53 } 54 55 private: 56 MaterializeFunction Materialize; 57 DiscardFunction Discard; 58 DestructorFunction Destructor; 59 }; 60 61 TEST(CoreAPIsTest, AsynchronousSymbolQuerySuccessfulResolutionOnly) { 62 SymbolStringPool SP; 63 auto Foo = SP.intern("foo"); 64 constexpr JITTargetAddress FakeAddr = 0xdeadbeef; 65 SymbolNameSet Names({Foo}); 66 67 bool OnResolutionRun = false; 68 bool OnReadyRun = false; 69 auto OnResolution = 70 [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) { 71 EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error"; 72 auto &Resolved = Result->Symbols; 73 auto I = Resolved.find(Foo); 74 EXPECT_NE(I, Resolved.end()) << "Could not find symbol definition"; 75 EXPECT_EQ(I->second.getAddress(), FakeAddr) 76 << "Resolution returned incorrect result"; 77 OnResolutionRun = true; 78 }; 79 auto OnReady = [&](Error Err) { 80 cantFail(std::move(Err)); 81 OnReadyRun = true; 82 }; 83 84 AsynchronousSymbolQuery Q(Names, OnResolution, OnReady); 85 86 Q.resolve(Foo, JITEvaluatedSymbol(FakeAddr, JITSymbolFlags::Exported)); 87 88 EXPECT_TRUE(Q.isFullyResolved()) << "Expected query to be fully resolved"; 89 90 if (!Q.isFullyResolved()) 91 return; 92 93 Q.handleFullyResolved(); 94 95 EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run"; 96 EXPECT_FALSE(OnReadyRun) << "OnReady unexpectedly run"; 97 } 98 99 TEST(CoreAPIsTest, ExecutionSessionFailQuery) { 100 ExecutionSession ES; 101 auto Foo = ES.getSymbolStringPool().intern("foo"); 102 SymbolNameSet Names({Foo}); 103 104 bool OnResolutionRun = false; 105 bool OnReadyRun = false; 106 107 auto OnResolution = 108 [&](Expected<AsynchronousSymbolQuery::ResolutionResult> 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(Names, OnResolution, OnReady); 120 121 ES.failQuery(Q, make_error<StringError>("xyz", inconvertibleErrorCode())); 122 123 EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run"; 124 EXPECT_FALSE(OnReadyRun) << "OnReady unexpectedly run"; 125 } 126 127 TEST(CoreAPIsTest, SimpleAsynchronousSymbolQueryAgainstVSO) { 128 ExecutionSession ES; 129 auto Foo = ES.getSymbolStringPool().intern("foo"); 130 constexpr JITTargetAddress FakeAddr = 0xdeadbeef; 131 SymbolNameSet Names({Foo}); 132 133 bool OnResolutionRun = false; 134 bool OnReadyRun = false; 135 136 auto OnResolution = 137 [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) { 138 EXPECT_TRUE(!!Result) << "Query unexpectedly returned error"; 139 auto &Resolved = Result->Symbols; 140 auto I = Resolved.find(Foo); 141 EXPECT_NE(I, Resolved.end()) << "Could not find symbol definition"; 142 EXPECT_EQ(I->second.getAddress(), FakeAddr) 143 << "Resolution returned incorrect result"; 144 OnResolutionRun = true; 145 }; 146 147 auto OnReady = [&](Error Err) { 148 cantFail(std::move(Err)); 149 OnReadyRun = true; 150 }; 151 152 auto Q = 153 std::make_shared<AsynchronousSymbolQuery>(Names, OnResolution, OnReady); 154 auto &V = ES.createVSO("V"); 155 156 auto Defs = absoluteSymbols( 157 {{Foo, JITEvaluatedSymbol(FakeAddr, JITSymbolFlags::Exported)}}); 158 cantFail(V.define(Defs)); 159 assert(Defs == nullptr && "Defs should have been accepted"); 160 V.lookup(Q, Names); 161 162 EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run"; 163 EXPECT_TRUE(OnReadyRun) << "OnReady was not run"; 164 } 165 166 TEST(CoreAPIsTest, EmptyVSOAndQueryLookup) { 167 ExecutionSession ES; 168 auto &V = ES.createVSO("V"); 169 170 bool OnResolvedRun = false; 171 bool OnReadyRun = false; 172 173 auto Q = std::make_shared<AsynchronousSymbolQuery>( 174 SymbolNameSet(), 175 [&](Expected<AsynchronousSymbolQuery::ResolutionResult> RR) { 176 cantFail(std::move(RR)); 177 OnResolvedRun = true; 178 }, 179 [&](Error Err) { 180 cantFail(std::move(Err)); 181 OnReadyRun = true; 182 }); 183 184 V.lookup(std::move(Q), {}); 185 186 EXPECT_TRUE(OnResolvedRun) << "OnResolved was not run for empty query"; 187 EXPECT_TRUE(OnReadyRun) << "OnReady was not run for empty query"; 188 } 189 190 TEST(CoreAPIsTest, ChainedVSOLookup) { 191 ExecutionSession ES; 192 auto Foo = ES.getSymbolStringPool().intern("foo"); 193 auto FooSym = JITEvaluatedSymbol(1U, JITSymbolFlags::Exported); 194 195 auto &V1 = ES.createVSO("V1"); 196 cantFail(V1.define(absoluteSymbols({{Foo, FooSym}}))); 197 198 auto &V2 = ES.createVSO("V2"); 199 200 bool OnResolvedRun = false; 201 bool OnReadyRun = false; 202 203 auto Q = std::make_shared<AsynchronousSymbolQuery>( 204 SymbolNameSet({Foo}), 205 [&](Expected<AsynchronousSymbolQuery::ResolutionResult> RR) { 206 cantFail(std::move(RR)); 207 OnResolvedRun = true; 208 }, 209 [&](Error Err) { 210 cantFail(std::move(Err)); 211 OnReadyRun = true; 212 }); 213 214 V2.lookup(Q, V1.lookup(Q, {Foo})); 215 216 EXPECT_TRUE(OnResolvedRun) << "OnResolved was not run for empty query"; 217 EXPECT_TRUE(OnReadyRun) << "OnReady was not run for empty query"; 218 } 219 220 TEST(CoreAPIsTest, LookupFlagsTest) { 221 222 // Test that lookupFlags works on a predefined symbol, and does not trigger 223 // materialization of a lazy symbol. 224 225 ExecutionSession ES; 226 auto Foo = ES.getSymbolStringPool().intern("foo"); 227 auto Bar = ES.getSymbolStringPool().intern("bar"); 228 auto Baz = ES.getSymbolStringPool().intern("baz"); 229 230 JITSymbolFlags FooFlags = JITSymbolFlags::Exported; 231 JITSymbolFlags BarFlags = static_cast<JITSymbolFlags::FlagNames>( 232 JITSymbolFlags::Exported | JITSymbolFlags::Weak); 233 234 VSO &V = ES.createVSO("V"); 235 236 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 237 SymbolFlagsMap({{Bar, BarFlags}}), 238 [](MaterializationResponsibility R) { 239 llvm_unreachable("Symbol materialized on flags lookup"); 240 }); 241 242 cantFail(V.define( 243 absoluteSymbols({{Foo, JITEvaluatedSymbol(0xdeadbeef, FooFlags)}}))); 244 cantFail(V.define(std::move(MU))); 245 246 SymbolNameSet Names({Foo, Bar, Baz}); 247 248 SymbolFlagsMap SymbolFlags; 249 auto SymbolsNotFound = V.lookupFlags(SymbolFlags, Names); 250 251 EXPECT_EQ(SymbolsNotFound.size(), 1U) << "Expected one not-found symbol"; 252 EXPECT_EQ(SymbolsNotFound.count(Baz), 1U) << "Expected Baz to be not-found"; 253 EXPECT_EQ(SymbolFlags.size(), 2U) 254 << "Returned symbol flags contains unexpected results"; 255 EXPECT_EQ(SymbolFlags.count(Foo), 1U) << "Missing lookupFlags result for Foo"; 256 EXPECT_EQ(SymbolFlags[Foo], FooFlags) << "Incorrect flags returned for Foo"; 257 EXPECT_EQ(SymbolFlags.count(Bar), 1U) 258 << "Missing lookupFlags result for Bar"; 259 EXPECT_EQ(SymbolFlags[Bar], BarFlags) << "Incorrect flags returned for Bar"; 260 } 261 262 TEST(CoreAPIsTest, TestAliases) { 263 ExecutionSession ES; 264 auto &V = ES.createVSO("V"); 265 266 auto Foo = ES.getSymbolStringPool().intern("foo"); 267 auto FooSym = JITEvaluatedSymbol(1U, JITSymbolFlags::Exported); 268 auto Bar = ES.getSymbolStringPool().intern("bar"); 269 auto BarSym = JITEvaluatedSymbol(2U, JITSymbolFlags::Exported); 270 271 auto Baz = ES.getSymbolStringPool().intern("baz"); 272 auto Qux = ES.getSymbolStringPool().intern("qux"); 273 274 auto QuxSym = JITEvaluatedSymbol(3U, JITSymbolFlags::Exported); 275 276 cantFail(V.define(absoluteSymbols({{Foo, FooSym}, {Bar, BarSym}}))); 277 cantFail(V.define(symbolAliases({{Baz, {Foo, JITSymbolFlags::Exported}}, 278 {Qux, {Bar, JITSymbolFlags::Weak}}}))); 279 cantFail(V.define(absoluteSymbols({{Qux, QuxSym}}))); 280 281 auto Result = lookup({&V}, {Baz, Qux}); 282 EXPECT_TRUE(!!Result) << "Unexpected lookup failure"; 283 EXPECT_EQ(Result->count(Baz), 1U) << "No result for \"baz\""; 284 EXPECT_EQ(Result->count(Qux), 1U) << "No result for \"qux\""; 285 EXPECT_EQ((*Result)[Baz].getAddress(), FooSym.getAddress()) 286 << "\"Baz\"'s address should match \"Foo\"'s"; 287 EXPECT_EQ((*Result)[Qux].getAddress(), QuxSym.getAddress()) 288 << "The \"Qux\" alias should have been overriden"; 289 } 290 291 TEST(CoreAPIsTest, TestTrivialCircularDependency) { 292 ExecutionSession ES; 293 294 auto &V = ES.createVSO("V"); 295 296 auto Foo = ES.getSymbolStringPool().intern("foo"); 297 auto FooFlags = JITSymbolFlags::Exported; 298 auto FooSym = JITEvaluatedSymbol(1U, FooFlags); 299 300 Optional<MaterializationResponsibility> FooR; 301 auto FooMU = llvm::make_unique<SimpleMaterializationUnit>( 302 SymbolFlagsMap({{Foo, FooFlags}}), 303 [&](MaterializationResponsibility R) { FooR.emplace(std::move(R)); }); 304 305 cantFail(V.define(FooMU)); 306 307 bool FooReady = false; 308 auto Q = 309 std::make_shared<AsynchronousSymbolQuery>( 310 SymbolNameSet({ Foo }), 311 [](Expected<AsynchronousSymbolQuery::ResolutionResult> R) { 312 cantFail(std::move(R)); 313 }, 314 [&](Error Err) { 315 cantFail(std::move(Err)); 316 FooReady = true; 317 }); 318 319 V.lookup(std::move(Q), { Foo }); 320 321 FooR->addDependencies({{&V, {Foo}}}); 322 FooR->resolve({{Foo, FooSym}}); 323 FooR->finalize(); 324 325 EXPECT_TRUE(FooReady) 326 << "Self-dependency prevented symbol from being marked ready"; 327 } 328 329 TEST(CoreAPIsTest, TestCircularDependenceInOneVSO) { 330 331 ExecutionSession ES; 332 333 auto &V = ES.createVSO("V"); 334 335 // Create three symbols: Foo, Bar and Baz. 336 auto Foo = ES.getSymbolStringPool().intern("foo"); 337 auto FooFlags = JITSymbolFlags::Exported; 338 auto FooSym = JITEvaluatedSymbol(1U, FooFlags); 339 340 auto Bar = ES.getSymbolStringPool().intern("bar"); 341 auto BarFlags = JITSymbolFlags::Exported; 342 auto BarSym = JITEvaluatedSymbol(2U, BarFlags); 343 344 auto Baz = ES.getSymbolStringPool().intern("baz"); 345 auto BazFlags = JITSymbolFlags::Exported; 346 auto BazSym = JITEvaluatedSymbol(3U, BazFlags); 347 348 // Create three MaterializationResponsibility objects: one for each symbol 349 // (these are optional because MaterializationResponsibility does not have 350 // a default constructor). 351 Optional<MaterializationResponsibility> FooR; 352 Optional<MaterializationResponsibility> BarR; 353 Optional<MaterializationResponsibility> BazR; 354 355 // Create a MaterializationUnit for each symbol that moves the 356 // MaterializationResponsibility into one of the locals above. 357 auto FooMU = llvm::make_unique<SimpleMaterializationUnit>( 358 SymbolFlagsMap({{Foo, FooFlags}}), 359 [&](MaterializationResponsibility R) { FooR.emplace(std::move(R)); }); 360 361 auto BarMU = llvm::make_unique<SimpleMaterializationUnit>( 362 SymbolFlagsMap({{Bar, BarFlags}}), 363 [&](MaterializationResponsibility R) { BarR.emplace(std::move(R)); }); 364 365 auto BazMU = llvm::make_unique<SimpleMaterializationUnit>( 366 SymbolFlagsMap({{Baz, BazFlags}}), 367 [&](MaterializationResponsibility R) { BazR.emplace(std::move(R)); }); 368 369 // Define the symbols. 370 cantFail(V.define(FooMU)); 371 cantFail(V.define(BarMU)); 372 cantFail(V.define(BazMU)); 373 374 // Query each of the symbols to trigger materialization. 375 bool FooResolved = false; 376 bool FooReady = false; 377 auto FooQ = std::make_shared<AsynchronousSymbolQuery>( 378 SymbolNameSet({Foo}), 379 [&](Expected<AsynchronousSymbolQuery::ResolutionResult> RR) { 380 cantFail(std::move(RR)); 381 FooResolved = true; 382 }, 383 [&](Error Err) { 384 cantFail(std::move(Err)); 385 FooReady = true; 386 }); 387 { 388 auto Unresolved = V.lookup(FooQ, {Foo}); 389 EXPECT_TRUE(Unresolved.empty()) << "Failed to resolve \"Foo\""; 390 } 391 392 bool BarResolved = false; 393 bool BarReady = false; 394 auto BarQ = std::make_shared<AsynchronousSymbolQuery>( 395 SymbolNameSet({Bar}), 396 [&](Expected<AsynchronousSymbolQuery::ResolutionResult> RR) { 397 cantFail(std::move(RR)); 398 BarResolved = true; 399 }, 400 [&](Error Err) { 401 cantFail(std::move(Err)); 402 BarReady = true; 403 }); 404 { 405 auto Unresolved = V.lookup(BarQ, {Bar}); 406 EXPECT_TRUE(Unresolved.empty()) << "Failed to resolve \"Bar\""; 407 } 408 409 bool BazResolved = false; 410 bool BazReady = false; 411 auto BazQ = std::make_shared<AsynchronousSymbolQuery>( 412 SymbolNameSet({Baz}), 413 [&](Expected<AsynchronousSymbolQuery::ResolutionResult> RR) { 414 cantFail(std::move(RR)); 415 BazResolved = true; 416 }, 417 [&](Error Err) { 418 cantFail(std::move(Err)); 419 BazReady = true; 420 }); 421 { 422 auto Unresolved = V.lookup(BazQ, {Baz}); 423 EXPECT_TRUE(Unresolved.empty()) << "Failed to resolve \"Baz\""; 424 } 425 426 // Add a circular dependency: Foo -> Bar, Bar -> Baz, Baz -> Foo. 427 FooR->addDependencies({{&V, SymbolNameSet({Bar})}}); 428 BarR->addDependencies({{&V, SymbolNameSet({Baz})}}); 429 BazR->addDependencies({{&V, SymbolNameSet({Foo})}}); 430 431 // Add self-dependencies for good measure. This tests that the implementation 432 // of addDependencies filters these out. 433 FooR->addDependencies({{&V, SymbolNameSet({Foo})}}); 434 BarR->addDependencies({{&V, SymbolNameSet({Bar})}}); 435 BazR->addDependencies({{&V, SymbolNameSet({Baz})}}); 436 437 EXPECT_FALSE(FooResolved) << "\"Foo\" should not be resolved yet"; 438 EXPECT_FALSE(BarResolved) << "\"Bar\" should not be resolved yet"; 439 EXPECT_FALSE(BazResolved) << "\"Baz\" should not be resolved yet"; 440 441 FooR->resolve({{Foo, FooSym}}); 442 BarR->resolve({{Bar, BarSym}}); 443 BazR->resolve({{Baz, BazSym}}); 444 445 EXPECT_TRUE(FooResolved) << "\"Foo\" should be resolved now"; 446 EXPECT_TRUE(BarResolved) << "\"Bar\" should be resolved now"; 447 EXPECT_TRUE(BazResolved) << "\"Baz\" should be resolved now"; 448 449 EXPECT_FALSE(FooReady) << "\"Foo\" should not be ready yet"; 450 EXPECT_FALSE(BarReady) << "\"Bar\" should not be ready yet"; 451 EXPECT_FALSE(BazReady) << "\"Baz\" should not be ready yet"; 452 453 FooR->finalize(); 454 BarR->finalize(); 455 456 // Verify that nothing is ready until the circular dependence is resolved. 457 458 EXPECT_FALSE(FooReady) << "\"Foo\" still should not be ready"; 459 EXPECT_FALSE(BarReady) << "\"Bar\" still should not be ready"; 460 EXPECT_FALSE(BazReady) << "\"Baz\" still should not be ready"; 461 462 BazR->finalize(); 463 464 // Verify that everything becomes ready once the circular dependence resolved. 465 EXPECT_TRUE(FooReady) << "\"Foo\" should be ready now"; 466 EXPECT_TRUE(BarReady) << "\"Bar\" should be ready now"; 467 EXPECT_TRUE(BazReady) << "\"Baz\" should be ready now"; 468 } 469 470 TEST(CoreAPIsTest, DropMaterializerWhenEmpty) { 471 ExecutionSession ES; 472 auto Foo = ES.getSymbolStringPool().intern("foo"); 473 auto Bar = ES.getSymbolStringPool().intern("bar"); 474 475 bool DestructorRun = false; 476 477 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 478 SymbolFlagsMap( 479 {{Foo, JITSymbolFlags::Weak}, {Bar, JITSymbolFlags::Weak}}), 480 [](MaterializationResponsibility R) { 481 llvm_unreachable("Unexpected call to materialize"); 482 }, 483 [&](const VSO &V, SymbolStringPtr Name) { 484 EXPECT_TRUE(Name == Foo || Name == Bar) 485 << "Discard of unexpected symbol?"; 486 }, 487 [&]() { DestructorRun = true; }); 488 489 auto &V = ES.createVSO("V"); 490 491 cantFail(V.define(MU)); 492 493 auto FooSym = JITEvaluatedSymbol(1, JITSymbolFlags::Exported); 494 auto BarSym = JITEvaluatedSymbol(2, JITSymbolFlags::Exported); 495 cantFail(V.define(absoluteSymbols({{Foo, FooSym}}))); 496 497 EXPECT_FALSE(DestructorRun) 498 << "MaterializationUnit should not have been destroyed yet"; 499 500 cantFail(V.define(absoluteSymbols({{Bar, BarSym}}))); 501 502 EXPECT_TRUE(DestructorRun) 503 << "MaterializationUnit should have been destroyed"; 504 } 505 506 TEST(CoreAPIsTest, AddAndMaterializeLazySymbol) { 507 508 constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef; 509 constexpr JITTargetAddress FakeBarAddr = 0xcafef00d; 510 511 ExecutionSession ES; 512 auto Foo = ES.getSymbolStringPool().intern("foo"); 513 auto Bar = ES.getSymbolStringPool().intern("bar"); 514 515 bool FooMaterialized = false; 516 bool BarDiscarded = false; 517 518 auto &V = ES.createVSO("V"); 519 520 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 521 SymbolFlagsMap( 522 {{Foo, JITSymbolFlags::Exported}, 523 {Bar, static_cast<JITSymbolFlags::FlagNames>( 524 JITSymbolFlags::Exported | JITSymbolFlags::Weak)}}), 525 [&](MaterializationResponsibility R) { 526 assert(BarDiscarded && "Bar should have been discarded by this point"); 527 SymbolMap SymbolsToResolve; 528 SymbolsToResolve[Foo] = 529 JITEvaluatedSymbol(FakeFooAddr, JITSymbolFlags::Exported); 530 R.resolve(std::move(SymbolsToResolve)); 531 R.finalize(); 532 FooMaterialized = true; 533 }, 534 [&](const VSO &V, SymbolStringPtr Name) { 535 EXPECT_EQ(Name, Bar) << "Expected Name to be Bar"; 536 BarDiscarded = true; 537 }); 538 539 cantFail(V.define(MU)); 540 541 ; 542 cantFail(V.define(absoluteSymbols( 543 {{Bar, JITEvaluatedSymbol(FakeBarAddr, JITSymbolFlags::Exported)}}))); 544 545 SymbolNameSet Names({Foo}); 546 547 bool OnResolutionRun = false; 548 bool OnReadyRun = false; 549 550 auto OnResolution = 551 [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) { 552 EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error"; 553 auto I = Result->Symbols.find(Foo); 554 EXPECT_NE(I, Result->Symbols.end()) 555 << "Could not find symbol definition"; 556 EXPECT_EQ(I->second.getAddress(), FakeFooAddr) 557 << "Resolution returned incorrect result"; 558 OnResolutionRun = true; 559 }; 560 561 auto OnReady = [&](Error Err) { 562 cantFail(std::move(Err)); 563 OnReadyRun = true; 564 }; 565 566 auto Q = 567 std::make_shared<AsynchronousSymbolQuery>(Names, OnResolution, OnReady); 568 569 auto Unresolved = V.lookup(std::move(Q), Names); 570 571 EXPECT_TRUE(Unresolved.empty()) << "Could not find Foo in dylib"; 572 EXPECT_TRUE(FooMaterialized) << "Foo was not materialized"; 573 EXPECT_TRUE(BarDiscarded) << "Bar was not discarded"; 574 EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run"; 575 EXPECT_TRUE(OnReadyRun) << "OnReady was not run"; 576 } 577 578 TEST(CoreAPIsTest, DefineMaterializingSymbol) { 579 ExecutionSession ES; 580 auto Foo = ES.getSymbolStringPool().intern("foo"); 581 auto Bar = ES.getSymbolStringPool().intern("bar"); 582 583 auto FooSym = JITEvaluatedSymbol(1, JITSymbolFlags::Exported); 584 auto BarSym = JITEvaluatedSymbol(2, JITSymbolFlags::Exported); 585 586 bool ExpectNoMoreMaterialization = false; 587 ES.setDispatchMaterialization( 588 [&](VSO &V, std::unique_ptr<MaterializationUnit> MU) { 589 if (ExpectNoMoreMaterialization) 590 ADD_FAILURE() << "Unexpected materialization"; 591 MU->doMaterialize(V); 592 }); 593 594 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 595 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 596 [&](MaterializationResponsibility R) { 597 cantFail( 598 R.defineMaterializing(SymbolFlagsMap({{Bar, BarSym.getFlags()}}))); 599 R.resolve(SymbolMap({{Foo, FooSym}, {Bar, BarSym}})); 600 R.finalize(); 601 }); 602 603 auto &V = ES.createVSO("V"); 604 cantFail(V.define(MU)); 605 606 auto OnResolution1 = 607 [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) { 608 cantFail(std::move(Result)); 609 }; 610 611 auto OnReady1 = [](Error Err) { cantFail(std::move(Err)); }; 612 613 auto Q1 = std::make_shared<AsynchronousSymbolQuery>(SymbolNameSet({Foo}), 614 OnResolution1, OnReady1); 615 616 V.lookup(std::move(Q1), {Foo}); 617 618 bool BarResolved = false; 619 auto OnResolution2 = 620 [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) { 621 auto R = cantFail(std::move(Result)); 622 EXPECT_EQ(R.Symbols.size(), 1U) << "Expected to resolve one symbol"; 623 EXPECT_EQ(R.Symbols.count(Bar), 1U) << "Expected to resolve 'Bar'"; 624 EXPECT_EQ(R.Symbols[Bar].getAddress(), BarSym.getAddress()) 625 << "Expected Bar == BarSym"; 626 BarResolved = true; 627 }; 628 629 auto OnReady2 = [](Error Err) { cantFail(std::move(Err)); }; 630 631 auto Q2 = std::make_shared<AsynchronousSymbolQuery>(SymbolNameSet({Bar}), 632 OnResolution2, OnReady2); 633 634 ExpectNoMoreMaterialization = true; 635 V.lookup(std::move(Q2), {Bar}); 636 637 EXPECT_TRUE(BarResolved) << "Bar should have been resolved"; 638 } 639 640 TEST(CoreAPIsTest, FallbackDefinitionGeneratorTest) { 641 constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef; 642 constexpr JITTargetAddress FakeBarAddr = 0xcafef00d; 643 644 ExecutionSession ES; 645 auto Foo = ES.getSymbolStringPool().intern("foo"); 646 auto Bar = ES.getSymbolStringPool().intern("bar"); 647 648 auto FooSym = JITEvaluatedSymbol(FakeFooAddr, JITSymbolFlags::Exported); 649 auto BarSym = JITEvaluatedSymbol(FakeBarAddr, JITSymbolFlags::Exported); 650 651 auto &V = ES.createVSO("V"); 652 653 cantFail(V.define(absoluteSymbols({{Foo, FooSym}}))); 654 655 V.setFallbackDefinitionGenerator([&](VSO &W, const SymbolNameSet &Names) { 656 cantFail(W.define(absoluteSymbols({{Bar, BarSym}}))); 657 return SymbolNameSet({Bar}); 658 }); 659 660 auto Result = cantFail(lookup({&V}, {Foo, Bar})); 661 662 EXPECT_EQ(Result.count(Bar), 1U) << "Expected to find fallback def for 'bar'"; 663 EXPECT_EQ(Result[Bar].getAddress(), FakeBarAddr) 664 << "Expected address of fallback def for 'bar' to be " << FakeBarAddr; 665 } 666 667 TEST(CoreAPIsTest, FailResolution) { 668 ExecutionSession ES; 669 auto Foo = ES.getSymbolStringPool().intern("foo"); 670 auto Bar = ES.getSymbolStringPool().intern("bar"); 671 672 SymbolNameSet Names({Foo, Bar}); 673 674 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 675 SymbolFlagsMap( 676 {{Foo, JITSymbolFlags::Weak}, {Bar, JITSymbolFlags::Weak}}), 677 [&](MaterializationResponsibility R) { R.failMaterialization(); }); 678 679 auto &V = ES.createVSO("V"); 680 681 cantFail(V.define(MU)); 682 683 auto OnResolution = 684 [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) { 685 handleAllErrors(Result.takeError(), 686 [&](FailedToMaterialize &F) { 687 EXPECT_EQ(F.getSymbols(), Names) 688 << "Expected to fail on symbols in Names"; 689 }, 690 [](ErrorInfoBase &EIB) { 691 std::string ErrMsg; 692 { 693 raw_string_ostream ErrOut(ErrMsg); 694 EIB.log(ErrOut); 695 } 696 ADD_FAILURE() 697 << "Expected a FailedToResolve error. Got:\n" 698 << ErrMsg; 699 }); 700 }; 701 702 auto OnReady = [](Error Err) { 703 cantFail(std::move(Err)); 704 ADD_FAILURE() << "OnReady should never be called"; 705 }; 706 707 auto Q = 708 std::make_shared<AsynchronousSymbolQuery>(Names, OnResolution, OnReady); 709 710 V.lookup(std::move(Q), Names); 711 } 712 713 TEST(CoreAPIsTest, TestLambdaSymbolResolver) { 714 JITEvaluatedSymbol FooSym(0xdeadbeef, JITSymbolFlags::Exported); 715 JITEvaluatedSymbol BarSym(0xcafef00d, JITSymbolFlags::Exported); 716 717 ExecutionSession ES; 718 719 auto Foo = ES.getSymbolStringPool().intern("foo"); 720 auto Bar = ES.getSymbolStringPool().intern("bar"); 721 auto Baz = ES.getSymbolStringPool().intern("baz"); 722 723 auto &V = ES.createVSO("V"); 724 cantFail(V.define(absoluteSymbols({{Foo, FooSym}, {Bar, BarSym}}))); 725 726 auto Resolver = createSymbolResolver( 727 [&](SymbolFlagsMap &SymbolFlags, const SymbolNameSet &Symbols) { 728 return V.lookupFlags(SymbolFlags, Symbols); 729 }, 730 [&](std::shared_ptr<AsynchronousSymbolQuery> Q, SymbolNameSet Symbols) { 731 return V.lookup(std::move(Q), Symbols); 732 }); 733 734 SymbolNameSet Symbols({Foo, Bar, Baz}); 735 736 SymbolFlagsMap SymbolFlags; 737 SymbolNameSet SymbolsNotFound = Resolver->lookupFlags(SymbolFlags, Symbols); 738 739 EXPECT_EQ(SymbolFlags.size(), 2U) 740 << "lookupFlags returned the wrong number of results"; 741 EXPECT_EQ(SymbolFlags.count(Foo), 1U) << "Missing lookupFlags result for foo"; 742 EXPECT_EQ(SymbolFlags.count(Bar), 1U) << "Missing lookupFlags result for bar"; 743 EXPECT_EQ(SymbolFlags[Foo], FooSym.getFlags()) 744 << "Incorrect lookupFlags result for Foo"; 745 EXPECT_EQ(SymbolFlags[Bar], BarSym.getFlags()) 746 << "Incorrect lookupFlags result for Bar"; 747 EXPECT_EQ(SymbolsNotFound.size(), 1U) 748 << "Expected one symbol not found in lookupFlags"; 749 EXPECT_EQ(SymbolsNotFound.count(Baz), 1U) 750 << "Expected baz not to be found in lookupFlags"; 751 752 bool OnResolvedRun = false; 753 754 auto OnResolved = 755 [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) { 756 OnResolvedRun = true; 757 EXPECT_TRUE(!!Result) << "Unexpected error"; 758 EXPECT_EQ(Result->Symbols.size(), 2U) 759 << "Unexpected number of resolved symbols"; 760 EXPECT_EQ(Result->Symbols.count(Foo), 1U) 761 << "Missing lookup result for foo"; 762 EXPECT_EQ(Result->Symbols.count(Bar), 1U) 763 << "Missing lookup result for bar"; 764 EXPECT_EQ(Result->Symbols[Foo].getAddress(), FooSym.getAddress()) 765 << "Incorrect address for foo"; 766 EXPECT_EQ(Result->Symbols[Bar].getAddress(), BarSym.getAddress()) 767 << "Incorrect address for bar"; 768 }; 769 auto OnReady = [&](Error Err) { 770 EXPECT_FALSE(!!Err) << "Finalization should never fail in this test"; 771 }; 772 773 auto Q = std::make_shared<AsynchronousSymbolQuery>(SymbolNameSet({Foo, Bar}), 774 OnResolved, OnReady); 775 auto Unresolved = Resolver->lookup(std::move(Q), Symbols); 776 777 EXPECT_EQ(Unresolved.size(), 1U) << "Expected one unresolved symbol"; 778 EXPECT_EQ(Unresolved.count(Baz), 1U) << "Expected baz to not be resolved"; 779 EXPECT_TRUE(OnResolvedRun) << "OnResolved was never run"; 780 } 781 782 TEST(CoreAPIsTest, TestLookupWithUnthreadedMaterialization) { 783 constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef; 784 JITEvaluatedSymbol FooSym(FakeFooAddr, JITSymbolFlags::Exported); 785 786 ExecutionSession ES(std::make_shared<SymbolStringPool>()); 787 auto Foo = ES.getSymbolStringPool().intern("foo"); 788 789 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 790 SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}}), 791 [&](MaterializationResponsibility R) { 792 R.resolve({{Foo, FooSym}}); 793 R.finalize(); 794 }); 795 796 auto &V = ES.createVSO("V"); 797 798 cantFail(V.define(MU)); 799 800 auto FooLookupResult = cantFail(lookup({&V}, Foo)); 801 802 EXPECT_EQ(FooLookupResult.getAddress(), FooSym.getAddress()) 803 << "lookup returned an incorrect address"; 804 EXPECT_EQ(FooLookupResult.getFlags(), FooSym.getFlags()) 805 << "lookup returned incorrect flags"; 806 } 807 808 TEST(CoreAPIsTest, TestLookupWithThreadedMaterialization) { 809 #if LLVM_ENABLE_THREADS 810 constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef; 811 JITEvaluatedSymbol FooSym(FakeFooAddr, JITSymbolFlags::Exported); 812 813 ExecutionSession ES(std::make_shared<SymbolStringPool>()); 814 815 std::thread MaterializationThread; 816 ES.setDispatchMaterialization( 817 [&](VSO &V, std::unique_ptr<MaterializationUnit> MU) { 818 auto SharedMU = std::shared_ptr<MaterializationUnit>(std::move(MU)); 819 MaterializationThread = 820 std::thread([SharedMU, &V]() { SharedMU->doMaterialize(V); }); 821 }); 822 auto Foo = ES.getSymbolStringPool().intern("foo"); 823 824 auto &V = ES.createVSO("V"); 825 cantFail(V.define(absoluteSymbols({{Foo, FooSym}}))); 826 827 auto FooLookupResult = cantFail(lookup({&V}, Foo)); 828 829 EXPECT_EQ(FooLookupResult.getAddress(), FooSym.getAddress()) 830 << "lookup returned an incorrect address"; 831 EXPECT_EQ(FooLookupResult.getFlags(), FooSym.getFlags()) 832 << "lookup returned incorrect flags"; 833 MaterializationThread.join(); 834 #endif 835 } 836 837 TEST(CoreAPIsTest, TestGetRequestedSymbolsAndDelegate) { 838 ExecutionSession ES; 839 auto Foo = ES.getSymbolStringPool().intern("foo"); 840 auto Bar = ES.getSymbolStringPool().intern("bar"); 841 842 JITEvaluatedSymbol FooSym(0xdeadbeef, JITSymbolFlags::Exported); 843 JITEvaluatedSymbol BarSym(0xcafef00d, JITSymbolFlags::Exported); 844 845 SymbolNameSet Names({Foo, Bar}); 846 847 bool FooMaterialized = false; 848 bool BarMaterialized = false; 849 850 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 851 SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}), 852 [&](MaterializationResponsibility R) { 853 auto Requested = R.getRequestedSymbols(); 854 EXPECT_EQ(Requested.size(), 1U) << "Expected one symbol requested"; 855 EXPECT_EQ(*Requested.begin(), Foo) << "Expected \"Foo\" requested"; 856 857 auto NewMU = llvm::make_unique<SimpleMaterializationUnit>( 858 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 859 [&](MaterializationResponsibility R2) { 860 R2.resolve(SymbolMap({{Bar, BarSym}})); 861 R2.finalize(); 862 BarMaterialized = true; 863 }); 864 865 R.delegate(std::move(NewMU)); 866 867 R.resolve(SymbolMap({{Foo, FooSym}})); 868 R.finalize(); 869 870 FooMaterialized = true; 871 }); 872 873 auto &V = ES.createVSO("V"); 874 875 cantFail(V.define(MU)); 876 877 EXPECT_FALSE(FooMaterialized) << "Foo should not be materialized yet"; 878 EXPECT_FALSE(BarMaterialized) << "Bar should not be materialized yet"; 879 880 auto FooSymResult = cantFail(lookup({&V}, Foo)); 881 EXPECT_EQ(FooSymResult.getAddress(), FooSym.getAddress()) 882 << "Address mismatch for Foo"; 883 884 EXPECT_TRUE(FooMaterialized) << "Foo should be materialized now"; 885 EXPECT_FALSE(BarMaterialized) << "Bar still should not be materialized"; 886 887 auto BarSymResult = cantFail(lookup({&V}, Bar)); 888 EXPECT_EQ(BarSymResult.getAddress(), BarSym.getAddress()) 889 << "Address mismatch for Bar"; 890 EXPECT_TRUE(BarMaterialized) << "Bar should be materialized now"; 891 } 892 893 TEST(CoreAPIsTest, TestMaterializeWeakSymbol) { 894 // Confirm that once a weak definition is selected for materialization it is 895 // treated as strong. 896 897 constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef; 898 JITSymbolFlags FooFlags = JITSymbolFlags::Exported; 899 FooFlags &= JITSymbolFlags::Weak; 900 auto FooSym = JITEvaluatedSymbol(FakeFooAddr, FooFlags); 901 902 ExecutionSession ES; 903 auto Foo = ES.getSymbolStringPool().intern("foo"); 904 905 auto &V = ES.createVSO("V"); 906 907 std::unique_ptr<MaterializationResponsibility> FooResponsibility; 908 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 909 SymbolFlagsMap({{Foo, FooFlags}}), [&](MaterializationResponsibility R) { 910 FooResponsibility = 911 llvm::make_unique<MaterializationResponsibility>(std::move(R)); 912 }); 913 914 cantFail(V.define(MU)); 915 auto Q = std::make_shared<AsynchronousSymbolQuery>( 916 SymbolNameSet({Foo}), 917 [](Expected<AsynchronousSymbolQuery::ResolutionResult> R) { 918 cantFail(std::move(R)); 919 }, 920 [](Error Err) { cantFail(std::move(Err)); }); 921 V.lookup(std::move(Q), SymbolNameSet({Foo})); 922 923 auto MU2 = llvm::make_unique<SimpleMaterializationUnit>( 924 SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}}), 925 [](MaterializationResponsibility R) { 926 llvm_unreachable("This unit should never be materialized"); 927 }); 928 929 auto Err = V.define(MU2); 930 EXPECT_TRUE(!!Err) << "Expected failure value"; 931 EXPECT_TRUE(Err.isA<DuplicateDefinition>()) 932 << "Expected a duplicate definition error"; 933 consumeError(std::move(Err)); 934 935 FooResponsibility->resolve(SymbolMap({{Foo, FooSym}})); 936 FooResponsibility->finalize(); 937 } 938 939 } // namespace 940