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