1 //===----------- CoreAPIsTest.cpp - Unit tests for Core ORC APIs ----------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "OrcTestCommon.h" 11 #include "llvm/Config/llvm-config.h" 12 #include "llvm/ExecutionEngine/Orc/Core.h" 13 #include "llvm/ExecutionEngine/Orc/OrcError.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 OnResolutionRun = false; 27 bool OnReadyRun = false; 28 29 auto OnResolution = [&](Expected<SymbolMap> Result) { 30 EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error"; 31 auto &Resolved = *Result; 32 auto I = Resolved.find(Foo); 33 EXPECT_NE(I, Resolved.end()) << "Could not find symbol definition"; 34 EXPECT_EQ(I->second.getAddress(), FooAddr) 35 << "Resolution returned incorrect result"; 36 OnResolutionRun = true; 37 }; 38 auto OnReady = [&](Error Err) { 39 cantFail(std::move(Err)); 40 OnReadyRun = true; 41 }; 42 43 std::shared_ptr<MaterializationResponsibility> FooMR; 44 45 cantFail(JD.define(llvm::make_unique<SimpleMaterializationUnit>( 46 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 47 [&](MaterializationResponsibility R) { 48 FooMR = std::make_shared<MaterializationResponsibility>(std::move(R)); 49 }))); 50 51 ES.lookup({&JD}, {Foo}, OnResolution, OnReady, NoDependenciesToRegister); 52 53 EXPECT_FALSE(OnResolutionRun) << "Should not have been resolved yet"; 54 EXPECT_FALSE(OnReadyRun) << "Should not have been marked ready yet"; 55 56 FooMR->resolve({{Foo, FooSym}}); 57 58 EXPECT_TRUE(OnResolutionRun) << "Should have been resolved"; 59 EXPECT_FALSE(OnReadyRun) << "Should not have been marked ready yet"; 60 61 FooMR->emit(); 62 63 EXPECT_TRUE(OnReadyRun) << "Should have been marked ready"; 64 } 65 66 TEST_F(CoreAPIsStandardTest, ExecutionSessionFailQuery) { 67 bool OnResolutionRun = false; 68 bool OnReadyRun = false; 69 70 auto OnResolution = [&](Expected<SymbolMap> Result) { 71 EXPECT_FALSE(!!Result) << "Resolution unexpectedly returned success"; 72 auto Msg = toString(Result.takeError()); 73 EXPECT_EQ(Msg, "xyz") << "Resolution returned incorrect result"; 74 OnResolutionRun = true; 75 }; 76 auto OnReady = [&](Error Err) { 77 cantFail(std::move(Err)); 78 OnReadyRun = true; 79 }; 80 81 AsynchronousSymbolQuery Q(SymbolNameSet({Foo}), OnResolution, OnReady); 82 83 ES.legacyFailQuery(Q, 84 make_error<StringError>("xyz", inconvertibleErrorCode())); 85 86 EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run"; 87 EXPECT_FALSE(OnReadyRun) << "OnReady unexpectedly run"; 88 } 89 90 TEST_F(CoreAPIsStandardTest, EmptyLookup) { 91 bool OnResolvedRun = false; 92 bool OnReadyRun = false; 93 94 auto OnResolution = [&](Expected<SymbolMap> Result) { 95 cantFail(std::move(Result)); 96 OnResolvedRun = true; 97 }; 98 99 auto OnReady = [&](Error Err) { 100 cantFail(std::move(Err)); 101 OnReadyRun = true; 102 }; 103 104 ES.lookup({&JD}, {}, OnResolution, OnReady, NoDependenciesToRegister); 105 106 EXPECT_TRUE(OnResolvedRun) << "OnResolved was not run for empty query"; 107 EXPECT_TRUE(OnReadyRun) << "OnReady was not run for empty query"; 108 } 109 110 TEST_F(CoreAPIsStandardTest, RemoveSymbolsTest) { 111 // Test that: 112 // (1) Missing symbols generate a SymbolsNotFound error. 113 // (2) Materializing symbols generate a SymbolCouldNotBeRemoved error. 114 // (3) Removal of unmaterialized symbols triggers discard on the 115 // materialization unit. 116 // (4) Removal of symbols destroys empty materialization units. 117 // (5) Removal of materialized symbols works. 118 119 // Foo will be fully materialized. 120 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 121 122 // Bar will be unmaterialized. 123 bool BarDiscarded = false; 124 bool BarMaterializerDestructed = false; 125 cantFail(JD.define(llvm::make_unique<SimpleMaterializationUnit>( 126 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 127 [this](MaterializationResponsibility R) { 128 ADD_FAILURE() << "Unexpected materialization of \"Bar\""; 129 R.resolve({{Bar, BarSym}}); 130 R.emit(); 131 }, 132 [&](const JITDylib &JD, const SymbolStringPtr &Name) { 133 EXPECT_EQ(Name, Bar) << "Expected \"Bar\" to be discarded"; 134 if (Name == Bar) 135 BarDiscarded = true; 136 }, 137 [&]() { BarMaterializerDestructed = true; }))); 138 139 // Baz will be in the materializing state initially, then 140 // materialized for the final removal attempt. 141 Optional<MaterializationResponsibility> BazR; 142 cantFail(JD.define(llvm::make_unique<SimpleMaterializationUnit>( 143 SymbolFlagsMap({{Baz, BazSym.getFlags()}}), 144 [&](MaterializationResponsibility R) { BazR.emplace(std::move(R)); }, 145 [](const JITDylib &JD, const SymbolStringPtr &Name) { 146 ADD_FAILURE() << "\"Baz\" discarded unexpectedly"; 147 }))); 148 149 bool OnResolvedRun = false; 150 bool OnReadyRun = false; 151 ES.lookup({&JD}, {Foo, Baz}, 152 [&](Expected<SymbolMap> Result) { 153 EXPECT_TRUE(!!Result) << "OnResolved failed unexpectedly"; 154 consumeError(Result.takeError()); 155 OnResolvedRun = true; 156 }, 157 [&](Error Err) { 158 EXPECT_FALSE(!!Err) << "OnReady failed unexpectedly"; 159 consumeError(std::move(Err)); 160 OnReadyRun = true; 161 }, 162 NoDependenciesToRegister); 163 164 { 165 // Attempt 1: Search for a missing symbol, Qux. 166 auto Err = JD.remove({Foo, Bar, Baz, Qux}); 167 EXPECT_TRUE(!!Err) << "Expected failure"; 168 EXPECT_TRUE(Err.isA<SymbolsNotFound>()) 169 << "Expected a SymbolsNotFound error"; 170 consumeError(std::move(Err)); 171 } 172 173 { 174 // Attempt 2: Search for a symbol that is still materializing, Baz. 175 auto Err = JD.remove({Foo, Bar, Baz}); 176 EXPECT_TRUE(!!Err) << "Expected failure"; 177 EXPECT_TRUE(Err.isA<SymbolsCouldNotBeRemoved>()) 178 << "Expected a SymbolsNotFound error"; 179 consumeError(std::move(Err)); 180 } 181 182 BazR->resolve({{Baz, BazSym}}); 183 BazR->emit(); 184 { 185 // Attempt 3: Search now that all symbols are fully materialized 186 // (Foo, Baz), or not yet materialized (Bar). 187 auto Err = JD.remove({Foo, Bar, Baz}); 188 EXPECT_FALSE(!!Err) << "Expected failure"; 189 } 190 191 EXPECT_TRUE(BarDiscarded) << "\"Bar\" should have been discarded"; 192 EXPECT_TRUE(BarMaterializerDestructed) 193 << "\"Bar\"'s materializer should have been destructed"; 194 EXPECT_TRUE(OnResolvedRun) << "OnResolved should have been run"; 195 EXPECT_TRUE(OnReadyRun) << "OnReady should have been run"; 196 } 197 198 TEST_F(CoreAPIsStandardTest, ChainedJITDylibLookup) { 199 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 200 201 auto &JD2 = ES.createJITDylib("JD2"); 202 203 bool OnResolvedRun = false; 204 bool OnReadyRun = false; 205 206 auto Q = std::make_shared<AsynchronousSymbolQuery>( 207 SymbolNameSet({Foo}), 208 [&](Expected<SymbolMap> Result) { 209 cantFail(std::move(Result)); 210 OnResolvedRun = true; 211 }, 212 [&](Error Err) { 213 cantFail(std::move(Err)); 214 OnReadyRun = true; 215 }); 216 217 JD2.legacyLookup(Q, JD.legacyLookup(Q, {Foo})); 218 219 EXPECT_TRUE(OnResolvedRun) << "OnResolved was not run for empty query"; 220 EXPECT_TRUE(OnReadyRun) << "OnReady was not run for empty query"; 221 } 222 223 TEST_F(CoreAPIsStandardTest, LookupWithHiddenSymbols) { 224 auto BarHiddenFlags = BarSym.getFlags() & ~JITSymbolFlags::Exported; 225 auto BarHiddenSym = JITEvaluatedSymbol(BarSym.getAddress(), BarHiddenFlags); 226 227 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}, {Bar, BarHiddenSym}}))); 228 229 auto &JD2 = ES.createJITDylib("JD2"); 230 cantFail(JD2.define(absoluteSymbols({{Bar, QuxSym}}))); 231 232 auto Result = cantFail(ES.lookup({&JD, &JD2}, {Foo, Bar})); 233 234 EXPECT_EQ(Result.size(), 2U) << "Unexpected number of results"; 235 EXPECT_EQ(Result.count(Foo), 1U) << "Missing result for \"Foo\""; 236 EXPECT_EQ(Result.count(Bar), 1U) << "Missing result for \"Bar\""; 237 EXPECT_EQ(Result[Bar].getAddress(), QuxSym.getAddress()) 238 << "Wrong result for \"Bar\""; 239 } 240 241 TEST_F(CoreAPIsStandardTest, LookupFlagsTest) { 242 // Test that lookupFlags works on a predefined symbol, and does not trigger 243 // materialization of a lazy symbol. Make the lazy symbol weak to test that 244 // the weak flag is propagated correctly. 245 246 BarSym.setFlags(static_cast<JITSymbolFlags::FlagNames>( 247 JITSymbolFlags::Exported | JITSymbolFlags::Weak)); 248 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 249 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 250 [](MaterializationResponsibility R) { 251 llvm_unreachable("Symbol materialized on flags lookup"); 252 }); 253 254 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 255 cantFail(JD.define(std::move(MU))); 256 257 SymbolNameSet Names({Foo, Bar, Baz}); 258 259 auto SymbolFlags = JD.lookupFlags(Names); 260 261 EXPECT_EQ(SymbolFlags.size(), 2U) 262 << "Returned symbol flags contains unexpected results"; 263 EXPECT_EQ(SymbolFlags.count(Foo), 1U) << "Missing lookupFlags result for Foo"; 264 EXPECT_EQ(SymbolFlags[Foo], FooSym.getFlags()) 265 << "Incorrect flags returned for Foo"; 266 EXPECT_EQ(SymbolFlags.count(Bar), 1U) 267 << "Missing lookupFlags result for Bar"; 268 EXPECT_EQ(SymbolFlags[Bar], BarSym.getFlags()) 269 << "Incorrect flags returned for Bar"; 270 } 271 272 TEST_F(CoreAPIsStandardTest, TestBasicAliases) { 273 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}, {Bar, BarSym}}))); 274 cantFail(JD.define(symbolAliases({{Baz, {Foo, JITSymbolFlags::Exported}}, 275 {Qux, {Bar, JITSymbolFlags::Weak}}}))); 276 cantFail(JD.define(absoluteSymbols({{Qux, QuxSym}}))); 277 278 auto Result = ES.lookup({&JD}, {Baz, Qux}); 279 EXPECT_TRUE(!!Result) << "Unexpected lookup failure"; 280 EXPECT_EQ(Result->count(Baz), 1U) << "No result for \"baz\""; 281 EXPECT_EQ(Result->count(Qux), 1U) << "No result for \"qux\""; 282 EXPECT_EQ((*Result)[Baz].getAddress(), FooSym.getAddress()) 283 << "\"Baz\"'s address should match \"Foo\"'s"; 284 EXPECT_EQ((*Result)[Qux].getAddress(), QuxSym.getAddress()) 285 << "The \"Qux\" alias should have been overriden"; 286 } 287 288 TEST_F(CoreAPIsStandardTest, TestChainedAliases) { 289 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 290 cantFail(JD.define(symbolAliases( 291 {{Baz, {Bar, BazSym.getFlags()}}, {Bar, {Foo, BarSym.getFlags()}}}))); 292 293 auto Result = ES.lookup({&JD}, {Bar, Baz}); 294 EXPECT_TRUE(!!Result) << "Unexpected lookup failure"; 295 EXPECT_EQ(Result->count(Bar), 1U) << "No result for \"bar\""; 296 EXPECT_EQ(Result->count(Baz), 1U) << "No result for \"baz\""; 297 EXPECT_EQ((*Result)[Bar].getAddress(), FooSym.getAddress()) 298 << "\"Bar\"'s address should match \"Foo\"'s"; 299 EXPECT_EQ((*Result)[Baz].getAddress(), FooSym.getAddress()) 300 << "\"Baz\"'s address should match \"Foo\"'s"; 301 } 302 303 TEST_F(CoreAPIsStandardTest, TestBasicReExports) { 304 // Test that the basic use case of re-exporting a single symbol from another 305 // JITDylib works. 306 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 307 308 auto &JD2 = ES.createJITDylib("JD2"); 309 310 cantFail(JD2.define(reexports(JD, {{Bar, {Foo, BarSym.getFlags()}}}))); 311 312 auto Result = cantFail(ES.lookup({&JD2}, Bar)); 313 EXPECT_EQ(Result.getAddress(), FooSym.getAddress()) 314 << "Re-export Bar for symbol Foo should match FooSym's address"; 315 } 316 317 TEST_F(CoreAPIsStandardTest, TestThatReExportsDontUnnecessarilyMaterialize) { 318 // Test that re-exports do not materialize symbols that have not been queried 319 // for. 320 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 321 322 bool BarMaterialized = false; 323 auto BarMU = llvm::make_unique<SimpleMaterializationUnit>( 324 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 325 [&](MaterializationResponsibility R) { 326 BarMaterialized = true; 327 R.resolve({{Bar, BarSym}}); 328 R.emit(); 329 }); 330 331 cantFail(JD.define(BarMU)); 332 333 auto &JD2 = ES.createJITDylib("JD2"); 334 335 cantFail(JD2.define(reexports( 336 JD, {{Baz, {Foo, BazSym.getFlags()}}, {Qux, {Bar, QuxSym.getFlags()}}}))); 337 338 auto Result = cantFail(ES.lookup({&JD2}, Baz)); 339 EXPECT_EQ(Result.getAddress(), FooSym.getAddress()) 340 << "Re-export Baz for symbol Foo should match FooSym's address"; 341 342 EXPECT_FALSE(BarMaterialized) << "Bar should not have been materialized"; 343 } 344 345 TEST_F(CoreAPIsStandardTest, TestReexportsGenerator) { 346 // Test that a re-exports generator can dynamically generate reexports. 347 348 auto &JD2 = ES.createJITDylib("JD2"); 349 cantFail(JD2.define(absoluteSymbols({{Foo, FooSym}, {Bar, BarSym}}))); 350 351 auto Filter = [this](SymbolStringPtr Name) { return Name != Bar; }; 352 353 JD.setGenerator(ReexportsGenerator(JD2, Filter)); 354 355 auto Flags = JD.lookupFlags({Foo, Bar, Baz}); 356 EXPECT_EQ(Flags.size(), 1U) << "Unexpected number of results"; 357 EXPECT_EQ(Flags[Foo], FooSym.getFlags()) << "Unexpected flags for Foo"; 358 359 auto Result = cantFail(ES.lookup({&JD}, Foo)); 360 361 EXPECT_EQ(Result.getAddress(), FooSym.getAddress()) 362 << "Incorrect reexported symbol address"; 363 } 364 365 TEST_F(CoreAPIsStandardTest, TestTrivialCircularDependency) { 366 Optional<MaterializationResponsibility> FooR; 367 auto FooMU = llvm::make_unique<SimpleMaterializationUnit>( 368 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 369 [&](MaterializationResponsibility R) { FooR.emplace(std::move(R)); }); 370 371 cantFail(JD.define(FooMU)); 372 373 bool FooReady = false; 374 auto OnResolution = [](Expected<SymbolMap> R) { cantFail(std::move(R)); }; 375 auto OnReady = [&](Error Err) { 376 cantFail(std::move(Err)); 377 FooReady = true; 378 }; 379 380 ES.lookup({&JD}, {Foo}, std::move(OnResolution), std::move(OnReady), 381 NoDependenciesToRegister); 382 383 FooR->resolve({{Foo, FooSym}}); 384 FooR->emit(); 385 386 EXPECT_TRUE(FooReady) 387 << "Self-dependency prevented symbol from being marked ready"; 388 } 389 390 TEST_F(CoreAPIsStandardTest, TestCircularDependenceInOneJITDylib) { 391 // Test that a circular symbol dependency between three symbols in a JITDylib 392 // does not prevent any symbol from becoming 'ready' once all symbols are 393 // emitted. 394 395 // Create three MaterializationResponsibility objects: one for each of Foo, 396 // Bar and Baz. These are optional because MaterializationResponsibility 397 // does not have a default constructor). 398 Optional<MaterializationResponsibility> FooR; 399 Optional<MaterializationResponsibility> BarR; 400 Optional<MaterializationResponsibility> BazR; 401 402 // Create a MaterializationUnit for each symbol that moves the 403 // MaterializationResponsibility into one of the locals above. 404 auto FooMU = llvm::make_unique<SimpleMaterializationUnit>( 405 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 406 [&](MaterializationResponsibility R) { FooR.emplace(std::move(R)); }); 407 408 auto BarMU = llvm::make_unique<SimpleMaterializationUnit>( 409 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 410 [&](MaterializationResponsibility R) { BarR.emplace(std::move(R)); }); 411 412 auto BazMU = llvm::make_unique<SimpleMaterializationUnit>( 413 SymbolFlagsMap({{Baz, BazSym.getFlags()}}), 414 [&](MaterializationResponsibility R) { BazR.emplace(std::move(R)); }); 415 416 // Define the symbols. 417 cantFail(JD.define(FooMU)); 418 cantFail(JD.define(BarMU)); 419 cantFail(JD.define(BazMU)); 420 421 // Query each of the symbols to trigger materialization. 422 bool FooResolved = false; 423 bool FooReady = false; 424 425 auto OnFooResolution = [&](Expected<SymbolMap> Result) { 426 cantFail(std::move(Result)); 427 FooResolved = true; 428 }; 429 430 auto OnFooReady = [&](Error Err) { 431 cantFail(std::move(Err)); 432 FooReady = true; 433 }; 434 435 // Issue a lookup for Foo. Use NoDependenciesToRegister: We're going to add 436 // the dependencies manually below. 437 ES.lookup({&JD}, {Foo}, std::move(OnFooResolution), std::move(OnFooReady), 438 NoDependenciesToRegister); 439 440 bool BarResolved = false; 441 bool BarReady = false; 442 auto OnBarResolution = [&](Expected<SymbolMap> Result) { 443 cantFail(std::move(Result)); 444 BarResolved = true; 445 }; 446 447 auto OnBarReady = [&](Error Err) { 448 cantFail(std::move(Err)); 449 BarReady = true; 450 }; 451 452 ES.lookup({&JD}, {Bar}, std::move(OnBarResolution), std::move(OnBarReady), 453 NoDependenciesToRegister); 454 455 bool BazResolved = false; 456 bool BazReady = false; 457 458 auto OnBazResolution = [&](Expected<SymbolMap> Result) { 459 cantFail(std::move(Result)); 460 BazResolved = true; 461 }; 462 463 auto OnBazReady = [&](Error Err) { 464 cantFail(std::move(Err)); 465 BazReady = true; 466 }; 467 468 ES.lookup({&JD}, {Baz}, std::move(OnBazResolution), std::move(OnBazReady), 469 NoDependenciesToRegister); 470 471 // Add a circular dependency: Foo -> Bar, Bar -> Baz, Baz -> Foo. 472 FooR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}}); 473 BarR->addDependenciesForAll({{&JD, SymbolNameSet({Baz})}}); 474 BazR->addDependenciesForAll({{&JD, SymbolNameSet({Foo})}}); 475 476 // Add self-dependencies for good measure. This tests that the implementation 477 // of addDependencies filters these out. 478 FooR->addDependenciesForAll({{&JD, SymbolNameSet({Foo})}}); 479 BarR->addDependenciesForAll({{&JD, SymbolNameSet({Bar})}}); 480 BazR->addDependenciesForAll({{&JD, SymbolNameSet({Baz})}}); 481 482 // Check that nothing has been resolved yet. 483 EXPECT_FALSE(FooResolved) << "\"Foo\" should not be resolved yet"; 484 EXPECT_FALSE(BarResolved) << "\"Bar\" should not be resolved yet"; 485 EXPECT_FALSE(BazResolved) << "\"Baz\" should not be resolved yet"; 486 487 // Resolve the symbols (but do not emit them). 488 FooR->resolve({{Foo, FooSym}}); 489 BarR->resolve({{Bar, BarSym}}); 490 BazR->resolve({{Baz, BazSym}}); 491 492 // Verify that the symbols have been resolved, but are not ready yet. 493 EXPECT_TRUE(FooResolved) << "\"Foo\" should be resolved now"; 494 EXPECT_TRUE(BarResolved) << "\"Bar\" should be resolved now"; 495 EXPECT_TRUE(BazResolved) << "\"Baz\" should be resolved now"; 496 497 EXPECT_FALSE(FooReady) << "\"Foo\" should not be ready yet"; 498 EXPECT_FALSE(BarReady) << "\"Bar\" should not be ready yet"; 499 EXPECT_FALSE(BazReady) << "\"Baz\" should not be ready yet"; 500 501 // Emit two of the symbols. 502 FooR->emit(); 503 BarR->emit(); 504 505 // Verify that nothing is ready until the circular dependence is resolved. 506 EXPECT_FALSE(FooReady) << "\"Foo\" still should not be ready"; 507 EXPECT_FALSE(BarReady) << "\"Bar\" still should not be ready"; 508 EXPECT_FALSE(BazReady) << "\"Baz\" still should not be ready"; 509 510 // Emit the last symbol. 511 BazR->emit(); 512 513 // Verify that everything becomes ready once the circular dependence resolved. 514 EXPECT_TRUE(FooReady) << "\"Foo\" should be ready now"; 515 EXPECT_TRUE(BarReady) << "\"Bar\" should be ready now"; 516 EXPECT_TRUE(BazReady) << "\"Baz\" should be ready now"; 517 } 518 519 TEST_F(CoreAPIsStandardTest, DropMaterializerWhenEmpty) { 520 bool DestructorRun = false; 521 522 JITSymbolFlags WeakExported(JITSymbolFlags::Exported); 523 WeakExported |= JITSymbolFlags::Weak; 524 525 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 526 SymbolFlagsMap({{Foo, WeakExported}, {Bar, WeakExported}}), 527 [](MaterializationResponsibility R) { 528 llvm_unreachable("Unexpected call to materialize"); 529 }, 530 [&](const JITDylib &JD, SymbolStringPtr Name) { 531 EXPECT_TRUE(Name == Foo || Name == Bar) 532 << "Discard of unexpected symbol?"; 533 }, 534 [&]() { DestructorRun = true; }); 535 536 cantFail(JD.define(MU)); 537 538 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 539 540 EXPECT_FALSE(DestructorRun) 541 << "MaterializationUnit should not have been destroyed yet"; 542 543 cantFail(JD.define(absoluteSymbols({{Bar, BarSym}}))); 544 545 EXPECT_TRUE(DestructorRun) 546 << "MaterializationUnit should have been destroyed"; 547 } 548 549 TEST_F(CoreAPIsStandardTest, AddAndMaterializeLazySymbol) { 550 bool FooMaterialized = false; 551 bool BarDiscarded = false; 552 553 JITSymbolFlags WeakExported(JITSymbolFlags::Exported); 554 WeakExported |= JITSymbolFlags::Weak; 555 556 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 557 SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}, {Bar, WeakExported}}), 558 [&](MaterializationResponsibility R) { 559 assert(BarDiscarded && "Bar should have been discarded by this point"); 560 R.resolve(SymbolMap({{Foo, FooSym}})); 561 R.emit(); 562 FooMaterialized = true; 563 }, 564 [&](const JITDylib &JD, SymbolStringPtr Name) { 565 EXPECT_EQ(Name, Bar) << "Expected Name to be Bar"; 566 BarDiscarded = true; 567 }); 568 569 cantFail(JD.define(MU)); 570 cantFail(JD.define(absoluteSymbols({{Bar, BarSym}}))); 571 572 SymbolNameSet Names({Foo}); 573 574 bool OnResolutionRun = false; 575 bool OnReadyRun = false; 576 577 auto OnResolution = [&](Expected<SymbolMap> Result) { 578 EXPECT_TRUE(!!Result) << "Resolution unexpectedly returned error"; 579 auto I = Result->find(Foo); 580 EXPECT_NE(I, Result->end()) << "Could not find symbol definition"; 581 EXPECT_EQ(I->second.getAddress(), FooSym.getAddress()) 582 << "Resolution returned incorrect result"; 583 OnResolutionRun = true; 584 }; 585 586 auto OnReady = [&](Error Err) { 587 cantFail(std::move(Err)); 588 OnReadyRun = true; 589 }; 590 591 ES.lookup({&JD}, Names, std::move(OnResolution), std::move(OnReady), 592 NoDependenciesToRegister); 593 594 EXPECT_TRUE(FooMaterialized) << "Foo was not materialized"; 595 EXPECT_TRUE(BarDiscarded) << "Bar was not discarded"; 596 EXPECT_TRUE(OnResolutionRun) << "OnResolutionCallback was not run"; 597 EXPECT_TRUE(OnReadyRun) << "OnReady was not run"; 598 } 599 600 TEST_F(CoreAPIsStandardTest, TestBasicWeakSymbolMaterialization) { 601 // Test that weak symbols are materialized correctly when we look them up. 602 BarSym.setFlags(BarSym.getFlags() | JITSymbolFlags::Weak); 603 604 bool BarMaterialized = false; 605 auto MU1 = llvm::make_unique<SimpleMaterializationUnit>( 606 SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}), 607 [&](MaterializationResponsibility R) { 608 R.resolve(SymbolMap({{Foo, FooSym}, {Bar, BarSym}})), R.emit(); 609 BarMaterialized = true; 610 }); 611 612 bool DuplicateBarDiscarded = false; 613 auto MU2 = llvm::make_unique<SimpleMaterializationUnit>( 614 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 615 [&](MaterializationResponsibility R) { 616 ADD_FAILURE() << "Attempt to materialize Bar from the wrong unit"; 617 R.failMaterialization(); 618 }, 619 [&](const JITDylib &JD, SymbolStringPtr Name) { 620 EXPECT_EQ(Name, Bar) << "Expected \"Bar\" to be discarded"; 621 DuplicateBarDiscarded = true; 622 }); 623 624 cantFail(JD.define(MU1)); 625 cantFail(JD.define(MU2)); 626 627 bool OnResolvedRun = false; 628 bool OnReadyRun = false; 629 630 auto OnResolution = [&](Expected<SymbolMap> Result) { 631 cantFail(std::move(Result)); 632 OnResolvedRun = true; 633 }; 634 635 auto OnReady = [&](Error Err) { 636 cantFail(std::move(Err)); 637 OnReadyRun = true; 638 }; 639 640 ES.lookup({&JD}, {Bar}, std::move(OnResolution), std::move(OnReady), 641 NoDependenciesToRegister); 642 643 EXPECT_TRUE(OnResolvedRun) << "OnResolved not run"; 644 EXPECT_TRUE(OnReadyRun) << "OnReady not run"; 645 EXPECT_TRUE(BarMaterialized) << "Bar was not materialized at all"; 646 EXPECT_TRUE(DuplicateBarDiscarded) 647 << "Duplicate bar definition not discarded"; 648 } 649 650 TEST_F(CoreAPIsStandardTest, DefineMaterializingSymbol) { 651 bool ExpectNoMoreMaterialization = false; 652 ES.setDispatchMaterialization( 653 [&](JITDylib &JD, std::unique_ptr<MaterializationUnit> MU) { 654 if (ExpectNoMoreMaterialization) 655 ADD_FAILURE() << "Unexpected materialization"; 656 MU->doMaterialize(JD); 657 }); 658 659 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 660 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 661 [&](MaterializationResponsibility R) { 662 cantFail( 663 R.defineMaterializing(SymbolFlagsMap({{Bar, BarSym.getFlags()}}))); 664 R.resolve(SymbolMap({{Foo, FooSym}, {Bar, BarSym}})); 665 R.emit(); 666 }); 667 668 cantFail(JD.define(MU)); 669 cantFail(ES.lookup({&JD}, Foo)); 670 671 // Assert that materialization is complete by now. 672 ExpectNoMoreMaterialization = true; 673 674 // Look up bar to verify that no further materialization happens. 675 auto BarResult = cantFail(ES.lookup({&JD}, Bar)); 676 EXPECT_EQ(BarResult.getAddress(), BarSym.getAddress()) 677 << "Expected Bar == BarSym"; 678 } 679 680 TEST_F(CoreAPIsStandardTest, GeneratorTest) { 681 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 682 683 JD.setGenerator([&](JITDylib &JD2, const SymbolNameSet &Names) { 684 cantFail(JD2.define(absoluteSymbols({{Bar, BarSym}}))); 685 return SymbolNameSet({Bar}); 686 }); 687 688 auto Result = cantFail(ES.lookup({&JD}, {Foo, Bar})); 689 690 EXPECT_EQ(Result.count(Bar), 1U) << "Expected to find fallback def for 'bar'"; 691 EXPECT_EQ(Result[Bar].getAddress(), BarSym.getAddress()) 692 << "Expected fallback def for Bar to be equal to BarSym"; 693 } 694 695 TEST_F(CoreAPIsStandardTest, FailResolution) { 696 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 697 SymbolFlagsMap({{Foo, JITSymbolFlags::Exported | JITSymbolFlags::Weak}, 698 {Bar, JITSymbolFlags::Exported | JITSymbolFlags::Weak}}), 699 [&](MaterializationResponsibility R) { R.failMaterialization(); }); 700 701 cantFail(JD.define(MU)); 702 703 SymbolNameSet Names({Foo, Bar}); 704 auto Result = ES.lookup({&JD}, Names); 705 706 EXPECT_FALSE(!!Result) << "Expected failure"; 707 if (!Result) { 708 handleAllErrors(Result.takeError(), 709 [&](FailedToMaterialize &F) { 710 EXPECT_EQ(F.getSymbols(), Names) 711 << "Expected to fail on symbols in Names"; 712 }, 713 [](ErrorInfoBase &EIB) { 714 std::string ErrMsg; 715 { 716 raw_string_ostream ErrOut(ErrMsg); 717 EIB.log(ErrOut); 718 } 719 ADD_FAILURE() 720 << "Expected a FailedToResolve error. Got:\n" 721 << ErrMsg; 722 }); 723 } 724 } 725 726 TEST_F(CoreAPIsStandardTest, TestLookupWithUnthreadedMaterialization) { 727 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 728 SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}}), 729 [&](MaterializationResponsibility R) { 730 R.resolve({{Foo, FooSym}}); 731 R.emit(); 732 }); 733 734 cantFail(JD.define(MU)); 735 736 auto FooLookupResult = cantFail(ES.lookup({&JD}, Foo)); 737 738 EXPECT_EQ(FooLookupResult.getAddress(), FooSym.getAddress()) 739 << "lookup returned an incorrect address"; 740 EXPECT_EQ(FooLookupResult.getFlags(), FooSym.getFlags()) 741 << "lookup returned incorrect flags"; 742 } 743 744 TEST_F(CoreAPIsStandardTest, TestLookupWithThreadedMaterialization) { 745 #if LLVM_ENABLE_THREADS 746 747 std::thread MaterializationThread; 748 ES.setDispatchMaterialization( 749 [&](JITDylib &JD, std::unique_ptr<MaterializationUnit> MU) { 750 auto SharedMU = std::shared_ptr<MaterializationUnit>(std::move(MU)); 751 MaterializationThread = 752 std::thread([SharedMU, &JD]() { SharedMU->doMaterialize(JD); }); 753 }); 754 755 cantFail(JD.define(absoluteSymbols({{Foo, FooSym}}))); 756 757 auto FooLookupResult = cantFail(ES.lookup({&JD}, Foo)); 758 759 EXPECT_EQ(FooLookupResult.getAddress(), FooSym.getAddress()) 760 << "lookup returned an incorrect address"; 761 EXPECT_EQ(FooLookupResult.getFlags(), FooSym.getFlags()) 762 << "lookup returned incorrect flags"; 763 MaterializationThread.join(); 764 #endif 765 } 766 767 TEST_F(CoreAPIsStandardTest, TestGetRequestedSymbolsAndReplace) { 768 // Test that GetRequestedSymbols returns the set of symbols that currently 769 // have pending queries, and test that MaterializationResponsibility's 770 // replace method can be used to return definitions to the JITDylib in a new 771 // MaterializationUnit. 772 SymbolNameSet Names({Foo, Bar}); 773 774 bool FooMaterialized = false; 775 bool BarMaterialized = false; 776 777 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 778 SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}), 779 [&](MaterializationResponsibility R) { 780 auto Requested = R.getRequestedSymbols(); 781 EXPECT_EQ(Requested.size(), 1U) << "Expected one symbol requested"; 782 EXPECT_EQ(*Requested.begin(), Foo) << "Expected \"Foo\" requested"; 783 784 auto NewMU = llvm::make_unique<SimpleMaterializationUnit>( 785 SymbolFlagsMap({{Bar, BarSym.getFlags()}}), 786 [&](MaterializationResponsibility R2) { 787 R2.resolve(SymbolMap({{Bar, BarSym}})); 788 R2.emit(); 789 BarMaterialized = true; 790 }); 791 792 R.replace(std::move(NewMU)); 793 794 R.resolve(SymbolMap({{Foo, FooSym}})); 795 R.emit(); 796 797 FooMaterialized = true; 798 }); 799 800 cantFail(JD.define(MU)); 801 802 EXPECT_FALSE(FooMaterialized) << "Foo should not be materialized yet"; 803 EXPECT_FALSE(BarMaterialized) << "Bar should not be materialized yet"; 804 805 auto FooSymResult = cantFail(ES.lookup({&JD}, Foo)); 806 EXPECT_EQ(FooSymResult.getAddress(), FooSym.getAddress()) 807 << "Address mismatch for Foo"; 808 809 EXPECT_TRUE(FooMaterialized) << "Foo should be materialized now"; 810 EXPECT_FALSE(BarMaterialized) << "Bar still should not be materialized"; 811 812 auto BarSymResult = cantFail(ES.lookup({&JD}, Bar)); 813 EXPECT_EQ(BarSymResult.getAddress(), BarSym.getAddress()) 814 << "Address mismatch for Bar"; 815 EXPECT_TRUE(BarMaterialized) << "Bar should be materialized now"; 816 } 817 818 TEST_F(CoreAPIsStandardTest, TestMaterializationResponsibilityDelegation) { 819 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 820 SymbolFlagsMap({{Foo, FooSym.getFlags()}, {Bar, BarSym.getFlags()}}), 821 [&](MaterializationResponsibility R) { 822 auto R2 = R.delegate({Bar}); 823 824 R.resolve({{Foo, FooSym}}); 825 R.emit(); 826 R2.resolve({{Bar, BarSym}}); 827 R2.emit(); 828 }); 829 830 cantFail(JD.define(MU)); 831 832 auto Result = ES.lookup({&JD}, {Foo, Bar}); 833 834 EXPECT_TRUE(!!Result) << "Result should be a success value"; 835 EXPECT_EQ(Result->count(Foo), 1U) << "\"Foo\" entry missing"; 836 EXPECT_EQ(Result->count(Bar), 1U) << "\"Bar\" entry missing"; 837 EXPECT_EQ((*Result)[Foo].getAddress(), FooSym.getAddress()) 838 << "Address mismatch for \"Foo\""; 839 EXPECT_EQ((*Result)[Bar].getAddress(), BarSym.getAddress()) 840 << "Address mismatch for \"Bar\""; 841 } 842 843 TEST_F(CoreAPIsStandardTest, TestMaterializeWeakSymbol) { 844 // Confirm that once a weak definition is selected for materialization it is 845 // treated as strong. 846 JITSymbolFlags WeakExported = JITSymbolFlags::Exported; 847 WeakExported &= JITSymbolFlags::Weak; 848 849 std::unique_ptr<MaterializationResponsibility> FooResponsibility; 850 auto MU = llvm::make_unique<SimpleMaterializationUnit>( 851 SymbolFlagsMap({{Foo, FooSym.getFlags()}}), 852 [&](MaterializationResponsibility R) { 853 FooResponsibility = 854 llvm::make_unique<MaterializationResponsibility>(std::move(R)); 855 }); 856 857 cantFail(JD.define(MU)); 858 auto OnResolution = [](Expected<SymbolMap> Result) { 859 cantFail(std::move(Result)); 860 }; 861 862 auto OnReady = [](Error Err) { cantFail(std::move(Err)); }; 863 864 ES.lookup({&JD}, {Foo}, std::move(OnResolution), std::move(OnReady), 865 NoDependenciesToRegister); 866 867 auto MU2 = llvm::make_unique<SimpleMaterializationUnit>( 868 SymbolFlagsMap({{Foo, JITSymbolFlags::Exported}}), 869 [](MaterializationResponsibility R) { 870 llvm_unreachable("This unit should never be materialized"); 871 }); 872 873 auto Err = JD.define(MU2); 874 EXPECT_TRUE(!!Err) << "Expected failure value"; 875 EXPECT_TRUE(Err.isA<DuplicateDefinition>()) 876 << "Expected a duplicate definition error"; 877 consumeError(std::move(Err)); 878 879 FooResponsibility->resolve(SymbolMap({{Foo, FooSym}})); 880 FooResponsibility->emit(); 881 } 882 883 } // namespace 884