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