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 "gtest/gtest.h" 14 15 #include <set> 16 #include <thread> 17 18 using namespace llvm; 19 using namespace llvm::orc; 20 21 namespace { 22 23 class SimpleMaterializationUnit : public MaterializationUnit { 24 public: 25 using MaterializeFunction = 26 std::function<void(MaterializationResponsibility)>; 27 using DiscardFunction = std::function<void(const VSO &, SymbolStringPtr)>; 28 using DestructorFunction = std::function<void()>; 29 30 SimpleMaterializationUnit( 31 SymbolFlagsMap SymbolFlags, MaterializeFunction Materialize, 32 DiscardFunction Discard = DiscardFunction(), 33 DestructorFunction Destructor = DestructorFunction()) 34 : MaterializationUnit(std::move(SymbolFlags)), 35 Materialize(std::move(Materialize)), Discard(std::move(Discard)), 36 Destructor(std::move(Destructor)) {} 37 38 ~SimpleMaterializationUnit() override { 39 if (Destructor) 40 Destructor(); 41 } 42 43 void materialize(MaterializationResponsibility R) override { 44 Materialize(std::move(R)); 45 } 46 47 void discard(const VSO &V, SymbolStringPtr Name) override { 48 if (Discard) 49 Discard(V, std::move(Name)); 50 else 51 llvm_unreachable("Discard not supported"); 52 } 53 54 private: 55 MaterializeFunction Materialize; 56 DiscardFunction Discard; 57 DestructorFunction Destructor; 58 }; 59 60 TEST(CoreAPIsTest, AsynchronousSymbolQuerySuccessfulResolutionOnly) { 61 SymbolStringPool SP; 62 auto Foo = SP.intern("foo"); 63 constexpr JITTargetAddress FakeAddr = 0xdeadbeef; 64 SymbolNameSet Names({Foo}); 65 66 bool OnResolutionRun = false; 67 bool OnReadyRun = false; 68 auto OnResolution = 69 [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) { 70 EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error"; 71 auto &Resolved = Result->Symbols; 72 auto I = Resolved.find(Foo); 73 EXPECT_NE(I, Resolved.end()) << "Could not find symbol definition"; 74 EXPECT_EQ(I->second.getAddress(), FakeAddr) 75 << "Resolution returned incorrect result"; 76 OnResolutionRun = true; 77 }; 78 auto OnReady = [&](Error Err) { 79 cantFail(std::move(Err)); 80 OnReadyRun = true; 81 }; 82 83 AsynchronousSymbolQuery Q(Names, OnResolution, OnReady); 84 85 Q.resolve(Foo, JITEvaluatedSymbol(FakeAddr, JITSymbolFlags::Exported)); 86 87 EXPECT_TRUE(Q.isFullyResolved()) << "Expected query to be fully resolved"; 88 89 if (!Q.isFullyResolved()) 90 return; 91 92 Q.handleFullyResolved(); 93 94 EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run"; 95 EXPECT_FALSE(OnReadyRun) << "OnReady unexpectedly run"; 96 } 97 98 TEST(CoreAPIsTest, ExecutionSessionFailQuery) { 99 ExecutionSession ES; 100 auto Foo = ES.getSymbolStringPool().intern("foo"); 101 SymbolNameSet Names({Foo}); 102 103 bool OnResolutionRun = false; 104 bool OnReadyRun = false; 105 106 auto OnResolution = 107 [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) { 108 EXPECT_FALSE(!!Result) << "Resolution unexpectedly returned success"; 109 auto Msg = toString(Result.takeError()); 110 EXPECT_EQ(Msg, "xyz") << "Resolution returned incorrect result"; 111 OnResolutionRun = true; 112 }; 113 auto OnReady = [&](Error Err) { 114 cantFail(std::move(Err)); 115 OnReadyRun = true; 116 }; 117 118 AsynchronousSymbolQuery Q(Names, OnResolution, OnReady); 119 120 ES.failQuery(Q, make_error<StringError>("xyz", inconvertibleErrorCode())); 121 122 EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run"; 123 EXPECT_FALSE(OnReadyRun) << "OnReady unexpectedly run"; 124 } 125 126 TEST(CoreAPIsTest, SimpleAsynchronousSymbolQueryAgainstVSO) { 127 ExecutionSession ES; 128 auto Foo = ES.getSymbolStringPool().intern("foo"); 129 constexpr JITTargetAddress FakeAddr = 0xdeadbeef; 130 SymbolNameSet Names({Foo}); 131 132 bool OnResolutionRun = false; 133 bool OnReadyRun = false; 134 135 auto OnResolution = 136 [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) { 137 EXPECT_TRUE(!!Result) << "Query unexpectedly returned error"; 138 auto &Resolved = Result->Symbols; 139 auto I = Resolved.find(Foo); 140 EXPECT_NE(I, Resolved.end()) << "Could not find symbol definition"; 141 EXPECT_EQ(I->second.getAddress(), FakeAddr) 142 << "Resolution returned incorrect result"; 143 OnResolutionRun = true; 144 }; 145 146 auto OnReady = [&](Error Err) { 147 cantFail(std::move(Err)); 148 OnReadyRun = true; 149 }; 150 151 auto Q = 152 std::make_shared<AsynchronousSymbolQuery>(Names, OnResolution, OnReady); 153 auto &V = ES.createVSO("V"); 154 155 auto Defs = absoluteSymbols( 156 {{Foo, JITEvaluatedSymbol(FakeAddr, JITSymbolFlags::Exported)}}); 157 cantFail(V.define(Defs)); 158 assert(Defs == nullptr && "Defs should have been accepted"); 159 V.lookup(Q, Names); 160 161 EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run"; 162 EXPECT_TRUE(OnReadyRun) << "OnReady was not run"; 163 } 164 165 TEST(CoreAPIsTest, LookupFlagsTest) { 166 167 // Test that lookupFlags works on a predefined symbol, and does not trigger 168 // materialization of a lazy symbol. 169 170 ExecutionSession ES; 171 auto Foo = ES.getSymbolStringPool().intern("foo"); 172 auto Bar = ES.getSymbolStringPool().intern("bar"); 173 auto Baz = ES.getSymbolStringPool().intern("baz"); 174 175 JITSymbolFlags FooFlags = JITSymbolFlags::Exported; 176 JITSymbolFlags BarFlags = static_cast<JITSymbolFlags::FlagNames>( 177 JITSymbolFlags::Exported | JITSymbolFlags::Weak); 178 179 VSO &V = ES.createVSO("V"); 180 181 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 182 SymbolFlagsMap({{Bar, BarFlags}}), 183 [](MaterializationResponsibility R) { 184 llvm_unreachable("Symbol materialized on flags lookup"); 185 }); 186 187 cantFail(V.define( 188 absoluteSymbols({{Foo, JITEvaluatedSymbol(0xdeadbeef, FooFlags)}}))); 189 cantFail(V.define(std::move(MU))); 190 191 SymbolNameSet Names({Foo, Bar, Baz}); 192 193 SymbolFlagsMap SymbolFlags; 194 auto SymbolsNotFound = V.lookupFlags(SymbolFlags, Names); 195 196 EXPECT_EQ(SymbolsNotFound.size(), 1U) << "Expected one not-found symbol"; 197 EXPECT_EQ(SymbolsNotFound.count(Baz), 1U) << "Expected Baz to be not-found"; 198 EXPECT_EQ(SymbolFlags.size(), 2U) 199 << "Returned symbol flags contains unexpected results"; 200 EXPECT_EQ(SymbolFlags.count(Foo), 1U) << "Missing lookupFlags result for Foo"; 201 EXPECT_EQ(SymbolFlags[Foo], FooFlags) << "Incorrect flags returned for Foo"; 202 EXPECT_EQ(SymbolFlags.count(Bar), 1U) 203 << "Missing lookupFlags result for Bar"; 204 EXPECT_EQ(SymbolFlags[Bar], BarFlags) << "Incorrect flags returned for Bar"; 205 } 206 207 TEST(CoreAPIsTest, TestCircularDependenceInOneVSO) { 208 209 ExecutionSession ES; 210 211 auto &V = ES.createVSO("V"); 212 213 // Create three symbols: Foo, Bar and Baz. 214 auto Foo = ES.getSymbolStringPool().intern("foo"); 215 auto FooFlags = JITSymbolFlags::Exported; 216 auto FooSym = JITEvaluatedSymbol(1U, FooFlags); 217 218 auto Bar = ES.getSymbolStringPool().intern("bar"); 219 auto BarFlags = JITSymbolFlags::Exported; 220 auto BarSym = JITEvaluatedSymbol(2U, BarFlags); 221 222 auto Baz = ES.getSymbolStringPool().intern("baz"); 223 auto BazFlags = JITSymbolFlags::Exported; 224 auto BazSym = JITEvaluatedSymbol(3U, BazFlags); 225 226 // Create three MaterializationResponsibility objects: one for each symbol 227 // (these are optional because MaterializationResponsibility does not have 228 // a default constructor). 229 Optional<MaterializationResponsibility> FooR; 230 Optional<MaterializationResponsibility> BarR; 231 Optional<MaterializationResponsibility> BazR; 232 233 // Create a MaterializationUnit for each symbol that moves the 234 // MaterializationResponsibility into one of the locals above. 235 auto FooMU = llvm::make_unique<SimpleMaterializationUnit>( 236 SymbolFlagsMap({{Foo, FooFlags}}), 237 [&](MaterializationResponsibility R) { FooR.emplace(std::move(R)); }); 238 239 auto BarMU = llvm::make_unique<SimpleMaterializationUnit>( 240 SymbolFlagsMap({{Bar, BarFlags}}), 241 [&](MaterializationResponsibility R) { BarR.emplace(std::move(R)); }); 242 243 auto BazMU = llvm::make_unique<SimpleMaterializationUnit>( 244 SymbolFlagsMap({{Baz, BazFlags}}), 245 [&](MaterializationResponsibility R) { BazR.emplace(std::move(R)); }); 246 247 // Define the symbols. 248 cantFail(V.define(FooMU)); 249 cantFail(V.define(BarMU)); 250 cantFail(V.define(BazMU)); 251 252 // Query each of the symbols to trigger materialization. 253 bool FooResolved = false; 254 bool FooReady = false; 255 auto FooQ = std::make_shared<AsynchronousSymbolQuery>( 256 SymbolNameSet({Foo}), 257 [&](Expected<AsynchronousSymbolQuery::ResolutionResult> RR) { 258 cantFail(std::move(RR)); 259 FooResolved = true; 260 }, 261 [&](Error Err) { 262 cantFail(std::move(Err)); 263 FooReady = true; 264 }); 265 { 266 auto Unresolved = V.lookup(FooQ, {Foo}); 267 EXPECT_TRUE(Unresolved.empty()) << "Failed to resolve \"Foo\""; 268 } 269 270 bool BarResolved = false; 271 bool BarReady = false; 272 auto BarQ = std::make_shared<AsynchronousSymbolQuery>( 273 SymbolNameSet({Bar}), 274 [&](Expected<AsynchronousSymbolQuery::ResolutionResult> RR) { 275 cantFail(std::move(RR)); 276 BarResolved = true; 277 }, 278 [&](Error Err) { 279 cantFail(std::move(Err)); 280 BarReady = true; 281 }); 282 { 283 auto Unresolved = V.lookup(BarQ, {Bar}); 284 EXPECT_TRUE(Unresolved.empty()) << "Failed to resolve \"Bar\""; 285 } 286 287 bool BazResolved = false; 288 bool BazReady = false; 289 auto BazQ = std::make_shared<AsynchronousSymbolQuery>( 290 SymbolNameSet({Baz}), 291 [&](Expected<AsynchronousSymbolQuery::ResolutionResult> RR) { 292 cantFail(std::move(RR)); 293 BazResolved = true; 294 }, 295 [&](Error Err) { 296 cantFail(std::move(Err)); 297 BazReady = true; 298 }); 299 { 300 auto Unresolved = V.lookup(BazQ, {Baz}); 301 EXPECT_TRUE(Unresolved.empty()) << "Failed to resolve \"Baz\""; 302 } 303 304 FooR->addDependencies({{&V, SymbolNameSet({Bar})}}); 305 BarR->addDependencies({{&V, SymbolNameSet({Baz})}}); 306 BazR->addDependencies({{&V, SymbolNameSet({Foo})}}); 307 308 EXPECT_FALSE(FooResolved) << "\"Foo\" should not be resolved yet"; 309 EXPECT_FALSE(BarResolved) << "\"Bar\" should not be resolved yet"; 310 EXPECT_FALSE(BazResolved) << "\"Baz\" should not be resolved yet"; 311 312 FooR->resolve({{Foo, FooSym}}); 313 BarR->resolve({{Bar, BarSym}}); 314 BazR->resolve({{Baz, BazSym}}); 315 316 EXPECT_TRUE(FooResolved) << "\"Foo\" should be resolved now"; 317 EXPECT_TRUE(BarResolved) << "\"Bar\" should be resolved now"; 318 EXPECT_TRUE(BazResolved) << "\"Baz\" should be resolved now"; 319 320 EXPECT_FALSE(FooReady) << "\"Foo\" should not be ready yet"; 321 EXPECT_FALSE(BarReady) << "\"Bar\" should not be ready yet"; 322 EXPECT_FALSE(BazReady) << "\"Baz\" should not be ready yet"; 323 324 FooR->finalize(); 325 BarR->finalize(); 326 327 // Verify that nothing is ready until the circular dependence is resolved. 328 329 EXPECT_FALSE(FooReady) << "\"Foo\" still should not be ready"; 330 EXPECT_FALSE(BarReady) << "\"Bar\" still should not be ready"; 331 EXPECT_FALSE(BazReady) << "\"Baz\" still should not be ready"; 332 333 BazR->finalize(); 334 335 // Verify that everything becomes ready once the circular dependence resolved. 336 EXPECT_TRUE(FooReady) << "\"Foo\" should be ready now"; 337 EXPECT_TRUE(BarReady) << "\"Bar\" should be ready now"; 338 EXPECT_TRUE(BazReady) << "\"Baz\" should be ready now"; 339 } 340 341 TEST(CoreAPIsTest, DropMaterializerWhenEmpty) { 342 ExecutionSession ES; 343 auto Foo = ES.getSymbolStringPool().intern("foo"); 344 auto Bar = ES.getSymbolStringPool().intern("bar"); 345 346 bool DestructorRun = false; 347 348 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 349 SymbolFlagsMap( 350 {{Foo, JITSymbolFlags::Weak}, {Bar, JITSymbolFlags::Weak}}), 351 [](MaterializationResponsibility R) { 352 llvm_unreachable("Unexpected call to materialize"); 353 }, 354 [&](const VSO &V, SymbolStringPtr Name) { 355 EXPECT_TRUE(Name == Foo || Name == Bar) 356 << "Discard of unexpected symbol?"; 357 }, 358 [&]() { DestructorRun = true; }); 359 360 auto &V = ES.createVSO("V"); 361 362 cantFail(V.define(MU)); 363 364 auto FooSym = JITEvaluatedSymbol(1, JITSymbolFlags::Exported); 365 auto BarSym = JITEvaluatedSymbol(2, JITSymbolFlags::Exported); 366 cantFail(V.define(absoluteSymbols({{Foo, FooSym}}))); 367 368 EXPECT_FALSE(DestructorRun) 369 << "MaterializationUnit should not have been destroyed yet"; 370 371 cantFail(V.define(absoluteSymbols({{Bar, BarSym}}))); 372 373 EXPECT_TRUE(DestructorRun) 374 << "MaterializationUnit should have been destroyed"; 375 } 376 377 TEST(CoreAPIsTest, AddAndMaterializeLazySymbol) { 378 379 constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef; 380 constexpr JITTargetAddress FakeBarAddr = 0xcafef00d; 381 382 ExecutionSession ES; 383 auto Foo = ES.getSymbolStringPool().intern("foo"); 384 auto Bar = ES.getSymbolStringPool().intern("bar"); 385 386 bool FooMaterialized = false; 387 bool BarDiscarded = false; 388 389 auto &V = ES.createVSO("V"); 390 391 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 392 SymbolFlagsMap( 393 {{Foo, JITSymbolFlags::Exported}, 394 {Bar, static_cast<JITSymbolFlags::FlagNames>( 395 JITSymbolFlags::Exported | JITSymbolFlags::Weak)}}), 396 [&](MaterializationResponsibility R) { 397 assert(BarDiscarded && "Bar should have been discarded by this point"); 398 SymbolMap SymbolsToResolve; 399 SymbolsToResolve[Foo] = 400 JITEvaluatedSymbol(FakeFooAddr, JITSymbolFlags::Exported); 401 R.resolve(std::move(SymbolsToResolve)); 402 R.finalize(); 403 FooMaterialized = true; 404 }, 405 [&](const VSO &V, SymbolStringPtr Name) { 406 EXPECT_EQ(Name, Bar) << "Expected Name to be Bar"; 407 BarDiscarded = true; 408 }); 409 410 cantFail(V.define(MU)); 411 412 ; 413 cantFail(V.define(absoluteSymbols( 414 {{Bar, JITEvaluatedSymbol(FakeBarAddr, JITSymbolFlags::Exported)}}))); 415 416 SymbolNameSet Names({Foo}); 417 418 bool OnResolutionRun = false; 419 bool OnReadyRun = false; 420 421 auto OnResolution = 422 [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) { 423 EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error"; 424 auto I = Result->Symbols.find(Foo); 425 EXPECT_NE(I, Result->Symbols.end()) 426 << "Could not find symbol definition"; 427 EXPECT_EQ(I->second.getAddress(), FakeFooAddr) 428 << "Resolution returned incorrect result"; 429 OnResolutionRun = true; 430 }; 431 432 auto OnReady = [&](Error Err) { 433 cantFail(std::move(Err)); 434 OnReadyRun = true; 435 }; 436 437 auto Q = 438 std::make_shared<AsynchronousSymbolQuery>(Names, OnResolution, OnReady); 439 440 auto Unresolved = V.lookup(std::move(Q), Names); 441 442 EXPECT_TRUE(Unresolved.empty()) << "Could not find Foo in dylib"; 443 EXPECT_TRUE(FooMaterialized) << "Foo was not materialized"; 444 EXPECT_TRUE(BarDiscarded) << "Bar was not discarded"; 445 EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run"; 446 EXPECT_TRUE(OnReadyRun) << "OnReady was not run"; 447 } 448 449 TEST(CoreAPIsTest, DefineMaterializingSymbol) { 450 ExecutionSession ES; 451 auto Foo = ES.getSymbolStringPool().intern("foo"); 452 auto Bar = ES.getSymbolStringPool().intern("bar"); 453 454 auto FooSym = JITEvaluatedSymbol(1, JITSymbolFlags::Exported); 455 auto BarSym = JITEvaluatedSymbol(2, JITSymbolFlags::Exported); 456 457 bool ExpectNoMoreMaterialization = false; 458 ES.setDispatchMaterialization( 459 [&](VSO &V, std::unique_ptr<MaterializationUnit> MU) { 460 if (ExpectNoMoreMaterialization) 461 ADD_FAILURE() << "Unexpected materialization"; 462 MU->doMaterialize(V); 463 }); 464 465 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 466 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 467 [&](MaterializationResponsibility R) { 468 cantFail( 469 R.defineMaterializing(SymbolFlagsMap({{Bar, BarSym.getFlags()}}))); 470 R.resolve(SymbolMap({{Foo, FooSym}, {Bar, BarSym}})); 471 R.finalize(); 472 }); 473 474 auto &V = ES.createVSO("V"); 475 cantFail(V.define(MU)); 476 477 auto OnResolution1 = 478 [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) { 479 cantFail(std::move(Result)); 480 }; 481 482 auto OnReady1 = [](Error Err) { cantFail(std::move(Err)); }; 483 484 auto Q1 = std::make_shared<AsynchronousSymbolQuery>(SymbolNameSet({Foo}), 485 OnResolution1, OnReady1); 486 487 V.lookup(std::move(Q1), {Foo}); 488 489 bool BarResolved = false; 490 auto OnResolution2 = 491 [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) { 492 auto R = cantFail(std::move(Result)); 493 EXPECT_EQ(R.Symbols.size(), 1U) << "Expected to resolve one symbol"; 494 EXPECT_EQ(R.Symbols.count(Bar), 1U) << "Expected to resolve 'Bar'"; 495 EXPECT_EQ(R.Symbols[Bar].getAddress(), BarSym.getAddress()) 496 << "Expected Bar == BarSym"; 497 BarResolved = true; 498 }; 499 500 auto OnReady2 = [](Error Err) { cantFail(std::move(Err)); }; 501 502 auto Q2 = std::make_shared<AsynchronousSymbolQuery>(SymbolNameSet({Bar}), 503 OnResolution2, OnReady2); 504 505 ExpectNoMoreMaterialization = true; 506 V.lookup(std::move(Q2), {Bar}); 507 508 EXPECT_TRUE(BarResolved) << "Bar should have been resolved"; 509 } 510 511 TEST(CoreAPIsTest, FailResolution) { 512 ExecutionSession ES; 513 auto Foo = ES.getSymbolStringPool().intern("foo"); 514 auto Bar = ES.getSymbolStringPool().intern("bar"); 515 516 SymbolNameSet Names({Foo, Bar}); 517 518 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 519 SymbolFlagsMap( 520 {{Foo, JITSymbolFlags::Weak}, {Bar, JITSymbolFlags::Weak}}), 521 [&](MaterializationResponsibility R) { R.failMaterialization(); }); 522 523 auto &V = ES.createVSO("V"); 524 525 cantFail(V.define(MU)); 526 527 auto OnResolution = 528 [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) { 529 handleAllErrors(Result.takeError(), 530 [&](FailedToMaterialize &F) { 531 EXPECT_EQ(F.getSymbols(), Names) 532 << "Expected to fail on symbols in Names"; 533 }, 534 [](ErrorInfoBase &EIB) { 535 std::string ErrMsg; 536 { 537 raw_string_ostream ErrOut(ErrMsg); 538 EIB.log(ErrOut); 539 } 540 ADD_FAILURE() 541 << "Expected a FailedToResolve error. Got:\n" 542 << ErrMsg; 543 }); 544 }; 545 546 auto OnReady = [](Error Err) { 547 cantFail(std::move(Err)); 548 ADD_FAILURE() << "OnReady should never be called"; 549 }; 550 551 auto Q = 552 std::make_shared<AsynchronousSymbolQuery>(Names, OnResolution, OnReady); 553 554 V.lookup(std::move(Q), Names); 555 } 556 557 TEST(CoreAPIsTest, TestLambdaSymbolResolver) { 558 JITEvaluatedSymbol FooSym(0xdeadbeef, JITSymbolFlags::Exported); 559 JITEvaluatedSymbol BarSym(0xcafef00d, JITSymbolFlags::Exported); 560 561 ExecutionSession ES; 562 563 auto Foo = ES.getSymbolStringPool().intern("foo"); 564 auto Bar = ES.getSymbolStringPool().intern("bar"); 565 auto Baz = ES.getSymbolStringPool().intern("baz"); 566 567 auto &V = ES.createVSO("V"); 568 cantFail(V.define(absoluteSymbols({{Foo, FooSym}, {Bar, BarSym}}))); 569 570 auto Resolver = createSymbolResolver( 571 [&](SymbolFlagsMap &SymbolFlags, const SymbolNameSet &Symbols) { 572 return V.lookupFlags(SymbolFlags, Symbols); 573 }, 574 [&](std::shared_ptr<AsynchronousSymbolQuery> Q, SymbolNameSet Symbols) { 575 return V.lookup(std::move(Q), Symbols); 576 }); 577 578 SymbolNameSet Symbols({Foo, Bar, Baz}); 579 580 SymbolFlagsMap SymbolFlags; 581 SymbolNameSet SymbolsNotFound = Resolver->lookupFlags(SymbolFlags, Symbols); 582 583 EXPECT_EQ(SymbolFlags.size(), 2U) 584 << "lookupFlags returned the wrong number of results"; 585 EXPECT_EQ(SymbolFlags.count(Foo), 1U) << "Missing lookupFlags result for foo"; 586 EXPECT_EQ(SymbolFlags.count(Bar), 1U) << "Missing lookupFlags result for bar"; 587 EXPECT_EQ(SymbolFlags[Foo], FooSym.getFlags()) 588 << "Incorrect lookupFlags result for Foo"; 589 EXPECT_EQ(SymbolFlags[Bar], BarSym.getFlags()) 590 << "Incorrect lookupFlags result for Bar"; 591 EXPECT_EQ(SymbolsNotFound.size(), 1U) 592 << "Expected one symbol not found in lookupFlags"; 593 EXPECT_EQ(SymbolsNotFound.count(Baz), 1U) 594 << "Expected baz not to be found in lookupFlags"; 595 596 bool OnResolvedRun = false; 597 598 auto OnResolved = 599 [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) { 600 OnResolvedRun = true; 601 EXPECT_TRUE(!!Result) << "Unexpected error"; 602 EXPECT_EQ(Result->Symbols.size(), 2U) 603 << "Unexpected number of resolved symbols"; 604 EXPECT_EQ(Result->Symbols.count(Foo), 1U) 605 << "Missing lookup result for foo"; 606 EXPECT_EQ(Result->Symbols.count(Bar), 1U) 607 << "Missing lookup result for bar"; 608 EXPECT_EQ(Result->Symbols[Foo].getAddress(), FooSym.getAddress()) 609 << "Incorrect address for foo"; 610 EXPECT_EQ(Result->Symbols[Bar].getAddress(), BarSym.getAddress()) 611 << "Incorrect address for bar"; 612 }; 613 auto OnReady = [&](Error Err) { 614 EXPECT_FALSE(!!Err) << "Finalization should never fail in this test"; 615 }; 616 617 auto Q = std::make_shared<AsynchronousSymbolQuery>(SymbolNameSet({Foo, Bar}), 618 OnResolved, OnReady); 619 auto Unresolved = Resolver->lookup(std::move(Q), Symbols); 620 621 EXPECT_EQ(Unresolved.size(), 1U) << "Expected one unresolved symbol"; 622 EXPECT_EQ(Unresolved.count(Baz), 1U) << "Expected baz to not be resolved"; 623 EXPECT_TRUE(OnResolvedRun) << "OnResolved was never run"; 624 } 625 626 TEST(CoreAPIsTest, TestLookupWithUnthreadedMaterialization) { 627 constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef; 628 JITEvaluatedSymbol FooSym(FakeFooAddr, JITSymbolFlags::Exported); 629 630 ExecutionSession ES(std::make_shared<SymbolStringPool>()); 631 auto Foo = ES.getSymbolStringPool().intern("foo"); 632 633 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 634 SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}}), 635 [&](MaterializationResponsibility R) { 636 R.resolve({{Foo, FooSym}}); 637 R.finalize(); 638 }); 639 640 auto &V = ES.createVSO("V"); 641 642 cantFail(V.define(MU)); 643 644 auto FooLookupResult = cantFail(lookup({&V}, Foo)); 645 646 EXPECT_EQ(FooLookupResult.getAddress(), FooSym.getAddress()) 647 << "lookup returned an incorrect address"; 648 EXPECT_EQ(FooLookupResult.getFlags(), FooSym.getFlags()) 649 << "lookup returned incorrect flags"; 650 } 651 652 TEST(CoreAPIsTest, TestLookupWithThreadedMaterialization) { 653 #if LLVM_ENABLE_THREADS 654 constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef; 655 JITEvaluatedSymbol FooSym(FakeFooAddr, JITSymbolFlags::Exported); 656 657 ExecutionSession ES(std::make_shared<SymbolStringPool>()); 658 659 std::thread MaterializationThread; 660 ES.setDispatchMaterialization( 661 [&](VSO &V, std::unique_ptr<MaterializationUnit> MU) { 662 auto SharedMU = std::shared_ptr<MaterializationUnit>(std::move(MU)); 663 MaterializationThread = 664 std::thread([SharedMU, &V]() { SharedMU->doMaterialize(V); }); 665 }); 666 auto Foo = ES.getSymbolStringPool().intern("foo"); 667 668 auto &V = ES.createVSO("V"); 669 cantFail(V.define(absoluteSymbols({{Foo, FooSym}}))); 670 671 auto FooLookupResult = cantFail(lookup({&V}, 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 MaterializationThread.join(); 678 #endif 679 } 680 681 TEST(CoreAPIsTest, TestGetRequestedSymbolsAndDelegate) { 682 ExecutionSession ES; 683 auto Foo = ES.getSymbolStringPool().intern("foo"); 684 auto Bar = ES.getSymbolStringPool().intern("bar"); 685 686 JITEvaluatedSymbol FooSym(0xdeadbeef, JITSymbolFlags::Exported); 687 JITEvaluatedSymbol BarSym(0xcafef00d, JITSymbolFlags::Exported); 688 689 SymbolNameSet Names({Foo, Bar}); 690 691 bool FooMaterialized = false; 692 bool BarMaterialized = false; 693 694 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 695 SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}), 696 [&](MaterializationResponsibility R) { 697 auto Requested = R.getRequestedSymbols(); 698 EXPECT_EQ(Requested.size(), 1U) << "Expected one symbol requested"; 699 EXPECT_EQ(*Requested.begin(), Foo) << "Expected \"Foo\" requested"; 700 701 auto NewMU = llvm::make_unique<SimpleMaterializationUnit>( 702 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 703 [&](MaterializationResponsibility R2) { 704 R2.resolve(SymbolMap({{Bar, BarSym}})); 705 R2.finalize(); 706 BarMaterialized = true; 707 }); 708 709 R.delegate(std::move(NewMU)); 710 711 R.resolve(SymbolMap({{Foo, FooSym}})); 712 R.finalize(); 713 714 FooMaterialized = true; 715 }); 716 717 auto &V = ES.createVSO("V"); 718 719 cantFail(V.define(MU)); 720 721 EXPECT_FALSE(FooMaterialized) << "Foo should not be materialized yet"; 722 EXPECT_FALSE(BarMaterialized) << "Bar should not be materialized yet"; 723 724 auto FooSymResult = cantFail(lookup({&V}, Foo)); 725 EXPECT_EQ(FooSymResult.getAddress(), FooSym.getAddress()) 726 << "Address mismatch for Foo"; 727 728 EXPECT_TRUE(FooMaterialized) << "Foo should be materialized now"; 729 EXPECT_FALSE(BarMaterialized) << "Bar still should not be materialized"; 730 731 auto BarSymResult = cantFail(lookup({&V}, Bar)); 732 EXPECT_EQ(BarSymResult.getAddress(), BarSym.getAddress()) 733 << "Address mismatch for Bar"; 734 EXPECT_TRUE(BarMaterialized) << "Bar should be materialized now"; 735 } 736 737 } // namespace 738