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, LookupFlagsTest) { 167 168 // Test that lookupFlags works on a predefined symbol, and does not trigger 169 // materialization of a lazy symbol. 170 171 ExecutionSession ES; 172 auto Foo = ES.getSymbolStringPool().intern("foo"); 173 auto Bar = ES.getSymbolStringPool().intern("bar"); 174 auto Baz = ES.getSymbolStringPool().intern("baz"); 175 176 JITSymbolFlags FooFlags = JITSymbolFlags::Exported; 177 JITSymbolFlags BarFlags = static_cast<JITSymbolFlags::FlagNames>( 178 JITSymbolFlags::Exported | JITSymbolFlags::Weak); 179 180 VSO &V = ES.createVSO("V"); 181 182 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 183 SymbolFlagsMap({{Bar, BarFlags}}), 184 [](MaterializationResponsibility R) { 185 llvm_unreachable("Symbol materialized on flags lookup"); 186 }); 187 188 cantFail(V.define( 189 absoluteSymbols({{Foo, JITEvaluatedSymbol(0xdeadbeef, FooFlags)}}))); 190 cantFail(V.define(std::move(MU))); 191 192 SymbolNameSet Names({Foo, Bar, Baz}); 193 194 SymbolFlagsMap SymbolFlags; 195 auto SymbolsNotFound = V.lookupFlags(SymbolFlags, Names); 196 197 EXPECT_EQ(SymbolsNotFound.size(), 1U) << "Expected one not-found symbol"; 198 EXPECT_EQ(SymbolsNotFound.count(Baz), 1U) << "Expected Baz to be not-found"; 199 EXPECT_EQ(SymbolFlags.size(), 2U) 200 << "Returned symbol flags contains unexpected results"; 201 EXPECT_EQ(SymbolFlags.count(Foo), 1U) << "Missing lookupFlags result for Foo"; 202 EXPECT_EQ(SymbolFlags[Foo], FooFlags) << "Incorrect flags returned for Foo"; 203 EXPECT_EQ(SymbolFlags.count(Bar), 1U) 204 << "Missing lookupFlags result for Bar"; 205 EXPECT_EQ(SymbolFlags[Bar], BarFlags) << "Incorrect flags returned for Bar"; 206 } 207 208 TEST(CoreAPIsTest, TestCircularDependenceInOneVSO) { 209 210 ExecutionSession ES; 211 212 auto &V = ES.createVSO("V"); 213 214 // Create three symbols: Foo, Bar and Baz. 215 auto Foo = ES.getSymbolStringPool().intern("foo"); 216 auto FooFlags = JITSymbolFlags::Exported; 217 auto FooSym = JITEvaluatedSymbol(1U, FooFlags); 218 219 auto Bar = ES.getSymbolStringPool().intern("bar"); 220 auto BarFlags = JITSymbolFlags::Exported; 221 auto BarSym = JITEvaluatedSymbol(2U, BarFlags); 222 223 auto Baz = ES.getSymbolStringPool().intern("baz"); 224 auto BazFlags = JITSymbolFlags::Exported; 225 auto BazSym = JITEvaluatedSymbol(3U, BazFlags); 226 227 // Create three MaterializationResponsibility objects: one for each symbol 228 // (these are optional because MaterializationResponsibility does not have 229 // a default constructor). 230 Optional<MaterializationResponsibility> FooR; 231 Optional<MaterializationResponsibility> BarR; 232 Optional<MaterializationResponsibility> BazR; 233 234 // Create a MaterializationUnit for each symbol that moves the 235 // MaterializationResponsibility into one of the locals above. 236 auto FooMU = llvm::make_unique<SimpleMaterializationUnit>( 237 SymbolFlagsMap({{Foo, FooFlags}}), 238 [&](MaterializationResponsibility R) { FooR.emplace(std::move(R)); }); 239 240 auto BarMU = llvm::make_unique<SimpleMaterializationUnit>( 241 SymbolFlagsMap({{Bar, BarFlags}}), 242 [&](MaterializationResponsibility R) { BarR.emplace(std::move(R)); }); 243 244 auto BazMU = llvm::make_unique<SimpleMaterializationUnit>( 245 SymbolFlagsMap({{Baz, BazFlags}}), 246 [&](MaterializationResponsibility R) { BazR.emplace(std::move(R)); }); 247 248 // Define the symbols. 249 cantFail(V.define(FooMU)); 250 cantFail(V.define(BarMU)); 251 cantFail(V.define(BazMU)); 252 253 // Query each of the symbols to trigger materialization. 254 bool FooResolved = false; 255 bool FooReady = false; 256 auto FooQ = std::make_shared<AsynchronousSymbolQuery>( 257 SymbolNameSet({Foo}), 258 [&](Expected<AsynchronousSymbolQuery::ResolutionResult> RR) { 259 cantFail(std::move(RR)); 260 FooResolved = true; 261 }, 262 [&](Error Err) { 263 cantFail(std::move(Err)); 264 FooReady = true; 265 }); 266 { 267 auto Unresolved = V.lookup(FooQ, {Foo}); 268 EXPECT_TRUE(Unresolved.empty()) << "Failed to resolve \"Foo\""; 269 } 270 271 bool BarResolved = false; 272 bool BarReady = false; 273 auto BarQ = std::make_shared<AsynchronousSymbolQuery>( 274 SymbolNameSet({Bar}), 275 [&](Expected<AsynchronousSymbolQuery::ResolutionResult> RR) { 276 cantFail(std::move(RR)); 277 BarResolved = true; 278 }, 279 [&](Error Err) { 280 cantFail(std::move(Err)); 281 BarReady = true; 282 }); 283 { 284 auto Unresolved = V.lookup(BarQ, {Bar}); 285 EXPECT_TRUE(Unresolved.empty()) << "Failed to resolve \"Bar\""; 286 } 287 288 bool BazResolved = false; 289 bool BazReady = false; 290 auto BazQ = std::make_shared<AsynchronousSymbolQuery>( 291 SymbolNameSet({Baz}), 292 [&](Expected<AsynchronousSymbolQuery::ResolutionResult> RR) { 293 cantFail(std::move(RR)); 294 BazResolved = true; 295 }, 296 [&](Error Err) { 297 cantFail(std::move(Err)); 298 BazReady = true; 299 }); 300 { 301 auto Unresolved = V.lookup(BazQ, {Baz}); 302 EXPECT_TRUE(Unresolved.empty()) << "Failed to resolve \"Baz\""; 303 } 304 305 // Add a circular dependency: Foo -> Bar, Bar -> Baz, Baz -> Foo. 306 FooR->addDependencies({{&V, SymbolNameSet({Bar})}}); 307 BarR->addDependencies({{&V, SymbolNameSet({Baz})}}); 308 BazR->addDependencies({{&V, SymbolNameSet({Foo})}}); 309 310 // Add self-dependencies for good measure. This tests that the implementation 311 // of addDependencies filters these out. 312 FooR->addDependencies({{&V, SymbolNameSet({Foo})}}); 313 BarR->addDependencies({{&V, SymbolNameSet({Bar})}}); 314 BazR->addDependencies({{&V, SymbolNameSet({Baz})}}); 315 316 EXPECT_FALSE(FooResolved) << "\"Foo\" should not be resolved yet"; 317 EXPECT_FALSE(BarResolved) << "\"Bar\" should not be resolved yet"; 318 EXPECT_FALSE(BazResolved) << "\"Baz\" should not be resolved yet"; 319 320 FooR->resolve({{Foo, FooSym}}); 321 BarR->resolve({{Bar, BarSym}}); 322 BazR->resolve({{Baz, BazSym}}); 323 324 EXPECT_TRUE(FooResolved) << "\"Foo\" should be resolved now"; 325 EXPECT_TRUE(BarResolved) << "\"Bar\" should be resolved now"; 326 EXPECT_TRUE(BazResolved) << "\"Baz\" should be resolved now"; 327 328 EXPECT_FALSE(FooReady) << "\"Foo\" should not be ready yet"; 329 EXPECT_FALSE(BarReady) << "\"Bar\" should not be ready yet"; 330 EXPECT_FALSE(BazReady) << "\"Baz\" should not be ready yet"; 331 332 FooR->finalize(); 333 BarR->finalize(); 334 335 // Verify that nothing is ready until the circular dependence is resolved. 336 337 EXPECT_FALSE(FooReady) << "\"Foo\" still should not be ready"; 338 EXPECT_FALSE(BarReady) << "\"Bar\" still should not be ready"; 339 EXPECT_FALSE(BazReady) << "\"Baz\" still should not be ready"; 340 341 BazR->finalize(); 342 343 // Verify that everything becomes ready once the circular dependence resolved. 344 EXPECT_TRUE(FooReady) << "\"Foo\" should be ready now"; 345 EXPECT_TRUE(BarReady) << "\"Bar\" should be ready now"; 346 EXPECT_TRUE(BazReady) << "\"Baz\" should be ready now"; 347 } 348 349 TEST(CoreAPIsTest, DropMaterializerWhenEmpty) { 350 ExecutionSession ES; 351 auto Foo = ES.getSymbolStringPool().intern("foo"); 352 auto Bar = ES.getSymbolStringPool().intern("bar"); 353 354 bool DestructorRun = false; 355 356 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 357 SymbolFlagsMap( 358 {{Foo, JITSymbolFlags::Weak}, {Bar, JITSymbolFlags::Weak}}), 359 [](MaterializationResponsibility R) { 360 llvm_unreachable("Unexpected call to materialize"); 361 }, 362 [&](const VSO &V, SymbolStringPtr Name) { 363 EXPECT_TRUE(Name == Foo || Name == Bar) 364 << "Discard of unexpected symbol?"; 365 }, 366 [&]() { DestructorRun = true; }); 367 368 auto &V = ES.createVSO("V"); 369 370 cantFail(V.define(MU)); 371 372 auto FooSym = JITEvaluatedSymbol(1, JITSymbolFlags::Exported); 373 auto BarSym = JITEvaluatedSymbol(2, JITSymbolFlags::Exported); 374 cantFail(V.define(absoluteSymbols({{Foo, FooSym}}))); 375 376 EXPECT_FALSE(DestructorRun) 377 << "MaterializationUnit should not have been destroyed yet"; 378 379 cantFail(V.define(absoluteSymbols({{Bar, BarSym}}))); 380 381 EXPECT_TRUE(DestructorRun) 382 << "MaterializationUnit should have been destroyed"; 383 } 384 385 TEST(CoreAPIsTest, AddAndMaterializeLazySymbol) { 386 387 constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef; 388 constexpr JITTargetAddress FakeBarAddr = 0xcafef00d; 389 390 ExecutionSession ES; 391 auto Foo = ES.getSymbolStringPool().intern("foo"); 392 auto Bar = ES.getSymbolStringPool().intern("bar"); 393 394 bool FooMaterialized = false; 395 bool BarDiscarded = false; 396 397 auto &V = ES.createVSO("V"); 398 399 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 400 SymbolFlagsMap( 401 {{Foo, JITSymbolFlags::Exported}, 402 {Bar, static_cast<JITSymbolFlags::FlagNames>( 403 JITSymbolFlags::Exported | JITSymbolFlags::Weak)}}), 404 [&](MaterializationResponsibility R) { 405 assert(BarDiscarded && "Bar should have been discarded by this point"); 406 SymbolMap SymbolsToResolve; 407 SymbolsToResolve[Foo] = 408 JITEvaluatedSymbol(FakeFooAddr, JITSymbolFlags::Exported); 409 R.resolve(std::move(SymbolsToResolve)); 410 R.finalize(); 411 FooMaterialized = true; 412 }, 413 [&](const VSO &V, SymbolStringPtr Name) { 414 EXPECT_EQ(Name, Bar) << "Expected Name to be Bar"; 415 BarDiscarded = true; 416 }); 417 418 cantFail(V.define(MU)); 419 420 ; 421 cantFail(V.define(absoluteSymbols( 422 {{Bar, JITEvaluatedSymbol(FakeBarAddr, JITSymbolFlags::Exported)}}))); 423 424 SymbolNameSet Names({Foo}); 425 426 bool OnResolutionRun = false; 427 bool OnReadyRun = false; 428 429 auto OnResolution = 430 [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) { 431 EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error"; 432 auto I = Result->Symbols.find(Foo); 433 EXPECT_NE(I, Result->Symbols.end()) 434 << "Could not find symbol definition"; 435 EXPECT_EQ(I->second.getAddress(), FakeFooAddr) 436 << "Resolution returned incorrect result"; 437 OnResolutionRun = true; 438 }; 439 440 auto OnReady = [&](Error Err) { 441 cantFail(std::move(Err)); 442 OnReadyRun = true; 443 }; 444 445 auto Q = 446 std::make_shared<AsynchronousSymbolQuery>(Names, OnResolution, OnReady); 447 448 auto Unresolved = V.lookup(std::move(Q), Names); 449 450 EXPECT_TRUE(Unresolved.empty()) << "Could not find Foo in dylib"; 451 EXPECT_TRUE(FooMaterialized) << "Foo was not materialized"; 452 EXPECT_TRUE(BarDiscarded) << "Bar was not discarded"; 453 EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run"; 454 EXPECT_TRUE(OnReadyRun) << "OnReady was not run"; 455 } 456 457 TEST(CoreAPIsTest, DefineMaterializingSymbol) { 458 ExecutionSession ES; 459 auto Foo = ES.getSymbolStringPool().intern("foo"); 460 auto Bar = ES.getSymbolStringPool().intern("bar"); 461 462 auto FooSym = JITEvaluatedSymbol(1, JITSymbolFlags::Exported); 463 auto BarSym = JITEvaluatedSymbol(2, JITSymbolFlags::Exported); 464 465 bool ExpectNoMoreMaterialization = false; 466 ES.setDispatchMaterialization( 467 [&](VSO &V, std::unique_ptr<MaterializationUnit> MU) { 468 if (ExpectNoMoreMaterialization) 469 ADD_FAILURE() << "Unexpected materialization"; 470 MU->doMaterialize(V); 471 }); 472 473 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 474 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 475 [&](MaterializationResponsibility R) { 476 cantFail( 477 R.defineMaterializing(SymbolFlagsMap({{Bar, BarSym.getFlags()}}))); 478 R.resolve(SymbolMap({{Foo, FooSym}, {Bar, BarSym}})); 479 R.finalize(); 480 }); 481 482 auto &V = ES.createVSO("V"); 483 cantFail(V.define(MU)); 484 485 auto OnResolution1 = 486 [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) { 487 cantFail(std::move(Result)); 488 }; 489 490 auto OnReady1 = [](Error Err) { cantFail(std::move(Err)); }; 491 492 auto Q1 = std::make_shared<AsynchronousSymbolQuery>(SymbolNameSet({Foo}), 493 OnResolution1, OnReady1); 494 495 V.lookup(std::move(Q1), {Foo}); 496 497 bool BarResolved = false; 498 auto OnResolution2 = 499 [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) { 500 auto R = cantFail(std::move(Result)); 501 EXPECT_EQ(R.Symbols.size(), 1U) << "Expected to resolve one symbol"; 502 EXPECT_EQ(R.Symbols.count(Bar), 1U) << "Expected to resolve 'Bar'"; 503 EXPECT_EQ(R.Symbols[Bar].getAddress(), BarSym.getAddress()) 504 << "Expected Bar == BarSym"; 505 BarResolved = true; 506 }; 507 508 auto OnReady2 = [](Error Err) { cantFail(std::move(Err)); }; 509 510 auto Q2 = std::make_shared<AsynchronousSymbolQuery>(SymbolNameSet({Bar}), 511 OnResolution2, OnReady2); 512 513 ExpectNoMoreMaterialization = true; 514 V.lookup(std::move(Q2), {Bar}); 515 516 EXPECT_TRUE(BarResolved) << "Bar should have been resolved"; 517 } 518 519 TEST(CoreAPIsTest, FallbackDefinitionGeneratorTest) { 520 constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef; 521 constexpr JITTargetAddress FakeBarAddr = 0xcafef00d; 522 523 ExecutionSession ES; 524 auto Foo = ES.getSymbolStringPool().intern("foo"); 525 auto Bar = ES.getSymbolStringPool().intern("bar"); 526 527 auto FooSym = JITEvaluatedSymbol(FakeFooAddr, JITSymbolFlags::Exported); 528 auto BarSym = JITEvaluatedSymbol(FakeBarAddr, JITSymbolFlags::Exported); 529 530 auto &V = ES.createVSO("V"); 531 532 cantFail(V.define(absoluteSymbols({{Foo, FooSym}}))); 533 534 V.setFallbackDefinitionGenerator([&](VSO &W, const SymbolNameSet &Names) { 535 cantFail(W.define(absoluteSymbols({{Bar, BarSym}}))); 536 return SymbolNameSet({Bar}); 537 }); 538 539 auto Result = cantFail(lookup({&V}, {Foo, Bar})); 540 541 EXPECT_EQ(Result.count(Bar), 1U) << "Expected to find fallback def for 'bar'"; 542 EXPECT_EQ(Result[Bar].getAddress(), FakeBarAddr) 543 << "Expected address of fallback def for 'bar' to be " << FakeBarAddr; 544 } 545 546 TEST(CoreAPIsTest, FailResolution) { 547 ExecutionSession ES; 548 auto Foo = ES.getSymbolStringPool().intern("foo"); 549 auto Bar = ES.getSymbolStringPool().intern("bar"); 550 551 SymbolNameSet Names({Foo, Bar}); 552 553 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 554 SymbolFlagsMap( 555 {{Foo, JITSymbolFlags::Weak}, {Bar, JITSymbolFlags::Weak}}), 556 [&](MaterializationResponsibility R) { R.failMaterialization(); }); 557 558 auto &V = ES.createVSO("V"); 559 560 cantFail(V.define(MU)); 561 562 auto OnResolution = 563 [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) { 564 handleAllErrors(Result.takeError(), 565 [&](FailedToMaterialize &F) { 566 EXPECT_EQ(F.getSymbols(), Names) 567 << "Expected to fail on symbols in Names"; 568 }, 569 [](ErrorInfoBase &EIB) { 570 std::string ErrMsg; 571 { 572 raw_string_ostream ErrOut(ErrMsg); 573 EIB.log(ErrOut); 574 } 575 ADD_FAILURE() 576 << "Expected a FailedToResolve error. Got:\n" 577 << ErrMsg; 578 }); 579 }; 580 581 auto OnReady = [](Error Err) { 582 cantFail(std::move(Err)); 583 ADD_FAILURE() << "OnReady should never be called"; 584 }; 585 586 auto Q = 587 std::make_shared<AsynchronousSymbolQuery>(Names, OnResolution, OnReady); 588 589 V.lookup(std::move(Q), Names); 590 } 591 592 TEST(CoreAPIsTest, TestLambdaSymbolResolver) { 593 JITEvaluatedSymbol FooSym(0xdeadbeef, JITSymbolFlags::Exported); 594 JITEvaluatedSymbol BarSym(0xcafef00d, JITSymbolFlags::Exported); 595 596 ExecutionSession ES; 597 598 auto Foo = ES.getSymbolStringPool().intern("foo"); 599 auto Bar = ES.getSymbolStringPool().intern("bar"); 600 auto Baz = ES.getSymbolStringPool().intern("baz"); 601 602 auto &V = ES.createVSO("V"); 603 cantFail(V.define(absoluteSymbols({{Foo, FooSym}, {Bar, BarSym}}))); 604 605 auto Resolver = createSymbolResolver( 606 [&](SymbolFlagsMap &SymbolFlags, const SymbolNameSet &Symbols) { 607 return V.lookupFlags(SymbolFlags, Symbols); 608 }, 609 [&](std::shared_ptr<AsynchronousSymbolQuery> Q, SymbolNameSet Symbols) { 610 return V.lookup(std::move(Q), Symbols); 611 }); 612 613 SymbolNameSet Symbols({Foo, Bar, Baz}); 614 615 SymbolFlagsMap SymbolFlags; 616 SymbolNameSet SymbolsNotFound = Resolver->lookupFlags(SymbolFlags, Symbols); 617 618 EXPECT_EQ(SymbolFlags.size(), 2U) 619 << "lookupFlags returned the wrong number of results"; 620 EXPECT_EQ(SymbolFlags.count(Foo), 1U) << "Missing lookupFlags result for foo"; 621 EXPECT_EQ(SymbolFlags.count(Bar), 1U) << "Missing lookupFlags result for bar"; 622 EXPECT_EQ(SymbolFlags[Foo], FooSym.getFlags()) 623 << "Incorrect lookupFlags result for Foo"; 624 EXPECT_EQ(SymbolFlags[Bar], BarSym.getFlags()) 625 << "Incorrect lookupFlags result for Bar"; 626 EXPECT_EQ(SymbolsNotFound.size(), 1U) 627 << "Expected one symbol not found in lookupFlags"; 628 EXPECT_EQ(SymbolsNotFound.count(Baz), 1U) 629 << "Expected baz not to be found in lookupFlags"; 630 631 bool OnResolvedRun = false; 632 633 auto OnResolved = 634 [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) { 635 OnResolvedRun = true; 636 EXPECT_TRUE(!!Result) << "Unexpected error"; 637 EXPECT_EQ(Result->Symbols.size(), 2U) 638 << "Unexpected number of resolved symbols"; 639 EXPECT_EQ(Result->Symbols.count(Foo), 1U) 640 << "Missing lookup result for foo"; 641 EXPECT_EQ(Result->Symbols.count(Bar), 1U) 642 << "Missing lookup result for bar"; 643 EXPECT_EQ(Result->Symbols[Foo].getAddress(), FooSym.getAddress()) 644 << "Incorrect address for foo"; 645 EXPECT_EQ(Result->Symbols[Bar].getAddress(), BarSym.getAddress()) 646 << "Incorrect address for bar"; 647 }; 648 auto OnReady = [&](Error Err) { 649 EXPECT_FALSE(!!Err) << "Finalization should never fail in this test"; 650 }; 651 652 auto Q = std::make_shared<AsynchronousSymbolQuery>(SymbolNameSet({Foo, Bar}), 653 OnResolved, OnReady); 654 auto Unresolved = Resolver->lookup(std::move(Q), Symbols); 655 656 EXPECT_EQ(Unresolved.size(), 1U) << "Expected one unresolved symbol"; 657 EXPECT_EQ(Unresolved.count(Baz), 1U) << "Expected baz to not be resolved"; 658 EXPECT_TRUE(OnResolvedRun) << "OnResolved was never run"; 659 } 660 661 TEST(CoreAPIsTest, TestLookupWithUnthreadedMaterialization) { 662 constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef; 663 JITEvaluatedSymbol FooSym(FakeFooAddr, JITSymbolFlags::Exported); 664 665 ExecutionSession ES(std::make_shared<SymbolStringPool>()); 666 auto Foo = ES.getSymbolStringPool().intern("foo"); 667 668 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 669 SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}}), 670 [&](MaterializationResponsibility R) { 671 R.resolve({{Foo, FooSym}}); 672 R.finalize(); 673 }); 674 675 auto &V = ES.createVSO("V"); 676 677 cantFail(V.define(MU)); 678 679 auto FooLookupResult = cantFail(lookup({&V}, Foo)); 680 681 EXPECT_EQ(FooLookupResult.getAddress(), FooSym.getAddress()) 682 << "lookup returned an incorrect address"; 683 EXPECT_EQ(FooLookupResult.getFlags(), FooSym.getFlags()) 684 << "lookup returned incorrect flags"; 685 } 686 687 TEST(CoreAPIsTest, TestLookupWithThreadedMaterialization) { 688 #if LLVM_ENABLE_THREADS 689 constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef; 690 JITEvaluatedSymbol FooSym(FakeFooAddr, JITSymbolFlags::Exported); 691 692 ExecutionSession ES(std::make_shared<SymbolStringPool>()); 693 694 std::thread MaterializationThread; 695 ES.setDispatchMaterialization( 696 [&](VSO &V, std::unique_ptr<MaterializationUnit> MU) { 697 auto SharedMU = std::shared_ptr<MaterializationUnit>(std::move(MU)); 698 MaterializationThread = 699 std::thread([SharedMU, &V]() { SharedMU->doMaterialize(V); }); 700 }); 701 auto Foo = ES.getSymbolStringPool().intern("foo"); 702 703 auto &V = ES.createVSO("V"); 704 cantFail(V.define(absoluteSymbols({{Foo, FooSym}}))); 705 706 auto FooLookupResult = cantFail(lookup({&V}, Foo)); 707 708 EXPECT_EQ(FooLookupResult.getAddress(), FooSym.getAddress()) 709 << "lookup returned an incorrect address"; 710 EXPECT_EQ(FooLookupResult.getFlags(), FooSym.getFlags()) 711 << "lookup returned incorrect flags"; 712 MaterializationThread.join(); 713 #endif 714 } 715 716 TEST(CoreAPIsTest, TestGetRequestedSymbolsAndDelegate) { 717 ExecutionSession ES; 718 auto Foo = ES.getSymbolStringPool().intern("foo"); 719 auto Bar = ES.getSymbolStringPool().intern("bar"); 720 721 JITEvaluatedSymbol FooSym(0xdeadbeef, JITSymbolFlags::Exported); 722 JITEvaluatedSymbol BarSym(0xcafef00d, JITSymbolFlags::Exported); 723 724 SymbolNameSet Names({Foo, Bar}); 725 726 bool FooMaterialized = false; 727 bool BarMaterialized = false; 728 729 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 730 SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}), 731 [&](MaterializationResponsibility R) { 732 auto Requested = R.getRequestedSymbols(); 733 EXPECT_EQ(Requested.size(), 1U) << "Expected one symbol requested"; 734 EXPECT_EQ(*Requested.begin(), Foo) << "Expected \"Foo\" requested"; 735 736 auto NewMU = llvm::make_unique<SimpleMaterializationUnit>( 737 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 738 [&](MaterializationResponsibility R2) { 739 R2.resolve(SymbolMap({{Bar, BarSym}})); 740 R2.finalize(); 741 BarMaterialized = true; 742 }); 743 744 R.delegate(std::move(NewMU)); 745 746 R.resolve(SymbolMap({{Foo, FooSym}})); 747 R.finalize(); 748 749 FooMaterialized = true; 750 }); 751 752 auto &V = ES.createVSO("V"); 753 754 cantFail(V.define(MU)); 755 756 EXPECT_FALSE(FooMaterialized) << "Foo should not be materialized yet"; 757 EXPECT_FALSE(BarMaterialized) << "Bar should not be materialized yet"; 758 759 auto FooSymResult = cantFail(lookup({&V}, Foo)); 760 EXPECT_EQ(FooSymResult.getAddress(), FooSym.getAddress()) 761 << "Address mismatch for Foo"; 762 763 EXPECT_TRUE(FooMaterialized) << "Foo should be materialized now"; 764 EXPECT_FALSE(BarMaterialized) << "Bar still should not be materialized"; 765 766 auto BarSymResult = cantFail(lookup({&V}, Bar)); 767 EXPECT_EQ(BarSymResult.getAddress(), BarSym.getAddress()) 768 << "Address mismatch for Bar"; 769 EXPECT_TRUE(BarMaterialized) << "Bar should be materialized now"; 770 } 771 772 TEST(CoreAPIsTest, TestMaterializeWeakSymbol) { 773 // Confirm that once a weak definition is selected for materialization it is 774 // treated as strong. 775 776 constexpr JITTargetAddress FakeFooAddr = 0xdeadbeef; 777 JITSymbolFlags FooFlags = JITSymbolFlags::Exported; 778 FooFlags &= JITSymbolFlags::Weak; 779 auto FooSym = JITEvaluatedSymbol(FakeFooAddr, FooFlags); 780 781 ExecutionSession ES; 782 auto Foo = ES.getSymbolStringPool().intern("foo"); 783 784 auto &V = ES.createVSO("V"); 785 786 std::unique_ptr<MaterializationResponsibility> FooResponsibility; 787 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 788 SymbolFlagsMap({{Foo, FooFlags}}), [&](MaterializationResponsibility R) { 789 FooResponsibility = 790 llvm::make_unique<MaterializationResponsibility>(std::move(R)); 791 }); 792 793 cantFail(V.define(MU)); 794 auto Q = std::make_shared<AsynchronousSymbolQuery>( 795 SymbolNameSet({Foo}), 796 [](Expected<AsynchronousSymbolQuery::ResolutionResult> R) { 797 cantFail(std::move(R)); 798 }, 799 [](Error Err) { cantFail(std::move(Err)); }); 800 V.lookup(std::move(Q), SymbolNameSet({Foo})); 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 = V.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->finalize(); 816 } 817 818 } // namespace 819