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(LookupKind::Static, makeJITDylibSearchOrder(&JD), 47 SymbolLookupSet(Foo), SymbolState::Ready, OnCompletion, 48 NoDependenciesToRegister); 49 50 EXPECT_FALSE(OnCompletionRun) << "Should not have been resolved yet"; 51 52 cantFail(FooMR->notifyResolved({{Foo, FooSym}})); 53 54 EXPECT_FALSE(OnCompletionRun) << "Should not be ready yet"; 55 56 cantFail(FooMR->notifyEmitted()); 57 58 EXPECT_TRUE(OnCompletionRun) << "Should have been marked ready"; 59 } 60 61 TEST_F(CoreAPIsStandardTest, ExecutionSessionFailQuery) { 62 bool OnCompletionRun = false; 63 64 auto OnCompletion = [&](Expected<SymbolMap> Result) { 65 EXPECT_FALSE(!!Result) << "Resolution unexpectedly returned success"; 66 auto Msg = toString(Result.takeError()); 67 EXPECT_EQ(Msg, "xyz") << "Resolution returned incorrect result"; 68 OnCompletionRun = true; 69 }; 70 71 AsynchronousSymbolQuery Q(SymbolLookupSet(Foo), SymbolState::Ready, 72 OnCompletion); 73 74 ES.legacyFailQuery(Q, 75 make_error<StringError>("xyz", inconvertibleErrorCode())); 76 77 EXPECT_TRUE(OnCompletionRun) << "OnCompletionCallback was not run"; 78 } 79 80 TEST_F(CoreAPIsStandardTest, EmptyLookup) { 81 bool OnCompletionRun = false; 82 83 auto OnCompletion = [&](Expected<SymbolMap> Result) { 84 cantFail(std::move(Result)); 85 OnCompletionRun = true; 86 }; 87 88 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), SymbolLookupSet(), 89 SymbolState::Ready, OnCompletion, NoDependenciesToRegister); 90 91 EXPECT_TRUE(OnCompletionRun) << "OnCompletion was not run for empty query"; 92 } 93 94 TEST_F(CoreAPIsStandardTest, RemoveSymbolsTest) { 95 // Test that: 96 // (1) Missing symbols generate a SymbolsNotFound error. 97 // (2) Materializing symbols generate a SymbolCouldNotBeRemoved error. 98 // (3) Removal of unmaterialized symbols triggers discard on the 99 // materialization unit. 100 // (4) Removal of symbols destroys empty materialization units. 101 // (5) Removal of materialized symbols works. 102 103 // Foo will be fully materialized. 104 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 105 106 // Bar will be unmaterialized. 107 bool BarDiscarded = false; 108 bool BarMaterializerDestructed = false; 109 cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>( 110 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 111 [this](MaterializationResponsibility R) { 112 ADD_FAILURE() << "Unexpected materialization of \"Bar\""; 113 cantFail(R.notifyResolved({{Bar, BarSym}})); 114 cantFail(R.notifyEmitted()); 115 }, 116 nullptr, 117 [&](const JITDylib &JD, const SymbolStringPtr &Name) { 118 EXPECT_EQ(Name, Bar) << "Expected \"Bar\" to be discarded"; 119 if (Name == Bar) 120 BarDiscarded = true; 121 }, 122 [&]() { BarMaterializerDestructed = true; }))); 123 124 // Baz will be in the materializing state initially, then 125 // materialized for the final removal attempt. 126 Optional<MaterializationResponsibility> BazR; 127 cantFail(JD.define(std::make_unique<SimpleMaterializationUnit>( 128 SymbolFlagsMap({{Baz, BazSym.getFlags()}}), 129 [&](MaterializationResponsibility R) { BazR.emplace(std::move(R)); }, 130 nullptr, 131 [](const JITDylib &JD, const SymbolStringPtr &Name) { 132 ADD_FAILURE() << "\"Baz\" discarded unexpectedly"; 133 }))); 134 135 bool OnCompletionRun = false; 136 ES.lookup( 137 LookupKind::Static, makeJITDylibSearchOrder(&JD), 138 SymbolLookupSet({Foo, Baz}), SymbolState::Ready, 139 [&](Expected<SymbolMap> Result) { 140 cantFail(Result.takeError()); 141 OnCompletionRun = true; 142 }, 143 NoDependenciesToRegister); 144 145 { 146 // Attempt 1: Search for a missing symbol, Qux. 147 auto Err = JD.remove({Foo, Bar, Baz, Qux}); 148 EXPECT_TRUE(!!Err) << "Expected failure"; 149 EXPECT_TRUE(Err.isA<SymbolsNotFound>()) 150 << "Expected a SymbolsNotFound error"; 151 consumeError(std::move(Err)); 152 } 153 154 { 155 // Attempt 2: Search for a symbol that is still materializing, Baz. 156 auto Err = JD.remove({Foo, Bar, Baz}); 157 EXPECT_TRUE(!!Err) << "Expected failure"; 158 EXPECT_TRUE(Err.isA<SymbolsCouldNotBeRemoved>()) 159 << "Expected a SymbolsNotFound error"; 160 consumeError(std::move(Err)); 161 } 162 163 cantFail(BazR->notifyResolved({{Baz, BazSym}})); 164 cantFail(BazR->notifyEmitted()); 165 { 166 // Attempt 3: Search now that all symbols are fully materialized 167 // (Foo, Baz), or not yet materialized (Bar). 168 auto Err = JD.remove({Foo, Bar, Baz}); 169 EXPECT_FALSE(!!Err) << "Expected failure"; 170 } 171 172 EXPECT_TRUE(BarDiscarded) << "\"Bar\" should have been discarded"; 173 EXPECT_TRUE(BarMaterializerDestructed) 174 << "\"Bar\"'s materializer should have been destructed"; 175 EXPECT_TRUE(OnCompletionRun) << "OnCompletion should have been run"; 176 } 177 178 TEST_F(CoreAPIsStandardTest, ChainedJITDylibLookup) { 179 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 180 181 auto &JD2 = ES.createBareJITDylib("JD2"); 182 183 bool OnCompletionRun = false; 184 185 auto Q = std::make_shared<AsynchronousSymbolQuery>( 186 SymbolLookupSet({Foo}), SymbolState::Ready, 187 [&](Expected<SymbolMap> Result) { 188 cantFail(std::move(Result)); 189 OnCompletionRun = true; 190 }); 191 192 cantFail(JD2.legacyLookup(Q, cantFail(JD.legacyLookup(Q, {Foo})))); 193 194 EXPECT_TRUE(OnCompletionRun) << "OnCompletion was not run for empty query"; 195 } 196 197 TEST_F(CoreAPIsStandardTest, LookupWithHiddenSymbols) { 198 auto BarHiddenFlags = BarSym.getFlags() & ~JITSymbolFlags::Exported; 199 auto BarHiddenSym = JITEvaluatedSymbol(BarSym.getAddress(), BarHiddenFlags); 200 201 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}, {Bar, BarHiddenSym}}))); 202 203 auto &JD2 = ES.createBareJITDylib("JD2"); 204 cantFail(JD2.define(absoluteSymbols({{Bar, QuxSym}}))); 205 206 /// Try a blocking lookup. 207 auto Result = cantFail(ES.lookup(makeJITDylibSearchOrder({&JD, &JD2}), 208 SymbolLookupSet({Foo, Bar}))); 209 210 EXPECT_EQ(Result.size(), 2U) << "Unexpected number of results"; 211 EXPECT_EQ(Result.count(Foo), 1U) << "Missing result for \"Foo\""; 212 EXPECT_EQ(Result.count(Bar), 1U) << "Missing result for \"Bar\""; 213 EXPECT_EQ(Result[Bar].getAddress(), QuxSym.getAddress()) 214 << "Wrong result for \"Bar\""; 215 } 216 217 TEST_F(CoreAPIsStandardTest, LookupFlagsTest) { 218 // Test that lookupFlags works on a predefined symbol, and does not trigger 219 // materialization of a lazy symbol. Make the lazy symbol weak to test that 220 // the weak flag is propagated correctly. 221 222 BarSym.setFlags(static_cast<JITSymbolFlags::FlagNames>( 223 JITSymbolFlags::Exported | JITSymbolFlags::Weak)); 224 auto MU = std::make_unique<SimpleMaterializationUnit>( 225 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 226 [](MaterializationResponsibility R) { 227 llvm_unreachable("Symbol materialized on flags lookup"); 228 }); 229 230 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 231 cantFail(JD.define(std::move(MU))); 232 233 auto SymbolFlags = cantFail(JD.lookupFlags( 234 LookupKind::Static, JITDylibLookupFlags::MatchExportedSymbolsOnly, 235 SymbolLookupSet({Foo, Bar, Baz}))); 236 237 EXPECT_EQ(SymbolFlags.size(), 2U) 238 << "Returned symbol flags contains unexpected results"; 239 EXPECT_EQ(SymbolFlags.count(Foo), 1U) << "Missing lookupFlags result for Foo"; 240 EXPECT_EQ(SymbolFlags[Foo], FooSym.getFlags()) 241 << "Incorrect flags returned for Foo"; 242 EXPECT_EQ(SymbolFlags.count(Bar), 1U) 243 << "Missing lookupFlags result for Bar"; 244 EXPECT_EQ(SymbolFlags[Bar], BarSym.getFlags()) 245 << "Incorrect flags returned for Bar"; 246 } 247 248 TEST_F(CoreAPIsStandardTest, LookupWithGeneratorFailure) { 249 250 class BadGenerator : public JITDylib::DefinitionGenerator { 251 public: 252 Error tryToGenerate(LookupKind K, JITDylib &, JITDylibLookupFlags, 253 const SymbolLookupSet &) override { 254 return make_error<StringError>("BadGenerator", inconvertibleErrorCode()); 255 } 256 }; 257 258 JD.addGenerator(std::make_unique<BadGenerator>()); 259 260 EXPECT_THAT_ERROR( 261 JD.lookupFlags(LookupKind::Static, 262 JITDylibLookupFlags::MatchExportedSymbolsOnly, 263 SymbolLookupSet(Foo)) 264 .takeError(), 265 Failed<StringError>()) 266 << "Generator failure did not propagate through lookupFlags"; 267 268 EXPECT_THAT_ERROR( 269 ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet(Foo)).takeError(), 270 Failed<StringError>()) 271 << "Generator failure did not propagate through lookup"; 272 } 273 274 TEST_F(CoreAPIsStandardTest, TestBasicAliases) { 275 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}, {Bar, BarSym}}))); 276 cantFail(JD.define(symbolAliases({{Baz, {Foo, JITSymbolFlags::Exported}}, 277 {Qux, {Bar, JITSymbolFlags::Weak}}}))); 278 cantFail(JD.define(absoluteSymbols({{Qux, QuxSym}}))); 279 280 auto Result = 281 ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Baz, Qux})); 282 EXPECT_TRUE(!!Result) << "Unexpected lookup failure"; 283 EXPECT_EQ(Result->count(Baz), 1U) << "No result for \"baz\""; 284 EXPECT_EQ(Result->count(Qux), 1U) << "No result for \"qux\""; 285 EXPECT_EQ((*Result)[Baz].getAddress(), FooSym.getAddress()) 286 << "\"Baz\"'s address should match \"Foo\"'s"; 287 EXPECT_EQ((*Result)[Qux].getAddress(), QuxSym.getAddress()) 288 << "The \"Qux\" alias should have been overriden"; 289 } 290 291 TEST_F(CoreAPIsStandardTest, TestChainedAliases) { 292 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 293 cantFail(JD.define(symbolAliases( 294 {{Baz, {Bar, BazSym.getFlags()}}, {Bar, {Foo, BarSym.getFlags()}}}))); 295 296 auto Result = 297 ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Bar, Baz})); 298 EXPECT_TRUE(!!Result) << "Unexpected lookup failure"; 299 EXPECT_EQ(Result->count(Bar), 1U) << "No result for \"bar\""; 300 EXPECT_EQ(Result->count(Baz), 1U) << "No result for \"baz\""; 301 EXPECT_EQ((*Result)[Bar].getAddress(), FooSym.getAddress()) 302 << "\"Bar\"'s address should match \"Foo\"'s"; 303 EXPECT_EQ((*Result)[Baz].getAddress(), FooSym.getAddress()) 304 << "\"Baz\"'s address should match \"Foo\"'s"; 305 } 306 307 TEST_F(CoreAPIsStandardTest, TestBasicReExports) { 308 // Test that the basic use case of re-exporting a single symbol from another 309 // JITDylib works. 310 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 311 312 auto &JD2 = ES.createBareJITDylib("JD2"); 313 314 cantFail(JD2.define(reexports(JD, {{Bar, {Foo, BarSym.getFlags()}}}))); 315 316 auto Result = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD2), Bar)); 317 EXPECT_EQ(Result.getAddress(), FooSym.getAddress()) 318 << "Re-export Bar for symbol Foo should match FooSym's address"; 319 } 320 321 TEST_F(CoreAPIsStandardTest, TestThatReExportsDontUnnecessarilyMaterialize) { 322 // Test that re-exports do not materialize symbols that have not been queried 323 // for. 324 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 325 326 bool BarMaterialized = false; 327 auto BarMU = std::make_unique<SimpleMaterializationUnit>( 328 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 329 [&](MaterializationResponsibility R) { 330 BarMaterialized = true; 331 cantFail(R.notifyResolved({{Bar, BarSym}})); 332 cantFail(R.notifyEmitted()); 333 }); 334 335 cantFail(JD.define(BarMU)); 336 337 auto &JD2 = ES.createBareJITDylib("JD2"); 338 339 cantFail(JD2.define(reexports( 340 JD, {{Baz, {Foo, BazSym.getFlags()}}, {Qux, {Bar, QuxSym.getFlags()}}}))); 341 342 auto Result = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD2), Baz)); 343 EXPECT_EQ(Result.getAddress(), FooSym.getAddress()) 344 << "Re-export Baz for symbol Foo should match FooSym's address"; 345 346 EXPECT_FALSE(BarMaterialized) << "Bar should not have been materialized"; 347 } 348 349 TEST_F(CoreAPIsStandardTest, TestReexportsGenerator) { 350 // Test that a re-exports generator can dynamically generate reexports. 351 352 auto &JD2 = ES.createBareJITDylib("JD2"); 353 cantFail(JD2.define(absoluteSymbols({{Foo, FooSym}, {Bar, BarSym}}))); 354 355 auto Filter = [this](SymbolStringPtr Name) { return Name != Bar; }; 356 357 JD.addGenerator(std::make_unique<ReexportsGenerator>( 358 JD2, JITDylibLookupFlags::MatchExportedSymbolsOnly, Filter)); 359 360 auto Flags = cantFail(JD.lookupFlags( 361 LookupKind::Static, JITDylibLookupFlags::MatchExportedSymbolsOnly, 362 SymbolLookupSet({Foo, Bar, Baz}))); 363 EXPECT_EQ(Flags.size(), 1U) << "Unexpected number of results"; 364 EXPECT_EQ(Flags[Foo], FooSym.getFlags()) << "Unexpected flags for Foo"; 365 366 auto Result = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Foo)); 367 368 EXPECT_EQ(Result.getAddress(), FooSym.getAddress()) 369 << "Incorrect reexported symbol address"; 370 } 371 372 TEST_F(CoreAPIsStandardTest, TestTrivialCircularDependency) { 373 Optional<MaterializationResponsibility> FooR; 374 auto FooMU = std::make_unique<SimpleMaterializationUnit>( 375 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 376 [&](MaterializationResponsibility R) { FooR.emplace(std::move(R)); }); 377 378 cantFail(JD.define(FooMU)); 379 380 bool FooReady = false; 381 auto OnCompletion = [&](Expected<SymbolMap> Result) { 382 cantFail(std::move(Result)); 383 FooReady = true; 384 }; 385 386 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 387 SymbolLookupSet({Foo}), SymbolState::Ready, OnCompletion, 388 NoDependenciesToRegister); 389 390 FooR->addDependenciesForAll({{&JD, SymbolNameSet({Foo})}}); 391 EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Succeeded()) 392 << "No symbols marked failed, but Foo failed to resolve"; 393 EXPECT_THAT_ERROR(FooR->notifyEmitted(), Succeeded()) 394 << "No symbols marked failed, but Foo failed to emit"; 395 396 EXPECT_TRUE(FooReady) 397 << "Self-dependency prevented symbol from being marked ready"; 398 } 399 400 TEST_F(CoreAPIsStandardTest, TestCircularDependenceInOneJITDylib) { 401 // Test that a circular symbol dependency between three symbols in a JITDylib 402 // does not prevent any symbol from becoming 'ready' once all symbols are 403 // emitted. 404 405 // Create three MaterializationResponsibility objects: one for each of Foo, 406 // Bar and Baz. These are optional because MaterializationResponsibility 407 // does not have a default constructor). 408 Optional<MaterializationResponsibility> FooR; 409 Optional<MaterializationResponsibility> BarR; 410 Optional<MaterializationResponsibility> BazR; 411 412 // Create a MaterializationUnit for each symbol that moves the 413 // MaterializationResponsibility into one of the locals above. 414 auto FooMU = std::make_unique<SimpleMaterializationUnit>( 415 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 416 [&](MaterializationResponsibility R) { FooR.emplace(std::move(R)); }); 417 418 auto BarMU = std::make_unique<SimpleMaterializationUnit>( 419 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 420 [&](MaterializationResponsibility R) { BarR.emplace(std::move(R)); }); 421 422 auto BazMU = std::make_unique<SimpleMaterializationUnit>( 423 SymbolFlagsMap({{Baz, BazSym.getFlags()}}), 424 [&](MaterializationResponsibility R) { BazR.emplace(std::move(R)); }); 425 426 // Define the symbols. 427 cantFail(JD.define(FooMU)); 428 cantFail(JD.define(BarMU)); 429 cantFail(JD.define(BazMU)); 430 431 // Query each of the symbols to trigger materialization. 432 bool FooResolved = false; 433 bool FooReady = false; 434 435 auto OnFooResolution = [&](Expected<SymbolMap> Result) { 436 cantFail(std::move(Result)); 437 FooResolved = true; 438 }; 439 440 auto OnFooReady = [&](Expected<SymbolMap> Result) { 441 cantFail(std::move(Result)); 442 FooReady = true; 443 }; 444 445 // Issue lookups for Foo. Use NoDependenciesToRegister: We're going to add 446 // the dependencies manually below. 447 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 448 SymbolLookupSet(Foo), SymbolState::Resolved, 449 std::move(OnFooResolution), NoDependenciesToRegister); 450 451 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 452 SymbolLookupSet(Foo), SymbolState::Ready, std::move(OnFooReady), 453 NoDependenciesToRegister); 454 455 bool BarResolved = false; 456 bool BarReady = false; 457 auto OnBarResolution = [&](Expected<SymbolMap> Result) { 458 cantFail(std::move(Result)); 459 BarResolved = true; 460 }; 461 462 auto OnBarReady = [&](Expected<SymbolMap> Result) { 463 cantFail(std::move(Result)); 464 BarReady = true; 465 }; 466 467 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 468 SymbolLookupSet(Bar), SymbolState::Resolved, 469 std::move(OnBarResolution), NoDependenciesToRegister); 470 471 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 472 SymbolLookupSet(Bar), SymbolState::Ready, std::move(OnBarReady), 473 NoDependenciesToRegister); 474 475 bool BazResolved = false; 476 bool BazReady = false; 477 478 auto OnBazResolution = [&](Expected<SymbolMap> Result) { 479 cantFail(std::move(Result)); 480 BazResolved = true; 481 }; 482 483 auto OnBazReady = [&](Expected<SymbolMap> Result) { 484 cantFail(std::move(Result)); 485 BazReady = true; 486 }; 487 488 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 489 SymbolLookupSet(Baz), SymbolState::Resolved, 490 std::move(OnBazResolution), NoDependenciesToRegister); 491 492 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 493 SymbolLookupSet(Baz), SymbolState::Ready, std::move(OnBazReady), 494 NoDependenciesToRegister); 495 496 // Add a circular dependency: Foo -> Bar, Bar -> Baz, Baz -> Foo. 497 FooR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}}); 498 BarR->addDependenciesForAll({{&JD, SymbolNameSet({Baz})}}); 499 BazR->addDependenciesForAll({{&JD, SymbolNameSet({Foo})}}); 500 501 // Add self-dependencies for good measure. This tests that the implementation 502 // of addDependencies filters these out. 503 FooR->addDependenciesForAll({{&JD, SymbolNameSet({Foo})}}); 504 BarR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}}); 505 BazR->addDependenciesForAll({{&JD, SymbolNameSet({Baz})}}); 506 507 // Check that nothing has been resolved yet. 508 EXPECT_FALSE(FooResolved) << "\"Foo\" should not be resolved yet"; 509 EXPECT_FALSE(BarResolved) << "\"Bar\" should not be resolved yet"; 510 EXPECT_FALSE(BazResolved) << "\"Baz\" should not be resolved yet"; 511 512 // Resolve the symbols (but do not emit them). 513 EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Succeeded()) 514 << "No symbols failed, but Foo failed to resolve"; 515 EXPECT_THAT_ERROR(BarR->notifyResolved({{Bar, BarSym}}), Succeeded()) 516 << "No symbols failed, but Bar failed to resolve"; 517 EXPECT_THAT_ERROR(BazR->notifyResolved({{Baz, BazSym}}), Succeeded()) 518 << "No symbols failed, but Baz failed to resolve"; 519 520 // Verify that the symbols have been resolved, but are not ready yet. 521 EXPECT_TRUE(FooResolved) << "\"Foo\" should be resolved now"; 522 EXPECT_TRUE(BarResolved) << "\"Bar\" should be resolved now"; 523 EXPECT_TRUE(BazResolved) << "\"Baz\" should be resolved now"; 524 525 EXPECT_FALSE(FooReady) << "\"Foo\" should not be ready yet"; 526 EXPECT_FALSE(BarReady) << "\"Bar\" should not be ready yet"; 527 EXPECT_FALSE(BazReady) << "\"Baz\" should not be ready yet"; 528 529 // Emit two of the symbols. 530 EXPECT_THAT_ERROR(FooR->notifyEmitted(), Succeeded()) 531 << "No symbols failed, but Foo failed to emit"; 532 EXPECT_THAT_ERROR(BarR->notifyEmitted(), Succeeded()) 533 << "No symbols failed, but Bar failed to emit"; 534 535 // Verify that nothing is ready until the circular dependence is resolved. 536 EXPECT_FALSE(FooReady) << "\"Foo\" still should not be ready"; 537 EXPECT_FALSE(BarReady) << "\"Bar\" still should not be ready"; 538 EXPECT_FALSE(BazReady) << "\"Baz\" still should not be ready"; 539 540 // Emit the last symbol. 541 EXPECT_THAT_ERROR(BazR->notifyEmitted(), Succeeded()) 542 << "No symbols failed, but Baz failed to emit"; 543 544 // Verify that everything becomes ready once the circular dependence resolved. 545 EXPECT_TRUE(FooReady) << "\"Foo\" should be ready now"; 546 EXPECT_TRUE(BarReady) << "\"Bar\" should be ready now"; 547 EXPECT_TRUE(BazReady) << "\"Baz\" should be ready now"; 548 } 549 550 TEST_F(CoreAPIsStandardTest, FailureInDependency) { 551 Optional<MaterializationResponsibility> FooR; 552 Optional<MaterializationResponsibility> BarR; 553 554 // Create a MaterializationUnit for each symbol that moves the 555 // MaterializationResponsibility into one of the locals above. 556 auto FooMU = std::make_unique<SimpleMaterializationUnit>( 557 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 558 [&](MaterializationResponsibility R) { FooR.emplace(std::move(R)); }); 559 560 auto BarMU = std::make_unique<SimpleMaterializationUnit>( 561 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 562 [&](MaterializationResponsibility R) { BarR.emplace(std::move(R)); }); 563 564 // Define the symbols. 565 cantFail(JD.define(FooMU)); 566 cantFail(JD.define(BarMU)); 567 568 bool OnFooReadyRun = false; 569 auto OnFooReady = [&](Expected<SymbolMap> Result) { 570 EXPECT_THAT_EXPECTED(std::move(Result), Failed()); 571 OnFooReadyRun = true; 572 }; 573 574 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 575 SymbolLookupSet(Foo), SymbolState::Ready, std::move(OnFooReady), 576 NoDependenciesToRegister); 577 578 bool OnBarReadyRun = false; 579 auto OnBarReady = [&](Expected<SymbolMap> Result) { 580 EXPECT_THAT_EXPECTED(std::move(Result), Failed()); 581 OnBarReadyRun = true; 582 }; 583 584 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 585 SymbolLookupSet(Bar), SymbolState::Ready, std::move(OnBarReady), 586 NoDependenciesToRegister); 587 588 // Add a dependency by Foo on Bar. 589 FooR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}}); 590 591 // Fail bar. 592 BarR->failMaterialization(); 593 594 // Verify that queries on Bar failed, but queries on Foo have not yet. 595 EXPECT_TRUE(OnBarReadyRun) << "Query for \"Bar\" was not run"; 596 EXPECT_FALSE(OnFooReadyRun) << "Query for \"Foo\" was run unexpectedly"; 597 598 // Check that we can still resolve Foo (even though it has been failed). 599 EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Failed()) 600 << "Expected resolution for \"Foo\" to fail."; 601 602 FooR->failMaterialization(); 603 604 // Verify that queries on Foo have now failed. 605 EXPECT_TRUE(OnFooReadyRun) << "Query for \"Foo\" was not run"; 606 607 // Verify that subsequent lookups on Bar and Foo fail. 608 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Bar}), Failed()) 609 << "Lookup on failed symbol should fail"; 610 611 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Foo}), Failed()) 612 << "Lookup on failed symbol should fail"; 613 } 614 615 TEST_F(CoreAPIsStandardTest, FailureInCircularDependency) { 616 Optional<MaterializationResponsibility> FooR; 617 Optional<MaterializationResponsibility> BarR; 618 619 // Create a MaterializationUnit for each symbol that moves the 620 // MaterializationResponsibility into one of the locals above. 621 auto FooMU = std::make_unique<SimpleMaterializationUnit>( 622 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 623 [&](MaterializationResponsibility R) { FooR.emplace(std::move(R)); }); 624 625 auto BarMU = std::make_unique<SimpleMaterializationUnit>( 626 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 627 [&](MaterializationResponsibility R) { BarR.emplace(std::move(R)); }); 628 629 // Define the symbols. 630 cantFail(JD.define(FooMU)); 631 cantFail(JD.define(BarMU)); 632 633 bool OnFooReadyRun = false; 634 auto OnFooReady = [&](Expected<SymbolMap> Result) { 635 EXPECT_THAT_EXPECTED(std::move(Result), Failed()); 636 OnFooReadyRun = true; 637 }; 638 639 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 640 SymbolLookupSet(Foo), SymbolState::Ready, std::move(OnFooReady), 641 NoDependenciesToRegister); 642 643 bool OnBarReadyRun = false; 644 auto OnBarReady = [&](Expected<SymbolMap> Result) { 645 EXPECT_THAT_EXPECTED(std::move(Result), Failed()); 646 OnBarReadyRun = true; 647 }; 648 649 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 650 SymbolLookupSet(Bar), SymbolState::Ready, std::move(OnBarReady), 651 NoDependenciesToRegister); 652 653 // Add a dependency by Foo on Bar and vice-versa. 654 FooR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}}); 655 BarR->addDependenciesForAll({{&JD, SymbolNameSet({Foo})}}); 656 657 // Fail bar. 658 BarR->failMaterialization(); 659 660 // Verify that queries on Bar failed, but queries on Foo have not yet. 661 EXPECT_TRUE(OnBarReadyRun) << "Query for \"Bar\" was not run"; 662 EXPECT_FALSE(OnFooReadyRun) << "Query for \"Foo\" was run unexpectedly"; 663 664 // Verify that trying to resolve Foo fails. 665 EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Failed()) 666 << "Expected resolution for \"Foo\" to fail."; 667 668 FooR->failMaterialization(); 669 670 // Verify that queries on Foo have now failed. 671 EXPECT_TRUE(OnFooReadyRun) << "Query for \"Foo\" was not run"; 672 673 // Verify that subsequent lookups on Bar and Foo fail. 674 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Bar}), Failed()) 675 << "Lookup on failed symbol should fail"; 676 677 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Foo}), Failed()) 678 << "Lookup on failed symbol should fail"; 679 } 680 681 TEST_F(CoreAPIsStandardTest, AddDependencyOnFailedSymbol) { 682 Optional<MaterializationResponsibility> FooR; 683 Optional<MaterializationResponsibility> BarR; 684 685 // Create a MaterializationUnit for each symbol that moves the 686 // MaterializationResponsibility into one of the locals above. 687 auto FooMU = std::make_unique<SimpleMaterializationUnit>( 688 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 689 [&](MaterializationResponsibility R) { FooR.emplace(std::move(R)); }); 690 691 auto BarMU = std::make_unique<SimpleMaterializationUnit>( 692 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 693 [&](MaterializationResponsibility R) { BarR.emplace(std::move(R)); }); 694 695 // Define the symbols. 696 cantFail(JD.define(FooMU)); 697 cantFail(JD.define(BarMU)); 698 699 bool OnFooReadyRun = false; 700 auto OnFooReady = [&](Expected<SymbolMap> Result) { 701 EXPECT_THAT_EXPECTED(std::move(Result), Failed()); 702 OnFooReadyRun = true; 703 }; 704 705 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 706 SymbolLookupSet(Foo), SymbolState::Ready, std::move(OnFooReady), 707 NoDependenciesToRegister); 708 709 bool OnBarReadyRun = false; 710 auto OnBarReady = [&](Expected<SymbolMap> Result) { 711 EXPECT_THAT_EXPECTED(std::move(Result), Failed()); 712 OnBarReadyRun = true; 713 }; 714 715 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 716 SymbolLookupSet(Bar), SymbolState::Ready, std::move(OnBarReady), 717 NoDependenciesToRegister); 718 719 // Fail bar. 720 BarR->failMaterialization(); 721 722 // We expect Bar's query to fail immediately, but Foo's query not to have run 723 // yet. 724 EXPECT_TRUE(OnBarReadyRun) << "Query for \"Bar\" was not run"; 725 EXPECT_FALSE(OnFooReadyRun) << "Query for \"Foo\" should not have run yet"; 726 727 // Add dependency of Foo on Bar. 728 FooR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}}); 729 730 // Check that we can still resolve Foo (even though it has been failed). 731 EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Failed()) 732 << "Expected resolution for \"Foo\" to fail."; 733 734 FooR->failMaterialization(); 735 736 // Foo's query should have failed before we return from addDependencies. 737 EXPECT_TRUE(OnFooReadyRun) << "Query for \"Foo\" was not run"; 738 739 // Verify that subsequent lookups on Bar and Foo fail. 740 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Bar}), Failed()) 741 << "Lookup on failed symbol should fail"; 742 743 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Foo}), Failed()) 744 << "Lookup on failed symbol should fail"; 745 } 746 747 TEST_F(CoreAPIsStandardTest, FailAfterMaterialization) { 748 Optional<MaterializationResponsibility> FooR; 749 Optional<MaterializationResponsibility> BarR; 750 751 // Create a MaterializationUnit for each symbol that moves the 752 // MaterializationResponsibility into one of the locals above. 753 auto FooMU = std::make_unique<SimpleMaterializationUnit>( 754 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 755 [&](MaterializationResponsibility R) { FooR.emplace(std::move(R)); }); 756 757 auto BarMU = std::make_unique<SimpleMaterializationUnit>( 758 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 759 [&](MaterializationResponsibility R) { BarR.emplace(std::move(R)); }); 760 761 // Define the symbols. 762 cantFail(JD.define(FooMU)); 763 cantFail(JD.define(BarMU)); 764 765 bool OnFooReadyRun = false; 766 auto OnFooReady = [&](Expected<SymbolMap> Result) { 767 EXPECT_THAT_EXPECTED(std::move(Result), Failed()); 768 OnFooReadyRun = true; 769 }; 770 771 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 772 SymbolLookupSet(Foo), SymbolState::Ready, std::move(OnFooReady), 773 NoDependenciesToRegister); 774 775 bool OnBarReadyRun = false; 776 auto OnBarReady = [&](Expected<SymbolMap> Result) { 777 EXPECT_THAT_EXPECTED(std::move(Result), Failed()); 778 OnBarReadyRun = true; 779 }; 780 781 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 782 SymbolLookupSet(Bar), SymbolState::Ready, std::move(OnBarReady), 783 NoDependenciesToRegister); 784 785 // Add a dependency by Foo on Bar and vice-versa. 786 FooR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}}); 787 BarR->addDependenciesForAll({{&JD, SymbolNameSet({Foo})}}); 788 789 // Materialize Foo. 790 EXPECT_THAT_ERROR(FooR->notifyResolved({{Foo, FooSym}}), Succeeded()) 791 << "Expected resolution for \"Foo\" to succeed."; 792 EXPECT_THAT_ERROR(FooR->notifyEmitted(), Succeeded()) 793 << "Expected emission for \"Foo\" to succeed."; 794 795 // Fail bar. 796 BarR->failMaterialization(); 797 798 // Verify that both queries failed. 799 EXPECT_TRUE(OnFooReadyRun) << "Query for Foo did not run"; 800 EXPECT_TRUE(OnBarReadyRun) << "Query for Bar did not run"; 801 } 802 803 TEST_F(CoreAPIsStandardTest, FailMaterializerWithUnqueriedSymbols) { 804 // Make sure that symbols with no queries aganist them still 805 // fail correctly. 806 807 bool MaterializerRun = false; 808 auto MU = std::make_unique<SimpleMaterializationUnit>( 809 SymbolFlagsMap( 810 {{Foo, JITSymbolFlags::Exported}, {Bar, JITSymbolFlags::Exported}}), 811 [&](MaterializationResponsibility R) { 812 MaterializerRun = true; 813 R.failMaterialization(); 814 }); 815 816 cantFail(JD.define(std::move(MU))); 817 818 // Issue a query for Foo, but not bar. 819 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Foo}), Failed()) 820 << "Expected lookup to fail."; 821 822 // Check that the materializer (and therefore failMaterialization) ran. 823 EXPECT_TRUE(MaterializerRun) << "Expected materializer to have run by now"; 824 825 // Check that subsequent queries against both symbols fail. 826 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Foo}), Failed()) 827 << "Expected lookup for Foo to fail."; 828 EXPECT_THAT_EXPECTED(ES.lookup({&JD}, {Bar}), Failed()) 829 << "Expected lookup for Bar to fail."; 830 } 831 832 TEST_F(CoreAPIsStandardTest, DropMaterializerWhenEmpty) { 833 bool DestructorRun = false; 834 835 JITSymbolFlags WeakExported(JITSymbolFlags::Exported); 836 WeakExported |= JITSymbolFlags::Weak; 837 838 auto MU = std::make_unique<SimpleMaterializationUnit>( 839 SymbolFlagsMap({{Foo, WeakExported}, {Bar, WeakExported}}), 840 [](MaterializationResponsibility R) { 841 llvm_unreachable("Unexpected call to materialize"); 842 }, 843 nullptr, 844 [&](const JITDylib &JD, SymbolStringPtr Name) { 845 EXPECT_TRUE(Name == Foo || Name == Bar) 846 << "Discard of unexpected symbol?"; 847 }, 848 [&]() { DestructorRun = true; }); 849 850 cantFail(JD.define(MU)); 851 852 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 853 854 EXPECT_FALSE(DestructorRun) 855 << "MaterializationUnit should not have been destroyed yet"; 856 857 cantFail(JD.define(absoluteSymbols({{Bar, BarSym}}))); 858 859 EXPECT_TRUE(DestructorRun) 860 << "MaterializationUnit should have been destroyed"; 861 } 862 863 TEST_F(CoreAPIsStandardTest, AddAndMaterializeLazySymbol) { 864 bool FooMaterialized = false; 865 bool BarDiscarded = false; 866 867 JITSymbolFlags WeakExported(JITSymbolFlags::Exported); 868 WeakExported |= JITSymbolFlags::Weak; 869 870 auto MU = std::make_unique<SimpleMaterializationUnit>( 871 SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}, {Bar, WeakExported}}), 872 [&](MaterializationResponsibility R) { 873 assert(BarDiscarded && "Bar should have been discarded by this point"); 874 cantFail(R.notifyResolved(SymbolMap({{Foo, FooSym}}))); 875 cantFail(R.notifyEmitted()); 876 FooMaterialized = true; 877 }, 878 nullptr, 879 [&](const JITDylib &JD, SymbolStringPtr Name) { 880 EXPECT_EQ(Name, Bar) << "Expected Name to be Bar"; 881 BarDiscarded = true; 882 }); 883 884 cantFail(JD.define(MU)); 885 cantFail(JD.define(absoluteSymbols({{Bar, BarSym}}))); 886 887 bool OnCompletionRun = false; 888 889 auto OnCompletion = [&](Expected<SymbolMap> Result) { 890 EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error"; 891 auto I = Result->find(Foo); 892 EXPECT_NE(I, Result->end()) << "Could not find symbol definition"; 893 EXPECT_EQ(I->second.getAddress(), FooSym.getAddress()) 894 << "Resolution returned incorrect result"; 895 OnCompletionRun = true; 896 }; 897 898 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 899 SymbolLookupSet(Foo), SymbolState::Ready, std::move(OnCompletion), 900 NoDependenciesToRegister); 901 902 EXPECT_TRUE(FooMaterialized) << "Foo was not materialized"; 903 EXPECT_TRUE(BarDiscarded) << "Bar was not discarded"; 904 EXPECT_TRUE(OnCompletionRun) << "OnResolutionCallback was not run"; 905 } 906 907 TEST_F(CoreAPIsStandardTest, TestBasicWeakSymbolMaterialization) { 908 // Test that weak symbols are materialized correctly when we look them up. 909 BarSym.setFlags(BarSym.getFlags() | JITSymbolFlags::Weak); 910 911 bool BarMaterialized = false; 912 auto MU1 = std::make_unique<SimpleMaterializationUnit>( 913 SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}), 914 [&](MaterializationResponsibility R) { 915 cantFail(R.notifyResolved(SymbolMap({{Foo, FooSym}, {Bar, BarSym}}))); 916 cantFail(R.notifyEmitted()); 917 BarMaterialized = true; 918 }); 919 920 bool DuplicateBarDiscarded = false; 921 auto MU2 = std::make_unique<SimpleMaterializationUnit>( 922 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 923 [&](MaterializationResponsibility R) { 924 ADD_FAILURE() << "Attempt to materialize Bar from the wrong unit"; 925 R.failMaterialization(); 926 }, 927 nullptr, 928 [&](const JITDylib &JD, SymbolStringPtr Name) { 929 EXPECT_EQ(Name, Bar) << "Expected \"Bar\" to be discarded"; 930 DuplicateBarDiscarded = true; 931 }); 932 933 cantFail(JD.define(MU1)); 934 cantFail(JD.define(MU2)); 935 936 bool OnCompletionRun = false; 937 938 auto OnCompletion = [&](Expected<SymbolMap> Result) { 939 cantFail(std::move(Result)); 940 OnCompletionRun = true; 941 }; 942 943 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 944 SymbolLookupSet(Bar), SymbolState::Ready, std::move(OnCompletion), 945 NoDependenciesToRegister); 946 947 EXPECT_TRUE(OnCompletionRun) << "OnCompletion not run"; 948 EXPECT_TRUE(BarMaterialized) << "Bar was not materialized at all"; 949 EXPECT_TRUE(DuplicateBarDiscarded) 950 << "Duplicate bar definition not discarded"; 951 } 952 953 TEST_F(CoreAPIsStandardTest, DefineMaterializingSymbol) { 954 bool ExpectNoMoreMaterialization = false; 955 ES.setDispatchMaterialization( 956 [&](JITDylib &JD, std::unique_ptr<MaterializationUnit> MU) { 957 if (ExpectNoMoreMaterialization) 958 ADD_FAILURE() << "Unexpected materialization"; 959 MU->doMaterialize(JD); 960 }); 961 962 auto MU = std::make_unique<SimpleMaterializationUnit>( 963 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 964 [&](MaterializationResponsibility R) { 965 cantFail( 966 R.defineMaterializing(SymbolFlagsMap({{Bar, BarSym.getFlags()}}))); 967 cantFail(R.notifyResolved(SymbolMap({{Foo, FooSym}, {Bar, BarSym}}))); 968 cantFail(R.notifyEmitted()); 969 }); 970 971 cantFail(JD.define(MU)); 972 cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Foo)); 973 974 // Assert that materialization is complete by now. 975 ExpectNoMoreMaterialization = true; 976 977 // Look up bar to verify that no further materialization happens. 978 auto BarResult = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Bar)); 979 EXPECT_EQ(BarResult.getAddress(), BarSym.getAddress()) 980 << "Expected Bar == BarSym"; 981 } 982 983 TEST_F(CoreAPIsStandardTest, GeneratorTest) { 984 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 985 986 class TestGenerator : public JITDylib::DefinitionGenerator { 987 public: 988 TestGenerator(SymbolMap Symbols) : Symbols(std::move(Symbols)) {} 989 Error tryToGenerate(LookupKind K, JITDylib &JD, 990 JITDylibLookupFlags JDLookupFlags, 991 const SymbolLookupSet &Names) { 992 SymbolMap NewDefs; 993 994 for (const auto &KV : Names) { 995 const auto &Name = KV.first; 996 if (Symbols.count(Name)) 997 NewDefs[Name] = Symbols[Name]; 998 } 999 1000 cantFail(JD.define(absoluteSymbols(std::move(NewDefs)))); 1001 return Error::success(); 1002 }; 1003 1004 private: 1005 SymbolMap Symbols; 1006 }; 1007 1008 JD.addGenerator(std::make_unique<TestGenerator>(SymbolMap({{Bar, BarSym}}))); 1009 1010 auto Result = cantFail( 1011 ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Foo, Bar}))); 1012 1013 EXPECT_EQ(Result.count(Bar), 1U) << "Expected to find fallback def for 'bar'"; 1014 EXPECT_EQ(Result[Bar].getAddress(), BarSym.getAddress()) 1015 << "Expected fallback def for Bar to be equal to BarSym"; 1016 } 1017 1018 TEST_F(CoreAPIsStandardTest, FailResolution) { 1019 auto MU = std::make_unique<SimpleMaterializationUnit>( 1020 SymbolFlagsMap({{Foo, JITSymbolFlags::Exported | JITSymbolFlags::Weak}, 1021 {Bar, JITSymbolFlags::Exported | JITSymbolFlags::Weak}}), 1022 [&](MaterializationResponsibility R) { 1023 R.failMaterialization(); 1024 }); 1025 1026 cantFail(JD.define(MU)); 1027 1028 SymbolNameSet Names({Foo, Bar}); 1029 auto Result = ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet(Names)); 1030 1031 EXPECT_FALSE(!!Result) << "Expected failure"; 1032 if (!Result) { 1033 handleAllErrors( 1034 Result.takeError(), 1035 [&](FailedToMaterialize &F) { 1036 EXPECT_TRUE(F.getSymbols().count(&JD)) 1037 << "Expected to fail on JITDylib JD"; 1038 EXPECT_EQ(F.getSymbols().find(&JD)->second, Names) 1039 << "Expected to fail on symbols in Names"; 1040 }, 1041 [](ErrorInfoBase &EIB) { 1042 std::string ErrMsg; 1043 { 1044 raw_string_ostream ErrOut(ErrMsg); 1045 EIB.log(ErrOut); 1046 } 1047 ADD_FAILURE() << "Expected a FailedToResolve error. Got:\n" << ErrMsg; 1048 }); 1049 } 1050 } 1051 1052 TEST_F(CoreAPIsStandardTest, FailEmissionAfterResolution) { 1053 1054 cantFail(JD.define(absoluteSymbols({{Baz, BazSym}}))); 1055 1056 auto MU = std::make_unique<SimpleMaterializationUnit>( 1057 SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}), 1058 [&](MaterializationResponsibility R) { 1059 cantFail(R.notifyResolved(SymbolMap({{Foo, FooSym}, {Bar, BarSym}}))); 1060 1061 ES.lookup( 1062 LookupKind::Static, makeJITDylibSearchOrder(&JD), 1063 SymbolLookupSet({Baz}), SymbolState::Resolved, 1064 [&R](Expected<SymbolMap> Result) { 1065 // Called when "baz" is resolved. We don't actually depend 1066 // on or care about baz, but use it to trigger failure of 1067 // this materialization before Baz has been finalized in 1068 // order to test that error propagation is correct in this 1069 // scenario. 1070 cantFail(std::move(Result)); 1071 R.failMaterialization(); 1072 }, 1073 [&](const SymbolDependenceMap &Deps) { 1074 R.addDependenciesForAll(Deps); 1075 }); 1076 }); 1077 1078 cantFail(JD.define(MU)); 1079 1080 auto Result = 1081 ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Foo, Bar})); 1082 1083 EXPECT_THAT_EXPECTED(std::move(Result), Failed()) 1084 << "Unexpected success while trying to test error propagation"; 1085 } 1086 1087 TEST_F(CoreAPIsStandardTest, FailAfterPartialResolution) { 1088 1089 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 1090 1091 // Fail materialization of bar. 1092 auto BarMU = std::make_unique<SimpleMaterializationUnit>( 1093 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 1094 [&](MaterializationResponsibility R) { R.failMaterialization(); }); 1095 1096 cantFail(JD.define(std::move(BarMU))); 1097 1098 bool QueryHandlerRun = false; 1099 ES.lookup( 1100 LookupKind::Static, makeJITDylibSearchOrder(&JD), 1101 SymbolLookupSet({Foo, Bar}), SymbolState::Resolved, 1102 [&](Expected<SymbolMap> Result) { 1103 EXPECT_THAT_EXPECTED(std::move(Result), Failed()) 1104 << "Expected query to fail"; 1105 QueryHandlerRun = true; 1106 }, 1107 NoDependenciesToRegister); 1108 EXPECT_TRUE(QueryHandlerRun) << "Query handler never ran"; 1109 } 1110 1111 TEST_F(CoreAPIsStandardTest, TestLookupWithUnthreadedMaterialization) { 1112 auto MU = std::make_unique<SimpleMaterializationUnit>( 1113 SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}}), 1114 [&](MaterializationResponsibility R) { 1115 cantFail(R.notifyResolved({{Foo, FooSym}})); 1116 cantFail(R.notifyEmitted()); 1117 }); 1118 1119 cantFail(JD.define(MU)); 1120 1121 auto FooLookupResult = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Foo)); 1122 1123 EXPECT_EQ(FooLookupResult.getAddress(), FooSym.getAddress()) 1124 << "lookup returned an incorrect address"; 1125 EXPECT_EQ(FooLookupResult.getFlags(), FooSym.getFlags()) 1126 << "lookup returned incorrect flags"; 1127 } 1128 1129 TEST_F(CoreAPIsStandardTest, TestLookupWithThreadedMaterialization) { 1130 #if LLVM_ENABLE_THREADS 1131 1132 std::thread MaterializationThread; 1133 ES.setDispatchMaterialization( 1134 [&](JITDylib &JD, std::unique_ptr<MaterializationUnit> MU) { 1135 MaterializationThread = 1136 std::thread([MU = std::move(MU), &JD] { MU->doMaterialize(JD); }); 1137 }); 1138 1139 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 1140 1141 auto FooLookupResult = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Foo)); 1142 1143 EXPECT_EQ(FooLookupResult.getAddress(), FooSym.getAddress()) 1144 << "lookup returned an incorrect address"; 1145 EXPECT_EQ(FooLookupResult.getFlags(), FooSym.getFlags()) 1146 << "lookup returned incorrect flags"; 1147 MaterializationThread.join(); 1148 #endif 1149 } 1150 1151 TEST_F(CoreAPIsStandardTest, TestGetRequestedSymbolsAndReplace) { 1152 // Test that GetRequestedSymbols returns the set of symbols that currently 1153 // have pending queries, and test that MaterializationResponsibility's 1154 // replace method can be used to return definitions to the JITDylib in a new 1155 // MaterializationUnit. 1156 SymbolNameSet Names({Foo, Bar}); 1157 1158 bool FooMaterialized = false; 1159 bool BarMaterialized = false; 1160 1161 auto MU = std::make_unique<SimpleMaterializationUnit>( 1162 SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}), 1163 [&](MaterializationResponsibility R) { 1164 auto Requested = R.getRequestedSymbols(); 1165 EXPECT_EQ(Requested.size(), 1U) << "Expected one symbol requested"; 1166 EXPECT_EQ(*Requested.begin(), Foo) << "Expected \"Foo\" requested"; 1167 1168 auto NewMU = std::make_unique<SimpleMaterializationUnit>( 1169 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 1170 [&](MaterializationResponsibility R2) { 1171 cantFail(R2.notifyResolved(SymbolMap({{Bar, BarSym}}))); 1172 cantFail(R2.notifyEmitted()); 1173 BarMaterialized = true; 1174 }); 1175 1176 R.replace(std::move(NewMU)); 1177 1178 cantFail(R.notifyResolved(SymbolMap({{Foo, FooSym}}))); 1179 cantFail(R.notifyEmitted()); 1180 1181 FooMaterialized = true; 1182 }); 1183 1184 cantFail(JD.define(MU)); 1185 1186 EXPECT_FALSE(FooMaterialized) << "Foo should not be materialized yet"; 1187 EXPECT_FALSE(BarMaterialized) << "Bar should not be materialized yet"; 1188 1189 auto FooSymResult = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Foo)); 1190 EXPECT_EQ(FooSymResult.getAddress(), FooSym.getAddress()) 1191 << "Address mismatch for Foo"; 1192 1193 EXPECT_TRUE(FooMaterialized) << "Foo should be materialized now"; 1194 EXPECT_FALSE(BarMaterialized) << "Bar still should not be materialized"; 1195 1196 auto BarSymResult = cantFail(ES.lookup(makeJITDylibSearchOrder(&JD), Bar)); 1197 EXPECT_EQ(BarSymResult.getAddress(), BarSym.getAddress()) 1198 << "Address mismatch for Bar"; 1199 EXPECT_TRUE(BarMaterialized) << "Bar should be materialized now"; 1200 } 1201 1202 TEST_F(CoreAPIsStandardTest, TestMaterializationResponsibilityDelegation) { 1203 auto MU = std::make_unique<SimpleMaterializationUnit>( 1204 SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}), 1205 [&](MaterializationResponsibility R) { 1206 auto R2 = R.delegate({Bar}); 1207 1208 cantFail(R.notifyResolved({{Foo, FooSym}})); 1209 cantFail(R.notifyEmitted()); 1210 cantFail(R2.notifyResolved({{Bar, BarSym}})); 1211 cantFail(R2.notifyEmitted()); 1212 }); 1213 1214 cantFail(JD.define(MU)); 1215 1216 auto Result = 1217 ES.lookup(makeJITDylibSearchOrder(&JD), SymbolLookupSet({Foo, Bar})); 1218 1219 EXPECT_TRUE(!!Result) << "Result should be a success value"; 1220 EXPECT_EQ(Result->count(Foo), 1U) << "\"Foo\" entry missing"; 1221 EXPECT_EQ(Result->count(Bar), 1U) << "\"Bar\" entry missing"; 1222 EXPECT_EQ((*Result)[Foo].getAddress(), FooSym.getAddress()) 1223 << "Address mismatch for \"Foo\""; 1224 EXPECT_EQ((*Result)[Bar].getAddress(), BarSym.getAddress()) 1225 << "Address mismatch for \"Bar\""; 1226 } 1227 1228 TEST_F(CoreAPIsStandardTest, TestMaterializeWeakSymbol) { 1229 // Confirm that once a weak definition is selected for materialization it is 1230 // treated as strong. 1231 JITSymbolFlags WeakExported = JITSymbolFlags::Exported; 1232 WeakExported &= JITSymbolFlags::Weak; 1233 1234 std::unique_ptr<MaterializationResponsibility> FooResponsibility; 1235 auto MU = std::make_unique<SimpleMaterializationUnit>( 1236 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 1237 [&](MaterializationResponsibility R) { 1238 FooResponsibility = 1239 std::make_unique<MaterializationResponsibility>(std::move(R)); 1240 }); 1241 1242 cantFail(JD.define(MU)); 1243 auto OnCompletion = [](Expected<SymbolMap> Result) { 1244 cantFail(std::move(Result)); 1245 }; 1246 1247 ES.lookup(LookupKind::Static, makeJITDylibSearchOrder(&JD), 1248 SymbolLookupSet({Foo}), SymbolState::Ready, std::move(OnCompletion), 1249 NoDependenciesToRegister); 1250 1251 auto MU2 = std::make_unique<SimpleMaterializationUnit>( 1252 SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}}), 1253 [](MaterializationResponsibility R) { 1254 llvm_unreachable("This unit should never be materialized"); 1255 }); 1256 1257 auto Err = JD.define(MU2); 1258 EXPECT_TRUE(!!Err) << "Expected failure value"; 1259 EXPECT_TRUE(Err.isA<DuplicateDefinition>()) 1260 << "Expected a duplicate definition error"; 1261 consumeError(std::move(Err)); 1262 1263 // No dependencies registered, can't fail: 1264 cantFail(FooResponsibility->notifyResolved(SymbolMap({{Foo, FooSym}}))); 1265 cantFail(FooResponsibility->notifyEmitted()); 1266 } 1267 1268 } // namespace 1269