1 //===--- Core.cpp - Core ORC APIs (MaterializationUnit, JITDylib, etc.) ---===// 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 "llvm/ExecutionEngine/Orc/Core.h" 11 #include "llvm/Config/llvm-config.h" 12 #include "llvm/ExecutionEngine/Orc/OrcError.h" 13 #include "llvm/IR/Mangler.h" 14 #include "llvm/Support/Debug.h" 15 #include "llvm/Support/Format.h" 16 17 #if LLVM_ENABLE_THREADS 18 #include <future> 19 #endif 20 21 namespace llvm { 22 namespace orc { 23 24 char FailedToMaterialize::ID = 0; 25 char SymbolsNotFound::ID = 0; 26 27 RegisterDependenciesFunction NoDependenciesToRegister = 28 RegisterDependenciesFunction(); 29 30 void MaterializationUnit::anchor() {} 31 32 raw_ostream &operator<<(raw_ostream &OS, const JITSymbolFlags &Flags) { 33 if (Flags.isCallable()) 34 OS << "[Callable]"; 35 else 36 OS << "[Data]"; 37 if (Flags.isWeak()) 38 OS << "[Weak]"; 39 else if (Flags.isCommon()) 40 OS << "[Common]"; 41 42 if (!Flags.isExported()) 43 OS << "[Hidden]"; 44 45 return OS; 46 } 47 48 raw_ostream &operator<<(raw_ostream &OS, const JITEvaluatedSymbol &Sym) { 49 OS << format("0x%016x", Sym.getAddress()) << " " << Sym.getFlags(); 50 return OS; 51 } 52 53 raw_ostream &operator<<(raw_ostream &OS, const SymbolMap::value_type &KV) { 54 OS << "\"" << *KV.first << "\": " << KV.second; 55 return OS; 56 } 57 58 raw_ostream &operator<<(raw_ostream &OS, const SymbolNameSet &Symbols) { 59 OS << "{"; 60 if (!Symbols.empty()) { 61 OS << " \"" << **Symbols.begin() << "\""; 62 for (auto &Sym : make_range(std::next(Symbols.begin()), Symbols.end())) 63 OS << ", \"" << *Sym << "\""; 64 } 65 OS << " }"; 66 return OS; 67 } 68 69 raw_ostream &operator<<(raw_ostream &OS, const SymbolMap &Symbols) { 70 OS << "{"; 71 if (!Symbols.empty()) { 72 OS << " {" << *Symbols.begin() << "}"; 73 for (auto &Sym : make_range(std::next(Symbols.begin()), Symbols.end())) 74 OS << ", {" << Sym << "}"; 75 } 76 OS << " }"; 77 return OS; 78 } 79 80 raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap &SymbolFlags) { 81 OS << "{"; 82 if (!SymbolFlags.empty()) { 83 OS << " {\"" << *SymbolFlags.begin()->first 84 << "\": " << SymbolFlags.begin()->second << "}"; 85 for (auto &KV : 86 make_range(std::next(SymbolFlags.begin()), SymbolFlags.end())) 87 OS << ", {\"" << *KV.first << "\": " << KV.second << "}"; 88 } 89 OS << " }"; 90 return OS; 91 } 92 93 raw_ostream &operator<<(raw_ostream &OS, const SymbolDependenceMap &Deps) { 94 OS << "{"; 95 if (!Deps.empty()) { 96 OS << " { " << Deps.begin()->first->getName() << ": " 97 << Deps.begin()->second << " }"; 98 for (auto &KV : make_range(std::next(Deps.begin()), Deps.end())) 99 OS << ", { " << KV.first->getName() << ": " << KV.second << " }"; 100 } 101 OS << " }"; 102 return OS; 103 } 104 105 raw_ostream &operator<<(raw_ostream &OS, const JITDylibList &JDs) { 106 OS << "["; 107 if (!JDs.empty()) { 108 assert(JDs.front() && "JITDylibList entries must not be null"); 109 OS << " " << JDs.front()->getName(); 110 for (auto *JD : make_range(std::next(JDs.begin()), JDs.end())) { 111 assert(JD && "JITDylibList entries must not be null"); 112 OS << ", " << JD->getName(); 113 } 114 } 115 OS << " ]"; 116 return OS; 117 } 118 119 FailedToMaterialize::FailedToMaterialize(SymbolNameSet Symbols) 120 : Symbols(std::move(Symbols)) { 121 assert(!this->Symbols.empty() && "Can not fail to resolve an empty set"); 122 } 123 124 std::error_code FailedToMaterialize::convertToErrorCode() const { 125 return orcError(OrcErrorCode::UnknownORCError); 126 } 127 128 void FailedToMaterialize::log(raw_ostream &OS) const { 129 OS << "Failed to materialize symbols: " << Symbols; 130 } 131 132 SymbolsNotFound::SymbolsNotFound(SymbolNameSet Symbols) 133 : Symbols(std::move(Symbols)) { 134 assert(!this->Symbols.empty() && "Can not fail to resolve an empty set"); 135 } 136 137 std::error_code SymbolsNotFound::convertToErrorCode() const { 138 return orcError(OrcErrorCode::UnknownORCError); 139 } 140 141 void SymbolsNotFound::log(raw_ostream &OS) const { 142 OS << "Symbols not found: " << Symbols; 143 } 144 145 void ExecutionSessionBase::legacyFailQuery(AsynchronousSymbolQuery &Q, 146 Error Err) { 147 assert(!!Err && "Error should be in failure state"); 148 149 bool SendErrorToQuery; 150 runSessionLocked([&]() { 151 Q.detach(); 152 SendErrorToQuery = Q.canStillFail(); 153 }); 154 155 if (SendErrorToQuery) 156 Q.handleFailed(std::move(Err)); 157 else 158 reportError(std::move(Err)); 159 } 160 161 Expected<SymbolMap> ExecutionSessionBase::legacyLookup( 162 ExecutionSessionBase &ES, LegacyAsyncLookupFunction AsyncLookup, 163 SymbolNameSet Names, bool WaitUntilReady, 164 RegisterDependenciesFunction RegisterDependencies) { 165 #if LLVM_ENABLE_THREADS 166 // In the threaded case we use promises to return the results. 167 std::promise<SymbolMap> PromisedResult; 168 std::mutex ErrMutex; 169 Error ResolutionError = Error::success(); 170 std::promise<void> PromisedReady; 171 Error ReadyError = Error::success(); 172 auto OnResolve = [&](Expected<SymbolMap> R) { 173 if (R) 174 PromisedResult.set_value(std::move(*R)); 175 else { 176 { 177 ErrorAsOutParameter _(&ResolutionError); 178 std::lock_guard<std::mutex> Lock(ErrMutex); 179 ResolutionError = R.takeError(); 180 } 181 PromisedResult.set_value(SymbolMap()); 182 } 183 }; 184 185 std::function<void(Error)> OnReady; 186 if (WaitUntilReady) { 187 OnReady = [&](Error Err) { 188 if (Err) { 189 ErrorAsOutParameter _(&ReadyError); 190 std::lock_guard<std::mutex> Lock(ErrMutex); 191 ReadyError = std::move(Err); 192 } 193 PromisedReady.set_value(); 194 }; 195 } else { 196 OnReady = [&](Error Err) { 197 if (Err) 198 ES.reportError(std::move(Err)); 199 }; 200 } 201 202 #else 203 SymbolMap Result; 204 Error ResolutionError = Error::success(); 205 Error ReadyError = Error::success(); 206 207 auto OnResolve = [&](Expected<SymbolMap> R) { 208 ErrorAsOutParameter _(&ResolutionError); 209 if (R) 210 Result = std::move(*R); 211 else 212 ResolutionError = R.takeError(); 213 }; 214 215 std::function<void(Error)> OnReady; 216 if (WaitUntilReady) { 217 OnReady = [&](Error Err) { 218 ErrorAsOutParameter _(&ReadyError); 219 if (Err) 220 ReadyError = std::move(Err); 221 }; 222 } else { 223 OnReady = [&](Error Err) { 224 if (Err) 225 ES.reportError(std::move(Err)); 226 }; 227 } 228 #endif 229 230 auto Query = std::make_shared<AsynchronousSymbolQuery>( 231 Names, std::move(OnResolve), std::move(OnReady)); 232 // FIXME: This should be run session locked along with the registration code 233 // and error reporting below. 234 SymbolNameSet UnresolvedSymbols = AsyncLookup(Query, std::move(Names)); 235 236 // If the query was lodged successfully then register the dependencies, 237 // otherwise fail it with an error. 238 if (UnresolvedSymbols.empty()) 239 RegisterDependencies(Query->QueryRegistrations); 240 else { 241 bool DeliverError = runSessionLocked([&]() { 242 Query->detach(); 243 return Query->canStillFail(); 244 }); 245 auto Err = make_error<SymbolsNotFound>(std::move(UnresolvedSymbols)); 246 if (DeliverError) 247 Query->handleFailed(std::move(Err)); 248 else 249 ES.reportError(std::move(Err)); 250 } 251 252 #if LLVM_ENABLE_THREADS 253 auto ResultFuture = PromisedResult.get_future(); 254 auto Result = ResultFuture.get(); 255 256 { 257 std::lock_guard<std::mutex> Lock(ErrMutex); 258 if (ResolutionError) { 259 // ReadyError will never be assigned. Consume the success value. 260 cantFail(std::move(ReadyError)); 261 return std::move(ResolutionError); 262 } 263 } 264 265 if (WaitUntilReady) { 266 auto ReadyFuture = PromisedReady.get_future(); 267 ReadyFuture.get(); 268 269 { 270 std::lock_guard<std::mutex> Lock(ErrMutex); 271 if (ReadyError) 272 return std::move(ReadyError); 273 } 274 } else 275 cantFail(std::move(ReadyError)); 276 277 return std::move(Result); 278 279 #else 280 if (ResolutionError) { 281 // ReadyError will never be assigned. Consume the success value. 282 cantFail(std::move(ReadyError)); 283 return std::move(ResolutionError); 284 } 285 286 if (ReadyError) 287 return std::move(ReadyError); 288 289 return Result; 290 #endif 291 } 292 293 void ExecutionSessionBase::lookup( 294 const JITDylibList &JDs, const SymbolNameSet &Symbols, 295 SymbolsResolvedCallback OnResolve, SymbolsReadyCallback OnReady, 296 RegisterDependenciesFunction RegisterDependencies) { 297 298 // lookup can be re-entered recursively if running on a single thread. Run any 299 // outstanding MUs in case this query depends on them, otherwise the main 300 // thread will starve waiting for a result from an MU that it failed to run. 301 runOutstandingMUs(); 302 303 auto Unresolved = std::move(Symbols); 304 std::map<JITDylib *, MaterializationUnitList> MUsMap; 305 auto Q = std::make_shared<AsynchronousSymbolQuery>( 306 Symbols, std::move(OnResolve), std::move(OnReady)); 307 bool QueryIsFullyResolved = false; 308 bool QueryIsFullyReady = false; 309 bool QueryFailed = false; 310 311 runSessionLocked([&]() { 312 for (auto *JD : JDs) { 313 assert(JD && "JITDylibList entries must not be null"); 314 assert(!MUsMap.count(JD) && 315 "JITDylibList should not contain duplicate entries"); 316 JD->lodgeQuery(Q, Unresolved, MUsMap[JD]); 317 } 318 319 if (Unresolved.empty()) { 320 // Query lodged successfully. 321 322 // Record whether this query is fully ready / resolved. We will use 323 // this to call handleFullyResolved/handleFullyReady outside the session 324 // lock. 325 QueryIsFullyResolved = Q->isFullyResolved(); 326 QueryIsFullyReady = Q->isFullyReady(); 327 328 // Call the register dependencies function. 329 if (RegisterDependencies && !Q->QueryRegistrations.empty()) 330 RegisterDependencies(Q->QueryRegistrations); 331 } else { 332 // Query failed due to unresolved symbols. 333 QueryFailed = true; 334 335 // Disconnect the query from its dependencies. 336 Q->detach(); 337 338 // Replace the MUs. 339 for (auto &KV : MUsMap) 340 for (auto &MU : KV.second) 341 KV.first->replace(std::move(MU)); 342 } 343 }); 344 345 if (QueryFailed) { 346 Q->handleFailed(make_error<SymbolsNotFound>(std::move(Unresolved))); 347 return; 348 } else { 349 if (QueryIsFullyResolved) 350 Q->handleFullyResolved(); 351 if (QueryIsFullyReady) 352 Q->handleFullyReady(); 353 } 354 355 // Move the MUs to the OutstandingMUs list, then materialize. 356 { 357 std::lock_guard<std::recursive_mutex> Lock(OutstandingMUsMutex); 358 359 for (auto &KV : MUsMap) 360 for (auto &MU : KV.second) 361 OutstandingMUs.push_back(std::make_pair(KV.first, std::move(MU))); 362 } 363 364 runOutstandingMUs(); 365 } 366 367 Expected<SymbolMap> ExecutionSessionBase::lookup( 368 const JITDylibList &JDs, const SymbolNameSet &Symbols, 369 RegisterDependenciesFunction RegisterDependencies, bool WaitUntilReady) { 370 #if LLVM_ENABLE_THREADS 371 // In the threaded case we use promises to return the results. 372 std::promise<SymbolMap> PromisedResult; 373 std::mutex ErrMutex; 374 Error ResolutionError = Error::success(); 375 std::promise<void> PromisedReady; 376 Error ReadyError = Error::success(); 377 auto OnResolve = [&](Expected<SymbolMap> R) { 378 if (R) 379 PromisedResult.set_value(std::move(*R)); 380 else { 381 { 382 ErrorAsOutParameter _(&ResolutionError); 383 std::lock_guard<std::mutex> Lock(ErrMutex); 384 ResolutionError = R.takeError(); 385 } 386 PromisedResult.set_value(SymbolMap()); 387 } 388 }; 389 390 std::function<void(Error)> OnReady; 391 if (WaitUntilReady) { 392 OnReady = [&](Error Err) { 393 if (Err) { 394 ErrorAsOutParameter _(&ReadyError); 395 std::lock_guard<std::mutex> Lock(ErrMutex); 396 ReadyError = std::move(Err); 397 } 398 PromisedReady.set_value(); 399 }; 400 } else { 401 OnReady = [&](Error Err) { 402 if (Err) 403 reportError(std::move(Err)); 404 }; 405 } 406 407 #else 408 SymbolMap Result; 409 Error ResolutionError = Error::success(); 410 Error ReadyError = Error::success(); 411 412 auto OnResolve = [&](Expected<SymbolMap> R) { 413 ErrorAsOutParameter _(&ResolutionError); 414 if (R) 415 Result = std::move(*R); 416 else 417 ResolutionError = R.takeError(); 418 }; 419 420 std::function<void(Error)> OnReady; 421 if (WaitUntilReady) { 422 OnReady = [&](Error Err) { 423 ErrorAsOutParameter _(&ReadyError); 424 if (Err) 425 ReadyError = std::move(Err); 426 }; 427 } else { 428 OnReady = [&](Error Err) { 429 if (Err) 430 reportError(std::move(Err)); 431 }; 432 } 433 #endif 434 435 // Perform the asynchronous lookup. 436 lookup(JDs, Symbols, OnResolve, OnReady, RegisterDependencies); 437 438 #if LLVM_ENABLE_THREADS 439 auto ResultFuture = PromisedResult.get_future(); 440 auto Result = ResultFuture.get(); 441 442 { 443 std::lock_guard<std::mutex> Lock(ErrMutex); 444 if (ResolutionError) { 445 // ReadyError will never be assigned. Consume the success value. 446 cantFail(std::move(ReadyError)); 447 return std::move(ResolutionError); 448 } 449 } 450 451 if (WaitUntilReady) { 452 auto ReadyFuture = PromisedReady.get_future(); 453 ReadyFuture.get(); 454 455 { 456 std::lock_guard<std::mutex> Lock(ErrMutex); 457 if (ReadyError) 458 return std::move(ReadyError); 459 } 460 } else 461 cantFail(std::move(ReadyError)); 462 463 return std::move(Result); 464 465 #else 466 if (ResolutionError) { 467 // ReadyError will never be assigned. Consume the success value. 468 cantFail(std::move(ReadyError)); 469 return std::move(ResolutionError); 470 } 471 472 if (ReadyError) 473 return std::move(ReadyError); 474 475 return Result; 476 #endif 477 } 478 479 void ExecutionSessionBase::runOutstandingMUs() { 480 while (1) { 481 std::pair<JITDylib *, std::unique_ptr<MaterializationUnit>> JITDylibAndMU; 482 483 { 484 std::lock_guard<std::recursive_mutex> Lock(OutstandingMUsMutex); 485 if (!OutstandingMUs.empty()) { 486 JITDylibAndMU = std::move(OutstandingMUs.back()); 487 OutstandingMUs.pop_back(); 488 } 489 } 490 491 if (JITDylibAndMU.first) { 492 assert(JITDylibAndMU.second && "JITDylib, but no MU?"); 493 dispatchMaterialization(*JITDylibAndMU.first, 494 std::move(JITDylibAndMU.second)); 495 } else 496 break; 497 } 498 } 499 500 AsynchronousSymbolQuery::AsynchronousSymbolQuery( 501 const SymbolNameSet &Symbols, SymbolsResolvedCallback NotifySymbolsResolved, 502 SymbolsReadyCallback NotifySymbolsReady) 503 : NotifySymbolsResolved(std::move(NotifySymbolsResolved)), 504 NotifySymbolsReady(std::move(NotifySymbolsReady)) { 505 NotYetResolvedCount = NotYetReadyCount = Symbols.size(); 506 507 for (auto &S : Symbols) 508 ResolvedSymbols[S] = nullptr; 509 } 510 511 void AsynchronousSymbolQuery::resolve(const SymbolStringPtr &Name, 512 JITEvaluatedSymbol Sym) { 513 auto I = ResolvedSymbols.find(Name); 514 assert(I != ResolvedSymbols.end() && 515 "Resolving symbol outside the requested set"); 516 assert(I->second.getAddress() == 0 && "Redundantly resolving symbol Name"); 517 I->second = std::move(Sym); 518 --NotYetResolvedCount; 519 } 520 521 void AsynchronousSymbolQuery::handleFullyResolved() { 522 assert(NotYetResolvedCount == 0 && "Not fully resolved?"); 523 assert(NotifySymbolsResolved && 524 "NotifySymbolsResolved already called or error occurred"); 525 NotifySymbolsResolved(std::move(ResolvedSymbols)); 526 NotifySymbolsResolved = SymbolsResolvedCallback(); 527 } 528 529 void AsynchronousSymbolQuery::notifySymbolReady() { 530 assert(NotYetReadyCount != 0 && "All symbols already emitted"); 531 --NotYetReadyCount; 532 } 533 534 void AsynchronousSymbolQuery::handleFullyReady() { 535 assert(QueryRegistrations.empty() && 536 "Query is still registered with some symbols"); 537 assert(!NotifySymbolsResolved && "Resolution not applied yet"); 538 NotifySymbolsReady(Error::success()); 539 NotifySymbolsReady = SymbolsReadyCallback(); 540 } 541 542 bool AsynchronousSymbolQuery::canStillFail() { 543 return (NotifySymbolsResolved || NotifySymbolsReady); 544 } 545 546 void AsynchronousSymbolQuery::handleFailed(Error Err) { 547 assert(QueryRegistrations.empty() && ResolvedSymbols.empty() && 548 NotYetResolvedCount == 0 && NotYetReadyCount == 0 && 549 "Query should already have been abandoned"); 550 if (NotifySymbolsResolved) { 551 NotifySymbolsResolved(std::move(Err)); 552 NotifySymbolsResolved = SymbolsResolvedCallback(); 553 } else { 554 assert(NotifySymbolsReady && "Failed after both callbacks issued?"); 555 NotifySymbolsReady(std::move(Err)); 556 } 557 NotifySymbolsReady = SymbolsReadyCallback(); 558 } 559 560 void AsynchronousSymbolQuery::addQueryDependence(JITDylib &JD, 561 SymbolStringPtr Name) { 562 bool Added = QueryRegistrations[&JD].insert(std::move(Name)).second; 563 (void)Added; 564 assert(Added && "Duplicate dependence notification?"); 565 } 566 567 void AsynchronousSymbolQuery::removeQueryDependence( 568 JITDylib &JD, const SymbolStringPtr &Name) { 569 auto QRI = QueryRegistrations.find(&JD); 570 assert(QRI != QueryRegistrations.end() && 571 "No dependencies registered for JD"); 572 assert(QRI->second.count(Name) && "No dependency on Name in JD"); 573 QRI->second.erase(Name); 574 if (QRI->second.empty()) 575 QueryRegistrations.erase(QRI); 576 } 577 578 void AsynchronousSymbolQuery::detach() { 579 ResolvedSymbols.clear(); 580 NotYetResolvedCount = 0; 581 NotYetReadyCount = 0; 582 for (auto &KV : QueryRegistrations) 583 KV.first->detachQueryHelper(*this, KV.second); 584 QueryRegistrations.clear(); 585 } 586 587 MaterializationResponsibility::MaterializationResponsibility( 588 JITDylib &JD, SymbolFlagsMap SymbolFlags) 589 : JD(JD), SymbolFlags(std::move(SymbolFlags)) { 590 assert(!this->SymbolFlags.empty() && "Materializing nothing?"); 591 592 #ifndef NDEBUG 593 for (auto &KV : this->SymbolFlags) 594 KV.second |= JITSymbolFlags::Materializing; 595 #endif 596 } 597 598 MaterializationResponsibility::~MaterializationResponsibility() { 599 assert(SymbolFlags.empty() && 600 "All symbols should have been explicitly materialized or failed"); 601 } 602 603 SymbolNameSet MaterializationResponsibility::getRequestedSymbols() { 604 return JD.getRequestedSymbols(SymbolFlags); 605 } 606 607 void MaterializationResponsibility::resolve(const SymbolMap &Symbols) { 608 #ifndef NDEBUG 609 for (auto &KV : Symbols) { 610 auto I = SymbolFlags.find(KV.first); 611 assert(I != SymbolFlags.end() && 612 "Resolving symbol outside this responsibility set"); 613 assert(I->second.isMaterializing() && "Duplicate resolution"); 614 I->second &= ~JITSymbolFlags::Materializing; 615 if (I->second.isWeak()) 616 assert(I->second == (KV.second.getFlags() | JITSymbolFlags::Weak) && 617 "Resolving symbol with incorrect flags"); 618 else 619 assert(I->second == KV.second.getFlags() && 620 "Resolving symbol with incorrect flags"); 621 } 622 #endif 623 624 JD.resolve(Symbols); 625 } 626 627 void MaterializationResponsibility::emit() { 628 #ifndef NDEBUG 629 for (auto &KV : SymbolFlags) 630 assert(!KV.second.isMaterializing() && 631 "Failed to resolve symbol before emission"); 632 #endif // NDEBUG 633 634 JD.emit(SymbolFlags); 635 SymbolFlags.clear(); 636 } 637 638 Error MaterializationResponsibility::defineMaterializing( 639 const SymbolFlagsMap &NewSymbolFlags) { 640 // Add the given symbols to this responsibility object. 641 // It's ok if we hit a duplicate here: In that case the new version will be 642 // discarded, and the JITDylib::defineMaterializing method will return a 643 // duplicate symbol error. 644 for (auto &KV : NewSymbolFlags) { 645 auto I = SymbolFlags.insert(KV).first; 646 (void)I; 647 #ifndef NDEBUG 648 I->second |= JITSymbolFlags::Materializing; 649 #endif 650 } 651 652 return JD.defineMaterializing(NewSymbolFlags); 653 } 654 655 void MaterializationResponsibility::failMaterialization() { 656 657 SymbolNameSet FailedSymbols; 658 for (auto &KV : SymbolFlags) 659 FailedSymbols.insert(KV.first); 660 661 JD.notifyFailed(FailedSymbols); 662 SymbolFlags.clear(); 663 } 664 665 void MaterializationResponsibility::replace( 666 std::unique_ptr<MaterializationUnit> MU) { 667 for (auto &KV : MU->getSymbols()) 668 SymbolFlags.erase(KV.first); 669 670 JD.replace(std::move(MU)); 671 } 672 673 MaterializationResponsibility 674 MaterializationResponsibility::delegate(const SymbolNameSet &Symbols) { 675 SymbolFlagsMap DelegatedFlags; 676 677 for (auto &Name : Symbols) { 678 auto I = SymbolFlags.find(Name); 679 assert(I != SymbolFlags.end() && 680 "Symbol is not tracked by this MaterializationResponsibility " 681 "instance"); 682 683 DelegatedFlags[Name] = std::move(I->second); 684 SymbolFlags.erase(I); 685 } 686 687 return MaterializationResponsibility(JD, std::move(DelegatedFlags)); 688 } 689 690 void MaterializationResponsibility::addDependencies( 691 const SymbolStringPtr &Name, const SymbolDependenceMap &Dependencies) { 692 assert(SymbolFlags.count(Name) && 693 "Symbol not covered by this MaterializationResponsibility instance"); 694 JD.addDependencies(Name, Dependencies); 695 } 696 697 void MaterializationResponsibility::addDependenciesForAll( 698 const SymbolDependenceMap &Dependencies) { 699 for (auto &KV : SymbolFlags) 700 JD.addDependencies(KV.first, Dependencies); 701 } 702 703 AbsoluteSymbolsMaterializationUnit::AbsoluteSymbolsMaterializationUnit( 704 SymbolMap Symbols) 705 : MaterializationUnit(extractFlags(Symbols)), Symbols(std::move(Symbols)) {} 706 707 void AbsoluteSymbolsMaterializationUnit::materialize( 708 MaterializationResponsibility R) { 709 R.resolve(Symbols); 710 R.emit(); 711 } 712 713 void AbsoluteSymbolsMaterializationUnit::discard(const JITDylib &JD, 714 SymbolStringPtr Name) { 715 assert(Symbols.count(Name) && "Symbol is not part of this MU"); 716 Symbols.erase(Name); 717 } 718 719 SymbolFlagsMap 720 AbsoluteSymbolsMaterializationUnit::extractFlags(const SymbolMap &Symbols) { 721 SymbolFlagsMap Flags; 722 for (const auto &KV : Symbols) 723 Flags[KV.first] = KV.second.getFlags(); 724 return Flags; 725 } 726 727 ReExportsMaterializationUnit::ReExportsMaterializationUnit( 728 JITDylib *SourceJD, SymbolAliasMap Aliases) 729 : MaterializationUnit(extractFlags(Aliases)), SourceJD(SourceJD), 730 Aliases(std::move(Aliases)) {} 731 732 void ReExportsMaterializationUnit::materialize( 733 MaterializationResponsibility R) { 734 735 auto &ES = R.getTargetJITDylib().getExecutionSession(); 736 JITDylib &TgtJD = R.getTargetJITDylib(); 737 JITDylib &SrcJD = SourceJD ? *SourceJD : TgtJD; 738 739 // Find the set of requested aliases and aliasees. Return any unrequested 740 // aliases back to the JITDylib so as to not prematurely materialize any 741 // aliasees. 742 auto RequestedSymbols = R.getRequestedSymbols(); 743 SymbolAliasMap RequestedAliases; 744 745 for (auto &Name : RequestedSymbols) { 746 auto I = Aliases.find(Name); 747 assert(I != Aliases.end() && "Symbol not found in aliases map?"); 748 RequestedAliases[Name] = std::move(I->second); 749 Aliases.erase(I); 750 } 751 752 if (!Aliases.empty()) { 753 if (SourceJD) 754 R.replace(reexports(*SourceJD, std::move(Aliases))); 755 else 756 R.replace(symbolAliases(std::move(Aliases))); 757 } 758 759 // The OnResolveInfo struct will hold the aliases and responsibilty for each 760 // query in the list. 761 struct OnResolveInfo { 762 OnResolveInfo(MaterializationResponsibility R, SymbolAliasMap Aliases) 763 : R(std::move(R)), Aliases(std::move(Aliases)) {} 764 765 MaterializationResponsibility R; 766 SymbolAliasMap Aliases; 767 }; 768 769 // Build a list of queries to issue. In each round we build the largest set of 770 // aliases that we can resolve without encountering a chain definition of the 771 // form Foo -> Bar, Bar -> Baz. Such a form would deadlock as the query would 772 // be waitin on a symbol that it itself had to resolve. Usually this will just 773 // involve one round and a single query. 774 775 std::vector<std::pair<SymbolNameSet, std::shared_ptr<OnResolveInfo>>> 776 QueryInfos; 777 while (!RequestedAliases.empty()) { 778 SymbolNameSet ResponsibilitySymbols; 779 SymbolNameSet QuerySymbols; 780 SymbolAliasMap QueryAliases; 781 782 for (auto I = RequestedAliases.begin(), E = RequestedAliases.end(); 783 I != E;) { 784 auto Tmp = I++; 785 786 // Chain detected. Skip this symbol for this round. 787 if (&SrcJD == &TgtJD && (QueryAliases.count(Tmp->second.Aliasee) || 788 RequestedAliases.count(Tmp->second.Aliasee))) 789 continue; 790 791 ResponsibilitySymbols.insert(Tmp->first); 792 QuerySymbols.insert(Tmp->second.Aliasee); 793 QueryAliases[Tmp->first] = std::move(Tmp->second); 794 RequestedAliases.erase(Tmp); 795 } 796 assert(!QuerySymbols.empty() && "Alias cycle detected!"); 797 798 auto QueryInfo = std::make_shared<OnResolveInfo>( 799 R.delegate(ResponsibilitySymbols), std::move(QueryAliases)); 800 QueryInfos.push_back( 801 make_pair(std::move(QuerySymbols), std::move(QueryInfo))); 802 } 803 804 // Issue the queries. 805 while (!QueryInfos.empty()) { 806 auto QuerySymbols = std::move(QueryInfos.back().first); 807 auto QueryInfo = std::move(QueryInfos.back().second); 808 809 QueryInfos.pop_back(); 810 811 auto RegisterDependencies = [QueryInfo, 812 &SrcJD](const SymbolDependenceMap &Deps) { 813 // If there were no materializing symbols, just bail out. 814 if (Deps.empty()) 815 return; 816 817 // Otherwise the only deps should be on SrcJD. 818 assert(Deps.size() == 1 && Deps.count(&SrcJD) && 819 "Unexpected dependencies for reexports"); 820 821 auto &SrcJDDeps = Deps.find(&SrcJD)->second; 822 SymbolDependenceMap PerAliasDepsMap; 823 auto &PerAliasDeps = PerAliasDepsMap[&SrcJD]; 824 825 for (auto &KV : QueryInfo->Aliases) 826 if (SrcJDDeps.count(KV.second.Aliasee)) { 827 PerAliasDeps = {KV.second.Aliasee}; 828 QueryInfo->R.addDependencies(KV.first, PerAliasDepsMap); 829 } 830 }; 831 832 auto OnResolve = [QueryInfo](Expected<SymbolMap> Result) { 833 if (Result) { 834 SymbolMap ResolutionMap; 835 for (auto &KV : QueryInfo->Aliases) { 836 assert(Result->count(KV.second.Aliasee) && 837 "Result map missing entry?"); 838 ResolutionMap[KV.first] = JITEvaluatedSymbol( 839 (*Result)[KV.second.Aliasee].getAddress(), KV.second.AliasFlags); 840 } 841 QueryInfo->R.resolve(ResolutionMap); 842 QueryInfo->R.emit(); 843 } else { 844 auto &ES = QueryInfo->R.getTargetJITDylib().getExecutionSession(); 845 ES.reportError(Result.takeError()); 846 QueryInfo->R.failMaterialization(); 847 } 848 }; 849 850 auto OnReady = [&ES](Error Err) { ES.reportError(std::move(Err)); }; 851 852 ES.lookup({&SrcJD}, QuerySymbols, std::move(OnResolve), std::move(OnReady), 853 std::move(RegisterDependencies)); 854 } 855 } 856 857 void ReExportsMaterializationUnit::discard(const JITDylib &JD, 858 SymbolStringPtr Name) { 859 assert(Aliases.count(Name) && 860 "Symbol not covered by this MaterializationUnit"); 861 Aliases.erase(Name); 862 } 863 864 SymbolFlagsMap 865 ReExportsMaterializationUnit::extractFlags(const SymbolAliasMap &Aliases) { 866 SymbolFlagsMap SymbolFlags; 867 for (auto &KV : Aliases) 868 SymbolFlags[KV.first] = KV.second.AliasFlags; 869 870 return SymbolFlags; 871 } 872 873 Expected<SymbolAliasMap> 874 buildSimpleReexportsAliasMap(JITDylib &SourceJD, const SymbolNameSet &Symbols) { 875 auto Flags = SourceJD.lookupFlags(Symbols); 876 877 if (Flags.size() != Symbols.size()) { 878 SymbolNameSet Unresolved = Symbols; 879 for (auto &KV : Flags) 880 Unresolved.erase(KV.first); 881 return make_error<SymbolsNotFound>(std::move(Unresolved)); 882 } 883 884 SymbolAliasMap Result; 885 for (auto &Name : Symbols) { 886 assert(Flags.count(Name) && "Missing entry in flags map"); 887 Result[Name] = SymbolAliasMapEntry(Name, Flags[Name]); 888 } 889 890 return Result; 891 } 892 893 ReexportsFallbackDefinitionGenerator::ReexportsFallbackDefinitionGenerator( 894 JITDylib &BackingJD, SymbolPredicate Allow) 895 : BackingJD(BackingJD), Allow(std::move(Allow)) {} 896 897 SymbolNameSet ReexportsFallbackDefinitionGenerator:: 898 operator()(JITDylib &JD, const SymbolNameSet &Names) { 899 orc::SymbolNameSet Added; 900 orc::SymbolAliasMap AliasMap; 901 902 auto Flags = BackingJD.lookupFlags(Names); 903 904 for (auto &KV : Flags) { 905 if (!Allow(KV.first)) 906 continue; 907 AliasMap[KV.first] = SymbolAliasMapEntry(KV.first, KV.second); 908 Added.insert(KV.first); 909 } 910 911 if (!Added.empty()) 912 cantFail(JD.define(reexports(BackingJD, AliasMap))); 913 914 return Added; 915 } 916 917 Error JITDylib::defineMaterializing(const SymbolFlagsMap &SymbolFlags) { 918 return ES.runSessionLocked([&]() -> Error { 919 std::vector<SymbolMap::iterator> AddedSyms; 920 921 for (auto &KV : SymbolFlags) { 922 SymbolMap::iterator EntryItr; 923 bool Added; 924 925 auto NewFlags = KV.second; 926 NewFlags |= JITSymbolFlags::Materializing; 927 928 std::tie(EntryItr, Added) = Symbols.insert( 929 std::make_pair(KV.first, JITEvaluatedSymbol(0, NewFlags))); 930 931 if (Added) 932 AddedSyms.push_back(EntryItr); 933 else { 934 // Remove any symbols already added. 935 for (auto &SI : AddedSyms) 936 Symbols.erase(SI); 937 938 // FIXME: Return all duplicates. 939 return make_error<DuplicateDefinition>(*KV.first); 940 } 941 } 942 943 return Error::success(); 944 }); 945 } 946 947 void JITDylib::replace(std::unique_ptr<MaterializationUnit> MU) { 948 assert(MU != nullptr && "Can not replace with a null MaterializationUnit"); 949 950 auto MustRunMU = 951 ES.runSessionLocked([&, this]() -> std::unique_ptr<MaterializationUnit> { 952 953 #ifndef NDEBUG 954 for (auto &KV : MU->getSymbols()) { 955 auto SymI = Symbols.find(KV.first); 956 assert(SymI != Symbols.end() && "Replacing unknown symbol"); 957 assert(!SymI->second.getFlags().isLazy() && 958 SymI->second.getFlags().isMaterializing() && 959 "Can not replace symbol that is not materializing"); 960 assert(UnmaterializedInfos.count(KV.first) == 0 && 961 "Symbol being replaced should have no UnmaterializedInfo"); 962 } 963 #endif // NDEBUG 964 965 // If any symbol has pending queries against it then we need to 966 // materialize MU immediately. 967 for (auto &KV : MU->getSymbols()) { 968 auto MII = MaterializingInfos.find(KV.first); 969 if (MII != MaterializingInfos.end()) { 970 if (!MII->second.PendingQueries.empty()) 971 return std::move(MU); 972 } 973 } 974 975 // Otherwise, make MU responsible for all the symbols. 976 auto UMI = std::make_shared<UnmaterializedInfo>(std::move(MU)); 977 for (auto &KV : UMI->MU->getSymbols()) { 978 assert(!KV.second.isLazy() && 979 "Lazy flag should be managed internally."); 980 assert(!KV.second.isMaterializing() && 981 "Materializing flags should be managed internally."); 982 983 auto SymI = Symbols.find(KV.first); 984 JITSymbolFlags ReplaceFlags = KV.second; 985 ReplaceFlags |= JITSymbolFlags::Lazy; 986 SymI->second = JITEvaluatedSymbol(SymI->second.getAddress(), 987 std::move(ReplaceFlags)); 988 UnmaterializedInfos[KV.first] = UMI; 989 } 990 991 return nullptr; 992 }); 993 994 if (MustRunMU) 995 ES.dispatchMaterialization(*this, std::move(MustRunMU)); 996 } 997 998 SymbolNameSet JITDylib::getRequestedSymbols(const SymbolFlagsMap &SymbolFlags) { 999 return ES.runSessionLocked([&]() { 1000 SymbolNameSet RequestedSymbols; 1001 1002 for (auto &KV : SymbolFlags) { 1003 assert(Symbols.count(KV.first) && "JITDylib does not cover this symbol?"); 1004 assert(Symbols[KV.first].getFlags().isMaterializing() && 1005 "getRequestedSymbols can only be called for materializing " 1006 "symbols"); 1007 auto I = MaterializingInfos.find(KV.first); 1008 if (I == MaterializingInfos.end()) 1009 continue; 1010 1011 if (!I->second.PendingQueries.empty()) 1012 RequestedSymbols.insert(KV.first); 1013 } 1014 1015 return RequestedSymbols; 1016 }); 1017 } 1018 1019 void JITDylib::addDependencies(const SymbolStringPtr &Name, 1020 const SymbolDependenceMap &Dependencies) { 1021 assert(Symbols.count(Name) && "Name not in symbol table"); 1022 assert((Symbols[Name].getFlags().isLazy() || 1023 Symbols[Name].getFlags().isMaterializing()) && 1024 "Symbol is not lazy or materializing"); 1025 1026 auto &MI = MaterializingInfos[Name]; 1027 assert(!MI.IsEmitted && "Can not add dependencies to an emitted symbol"); 1028 1029 for (auto &KV : Dependencies) { 1030 assert(KV.first && "Null JITDylib in dependency?"); 1031 auto &OtherJITDylib = *KV.first; 1032 auto &DepsOnOtherJITDylib = MI.UnemittedDependencies[&OtherJITDylib]; 1033 1034 for (auto &OtherSymbol : KV.second) { 1035 #ifndef NDEBUG 1036 // Assert that this symbol exists and has not been emitted already. 1037 auto SymI = OtherJITDylib.Symbols.find(OtherSymbol); 1038 assert(SymI != OtherJITDylib.Symbols.end() && 1039 (SymI->second.getFlags().isLazy() || 1040 SymI->second.getFlags().isMaterializing()) && 1041 "Dependency on emitted symbol"); 1042 #endif 1043 1044 auto &OtherMI = OtherJITDylib.MaterializingInfos[OtherSymbol]; 1045 1046 if (OtherMI.IsEmitted) 1047 transferEmittedNodeDependencies(MI, Name, OtherMI); 1048 else if (&OtherJITDylib != this || OtherSymbol != Name) { 1049 OtherMI.Dependants[this].insert(Name); 1050 DepsOnOtherJITDylib.insert(OtherSymbol); 1051 } 1052 } 1053 1054 if (DepsOnOtherJITDylib.empty()) 1055 MI.UnemittedDependencies.erase(&OtherJITDylib); 1056 } 1057 } 1058 1059 void JITDylib::resolve(const SymbolMap &Resolved) { 1060 auto FullyResolvedQueries = ES.runSessionLocked([&, this]() { 1061 AsynchronousSymbolQuerySet FullyResolvedQueries; 1062 for (const auto &KV : Resolved) { 1063 auto &Name = KV.first; 1064 auto Sym = KV.second; 1065 1066 assert(!Sym.getFlags().isLazy() && !Sym.getFlags().isMaterializing() && 1067 "Materializing flags should be managed internally"); 1068 1069 auto I = Symbols.find(Name); 1070 1071 assert(I != Symbols.end() && "Symbol not found"); 1072 assert(!I->second.getFlags().isLazy() && 1073 I->second.getFlags().isMaterializing() && 1074 "Symbol should be materializing"); 1075 assert(I->second.getAddress() == 0 && "Symbol has already been resolved"); 1076 1077 assert((Sym.getFlags() & ~JITSymbolFlags::Weak) == 1078 (JITSymbolFlags::stripTransientFlags(I->second.getFlags()) & 1079 ~JITSymbolFlags::Weak) && 1080 "Resolved flags should match the declared flags"); 1081 1082 // Once resolved, symbols can never be weak. 1083 JITSymbolFlags ResolvedFlags = Sym.getFlags(); 1084 ResolvedFlags &= ~JITSymbolFlags::Weak; 1085 ResolvedFlags |= JITSymbolFlags::Materializing; 1086 I->second = JITEvaluatedSymbol(Sym.getAddress(), ResolvedFlags); 1087 1088 auto &MI = MaterializingInfos[Name]; 1089 for (auto &Q : MI.PendingQueries) { 1090 Q->resolve(Name, Sym); 1091 if (Q->isFullyResolved()) 1092 FullyResolvedQueries.insert(Q); 1093 } 1094 } 1095 1096 return FullyResolvedQueries; 1097 }); 1098 1099 for (auto &Q : FullyResolvedQueries) { 1100 assert(Q->isFullyResolved() && "Q not fully resolved"); 1101 Q->handleFullyResolved(); 1102 } 1103 } 1104 1105 void JITDylib::emit(const SymbolFlagsMap &Emitted) { 1106 auto FullyReadyQueries = ES.runSessionLocked([&, this]() { 1107 AsynchronousSymbolQuerySet ReadyQueries; 1108 1109 for (const auto &KV : Emitted) { 1110 const auto &Name = KV.first; 1111 1112 auto MII = MaterializingInfos.find(Name); 1113 assert(MII != MaterializingInfos.end() && 1114 "Missing MaterializingInfo entry"); 1115 1116 auto &MI = MII->second; 1117 1118 // For each dependant, transfer this node's emitted dependencies to 1119 // it. If the dependant node is ready (i.e. has no unemitted 1120 // dependencies) then notify any pending queries. 1121 for (auto &KV : MI.Dependants) { 1122 auto &DependantJD = *KV.first; 1123 for (auto &DependantName : KV.second) { 1124 auto DependantMII = 1125 DependantJD.MaterializingInfos.find(DependantName); 1126 assert(DependantMII != DependantJD.MaterializingInfos.end() && 1127 "Dependant should have MaterializingInfo"); 1128 1129 auto &DependantMI = DependantMII->second; 1130 1131 // Remove the dependant's dependency on this node. 1132 assert(DependantMI.UnemittedDependencies[this].count(Name) && 1133 "Dependant does not count this symbol as a dependency?"); 1134 DependantMI.UnemittedDependencies[this].erase(Name); 1135 if (DependantMI.UnemittedDependencies[this].empty()) 1136 DependantMI.UnemittedDependencies.erase(this); 1137 1138 // Transfer unemitted dependencies from this node to the dependant. 1139 DependantJD.transferEmittedNodeDependencies(DependantMI, 1140 DependantName, MI); 1141 1142 // If the dependant is emitted and this node was the last of its 1143 // unemitted dependencies then the dependant node is now ready, so 1144 // notify any pending queries on the dependant node. 1145 if (DependantMI.IsEmitted && 1146 DependantMI.UnemittedDependencies.empty()) { 1147 assert(DependantMI.Dependants.empty() && 1148 "Dependants should be empty by now"); 1149 for (auto &Q : DependantMI.PendingQueries) { 1150 Q->notifySymbolReady(); 1151 if (Q->isFullyReady()) 1152 ReadyQueries.insert(Q); 1153 Q->removeQueryDependence(DependantJD, DependantName); 1154 } 1155 1156 // Since this dependant is now ready, we erase its MaterializingInfo 1157 // and update its materializing state. 1158 assert(DependantJD.Symbols.count(DependantName) && 1159 "Dependant has no entry in the Symbols table"); 1160 auto &DependantSym = DependantJD.Symbols[DependantName]; 1161 DependantSym.setFlags(static_cast<JITSymbolFlags::FlagNames>( 1162 DependantSym.getFlags() & ~JITSymbolFlags::Materializing)); 1163 DependantJD.MaterializingInfos.erase(DependantMII); 1164 } 1165 } 1166 } 1167 MI.Dependants.clear(); 1168 MI.IsEmitted = true; 1169 1170 if (MI.UnemittedDependencies.empty()) { 1171 for (auto &Q : MI.PendingQueries) { 1172 Q->notifySymbolReady(); 1173 if (Q->isFullyReady()) 1174 ReadyQueries.insert(Q); 1175 Q->removeQueryDependence(*this, Name); 1176 } 1177 assert(Symbols.count(Name) && 1178 "Symbol has no entry in the Symbols table"); 1179 auto &Sym = Symbols[Name]; 1180 Sym.setFlags(static_cast<JITSymbolFlags::FlagNames>( 1181 Sym.getFlags() & ~JITSymbolFlags::Materializing)); 1182 MaterializingInfos.erase(MII); 1183 } 1184 } 1185 1186 return ReadyQueries; 1187 }); 1188 1189 for (auto &Q : FullyReadyQueries) { 1190 assert(Q->isFullyReady() && "Q is not fully ready"); 1191 Q->handleFullyReady(); 1192 } 1193 } 1194 1195 void JITDylib::notifyFailed(const SymbolNameSet &FailedSymbols) { 1196 1197 // FIXME: This should fail any transitively dependant symbols too. 1198 1199 auto FailedQueriesToNotify = ES.runSessionLocked([&, this]() { 1200 AsynchronousSymbolQuerySet FailedQueries; 1201 1202 for (auto &Name : FailedSymbols) { 1203 auto I = Symbols.find(Name); 1204 assert(I != Symbols.end() && "Symbol not present in this JITDylib"); 1205 Symbols.erase(I); 1206 1207 auto MII = MaterializingInfos.find(Name); 1208 1209 // If we have not created a MaterializingInfo for this symbol yet then 1210 // there is nobody to notify. 1211 if (MII == MaterializingInfos.end()) 1212 continue; 1213 1214 // Copy all the queries to the FailedQueries list, then abandon them. 1215 // This has to be a copy, and the copy has to come before the abandon 1216 // operation: Each Q.detach() call will reach back into this 1217 // PendingQueries list to remove Q. 1218 for (auto &Q : MII->second.PendingQueries) 1219 FailedQueries.insert(Q); 1220 1221 for (auto &Q : FailedQueries) 1222 Q->detach(); 1223 1224 assert(MII->second.PendingQueries.empty() && 1225 "Queries remain after symbol was failed"); 1226 1227 MaterializingInfos.erase(MII); 1228 } 1229 1230 return FailedQueries; 1231 }); 1232 1233 for (auto &Q : FailedQueriesToNotify) 1234 Q->handleFailed(make_error<FailedToMaterialize>(FailedSymbols)); 1235 } 1236 1237 void JITDylib::setSearchOrder(JITDylibList NewSearchOrder, 1238 bool SearchThisJITDylibFirst) { 1239 if (SearchThisJITDylibFirst && NewSearchOrder.front() != this) 1240 NewSearchOrder.insert(NewSearchOrder.begin(), this); 1241 1242 ES.runSessionLocked([&]() { SearchOrder = std::move(NewSearchOrder); }); 1243 } 1244 1245 void JITDylib::addToSearchOrder(JITDylib &JD) { 1246 ES.runSessionLocked([&]() { SearchOrder.push_back(&JD); }); 1247 } 1248 1249 void JITDylib::replaceInSearchOrder(JITDylib &OldJD, JITDylib &NewJD) { 1250 ES.runSessionLocked([&]() { 1251 auto I = std::find(SearchOrder.begin(), SearchOrder.end(), &OldJD); 1252 1253 if (I != SearchOrder.end()) 1254 *I = &NewJD; 1255 }); 1256 } 1257 1258 void JITDylib::removeFromSearchOrder(JITDylib &JD) { 1259 ES.runSessionLocked([&]() { 1260 auto I = std::find(SearchOrder.begin(), SearchOrder.end(), &JD); 1261 if (I != SearchOrder.end()) 1262 SearchOrder.erase(I); 1263 }); 1264 } 1265 1266 SymbolFlagsMap JITDylib::lookupFlags(const SymbolNameSet &Names) { 1267 return ES.runSessionLocked([&, this]() { 1268 SymbolFlagsMap Result; 1269 auto Unresolved = lookupFlagsImpl(Result, Names); 1270 if (FallbackDefinitionGenerator && !Unresolved.empty()) { 1271 auto FallbackDefs = FallbackDefinitionGenerator(*this, Unresolved); 1272 if (!FallbackDefs.empty()) { 1273 auto Unresolved2 = lookupFlagsImpl(Result, FallbackDefs); 1274 (void)Unresolved2; 1275 assert(Unresolved2.empty() && 1276 "All fallback defs should have been found by lookupFlagsImpl"); 1277 } 1278 }; 1279 return Result; 1280 }); 1281 } 1282 1283 SymbolNameSet JITDylib::lookupFlagsImpl(SymbolFlagsMap &Flags, 1284 const SymbolNameSet &Names) { 1285 SymbolNameSet Unresolved; 1286 1287 for (auto &Name : Names) { 1288 auto I = Symbols.find(Name); 1289 1290 if (I == Symbols.end()) { 1291 Unresolved.insert(Name); 1292 continue; 1293 } 1294 1295 assert(!Flags.count(Name) && "Symbol already present in Flags map"); 1296 Flags[Name] = JITSymbolFlags::stripTransientFlags(I->second.getFlags()); 1297 } 1298 1299 return Unresolved; 1300 } 1301 1302 void JITDylib::lodgeQuery(std::shared_ptr<AsynchronousSymbolQuery> &Q, 1303 SymbolNameSet &Unresolved, 1304 MaterializationUnitList &MUs) { 1305 assert(Q && "Query can not be null"); 1306 1307 lodgeQueryImpl(Q, Unresolved, MUs); 1308 if (FallbackDefinitionGenerator && !Unresolved.empty()) { 1309 auto FallbackDefs = FallbackDefinitionGenerator(*this, Unresolved); 1310 if (!FallbackDefs.empty()) { 1311 for (auto &D : FallbackDefs) 1312 Unresolved.erase(D); 1313 lodgeQueryImpl(Q, FallbackDefs, MUs); 1314 assert(FallbackDefs.empty() && 1315 "All fallback defs should have been found by lookupImpl"); 1316 } 1317 } 1318 } 1319 1320 void JITDylib::lodgeQueryImpl( 1321 std::shared_ptr<AsynchronousSymbolQuery> &Q, SymbolNameSet &Unresolved, 1322 std::vector<std::unique_ptr<MaterializationUnit>> &MUs) { 1323 for (auto I = Unresolved.begin(), E = Unresolved.end(); I != E;) { 1324 auto TmpI = I++; 1325 auto Name = *TmpI; 1326 1327 // Search for the name in Symbols. Skip it if not found. 1328 auto SymI = Symbols.find(Name); 1329 if (SymI == Symbols.end()) 1330 continue; 1331 1332 // If we found Name in JD, remove it frome the Unresolved set and add it 1333 // to the added set. 1334 Unresolved.erase(TmpI); 1335 1336 // If the symbol has an address then resolve it. 1337 if (SymI->second.getAddress() != 0) 1338 Q->resolve(Name, SymI->second); 1339 1340 // If the symbol is lazy, get the MaterialiaztionUnit for it. 1341 if (SymI->second.getFlags().isLazy()) { 1342 assert(SymI->second.getAddress() == 0 && 1343 "Lazy symbol should not have a resolved address"); 1344 assert(!SymI->second.getFlags().isMaterializing() && 1345 "Materializing and lazy should not both be set"); 1346 auto UMII = UnmaterializedInfos.find(Name); 1347 assert(UMII != UnmaterializedInfos.end() && 1348 "Lazy symbol should have UnmaterializedInfo"); 1349 auto MU = std::move(UMII->second->MU); 1350 assert(MU != nullptr && "Materializer should not be null"); 1351 1352 // Move all symbols associated with this MaterializationUnit into 1353 // materializing state. 1354 for (auto &KV : MU->getSymbols()) { 1355 auto SymK = Symbols.find(KV.first); 1356 auto Flags = SymK->second.getFlags(); 1357 Flags &= ~JITSymbolFlags::Lazy; 1358 Flags |= JITSymbolFlags::Materializing; 1359 SymK->second.setFlags(Flags); 1360 UnmaterializedInfos.erase(KV.first); 1361 } 1362 1363 // Add MU to the list of MaterializationUnits to be materialized. 1364 MUs.push_back(std::move(MU)); 1365 } else if (!SymI->second.getFlags().isMaterializing()) { 1366 // The symbol is neither lazy nor materializing, so it must be 1367 // ready. Notify the query and continue. 1368 Q->notifySymbolReady(); 1369 continue; 1370 } 1371 1372 // Add the query to the PendingQueries list. 1373 assert(SymI->second.getFlags().isMaterializing() && 1374 "By this line the symbol should be materializing"); 1375 auto &MI = MaterializingInfos[Name]; 1376 MI.PendingQueries.push_back(Q); 1377 Q->addQueryDependence(*this, Name); 1378 } 1379 } 1380 1381 SymbolNameSet JITDylib::legacyLookup(std::shared_ptr<AsynchronousSymbolQuery> Q, 1382 SymbolNameSet Names) { 1383 assert(Q && "Query can not be null"); 1384 1385 ES.runOutstandingMUs(); 1386 1387 LookupImplActionFlags ActionFlags = None; 1388 std::vector<std::unique_ptr<MaterializationUnit>> MUs; 1389 1390 SymbolNameSet Unresolved = std::move(Names); 1391 ES.runSessionLocked([&, this]() { 1392 ActionFlags = lookupImpl(Q, MUs, Unresolved); 1393 if (FallbackDefinitionGenerator && !Unresolved.empty()) { 1394 assert(ActionFlags == None && 1395 "ActionFlags set but unresolved symbols remain?"); 1396 auto FallbackDefs = FallbackDefinitionGenerator(*this, Unresolved); 1397 if (!FallbackDefs.empty()) { 1398 for (auto &D : FallbackDefs) 1399 Unresolved.erase(D); 1400 ActionFlags = lookupImpl(Q, MUs, FallbackDefs); 1401 assert(FallbackDefs.empty() && 1402 "All fallback defs should have been found by lookupImpl"); 1403 } 1404 } 1405 }); 1406 1407 assert((MUs.empty() || ActionFlags == None) && 1408 "If action flags are set, there should be no work to do (so no MUs)"); 1409 1410 if (ActionFlags & NotifyFullyResolved) 1411 Q->handleFullyResolved(); 1412 1413 if (ActionFlags & NotifyFullyReady) 1414 Q->handleFullyReady(); 1415 1416 // FIXME: Swap back to the old code below once RuntimeDyld works with 1417 // callbacks from asynchronous queries. 1418 // Add MUs to the OutstandingMUs list. 1419 { 1420 std::lock_guard<std::recursive_mutex> Lock(ES.OutstandingMUsMutex); 1421 for (auto &MU : MUs) 1422 ES.OutstandingMUs.push_back(make_pair(this, std::move(MU))); 1423 } 1424 ES.runOutstandingMUs(); 1425 1426 // Dispatch any required MaterializationUnits for materialization. 1427 // for (auto &MU : MUs) 1428 // ES.dispatchMaterialization(*this, std::move(MU)); 1429 1430 return Unresolved; 1431 } 1432 1433 JITDylib::LookupImplActionFlags 1434 JITDylib::lookupImpl(std::shared_ptr<AsynchronousSymbolQuery> &Q, 1435 std::vector<std::unique_ptr<MaterializationUnit>> &MUs, 1436 SymbolNameSet &Unresolved) { 1437 LookupImplActionFlags ActionFlags = None; 1438 1439 for (auto I = Unresolved.begin(), E = Unresolved.end(); I != E;) { 1440 auto TmpI = I++; 1441 auto Name = *TmpI; 1442 1443 // Search for the name in Symbols. Skip it if not found. 1444 auto SymI = Symbols.find(Name); 1445 if (SymI == Symbols.end()) 1446 continue; 1447 1448 // If we found Name, remove it frome the Unresolved set and add it 1449 // to the dependencies set. 1450 Unresolved.erase(TmpI); 1451 1452 // If the symbol has an address then resolve it. 1453 if (SymI->second.getAddress() != 0) { 1454 Q->resolve(Name, SymI->second); 1455 if (Q->isFullyResolved()) 1456 ActionFlags |= NotifyFullyResolved; 1457 } 1458 1459 // If the symbol is lazy, get the MaterialiaztionUnit for it. 1460 if (SymI->second.getFlags().isLazy()) { 1461 assert(SymI->second.getAddress() == 0 && 1462 "Lazy symbol should not have a resolved address"); 1463 assert(!SymI->second.getFlags().isMaterializing() && 1464 "Materializing and lazy should not both be set"); 1465 auto UMII = UnmaterializedInfos.find(Name); 1466 assert(UMII != UnmaterializedInfos.end() && 1467 "Lazy symbol should have UnmaterializedInfo"); 1468 auto MU = std::move(UMII->second->MU); 1469 assert(MU != nullptr && "Materializer should not be null"); 1470 1471 // Kick all symbols associated with this MaterializationUnit into 1472 // materializing state. 1473 for (auto &KV : MU->getSymbols()) { 1474 auto SymK = Symbols.find(KV.first); 1475 auto Flags = SymK->second.getFlags(); 1476 Flags &= ~JITSymbolFlags::Lazy; 1477 Flags |= JITSymbolFlags::Materializing; 1478 SymK->second.setFlags(Flags); 1479 UnmaterializedInfos.erase(KV.first); 1480 } 1481 1482 // Add MU to the list of MaterializationUnits to be materialized. 1483 MUs.push_back(std::move(MU)); 1484 } else if (!SymI->second.getFlags().isMaterializing()) { 1485 // The symbol is neither lazy nor materializing, so it must be ready. 1486 // Notify the query and continue. 1487 Q->notifySymbolReady(); 1488 if (Q->isFullyReady()) 1489 ActionFlags |= NotifyFullyReady; 1490 continue; 1491 } 1492 1493 // Add the query to the PendingQueries list. 1494 assert(SymI->second.getFlags().isMaterializing() && 1495 "By this line the symbol should be materializing"); 1496 auto &MI = MaterializingInfos[Name]; 1497 MI.PendingQueries.push_back(Q); 1498 Q->addQueryDependence(*this, Name); 1499 } 1500 1501 return ActionFlags; 1502 } 1503 1504 void JITDylib::dump(raw_ostream &OS) { 1505 ES.runSessionLocked([&, this]() { 1506 OS << "JITDylib \"" << JITDylibName 1507 << "\" (ES: " << format("0x%016x", reinterpret_cast<uintptr_t>(&ES)) 1508 << "):\n" 1509 << "Symbol table:\n"; 1510 1511 for (auto &KV : Symbols) { 1512 OS << " \"" << *KV.first 1513 << "\": " << format("0x%016x", KV.second.getAddress()); 1514 if (KV.second.getFlags().isLazy() || 1515 KV.second.getFlags().isMaterializing()) { 1516 OS << " ("; 1517 if (KV.second.getFlags().isLazy()) { 1518 auto I = UnmaterializedInfos.find(KV.first); 1519 assert(I != UnmaterializedInfos.end() && 1520 "Lazy symbol should have UnmaterializedInfo"); 1521 OS << " Lazy (MU=" << I->second->MU.get() << ")"; 1522 } 1523 if (KV.second.getFlags().isMaterializing()) 1524 OS << " Materializing"; 1525 OS << " )\n"; 1526 } else 1527 OS << "\n"; 1528 } 1529 1530 if (!MaterializingInfos.empty()) 1531 OS << " MaterializingInfos entries:\n"; 1532 for (auto &KV : MaterializingInfos) { 1533 OS << " \"" << *KV.first << "\":\n" 1534 << " IsEmitted = " << (KV.second.IsEmitted ? "true" : "false") 1535 << "\n" 1536 << " " << KV.second.PendingQueries.size() 1537 << " pending queries: { "; 1538 for (auto &Q : KV.second.PendingQueries) 1539 OS << Q.get() << " "; 1540 OS << "}\n Dependants:\n"; 1541 for (auto &KV2 : KV.second.Dependants) 1542 OS << " " << KV2.first->getName() << ": " << KV2.second << "\n"; 1543 OS << " Unemitted Dependencies:\n"; 1544 for (auto &KV2 : KV.second.UnemittedDependencies) 1545 OS << " " << KV2.first->getName() << ": " << KV2.second << "\n"; 1546 } 1547 }); 1548 } 1549 1550 JITDylib::JITDylib(ExecutionSessionBase &ES, std::string Name) 1551 : ES(ES), JITDylibName(std::move(Name)) { 1552 SearchOrder.push_back(this); 1553 } 1554 1555 Error JITDylib::defineImpl(MaterializationUnit &MU) { 1556 SymbolNameSet Duplicates; 1557 SymbolNameSet MUDefsOverridden; 1558 1559 struct ExistingDefOverriddenEntry { 1560 SymbolMap::iterator ExistingDefItr; 1561 JITSymbolFlags NewFlags; 1562 }; 1563 std::vector<ExistingDefOverriddenEntry> ExistingDefsOverridden; 1564 1565 for (auto &KV : MU.getSymbols()) { 1566 assert(!KV.second.isLazy() && "Lazy flag should be managed internally."); 1567 assert(!KV.second.isMaterializing() && 1568 "Materializing flags should be managed internally."); 1569 1570 SymbolMap::iterator EntryItr; 1571 bool Added; 1572 1573 auto NewFlags = KV.second; 1574 NewFlags |= JITSymbolFlags::Lazy; 1575 1576 std::tie(EntryItr, Added) = Symbols.insert( 1577 std::make_pair(KV.first, JITEvaluatedSymbol(0, NewFlags))); 1578 1579 if (!Added) { 1580 if (KV.second.isStrong()) { 1581 if (EntryItr->second.getFlags().isStrong() || 1582 (EntryItr->second.getFlags() & JITSymbolFlags::Materializing)) 1583 Duplicates.insert(KV.first); 1584 else 1585 ExistingDefsOverridden.push_back({EntryItr, NewFlags}); 1586 } else 1587 MUDefsOverridden.insert(KV.first); 1588 } 1589 } 1590 1591 if (!Duplicates.empty()) { 1592 // We need to remove the symbols we added. 1593 for (auto &KV : MU.getSymbols()) { 1594 if (Duplicates.count(KV.first)) 1595 continue; 1596 1597 bool Found = false; 1598 for (const auto &EDO : ExistingDefsOverridden) 1599 if (EDO.ExistingDefItr->first == KV.first) 1600 Found = true; 1601 1602 if (!Found) 1603 Symbols.erase(KV.first); 1604 } 1605 1606 // FIXME: Return all duplicates. 1607 return make_error<DuplicateDefinition>(**Duplicates.begin()); 1608 } 1609 1610 // Update flags on existing defs and call discard on their materializers. 1611 for (auto &EDO : ExistingDefsOverridden) { 1612 assert(EDO.ExistingDefItr->second.getFlags().isLazy() && 1613 !EDO.ExistingDefItr->second.getFlags().isMaterializing() && 1614 "Overridden existing def should be in the Lazy state"); 1615 1616 EDO.ExistingDefItr->second.setFlags(EDO.NewFlags); 1617 1618 auto UMII = UnmaterializedInfos.find(EDO.ExistingDefItr->first); 1619 assert(UMII != UnmaterializedInfos.end() && 1620 "Overridden existing def should have an UnmaterializedInfo"); 1621 1622 UMII->second->MU->doDiscard(*this, EDO.ExistingDefItr->first); 1623 } 1624 1625 // Discard overridden symbols povided by MU. 1626 for (auto &Sym : MUDefsOverridden) 1627 MU.doDiscard(*this, Sym); 1628 1629 return Error::success(); 1630 } 1631 1632 void JITDylib::detachQueryHelper(AsynchronousSymbolQuery &Q, 1633 const SymbolNameSet &QuerySymbols) { 1634 for (auto &QuerySymbol : QuerySymbols) { 1635 assert(MaterializingInfos.count(QuerySymbol) && 1636 "QuerySymbol does not have MaterializingInfo"); 1637 auto &MI = MaterializingInfos[QuerySymbol]; 1638 1639 auto IdenticalQuery = 1640 [&](const std::shared_ptr<AsynchronousSymbolQuery> &R) { 1641 return R.get() == &Q; 1642 }; 1643 1644 auto I = std::find_if(MI.PendingQueries.begin(), MI.PendingQueries.end(), 1645 IdenticalQuery); 1646 assert(I != MI.PendingQueries.end() && 1647 "Query Q should be in the PendingQueries list for QuerySymbol"); 1648 MI.PendingQueries.erase(I); 1649 } 1650 } 1651 1652 void JITDylib::transferEmittedNodeDependencies( 1653 MaterializingInfo &DependantMI, const SymbolStringPtr &DependantName, 1654 MaterializingInfo &EmittedMI) { 1655 for (auto &KV : EmittedMI.UnemittedDependencies) { 1656 auto &DependencyJD = *KV.first; 1657 SymbolNameSet *UnemittedDependenciesOnDependencyJD = nullptr; 1658 1659 for (auto &DependencyName : KV.second) { 1660 auto &DependencyMI = DependencyJD.MaterializingInfos[DependencyName]; 1661 1662 // Do not add self dependencies. 1663 if (&DependencyMI == &DependantMI) 1664 continue; 1665 1666 // If we haven't looked up the dependencies for DependencyJD yet, do it 1667 // now and cache the result. 1668 if (!UnemittedDependenciesOnDependencyJD) 1669 UnemittedDependenciesOnDependencyJD = 1670 &DependantMI.UnemittedDependencies[&DependencyJD]; 1671 1672 DependencyMI.Dependants[this].insert(DependantName); 1673 UnemittedDependenciesOnDependencyJD->insert(DependencyName); 1674 } 1675 } 1676 } 1677 1678 JITDylib &ExecutionSession::createJITDylib(std::string Name) { 1679 return runSessionLocked([&, this]() -> JITDylib & { 1680 JDs.push_back( 1681 std::unique_ptr<JITDylib>(new JITDylib(*this, std::move(Name)))); 1682 return *JDs.back(); 1683 }); 1684 } 1685 1686 Expected<SymbolMap> lookup(const JITDylibList &JDs, SymbolNameSet Names) { 1687 1688 if (JDs.empty()) 1689 return SymbolMap(); 1690 1691 auto &ES = (*JDs.begin())->getExecutionSession(); 1692 1693 return ES.lookup(JDs, Names, NoDependenciesToRegister, true); 1694 } 1695 1696 /// Look up a symbol by searching a list of JDs. 1697 Expected<JITEvaluatedSymbol> lookup(const JITDylibList &JDs, 1698 SymbolStringPtr Name) { 1699 SymbolNameSet Names({Name}); 1700 if (auto ResultMap = lookup(JDs, std::move(Names))) { 1701 assert(ResultMap->size() == 1 && "Unexpected number of results"); 1702 assert(ResultMap->count(Name) && "Missing result for symbol"); 1703 return std::move(ResultMap->begin()->second); 1704 } else 1705 return ResultMap.takeError(); 1706 } 1707 1708 MangleAndInterner::MangleAndInterner(ExecutionSessionBase &ES, 1709 const DataLayout &DL) 1710 : ES(ES), DL(DL) {} 1711 1712 SymbolStringPtr MangleAndInterner::operator()(StringRef Name) { 1713 std::string MangledName; 1714 { 1715 raw_string_ostream MangledNameStream(MangledName); 1716 Mangler::getNameWithPrefix(MangledNameStream, Name, DL); 1717 } 1718 return ES.getSymbolStringPool().intern(MangledName); 1719 } 1720 1721 } // End namespace orc. 1722 } // End namespace llvm. 1723