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