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(std::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 cantFail(FooMR->notifyResolved({{Foo, FooSym}})); 52 53 EXPECT_FALSE(OnCompletionRun) << "Should not be ready yet"; 54 55 cantFail(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(std::make_unique<SimpleMaterializationUnit>( 109 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 110 [this](MaterializationResponsibility R) { 111 ADD_FAILURE() << "Unexpected materialization of \"Bar\""; 112 cantFail(R.notifyResolved({{Bar, BarSym}})); 113 cantFail(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(std::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 cantFail(BazR->notifyResolved({{Baz, BazSym}})); 160 cantFail(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 = std::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(std::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 = std::make_unique<SimpleMaterializationUnit>( 318 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 319 [&](MaterializationResponsibility R) { 320 BarMaterialized = true; 321 cantFail(R.notifyResolved({{Bar, BarSym}})); 322 cantFail(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(std::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 = std::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->addDependenciesForAll({{&JD, SymbolNameSet({Foo})}}); 377 EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Succeeded()) 378 << "No symbols marked failed, but Foo failed to resolve"; 379 EXPECT_THAT_ERROR(FooR->notifyEmitted(), Succeeded()) 380 << "No symbols marked failed, but Foo failed to emit"; 381 382 EXPECT_TRUE(FooReady) 383 << "Self-dependency prevented symbol from being marked ready"; 384 } 385 386 TEST_F(CoreAPIsStandardTest, TestCircularDependenceInOneJITDylib) { 387 // Test that a circular symbol dependency between three symbols in a JITDylib 388 // does not prevent any symbol from becoming 'ready' once all symbols are 389 // emitted. 390 391 // Create three MaterializationResponsibility objects: one for each of Foo, 392 // Bar and Baz. These are optional because MaterializationResponsibility 393 // does not have a default constructor). 394 Optional<MaterializationResponsibility> FooR; 395 Optional<MaterializationResponsibility> BarR; 396 Optional<MaterializationResponsibility> BazR; 397 398 // Create a MaterializationUnit for each symbol that moves the 399 // MaterializationResponsibility into one of the locals above. 400 auto FooMU = std::make_unique<SimpleMaterializationUnit>( 401 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 402 [&](MaterializationResponsibility R) { FooR.emplace(std::move(R)); }); 403 404 auto BarMU = std::make_unique<SimpleMaterializationUnit>( 405 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 406 [&](MaterializationResponsibility R) { BarR.emplace(std::move(R)); }); 407 408 auto BazMU = std::make_unique<SimpleMaterializationUnit>( 409 SymbolFlagsMap({{Baz, BazSym.getFlags()}}), 410 [&](MaterializationResponsibility R) { BazR.emplace(std::move(R)); }); 411 412 // Define the symbols. 413 cantFail(JD.define(FooMU)); 414 cantFail(JD.define(BarMU)); 415 cantFail(JD.define(BazMU)); 416 417 // Query each of the symbols to trigger materialization. 418 bool FooResolved = false; 419 bool FooReady = false; 420 421 auto OnFooResolution = [&](Expected<SymbolMap> Result) { 422 cantFail(std::move(Result)); 423 FooResolved = true; 424 }; 425 426 auto OnFooReady = [&](Expected<SymbolMap> Result) { 427 cantFail(std::move(Result)); 428 FooReady = true; 429 }; 430 431 // Issue lookups for Foo. Use NoDependenciesToRegister: We're going to add 432 // the dependencies manually below. 433 ES.lookup(JITDylibSearchList({{&JD, false}}), {Foo}, SymbolState::Resolved, 434 std::move(OnFooResolution), NoDependenciesToRegister); 435 436 ES.lookup(JITDylibSearchList({{&JD, false}}), {Foo}, SymbolState::Ready, 437 std::move(OnFooReady), NoDependenciesToRegister); 438 439 bool BarResolved = false; 440 bool BarReady = false; 441 auto OnBarResolution = [&](Expected<SymbolMap> Result) { 442 cantFail(std::move(Result)); 443 BarResolved = true; 444 }; 445 446 auto OnBarReady = [&](Expected<SymbolMap> Result) { 447 cantFail(std::move(Result)); 448 BarReady = true; 449 }; 450 451 ES.lookup(JITDylibSearchList({{&JD, false}}), {Bar}, SymbolState::Resolved, 452 std::move(OnBarResolution), NoDependenciesToRegister); 453 454 ES.lookup(JITDylibSearchList({{&JD, false}}), {Bar}, SymbolState::Ready, 455 std::move(OnBarReady), NoDependenciesToRegister); 456 457 bool BazResolved = false; 458 bool BazReady = false; 459 460 auto OnBazResolution = [&](Expected<SymbolMap> Result) { 461 cantFail(std::move(Result)); 462 BazResolved = true; 463 }; 464 465 auto OnBazReady = [&](Expected<SymbolMap> Result) { 466 cantFail(std::move(Result)); 467 BazReady = true; 468 }; 469 470 ES.lookup(JITDylibSearchList({{&JD, false}}), {Baz}, SymbolState::Resolved, 471 std::move(OnBazResolution), NoDependenciesToRegister); 472 473 ES.lookup(JITDylibSearchList({{&JD, false}}), {Baz}, SymbolState::Ready, 474 std::move(OnBazReady), NoDependenciesToRegister); 475 476 // Add a circular dependency: Foo -> Bar, Bar -> Baz, Baz -> Foo. 477 FooR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}}); 478 BarR->addDependenciesForAll({{&JD, SymbolNameSet({Baz})}}); 479 BazR->addDependenciesForAll({{&JD, SymbolNameSet({Foo})}}); 480 481 // Add self-dependencies for good measure. This tests that the implementation 482 // of addDependencies filters these out. 483 FooR->addDependenciesForAll({{&JD, SymbolNameSet({Foo})}}); 484 BarR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}}); 485 BazR->addDependenciesForAll({{&JD, SymbolNameSet({Baz})}}); 486 487 // Check that nothing has been resolved yet. 488 EXPECT_FALSE(FooResolved) << "\"Foo\" should not be resolved yet"; 489 EXPECT_FALSE(BarResolved) << "\"Bar\" should not be resolved yet"; 490 EXPECT_FALSE(BazResolved) << "\"Baz\" should not be resolved yet"; 491 492 // Resolve the symbols (but do not emit them). 493 EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Succeeded()) 494 << "No symbols failed, but Foo failed to resolve"; 495 EXPECT_THAT_ERROR(BarR->notifyResolved({{Bar, BarSym}}), Succeeded()) 496 << "No symbols failed, but Bar failed to resolve"; 497 EXPECT_THAT_ERROR(BazR->notifyResolved({{Baz, BazSym}}), Succeeded()) 498 << "No symbols failed, but Baz failed to resolve"; 499 500 // Verify that the symbols have been resolved, but are not ready yet. 501 EXPECT_TRUE(FooResolved) << "\"Foo\" should be resolved now"; 502 EXPECT_TRUE(BarResolved) << "\"Bar\" should be resolved now"; 503 EXPECT_TRUE(BazResolved) << "\"Baz\" should be resolved now"; 504 505 EXPECT_FALSE(FooReady) << "\"Foo\" should not be ready yet"; 506 EXPECT_FALSE(BarReady) << "\"Bar\" should not be ready yet"; 507 EXPECT_FALSE(BazReady) << "\"Baz\" should not be ready yet"; 508 509 // Emit two of the symbols. 510 EXPECT_THAT_ERROR(FooR->notifyEmitted(), Succeeded()) 511 << "No symbols failed, but Foo failed to emit"; 512 EXPECT_THAT_ERROR(BarR->notifyEmitted(), Succeeded()) 513 << "No symbols failed, but Bar failed to emit"; 514 515 // Verify that nothing is ready until the circular dependence is resolved. 516 EXPECT_FALSE(FooReady) << "\"Foo\" still should not be ready"; 517 EXPECT_FALSE(BarReady) << "\"Bar\" still should not be ready"; 518 EXPECT_FALSE(BazReady) << "\"Baz\" still should not be ready"; 519 520 // Emit the last symbol. 521 EXPECT_THAT_ERROR(BazR->notifyEmitted(), Succeeded()) 522 << "No symbols failed, but Baz failed to emit"; 523 524 // Verify that everything becomes ready once the circular dependence resolved. 525 EXPECT_TRUE(FooReady) << "\"Foo\" should be ready now"; 526 EXPECT_TRUE(BarReady) << "\"Bar\" should be ready now"; 527 EXPECT_TRUE(BazReady) << "\"Baz\" should be ready now"; 528 } 529 530 TEST_F(CoreAPIsStandardTest, FailureInDependency) { 531 Optional<MaterializationResponsibility> FooR; 532 Optional<MaterializationResponsibility> BarR; 533 534 // Create a MaterializationUnit for each symbol that moves the 535 // MaterializationResponsibility into one of the locals above. 536 auto FooMU = std::make_unique<SimpleMaterializationUnit>( 537 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 538 [&](MaterializationResponsibility R) { FooR.emplace(std::move(R)); }); 539 540 auto BarMU = std::make_unique<SimpleMaterializationUnit>( 541 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 542 [&](MaterializationResponsibility R) { BarR.emplace(std::move(R)); }); 543 544 // Define the symbols. 545 cantFail(JD.define(FooMU)); 546 cantFail(JD.define(BarMU)); 547 548 bool OnFooReadyRun = false; 549 auto OnFooReady = [&](Expected<SymbolMap> Result) { 550 EXPECT_THAT_EXPECTED(std::move(Result), Failed()); 551 OnFooReadyRun = true; 552 }; 553 554 ES.lookup(JITDylibSearchList({{&JD, false}}), {Foo}, SymbolState::Ready, 555 std::move(OnFooReady), NoDependenciesToRegister); 556 557 bool OnBarReadyRun = false; 558 auto OnBarReady = [&](Expected<SymbolMap> Result) { 559 EXPECT_THAT_EXPECTED(std::move(Result), Failed()); 560 OnBarReadyRun = true; 561 }; 562 563 ES.lookup(JITDylibSearchList({{&JD, false}}), {Bar}, SymbolState::Ready, 564 std::move(OnBarReady), NoDependenciesToRegister); 565 566 // Add a dependency by Foo on Bar. 567 FooR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}}); 568 569 // Fail bar. 570 BarR->failMaterialization(); 571 572 // Verify that queries on Bar failed, but queries on Foo have not yet. 573 EXPECT_TRUE(OnBarReadyRun) << "Query for \"Bar\" was not run"; 574 EXPECT_FALSE(OnFooReadyRun) << "Query for \"Foo\" was run unexpectedly"; 575 576 // Check that we can still resolve Foo (even though it has been failed). 577 EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Failed()) 578 << "Expected resolution for \"Foo\" to fail."; 579 580 FooR->failMaterialization(); 581 582 // Verify that queries on Foo have now failed. 583 EXPECT_TRUE(OnFooReadyRun) << "Query for \"Foo\" was not run"; 584 585 // Verify that subsequent lookups on Bar and Foo fail. 586 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Bar}), Failed()) 587 << "Lookup on failed symbol should fail"; 588 589 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Foo}), Failed()) 590 << "Lookup on failed symbol should fail"; 591 } 592 593 TEST_F(CoreAPIsStandardTest, FailureInCircularDependency) { 594 Optional<MaterializationResponsibility> FooR; 595 Optional<MaterializationResponsibility> BarR; 596 597 // Create a MaterializationUnit for each symbol that moves the 598 // MaterializationResponsibility into one of the locals above. 599 auto FooMU = std::make_unique<SimpleMaterializationUnit>( 600 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 601 [&](MaterializationResponsibility R) { FooR.emplace(std::move(R)); }); 602 603 auto BarMU = std::make_unique<SimpleMaterializationUnit>( 604 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 605 [&](MaterializationResponsibility R) { BarR.emplace(std::move(R)); }); 606 607 // Define the symbols. 608 cantFail(JD.define(FooMU)); 609 cantFail(JD.define(BarMU)); 610 611 bool OnFooReadyRun = false; 612 auto OnFooReady = [&](Expected<SymbolMap> Result) { 613 EXPECT_THAT_EXPECTED(std::move(Result), Failed()); 614 OnFooReadyRun = true; 615 }; 616 617 ES.lookup(JITDylibSearchList({{&JD, false}}), {Foo}, SymbolState::Ready, 618 std::move(OnFooReady), NoDependenciesToRegister); 619 620 bool OnBarReadyRun = false; 621 auto OnBarReady = [&](Expected<SymbolMap> Result) { 622 EXPECT_THAT_EXPECTED(std::move(Result), Failed()); 623 OnBarReadyRun = true; 624 }; 625 626 ES.lookup(JITDylibSearchList({{&JD, false}}), {Bar}, SymbolState::Ready, 627 std::move(OnBarReady), NoDependenciesToRegister); 628 629 // Add a dependency by Foo on Bar and vice-versa. 630 FooR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}}); 631 BarR->addDependenciesForAll({{&JD, SymbolNameSet({Foo})}}); 632 633 // Fail bar. 634 BarR->failMaterialization(); 635 636 // Verify that queries on Bar failed, but queries on Foo have not yet. 637 EXPECT_TRUE(OnBarReadyRun) << "Query for \"Bar\" was not run"; 638 EXPECT_FALSE(OnFooReadyRun) << "Query for \"Foo\" was run unexpectedly"; 639 640 // Verify that trying to resolve Foo fails. 641 EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Failed()) 642 << "Expected resolution for \"Foo\" to fail."; 643 644 FooR->failMaterialization(); 645 646 // Verify that queries on Foo have now failed. 647 EXPECT_TRUE(OnFooReadyRun) << "Query for \"Foo\" was not run"; 648 649 // Verify that subsequent lookups on Bar and Foo fail. 650 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Bar}), Failed()) 651 << "Lookup on failed symbol should fail"; 652 653 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Foo}), Failed()) 654 << "Lookup on failed symbol should fail"; 655 } 656 657 TEST_F(CoreAPIsStandardTest, AddDependencyOnFailedSymbol) { 658 Optional<MaterializationResponsibility> FooR; 659 Optional<MaterializationResponsibility> BarR; 660 661 // Create a MaterializationUnit for each symbol that moves the 662 // MaterializationResponsibility into one of the locals above. 663 auto FooMU = std::make_unique<SimpleMaterializationUnit>( 664 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 665 [&](MaterializationResponsibility R) { FooR.emplace(std::move(R)); }); 666 667 auto BarMU = std::make_unique<SimpleMaterializationUnit>( 668 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 669 [&](MaterializationResponsibility R) { BarR.emplace(std::move(R)); }); 670 671 // Define the symbols. 672 cantFail(JD.define(FooMU)); 673 cantFail(JD.define(BarMU)); 674 675 bool OnFooReadyRun = false; 676 auto OnFooReady = [&](Expected<SymbolMap> Result) { 677 EXPECT_THAT_EXPECTED(std::move(Result), Failed()); 678 OnFooReadyRun = true; 679 }; 680 681 ES.lookup(JITDylibSearchList({{&JD, false}}), {Foo}, SymbolState::Ready, 682 std::move(OnFooReady), NoDependenciesToRegister); 683 684 bool OnBarReadyRun = false; 685 auto OnBarReady = [&](Expected<SymbolMap> Result) { 686 EXPECT_THAT_EXPECTED(std::move(Result), Failed()); 687 OnBarReadyRun = true; 688 }; 689 690 ES.lookup(JITDylibSearchList({{&JD, false}}), {Bar}, SymbolState::Ready, 691 std::move(OnBarReady), NoDependenciesToRegister); 692 693 // Fail bar. 694 BarR->failMaterialization(); 695 696 // We expect Bar's query to fail immediately, but Foo's query not to have run 697 // yet. 698 EXPECT_TRUE(OnBarReadyRun) << "Query for \"Bar\" was not run"; 699 EXPECT_FALSE(OnFooReadyRun) << "Query for \"Foo\" should not have run yet"; 700 701 // Add dependency of Foo on Bar. 702 FooR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}}); 703 704 // Check that we can still resolve Foo (even though it has been failed). 705 EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Failed()) 706 << "Expected resolution for \"Foo\" to fail."; 707 708 FooR->failMaterialization(); 709 710 // Foo's query should have failed before we return from addDependencies. 711 EXPECT_TRUE(OnFooReadyRun) << "Query for \"Foo\" was not run"; 712 713 // Verify that subsequent lookups on Bar and Foo fail. 714 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Bar}), Failed()) 715 << "Lookup on failed symbol should fail"; 716 717 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Foo}), Failed()) 718 << "Lookup on failed symbol should fail"; 719 } 720 721 TEST_F(CoreAPIsStandardTest, FailAfterMaterialization) { 722 Optional<MaterializationResponsibility> FooR; 723 Optional<MaterializationResponsibility> BarR; 724 725 // Create a MaterializationUnit for each symbol that moves the 726 // MaterializationResponsibility into one of the locals above. 727 auto FooMU = std::make_unique<SimpleMaterializationUnit>( 728 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 729 [&](MaterializationResponsibility R) { FooR.emplace(std::move(R)); }); 730 731 auto BarMU = std::make_unique<SimpleMaterializationUnit>( 732 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 733 [&](MaterializationResponsibility R) { BarR.emplace(std::move(R)); }); 734 735 // Define the symbols. 736 cantFail(JD.define(FooMU)); 737 cantFail(JD.define(BarMU)); 738 739 bool OnFooReadyRun = false; 740 auto OnFooReady = [&](Expected<SymbolMap> Result) { 741 EXPECT_THAT_EXPECTED(std::move(Result), Failed()); 742 OnFooReadyRun = true; 743 }; 744 745 ES.lookup(JITDylibSearchList({{&JD, false}}), {Foo}, SymbolState::Ready, 746 std::move(OnFooReady), NoDependenciesToRegister); 747 748 bool OnBarReadyRun = false; 749 auto OnBarReady = [&](Expected<SymbolMap> Result) { 750 EXPECT_THAT_EXPECTED(std::move(Result), Failed()); 751 OnBarReadyRun = true; 752 }; 753 754 ES.lookup(JITDylibSearchList({{&JD, false}}), {Bar}, SymbolState::Ready, 755 std::move(OnBarReady), NoDependenciesToRegister); 756 757 // Add a dependency by Foo on Bar and vice-versa. 758 FooR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}}); 759 BarR->addDependenciesForAll({{&JD, SymbolNameSet({Foo})}}); 760 761 // Materialize Foo. 762 EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Succeeded()) 763 << "Expected resolution for \"Foo\" to succeed."; 764 EXPECT_THAT_ERROR(FooR->notifyEmitted(), Succeeded()) 765 << "Expected emission for \"Foo\" to succeed."; 766 767 // Fail bar. 768 BarR->failMaterialization(); 769 770 // Verify that both queries failed. 771 EXPECT_TRUE(OnFooReadyRun) << "Query for Foo did not run"; 772 EXPECT_TRUE(OnBarReadyRun) << "Query for Bar did not run"; 773 } 774 775 TEST_F(CoreAPIsStandardTest, FailMaterializerWithUnqueriedSymbols) { 776 // Make sure that symbols with no queries aganist them still 777 // fail correctly. 778 779 bool MaterializerRun = false; 780 auto MU = std::make_unique<SimpleMaterializationUnit>( 781 SymbolFlagsMap( 782 {{Foo, JITSymbolFlags::Exported}, {Bar, JITSymbolFlags::Exported}}), 783 [&](MaterializationResponsibility R) { 784 MaterializerRun = true; 785 R.failMaterialization(); 786 }); 787 788 cantFail(JD.define(std::move(MU))); 789 790 // Issue a query for Foo, but not bar. 791 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Foo}), Failed()) 792 << "Expected lookup to fail."; 793 794 // Check that the materializer (and therefore failMaterialization) ran. 795 EXPECT_TRUE(MaterializerRun) << "Expected materializer to have run by now"; 796 797 // Check that subsequent queries against both symbols fail. 798 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Foo}), Failed()) 799 << "Expected lookup for Foo to fail."; 800 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Bar}), Failed()) 801 << "Expected lookup for Bar to fail."; 802 } 803 804 TEST_F(CoreAPIsStandardTest, DropMaterializerWhenEmpty) { 805 bool DestructorRun = false; 806 807 JITSymbolFlags WeakExported(JITSymbolFlags::Exported); 808 WeakExported |= JITSymbolFlags::Weak; 809 810 auto MU = std::make_unique<SimpleMaterializationUnit>( 811 SymbolFlagsMap({{Foo, WeakExported}, {Bar, WeakExported}}), 812 [](MaterializationResponsibility R) { 813 llvm_unreachable("Unexpected call to materialize"); 814 }, 815 [&](const JITDylib &JD, SymbolStringPtr Name) { 816 EXPECT_TRUE(Name == Foo || Name == Bar) 817 << "Discard of unexpected symbol?"; 818 }, 819 [&]() { DestructorRun = true; }); 820 821 cantFail(JD.define(MU)); 822 823 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 824 825 EXPECT_FALSE(DestructorRun) 826 << "MaterializationUnit should not have been destroyed yet"; 827 828 cantFail(JD.define(absoluteSymbols({{Bar, BarSym}}))); 829 830 EXPECT_TRUE(DestructorRun) 831 << "MaterializationUnit should have been destroyed"; 832 } 833 834 TEST_F(CoreAPIsStandardTest, AddAndMaterializeLazySymbol) { 835 bool FooMaterialized = false; 836 bool BarDiscarded = false; 837 838 JITSymbolFlags WeakExported(JITSymbolFlags::Exported); 839 WeakExported |= JITSymbolFlags::Weak; 840 841 auto MU = std::make_unique<SimpleMaterializationUnit>( 842 SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}, {Bar, WeakExported}}), 843 [&](MaterializationResponsibility R) { 844 assert(BarDiscarded && "Bar should have been discarded by this point"); 845 cantFail(R.notifyResolved(SymbolMap({{Foo, FooSym}}))); 846 cantFail(R.notifyEmitted()); 847 FooMaterialized = true; 848 }, 849 [&](const JITDylib &JD, SymbolStringPtr Name) { 850 EXPECT_EQ(Name, Bar) << "Expected Name to be Bar"; 851 BarDiscarded = true; 852 }); 853 854 cantFail(JD.define(MU)); 855 cantFail(JD.define(absoluteSymbols({{Bar, BarSym}}))); 856 857 SymbolNameSet Names({Foo}); 858 859 bool OnCompletionRun = false; 860 861 auto OnCompletion = [&](Expected<SymbolMap> Result) { 862 EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error"; 863 auto I = Result->find(Foo); 864 EXPECT_NE(I, Result->end()) << "Could not find symbol definition"; 865 EXPECT_EQ(I->second.getAddress(), FooSym.getAddress()) 866 << "Resolution returned incorrect result"; 867 OnCompletionRun = true; 868 }; 869 870 ES.lookup(JITDylibSearchList({{&JD, false}}), Names, SymbolState::Ready, 871 std::move(OnCompletion), NoDependenciesToRegister); 872 873 EXPECT_TRUE(FooMaterialized) << "Foo was not materialized"; 874 EXPECT_TRUE(BarDiscarded) << "Bar was not discarded"; 875 EXPECT_TRUE(OnCompletionRun) << "OnResolutionCallback was not run"; 876 } 877 878 TEST_F(CoreAPIsStandardTest, TestBasicWeakSymbolMaterialization) { 879 // Test that weak symbols are materialized correctly when we look them up. 880 BarSym.setFlags(BarSym.getFlags() | JITSymbolFlags::Weak); 881 882 bool BarMaterialized = false; 883 auto MU1 = std::make_unique<SimpleMaterializationUnit>( 884 SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}), 885 [&](MaterializationResponsibility R) { 886 cantFail(R.notifyResolved(SymbolMap({{Foo, FooSym}, {Bar, BarSym}}))); 887 cantFail(R.notifyEmitted()); 888 BarMaterialized = true; 889 }); 890 891 bool DuplicateBarDiscarded = false; 892 auto MU2 = std::make_unique<SimpleMaterializationUnit>( 893 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 894 [&](MaterializationResponsibility R) { 895 ADD_FAILURE() << "Attempt to materialize Bar from the wrong unit"; 896 R.failMaterialization(); 897 }, 898 [&](const JITDylib &JD, SymbolStringPtr Name) { 899 EXPECT_EQ(Name, Bar) << "Expected \"Bar\" to be discarded"; 900 DuplicateBarDiscarded = true; 901 }); 902 903 cantFail(JD.define(MU1)); 904 cantFail(JD.define(MU2)); 905 906 bool OnCompletionRun = false; 907 908 auto OnCompletion = [&](Expected<SymbolMap> Result) { 909 cantFail(std::move(Result)); 910 OnCompletionRun = true; 911 }; 912 913 ES.lookup(JITDylibSearchList({{&JD, false}}), {Bar}, SymbolState::Ready, 914 std::move(OnCompletion), NoDependenciesToRegister); 915 916 EXPECT_TRUE(OnCompletionRun) << "OnCompletion not run"; 917 EXPECT_TRUE(BarMaterialized) << "Bar was not materialized at all"; 918 EXPECT_TRUE(DuplicateBarDiscarded) 919 << "Duplicate bar definition not discarded"; 920 } 921 922 TEST_F(CoreAPIsStandardTest, DefineMaterializingSymbol) { 923 bool ExpectNoMoreMaterialization = false; 924 ES.setDispatchMaterialization( 925 [&](JITDylib &JD, std::unique_ptr<MaterializationUnit> MU) { 926 if (ExpectNoMoreMaterialization) 927 ADD_FAILURE() << "Unexpected materialization"; 928 MU->doMaterialize(JD); 929 }); 930 931 auto MU = std::make_unique<SimpleMaterializationUnit>( 932 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 933 [&](MaterializationResponsibility R) { 934 cantFail( 935 R.defineMaterializing(SymbolFlagsMap({{Bar, BarSym.getFlags()}}))); 936 cantFail(R.notifyResolved(SymbolMap({{Foo, FooSym}, {Bar, BarSym}}))); 937 cantFail(R.notifyEmitted()); 938 }); 939 940 cantFail(JD.define(MU)); 941 cantFail(ES.lookup(JITDylibSearchList({{&JD, false}}), Foo)); 942 943 // Assert that materialization is complete by now. 944 ExpectNoMoreMaterialization = true; 945 946 // Look up bar to verify that no further materialization happens. 947 auto BarResult = cantFail(ES.lookup(JITDylibSearchList({{&JD, false}}), Bar)); 948 EXPECT_EQ(BarResult.getAddress(), BarSym.getAddress()) 949 << "Expected Bar == BarSym"; 950 } 951 952 TEST_F(CoreAPIsStandardTest, GeneratorTest) { 953 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 954 955 class TestGenerator : public JITDylib::DefinitionGenerator { 956 public: 957 TestGenerator(SymbolMap Symbols) : Symbols(std::move(Symbols)) {} 958 Expected<SymbolNameSet> tryToGenerate(JITDylib &JD, 959 const SymbolNameSet &Names) { 960 SymbolMap NewDefs; 961 SymbolNameSet NewNames; 962 963 for (auto &Name : Names) { 964 if (Symbols.count(Name)) { 965 NewDefs[Name] = Symbols[Name]; 966 NewNames.insert(Name); 967 } 968 } 969 cantFail(JD.define(absoluteSymbols(std::move(NewDefs)))); 970 return NewNames; 971 }; 972 973 private: 974 SymbolMap Symbols; 975 }; 976 977 JD.addGenerator(std::make_unique<TestGenerator>(SymbolMap({{Bar, BarSym}}))); 978 979 auto Result = 980 cantFail(ES.lookup(JITDylibSearchList({{&JD, false}}), {Foo, Bar})); 981 982 EXPECT_EQ(Result.count(Bar), 1U) << "Expected to find fallback def for 'bar'"; 983 EXPECT_EQ(Result[Bar].getAddress(), BarSym.getAddress()) 984 << "Expected fallback def for Bar to be equal to BarSym"; 985 } 986 987 TEST_F(CoreAPIsStandardTest, FailResolution) { 988 auto MU = std::make_unique<SimpleMaterializationUnit>( 989 SymbolFlagsMap({{Foo, JITSymbolFlags::Exported | JITSymbolFlags::Weak}, 990 {Bar, JITSymbolFlags::Exported | JITSymbolFlags::Weak}}), 991 [&](MaterializationResponsibility R) { 992 R.failMaterialization(); 993 }); 994 995 cantFail(JD.define(MU)); 996 997 SymbolNameSet Names({Foo, Bar}); 998 auto Result = ES.lookup(JITDylibSearchList({{&JD, false}}), Names); 999 1000 EXPECT_FALSE(!!Result) << "Expected failure"; 1001 if (!Result) { 1002 handleAllErrors( 1003 Result.takeError(), 1004 [&](FailedToMaterialize &F) { 1005 EXPECT_TRUE(F.getSymbols().count(&JD)) 1006 << "Expected to fail on JITDylib JD"; 1007 EXPECT_EQ(F.getSymbols().find(&JD)->second, Names) 1008 << "Expected to fail on symbols in Names"; 1009 }, 1010 [](ErrorInfoBase &EIB) { 1011 std::string ErrMsg; 1012 { 1013 raw_string_ostream ErrOut(ErrMsg); 1014 EIB.log(ErrOut); 1015 } 1016 ADD_FAILURE() << "Expected a FailedToResolve error. Got:\n" << ErrMsg; 1017 }); 1018 } 1019 } 1020 1021 TEST_F(CoreAPIsStandardTest, FailEmissionAfterResolution) { 1022 1023 cantFail(JD.define(absoluteSymbols({{Baz, BazSym}}))); 1024 1025 auto MU = std::make_unique<SimpleMaterializationUnit>( 1026 SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}), 1027 [&](MaterializationResponsibility R) { 1028 cantFail(R.notifyResolved(SymbolMap({{Foo, FooSym}, {Bar, BarSym}}))); 1029 1030 ES.lookup( 1031 JITDylibSearchList({{&JD, false}}), SymbolNameSet({Baz}), 1032 SymbolState::Resolved, 1033 [&R](Expected<SymbolMap> Result) { 1034 // Called when "baz" is resolved. We don't actually depend 1035 // on or care about baz, but use it to trigger failure of 1036 // this materialization before Baz has been finalized in 1037 // order to test that error propagation is correct in this 1038 // scenario. 1039 cantFail(std::move(Result)); 1040 R.failMaterialization(); 1041 }, 1042 [&](const SymbolDependenceMap &Deps) { 1043 R.addDependenciesForAll(Deps); 1044 }); 1045 }); 1046 1047 cantFail(JD.define(MU)); 1048 1049 SymbolNameSet Names({Foo, Bar}); 1050 auto Result = ES.lookup(JITDylibSearchList({{&JD, false}}), Names); 1051 1052 EXPECT_THAT_EXPECTED(std::move(Result), Failed()) 1053 << "Unexpected success while trying to test error propagation"; 1054 } 1055 1056 TEST_F(CoreAPIsStandardTest, FailAfterPartialResolution) { 1057 1058 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 1059 1060 // Fail materialization of bar. 1061 auto BarMU = std::make_unique<SimpleMaterializationUnit>( 1062 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 1063 [&](MaterializationResponsibility R) { R.failMaterialization(); }); 1064 1065 cantFail(JD.define(std::move(BarMU))); 1066 1067 bool QueryHandlerRun = false; 1068 ES.lookup( 1069 JITDylibSearchList({{&JD, false}}), SymbolNameSet({Foo, Bar}), 1070 SymbolState::Resolved, 1071 [&](Expected<SymbolMap> Result) { 1072 EXPECT_THAT_EXPECTED(std::move(Result), Failed()) 1073 << "Expected query to fail"; 1074 QueryHandlerRun = true; 1075 }, 1076 NoDependenciesToRegister); 1077 EXPECT_TRUE(QueryHandlerRun) << "Query handler never ran"; 1078 } 1079 1080 TEST_F(CoreAPIsStandardTest, TestLookupWithUnthreadedMaterialization) { 1081 auto MU = std::make_unique<SimpleMaterializationUnit>( 1082 SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}}), 1083 [&](MaterializationResponsibility R) { 1084 cantFail(R.notifyResolved({{Foo, FooSym}})); 1085 cantFail(R.notifyEmitted()); 1086 }); 1087 1088 cantFail(JD.define(MU)); 1089 1090 auto FooLookupResult = 1091 cantFail(ES.lookup(JITDylibSearchList({{&JD, false}}), Foo)); 1092 1093 EXPECT_EQ(FooLookupResult.getAddress(), FooSym.getAddress()) 1094 << "lookup returned an incorrect address"; 1095 EXPECT_EQ(FooLookupResult.getFlags(), FooSym.getFlags()) 1096 << "lookup returned incorrect flags"; 1097 } 1098 1099 TEST_F(CoreAPIsStandardTest, TestLookupWithThreadedMaterialization) { 1100 #if LLVM_ENABLE_THREADS 1101 1102 std::thread MaterializationThread; 1103 ES.setDispatchMaterialization( 1104 [&](JITDylib &JD, std::unique_ptr<MaterializationUnit> MU) { 1105 auto SharedMU = std::shared_ptr<MaterializationUnit>(std::move(MU)); 1106 MaterializationThread = 1107 std::thread([SharedMU, &JD]() { SharedMU->doMaterialize(JD); }); 1108 }); 1109 1110 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 1111 1112 auto FooLookupResult = 1113 cantFail(ES.lookup(JITDylibSearchList({{&JD, false}}), Foo)); 1114 1115 EXPECT_EQ(FooLookupResult.getAddress(), FooSym.getAddress()) 1116 << "lookup returned an incorrect address"; 1117 EXPECT_EQ(FooLookupResult.getFlags(), FooSym.getFlags()) 1118 << "lookup returned incorrect flags"; 1119 MaterializationThread.join(); 1120 #endif 1121 } 1122 1123 TEST_F(CoreAPIsStandardTest, TestGetRequestedSymbolsAndReplace) { 1124 // Test that GetRequestedSymbols returns the set of symbols that currently 1125 // have pending queries, and test that MaterializationResponsibility's 1126 // replace method can be used to return definitions to the JITDylib in a new 1127 // MaterializationUnit. 1128 SymbolNameSet Names({Foo, Bar}); 1129 1130 bool FooMaterialized = false; 1131 bool BarMaterialized = false; 1132 1133 auto MU = std::make_unique<SimpleMaterializationUnit>( 1134 SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}), 1135 [&](MaterializationResponsibility R) { 1136 auto Requested = R.getRequestedSymbols(); 1137 EXPECT_EQ(Requested.size(), 1U) << "Expected one symbol requested"; 1138 EXPECT_EQ(*Requested.begin(), Foo) << "Expected \"Foo\" requested"; 1139 1140 auto NewMU = std::make_unique<SimpleMaterializationUnit>( 1141 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 1142 [&](MaterializationResponsibility R2) { 1143 cantFail(R2.notifyResolved(SymbolMap({{Bar, BarSym}}))); 1144 cantFail(R2.notifyEmitted()); 1145 BarMaterialized = true; 1146 }); 1147 1148 R.replace(std::move(NewMU)); 1149 1150 cantFail(R.notifyResolved(SymbolMap({{Foo, FooSym}}))); 1151 cantFail(R.notifyEmitted()); 1152 1153 FooMaterialized = true; 1154 }); 1155 1156 cantFail(JD.define(MU)); 1157 1158 EXPECT_FALSE(FooMaterialized) << "Foo should not be materialized yet"; 1159 EXPECT_FALSE(BarMaterialized) << "Bar should not be materialized yet"; 1160 1161 auto FooSymResult = 1162 cantFail(ES.lookup(JITDylibSearchList({{&JD, false}}), Foo)); 1163 EXPECT_EQ(FooSymResult.getAddress(), FooSym.getAddress()) 1164 << "Address mismatch for Foo"; 1165 1166 EXPECT_TRUE(FooMaterialized) << "Foo should be materialized now"; 1167 EXPECT_FALSE(BarMaterialized) << "Bar still should not be materialized"; 1168 1169 auto BarSymResult = 1170 cantFail(ES.lookup(JITDylibSearchList({{&JD, false}}), Bar)); 1171 EXPECT_EQ(BarSymResult.getAddress(), BarSym.getAddress()) 1172 << "Address mismatch for Bar"; 1173 EXPECT_TRUE(BarMaterialized) << "Bar should be materialized now"; 1174 } 1175 1176 TEST_F(CoreAPIsStandardTest, TestMaterializationResponsibilityDelegation) { 1177 auto MU = std::make_unique<SimpleMaterializationUnit>( 1178 SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}), 1179 [&](MaterializationResponsibility R) { 1180 auto R2 = R.delegate({Bar}); 1181 1182 cantFail(R.notifyResolved({{Foo, FooSym}})); 1183 cantFail(R.notifyEmitted()); 1184 cantFail(R2.notifyResolved({{Bar, BarSym}})); 1185 cantFail(R2.notifyEmitted()); 1186 }); 1187 1188 cantFail(JD.define(MU)); 1189 1190 auto Result = ES.lookup(JITDylibSearchList({{&JD, false}}), {Foo, Bar}); 1191 1192 EXPECT_TRUE(!!Result) << "Result should be a success value"; 1193 EXPECT_EQ(Result->count(Foo), 1U) << "\"Foo\" entry missing"; 1194 EXPECT_EQ(Result->count(Bar), 1U) << "\"Bar\" entry missing"; 1195 EXPECT_EQ((*Result)[Foo].getAddress(), FooSym.getAddress()) 1196 << "Address mismatch for \"Foo\""; 1197 EXPECT_EQ((*Result)[Bar].getAddress(), BarSym.getAddress()) 1198 << "Address mismatch for \"Bar\""; 1199 } 1200 1201 TEST_F(CoreAPIsStandardTest, TestMaterializeWeakSymbol) { 1202 // Confirm that once a weak definition is selected for materialization it is 1203 // treated as strong. 1204 JITSymbolFlags WeakExported = JITSymbolFlags::Exported; 1205 WeakExported &= JITSymbolFlags::Weak; 1206 1207 std::unique_ptr<MaterializationResponsibility> FooResponsibility; 1208 auto MU = std::make_unique<SimpleMaterializationUnit>( 1209 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 1210 [&](MaterializationResponsibility R) { 1211 FooResponsibility = 1212 std::make_unique<MaterializationResponsibility>(std::move(R)); 1213 }); 1214 1215 cantFail(JD.define(MU)); 1216 auto OnCompletion = [](Expected<SymbolMap> Result) { 1217 cantFail(std::move(Result)); 1218 }; 1219 1220 ES.lookup(JITDylibSearchList({{&JD, false}}), {Foo}, SymbolState::Ready, 1221 std::move(OnCompletion), NoDependenciesToRegister); 1222 1223 auto MU2 = std::make_unique<SimpleMaterializationUnit>( 1224 SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}}), 1225 [](MaterializationResponsibility R) { 1226 llvm_unreachable("This unit should never be materialized"); 1227 }); 1228 1229 auto Err = JD.define(MU2); 1230 EXPECT_TRUE(!!Err) << "Expected failure value"; 1231 EXPECT_TRUE(Err.isA<DuplicateDefinition>()) 1232 << "Expected a duplicate definition error"; 1233 consumeError(std::move(Err)); 1234 1235 // No dependencies registered, can't fail: 1236 cantFail(FooResponsibility->notifyResolved(SymbolMap({{Foo, FooSym}}))); 1237 cantFail(FooResponsibility->notifyEmitted()); 1238 } 1239 1240 } // namespace 1241