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