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