1 //===----- Core.cpp - Core ORC APIs (MaterializationUnit, VSO, 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 VSOList &VSOs) { 106 OS << "["; 107 if (!VSOs.empty()) { 108 assert(VSOs.front() && "VSOList entries must not be null"); 109 OS << " " << VSOs.front()->getName(); 110 for (auto *V : make_range(std::next(VSOs.begin()), VSOs.end())) { 111 assert(V && "VSOList entries must not be null"); 112 OS << ", " << V->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 VSOList &VSOs, 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<VSO *, 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 *V : VSOs) { 313 assert(V && "VSOList entries must not be null"); 314 assert(!MUsMap.count(V) && 315 "VSOList should not contain duplicate entries"); 316 V->lodgeQuery(Q, Unresolved, MUsMap[V]); 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> 368 ExecutionSessionBase::lookup(const VSOList &VSOs, const SymbolNameSet &Symbols, 369 RegisterDependenciesFunction RegisterDependencies, 370 bool WaitUntilReady) { 371 #if LLVM_ENABLE_THREADS 372 // In the threaded case we use promises to return the results. 373 std::promise<SymbolMap> PromisedResult; 374 std::mutex ErrMutex; 375 Error ResolutionError = Error::success(); 376 std::promise<void> PromisedReady; 377 Error ReadyError = Error::success(); 378 auto OnResolve = [&](Expected<SymbolMap> R) { 379 if (R) 380 PromisedResult.set_value(std::move(*R)); 381 else { 382 { 383 ErrorAsOutParameter _(&ResolutionError); 384 std::lock_guard<std::mutex> Lock(ErrMutex); 385 ResolutionError = R.takeError(); 386 } 387 PromisedResult.set_value(SymbolMap()); 388 } 389 }; 390 391 std::function<void(Error)> OnReady; 392 if (WaitUntilReady) { 393 OnReady = [&](Error Err) { 394 if (Err) { 395 ErrorAsOutParameter _(&ReadyError); 396 std::lock_guard<std::mutex> Lock(ErrMutex); 397 ReadyError = std::move(Err); 398 } 399 PromisedReady.set_value(); 400 }; 401 } else { 402 OnReady = [&](Error Err) { 403 if (Err) 404 reportError(std::move(Err)); 405 }; 406 } 407 408 #else 409 SymbolMap Result; 410 Error ResolutionError = Error::success(); 411 Error ReadyError = Error::success(); 412 413 auto OnResolve = [&](Expected<SymbolMap> R) { 414 ErrorAsOutParameter _(&ResolutionError); 415 if (R) 416 Result = std::move(*R); 417 else 418 ResolutionError = R.takeError(); 419 }; 420 421 std::function<void(Error)> OnReady; 422 if (WaitUntilReady) { 423 OnReady = [&](Error Err) { 424 ErrorAsOutParameter _(&ReadyError); 425 if (Err) 426 ReadyError = std::move(Err); 427 }; 428 } else { 429 OnReady = [&](Error Err) { 430 if (Err) 431 reportError(std::move(Err)); 432 }; 433 } 434 #endif 435 436 // Perform the asynchronous lookup. 437 lookup(VSOs, Symbols, OnResolve, OnReady, RegisterDependencies); 438 439 #if LLVM_ENABLE_THREADS 440 auto ResultFuture = PromisedResult.get_future(); 441 auto Result = ResultFuture.get(); 442 443 { 444 std::lock_guard<std::mutex> Lock(ErrMutex); 445 if (ResolutionError) { 446 // ReadyError will never be assigned. Consume the success value. 447 cantFail(std::move(ReadyError)); 448 return std::move(ResolutionError); 449 } 450 } 451 452 if (WaitUntilReady) { 453 auto ReadyFuture = PromisedReady.get_future(); 454 ReadyFuture.get(); 455 456 { 457 std::lock_guard<std::mutex> Lock(ErrMutex); 458 if (ReadyError) 459 return std::move(ReadyError); 460 } 461 } else 462 cantFail(std::move(ReadyError)); 463 464 return std::move(Result); 465 466 #else 467 if (ResolutionError) { 468 // ReadyError will never be assigned. Consume the success value. 469 cantFail(std::move(ReadyError)); 470 return std::move(ResolutionError); 471 } 472 473 if (ReadyError) 474 return std::move(ReadyError); 475 476 return Result; 477 #endif 478 } 479 480 void ExecutionSessionBase::runOutstandingMUs() { 481 while (1) { 482 std::pair<VSO *, std::unique_ptr<MaterializationUnit>> VSOAndMU; 483 484 { 485 std::lock_guard<std::recursive_mutex> Lock(OutstandingMUsMutex); 486 if (!OutstandingMUs.empty()) { 487 VSOAndMU = std::move(OutstandingMUs.back()); 488 OutstandingMUs.pop_back(); 489 } 490 } 491 492 if (VSOAndMU.first) { 493 assert(VSOAndMU.second && "VSO, but no MU?"); 494 dispatchMaterialization(*VSOAndMU.first, std::move(VSOAndMU.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 finalized"); 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(VSO &V, SymbolStringPtr Name) { 561 bool Added = QueryRegistrations[&V].insert(std::move(Name)).second; 562 (void)Added; 563 assert(Added && "Duplicate dependence notification?"); 564 } 565 566 void AsynchronousSymbolQuery::removeQueryDependence( 567 VSO &V, const SymbolStringPtr &Name) { 568 auto QRI = QueryRegistrations.find(&V); 569 assert(QRI != QueryRegistrations.end() && "No dependencies registered for V"); 570 assert(QRI->second.count(Name) && "No dependency on Name in V"); 571 QRI->second.erase(Name); 572 if (QRI->second.empty()) 573 QueryRegistrations.erase(QRI); 574 } 575 576 void AsynchronousSymbolQuery::detach() { 577 ResolvedSymbols.clear(); 578 NotYetResolvedCount = 0; 579 NotYetReadyCount = 0; 580 for (auto &KV : QueryRegistrations) 581 KV.first->detachQueryHelper(*this, KV.second); 582 QueryRegistrations.clear(); 583 } 584 585 MaterializationResponsibility::MaterializationResponsibility( 586 VSO &V, SymbolFlagsMap SymbolFlags) 587 : V(V), SymbolFlags(std::move(SymbolFlags)) { 588 assert(!this->SymbolFlags.empty() && "Materializing nothing?"); 589 590 #ifndef NDEBUG 591 for (auto &KV : this->SymbolFlags) 592 KV.second |= JITSymbolFlags::Materializing; 593 #endif 594 } 595 596 MaterializationResponsibility::~MaterializationResponsibility() { 597 assert(SymbolFlags.empty() && 598 "All symbols should have been explicitly materialized or failed"); 599 } 600 601 SymbolNameSet MaterializationResponsibility::getRequestedSymbols() { 602 return V.getRequestedSymbols(SymbolFlags); 603 } 604 605 void MaterializationResponsibility::resolve(const SymbolMap &Symbols) { 606 #ifndef NDEBUG 607 for (auto &KV : Symbols) { 608 auto I = SymbolFlags.find(KV.first); 609 assert(I != SymbolFlags.end() && 610 "Resolving symbol outside this responsibility set"); 611 assert(I->second.isMaterializing() && "Duplicate resolution"); 612 I->second &= ~JITSymbolFlags::Materializing; 613 if (I->second.isWeak()) 614 assert(I->second == (KV.second.getFlags() | JITSymbolFlags::Weak) && 615 "Resolving symbol with incorrect flags"); 616 else 617 assert(I->second == KV.second.getFlags() && 618 "Resolving symbol with incorrect flags"); 619 } 620 #endif 621 622 V.resolve(Symbols); 623 } 624 625 void MaterializationResponsibility::finalize() { 626 #ifndef NDEBUG 627 for (auto &KV : SymbolFlags) 628 assert(!KV.second.isMaterializing() && 629 "Failed to resolve symbol before finalization"); 630 #endif // NDEBUG 631 632 V.finalize(SymbolFlags); 633 SymbolFlags.clear(); 634 } 635 636 Error MaterializationResponsibility::defineMaterializing( 637 const SymbolFlagsMap &NewSymbolFlags) { 638 // Add the given symbols to this responsibility object. 639 // It's ok if we hit a duplicate here: In that case the new version will be 640 // discarded, and the VSO::defineMaterializing method will return a duplicate 641 // symbol error. 642 for (auto &KV : NewSymbolFlags) { 643 auto I = SymbolFlags.insert(KV).first; 644 (void)I; 645 #ifndef NDEBUG 646 I->second |= JITSymbolFlags::Materializing; 647 #endif 648 } 649 650 return V.defineMaterializing(NewSymbolFlags); 651 } 652 653 void MaterializationResponsibility::failMaterialization() { 654 655 SymbolNameSet FailedSymbols; 656 for (auto &KV : SymbolFlags) 657 FailedSymbols.insert(KV.first); 658 659 V.notifyFailed(FailedSymbols); 660 SymbolFlags.clear(); 661 } 662 663 void MaterializationResponsibility::replace( 664 std::unique_ptr<MaterializationUnit> MU) { 665 for (auto &KV : MU->getSymbols()) 666 SymbolFlags.erase(KV.first); 667 668 V.replace(std::move(MU)); 669 } 670 671 MaterializationResponsibility 672 MaterializationResponsibility::delegate(const SymbolNameSet &Symbols) { 673 SymbolFlagsMap DelegatedFlags; 674 675 for (auto &Name : Symbols) { 676 auto I = SymbolFlags.find(Name); 677 assert(I != SymbolFlags.end() && 678 "Symbol is not tracked by this MaterializationResponsibility " 679 "instance"); 680 681 DelegatedFlags[Name] = std::move(I->second); 682 SymbolFlags.erase(I); 683 } 684 685 return MaterializationResponsibility(V, std::move(DelegatedFlags)); 686 } 687 688 void MaterializationResponsibility::addDependencies( 689 const SymbolStringPtr &Name, const SymbolDependenceMap &Dependencies) { 690 assert(SymbolFlags.count(Name) && 691 "Symbol not covered by this MaterializationResponsibility instance"); 692 V.addDependencies(Name, Dependencies); 693 } 694 695 void MaterializationResponsibility::addDependenciesForAll( 696 const SymbolDependenceMap &Dependencies) { 697 for (auto &KV : SymbolFlags) 698 V.addDependencies(KV.first, Dependencies); 699 } 700 701 AbsoluteSymbolsMaterializationUnit::AbsoluteSymbolsMaterializationUnit( 702 SymbolMap Symbols) 703 : MaterializationUnit(extractFlags(Symbols)), Symbols(std::move(Symbols)) {} 704 705 void AbsoluteSymbolsMaterializationUnit::materialize( 706 MaterializationResponsibility R) { 707 R.resolve(Symbols); 708 R.finalize(); 709 } 710 711 void AbsoluteSymbolsMaterializationUnit::discard(const VSO &V, 712 SymbolStringPtr Name) { 713 assert(Symbols.count(Name) && "Symbol is not part of this MU"); 714 Symbols.erase(Name); 715 } 716 717 SymbolFlagsMap 718 AbsoluteSymbolsMaterializationUnit::extractFlags(const SymbolMap &Symbols) { 719 SymbolFlagsMap Flags; 720 for (const auto &KV : Symbols) 721 Flags[KV.first] = KV.second.getFlags(); 722 return Flags; 723 } 724 725 ReExportsMaterializationUnit::ReExportsMaterializationUnit( 726 VSO *SourceVSO, SymbolAliasMap Aliases) 727 : MaterializationUnit(extractFlags(Aliases)), SourceVSO(SourceVSO), 728 Aliases(std::move(Aliases)) {} 729 730 void ReExportsMaterializationUnit::materialize( 731 MaterializationResponsibility R) { 732 733 auto &ES = R.getTargetVSO().getExecutionSession(); 734 VSO &TgtV = R.getTargetVSO(); 735 VSO &SrcV = SourceVSO ? *SourceVSO : TgtV; 736 737 // Find the set of requested aliases and aliasees. Return any unrequested 738 // aliases back to the VSO so as to not prematurely materialize any aliasees. 739 auto RequestedSymbols = R.getRequestedSymbols(); 740 SymbolAliasMap RequestedAliases; 741 742 for (auto &Name : RequestedSymbols) { 743 auto I = Aliases.find(Name); 744 assert(I != Aliases.end() && "Symbol not found in aliases map?"); 745 RequestedAliases[Name] = std::move(I->second); 746 Aliases.erase(I); 747 } 748 749 if (!Aliases.empty()) { 750 if (SourceVSO) 751 R.replace(reexports(*SourceVSO, std::move(Aliases))); 752 else 753 R.replace(symbolAliases(std::move(Aliases))); 754 } 755 756 // The OnResolveInfo struct will hold the aliases and responsibilty for each 757 // query in the list. 758 struct OnResolveInfo { 759 OnResolveInfo(MaterializationResponsibility R, SymbolAliasMap Aliases) 760 : R(std::move(R)), Aliases(std::move(Aliases)) {} 761 762 MaterializationResponsibility R; 763 SymbolAliasMap Aliases; 764 }; 765 766 // Build a list of queries to issue. In each round we build the largest set of 767 // aliases that we can resolve without encountering a chain definition of the 768 // form Foo -> Bar, Bar -> Baz. Such a form would deadlock as the query would 769 // be waitin on a symbol that it itself had to resolve. Usually this will just 770 // involve one round and a single query. 771 772 std::vector<std::pair<SymbolNameSet, std::shared_ptr<OnResolveInfo>>> 773 QueryInfos; 774 while (!RequestedAliases.empty()) { 775 SymbolNameSet ResponsibilitySymbols; 776 SymbolNameSet QuerySymbols; 777 SymbolAliasMap QueryAliases; 778 779 for (auto I = RequestedAliases.begin(), E = RequestedAliases.end(); 780 I != E;) { 781 auto Tmp = I++; 782 783 // Chain detected. Skip this symbol for this round. 784 if (&SrcV == &TgtV && (QueryAliases.count(Tmp->second.Aliasee) || 785 RequestedAliases.count(Tmp->second.Aliasee))) 786 continue; 787 788 ResponsibilitySymbols.insert(Tmp->first); 789 QuerySymbols.insert(Tmp->second.Aliasee); 790 QueryAliases[Tmp->first] = std::move(Tmp->second); 791 RequestedAliases.erase(Tmp); 792 } 793 assert(!QuerySymbols.empty() && "Alias cycle detected!"); 794 795 auto QueryInfo = std::make_shared<OnResolveInfo>( 796 R.delegate(ResponsibilitySymbols), std::move(QueryAliases)); 797 QueryInfos.push_back( 798 make_pair(std::move(QuerySymbols), std::move(QueryInfo))); 799 } 800 801 // Issue the queries. 802 while (!QueryInfos.empty()) { 803 auto QuerySymbols = std::move(QueryInfos.back().first); 804 auto QueryInfo = std::move(QueryInfos.back().second); 805 806 QueryInfos.pop_back(); 807 808 auto RegisterDependencies = [QueryInfo, 809 &SrcV](const SymbolDependenceMap &Deps) { 810 // If there were no materializing symbols, just bail out. 811 if (Deps.empty()) 812 return; 813 814 // Otherwise the only deps should be on SrcV. 815 assert(Deps.size() == 1 && Deps.count(&SrcV) && 816 "Unexpected dependencies for reexports"); 817 818 auto &SrcVDeps = Deps.find(&SrcV)->second; 819 SymbolDependenceMap PerAliasDepsMap; 820 auto &PerAliasDeps = PerAliasDepsMap[&SrcV]; 821 822 for (auto &KV : QueryInfo->Aliases) 823 if (SrcVDeps.count(KV.second.Aliasee)) { 824 PerAliasDeps = {KV.second.Aliasee}; 825 QueryInfo->R.addDependencies(KV.first, PerAliasDepsMap); 826 } 827 }; 828 829 auto OnResolve = [QueryInfo](Expected<SymbolMap> Result) { 830 if (Result) { 831 SymbolMap ResolutionMap; 832 for (auto &KV : QueryInfo->Aliases) { 833 assert(Result->count(KV.second.Aliasee) && 834 "Result map missing entry?"); 835 ResolutionMap[KV.first] = JITEvaluatedSymbol( 836 (*Result)[KV.second.Aliasee].getAddress(), KV.second.AliasFlags); 837 } 838 QueryInfo->R.resolve(ResolutionMap); 839 QueryInfo->R.finalize(); 840 } else { 841 auto &ES = QueryInfo->R.getTargetVSO().getExecutionSession(); 842 ES.reportError(Result.takeError()); 843 QueryInfo->R.failMaterialization(); 844 } 845 }; 846 847 auto OnReady = [&ES](Error Err) { ES.reportError(std::move(Err)); }; 848 849 ES.lookup({&SrcV}, QuerySymbols, std::move(OnResolve), std::move(OnReady), 850 std::move(RegisterDependencies)); 851 } 852 } 853 854 void ReExportsMaterializationUnit::discard(const VSO &V, SymbolStringPtr Name) { 855 assert(Aliases.count(Name) && 856 "Symbol not covered by this MaterializationUnit"); 857 Aliases.erase(Name); 858 } 859 860 SymbolFlagsMap 861 ReExportsMaterializationUnit::extractFlags(const SymbolAliasMap &Aliases) { 862 SymbolFlagsMap SymbolFlags; 863 for (auto &KV : Aliases) 864 SymbolFlags[KV.first] = KV.second.AliasFlags; 865 866 return SymbolFlags; 867 } 868 869 Expected<SymbolAliasMap> 870 buildSimpleReexportsAliasMap(VSO &SourceV, const SymbolNameSet &Symbols) { 871 auto Flags = SourceV.lookupFlags(Symbols); 872 873 if (Flags.size() != Symbols.size()) { 874 SymbolNameSet Unresolved = Symbols; 875 for (auto &KV : Flags) 876 Unresolved.erase(KV.first); 877 return make_error<SymbolsNotFound>(std::move(Unresolved)); 878 } 879 880 SymbolAliasMap Result; 881 for (auto &Name : Symbols) { 882 assert(Flags.count(Name) && "Missing entry in flags map"); 883 Result[Name] = SymbolAliasMapEntry(Name, Flags[Name]); 884 } 885 886 return Result; 887 } 888 889 ReexportsFallbackDefinitionGenerator::ReexportsFallbackDefinitionGenerator( 890 VSO &BackingVSO, SymbolPredicate Allow) 891 : BackingVSO(BackingVSO), Allow(std::move(Allow)) {} 892 893 SymbolNameSet ReexportsFallbackDefinitionGenerator:: 894 operator()(VSO &V, const SymbolNameSet &Names) { 895 orc::SymbolNameSet Added; 896 orc::SymbolAliasMap AliasMap; 897 898 auto Flags = BackingVSO.lookupFlags(Names); 899 900 for (auto &KV : Flags) { 901 if (!Allow(KV.first)) 902 continue; 903 AliasMap[KV.first] = SymbolAliasMapEntry(KV.first, KV.second); 904 Added.insert(KV.first); 905 } 906 907 if (!Added.empty()) 908 cantFail(V.define(reexports(BackingVSO, AliasMap))); 909 910 return Added; 911 } 912 913 Error VSO::defineMaterializing(const SymbolFlagsMap &SymbolFlags) { 914 return ES.runSessionLocked([&]() -> Error { 915 std::vector<SymbolMap::iterator> AddedSyms; 916 917 for (auto &KV : SymbolFlags) { 918 SymbolMap::iterator EntryItr; 919 bool Added; 920 921 auto NewFlags = KV.second; 922 NewFlags |= JITSymbolFlags::Materializing; 923 924 std::tie(EntryItr, Added) = Symbols.insert( 925 std::make_pair(KV.first, JITEvaluatedSymbol(0, NewFlags))); 926 927 if (Added) 928 AddedSyms.push_back(EntryItr); 929 else { 930 // Remove any symbols already added. 931 for (auto &SI : AddedSyms) 932 Symbols.erase(SI); 933 934 // FIXME: Return all duplicates. 935 return make_error<DuplicateDefinition>(*KV.first); 936 } 937 } 938 939 return Error::success(); 940 }); 941 } 942 943 void VSO::replace(std::unique_ptr<MaterializationUnit> MU) { 944 assert(MU != nullptr && "Can not replace with a null MaterializationUnit"); 945 946 auto MustRunMU = 947 ES.runSessionLocked([&, this]() -> std::unique_ptr<MaterializationUnit> { 948 949 #ifndef NDEBUG 950 for (auto &KV : MU->getSymbols()) { 951 auto SymI = Symbols.find(KV.first); 952 assert(SymI != Symbols.end() && "Replacing unknown symbol"); 953 assert(!SymI->second.getFlags().isLazy() && 954 SymI->second.getFlags().isMaterializing() && 955 "Can not replace symbol that is not materializing"); 956 assert(UnmaterializedInfos.count(KV.first) == 0 && 957 "Symbol being replaced should have no UnmaterializedInfo"); 958 } 959 #endif // NDEBUG 960 961 // If any symbol has pending queries against it then we need to 962 // materialize MU immediately. 963 for (auto &KV : MU->getSymbols()) { 964 auto MII = MaterializingInfos.find(KV.first); 965 if (MII != MaterializingInfos.end()) { 966 if (!MII->second.PendingQueries.empty()) 967 return std::move(MU); 968 } 969 } 970 971 // Otherwise, make MU responsible for all the symbols. 972 auto UMI = std::make_shared<UnmaterializedInfo>(std::move(MU)); 973 for (auto &KV : UMI->MU->getSymbols()) { 974 assert(!KV.second.isLazy() && 975 "Lazy flag should be managed internally."); 976 assert(!KV.second.isMaterializing() && 977 "Materializing flags should be managed internally."); 978 979 auto SymI = Symbols.find(KV.first); 980 JITSymbolFlags ReplaceFlags = KV.second; 981 ReplaceFlags |= JITSymbolFlags::Lazy; 982 SymI->second = JITEvaluatedSymbol(SymI->second.getAddress(), 983 std::move(ReplaceFlags)); 984 UnmaterializedInfos[KV.first] = UMI; 985 } 986 987 return nullptr; 988 }); 989 990 if (MustRunMU) 991 ES.dispatchMaterialization(*this, std::move(MustRunMU)); 992 } 993 994 SymbolNameSet VSO::getRequestedSymbols(const SymbolFlagsMap &SymbolFlags) { 995 return ES.runSessionLocked([&]() { 996 SymbolNameSet RequestedSymbols; 997 998 for (auto &KV : SymbolFlags) { 999 assert(Symbols.count(KV.first) && "VSO does not cover this symbol?"); 1000 assert(Symbols[KV.first].getFlags().isMaterializing() && 1001 "getRequestedSymbols can only be called for materializing " 1002 "symbols"); 1003 auto I = MaterializingInfos.find(KV.first); 1004 if (I == MaterializingInfos.end()) 1005 continue; 1006 1007 if (!I->second.PendingQueries.empty()) 1008 RequestedSymbols.insert(KV.first); 1009 } 1010 1011 return RequestedSymbols; 1012 }); 1013 } 1014 1015 void VSO::addDependencies(const SymbolStringPtr &Name, 1016 const SymbolDependenceMap &Dependencies) { 1017 assert(Symbols.count(Name) && "Name not in symbol table"); 1018 assert((Symbols[Name].getFlags().isLazy() || 1019 Symbols[Name].getFlags().isMaterializing()) && 1020 "Symbol is not lazy or materializing"); 1021 1022 auto &MI = MaterializingInfos[Name]; 1023 assert(!MI.IsFinalized && "Can not add dependencies to finalized symbol"); 1024 1025 for (auto &KV : Dependencies) { 1026 assert(KV.first && "Null VSO in dependency?"); 1027 auto &OtherVSO = *KV.first; 1028 auto &DepsOnOtherVSO = MI.UnfinalizedDependencies[&OtherVSO]; 1029 1030 for (auto &OtherSymbol : KV.second) { 1031 #ifndef NDEBUG 1032 // Assert that this symbol exists and has not been finalized already. 1033 auto SymI = OtherVSO.Symbols.find(OtherSymbol); 1034 assert(SymI != OtherVSO.Symbols.end() && 1035 (SymI->second.getFlags().isLazy() || 1036 SymI->second.getFlags().isMaterializing()) && 1037 "Dependency on finalized symbol"); 1038 #endif 1039 1040 auto &OtherMI = OtherVSO.MaterializingInfos[OtherSymbol]; 1041 1042 if (OtherMI.IsFinalized) 1043 transferFinalizedNodeDependencies(MI, Name, OtherMI); 1044 else if (&OtherVSO != this || OtherSymbol != Name) { 1045 OtherMI.Dependants[this].insert(Name); 1046 DepsOnOtherVSO.insert(OtherSymbol); 1047 } 1048 } 1049 1050 if (DepsOnOtherVSO.empty()) 1051 MI.UnfinalizedDependencies.erase(&OtherVSO); 1052 } 1053 } 1054 1055 void VSO::resolve(const SymbolMap &Resolved) { 1056 auto FullyResolvedQueries = ES.runSessionLocked([&, this]() { 1057 AsynchronousSymbolQuerySet FullyResolvedQueries; 1058 for (const auto &KV : Resolved) { 1059 auto &Name = KV.first; 1060 auto Sym = KV.second; 1061 1062 assert(!Sym.getFlags().isLazy() && !Sym.getFlags().isMaterializing() && 1063 "Materializing flags should be managed internally"); 1064 1065 auto I = Symbols.find(Name); 1066 1067 assert(I != Symbols.end() && "Symbol not found"); 1068 assert(!I->second.getFlags().isLazy() && 1069 I->second.getFlags().isMaterializing() && 1070 "Symbol should be materializing"); 1071 assert(I->second.getAddress() == 0 && "Symbol has already been resolved"); 1072 1073 assert((Sym.getFlags() & ~JITSymbolFlags::Weak) == 1074 (JITSymbolFlags::stripTransientFlags(I->second.getFlags()) & 1075 ~JITSymbolFlags::Weak) && 1076 "Resolved flags should match the declared flags"); 1077 1078 // Once resolved, symbols can never be weak. 1079 JITSymbolFlags ResolvedFlags = Sym.getFlags(); 1080 ResolvedFlags &= ~JITSymbolFlags::Weak; 1081 ResolvedFlags |= JITSymbolFlags::Materializing; 1082 I->second = JITEvaluatedSymbol(Sym.getAddress(), ResolvedFlags); 1083 1084 auto &MI = MaterializingInfos[Name]; 1085 for (auto &Q : MI.PendingQueries) { 1086 Q->resolve(Name, Sym); 1087 if (Q->isFullyResolved()) 1088 FullyResolvedQueries.insert(Q); 1089 } 1090 } 1091 1092 return FullyResolvedQueries; 1093 }); 1094 1095 for (auto &Q : FullyResolvedQueries) { 1096 assert(Q->isFullyResolved() && "Q not fully resolved"); 1097 Q->handleFullyResolved(); 1098 } 1099 } 1100 1101 void VSO::finalize(const SymbolFlagsMap &Finalized) { 1102 auto FullyReadyQueries = ES.runSessionLocked([&, this]() { 1103 AsynchronousSymbolQuerySet ReadyQueries; 1104 1105 for (const auto &KV : Finalized) { 1106 const auto &Name = KV.first; 1107 1108 auto MII = MaterializingInfos.find(Name); 1109 assert(MII != MaterializingInfos.end() && 1110 "Missing MaterializingInfo entry"); 1111 1112 auto &MI = MII->second; 1113 1114 // For each dependant, transfer this node's unfinalized dependencies to 1115 // it. If the dependant node is fully finalized then notify any pending 1116 // queries. 1117 for (auto &KV : MI.Dependants) { 1118 auto &DependantVSO = *KV.first; 1119 for (auto &DependantName : KV.second) { 1120 auto DependantMII = 1121 DependantVSO.MaterializingInfos.find(DependantName); 1122 assert(DependantMII != DependantVSO.MaterializingInfos.end() && 1123 "Dependant should have MaterializingInfo"); 1124 1125 auto &DependantMI = DependantMII->second; 1126 1127 // Remove the dependant's dependency on this node. 1128 assert(DependantMI.UnfinalizedDependencies[this].count(Name) && 1129 "Dependant does not count this symbol as a dependency?"); 1130 DependantMI.UnfinalizedDependencies[this].erase(Name); 1131 if (DependantMI.UnfinalizedDependencies[this].empty()) 1132 DependantMI.UnfinalizedDependencies.erase(this); 1133 1134 // Transfer unfinalized dependencies from this node to the dependant. 1135 DependantVSO.transferFinalizedNodeDependencies(DependantMI, 1136 DependantName, MI); 1137 1138 // If the dependant is finalized and this node was the last of its 1139 // unfinalized dependencies then notify any pending queries on the 1140 // dependant node. 1141 if (DependantMI.IsFinalized && 1142 DependantMI.UnfinalizedDependencies.empty()) { 1143 assert(DependantMI.Dependants.empty() && 1144 "Dependants should be empty by now"); 1145 for (auto &Q : DependantMI.PendingQueries) { 1146 Q->notifySymbolReady(); 1147 if (Q->isFullyReady()) 1148 ReadyQueries.insert(Q); 1149 Q->removeQueryDependence(DependantVSO, DependantName); 1150 } 1151 1152 // If this dependant node was fully finalized we can erase its 1153 // MaterializingInfo and update its materializing state. 1154 assert(DependantVSO.Symbols.count(DependantName) && 1155 "Dependant has no entry in the Symbols table"); 1156 auto &DependantSym = DependantVSO.Symbols[DependantName]; 1157 DependantSym.setFlags(static_cast<JITSymbolFlags::FlagNames>( 1158 DependantSym.getFlags() & ~JITSymbolFlags::Materializing)); 1159 DependantVSO.MaterializingInfos.erase(DependantMII); 1160 } 1161 } 1162 } 1163 MI.Dependants.clear(); 1164 MI.IsFinalized = true; 1165 1166 if (MI.UnfinalizedDependencies.empty()) { 1167 for (auto &Q : MI.PendingQueries) { 1168 Q->notifySymbolReady(); 1169 if (Q->isFullyReady()) 1170 ReadyQueries.insert(Q); 1171 Q->removeQueryDependence(*this, Name); 1172 } 1173 assert(Symbols.count(Name) && 1174 "Symbol has no entry in the Symbols table"); 1175 auto &Sym = Symbols[Name]; 1176 Sym.setFlags(static_cast<JITSymbolFlags::FlagNames>( 1177 Sym.getFlags() & ~JITSymbolFlags::Materializing)); 1178 MaterializingInfos.erase(MII); 1179 } 1180 } 1181 1182 return ReadyQueries; 1183 }); 1184 1185 for (auto &Q : FullyReadyQueries) { 1186 assert(Q->isFullyReady() && "Q is not fully ready"); 1187 Q->handleFullyReady(); 1188 } 1189 } 1190 1191 void VSO::notifyFailed(const SymbolNameSet &FailedSymbols) { 1192 1193 // FIXME: This should fail any transitively dependant symbols too. 1194 1195 auto FailedQueriesToNotify = ES.runSessionLocked([&, this]() { 1196 AsynchronousSymbolQuerySet FailedQueries; 1197 1198 for (auto &Name : FailedSymbols) { 1199 auto I = Symbols.find(Name); 1200 assert(I != Symbols.end() && "Symbol not present in this VSO"); 1201 Symbols.erase(I); 1202 1203 auto MII = MaterializingInfos.find(Name); 1204 1205 // If we have not created a MaterializingInfo for this symbol yet then 1206 // there is nobody to notify. 1207 if (MII == MaterializingInfos.end()) 1208 continue; 1209 1210 // Copy all the queries to the FailedQueries list, then abandon them. 1211 // This has to be a copy, and the copy has to come before the abandon 1212 // operation: Each Q.detach() call will reach back into this 1213 // PendingQueries list to remove Q. 1214 for (auto &Q : MII->second.PendingQueries) 1215 FailedQueries.insert(Q); 1216 1217 for (auto &Q : FailedQueries) 1218 Q->detach(); 1219 1220 assert(MII->second.PendingQueries.empty() && 1221 "Queries remain after symbol was failed"); 1222 1223 MaterializingInfos.erase(MII); 1224 } 1225 1226 return FailedQueries; 1227 }); 1228 1229 for (auto &Q : FailedQueriesToNotify) 1230 Q->handleFailed(make_error<FailedToMaterialize>(FailedSymbols)); 1231 } 1232 1233 void VSO::setSearchOrder(VSOList NewSearchOrder, bool SearchThisVSOFirst) { 1234 if (SearchThisVSOFirst && NewSearchOrder.front() != this) 1235 NewSearchOrder.insert(NewSearchOrder.begin(), this); 1236 1237 ES.runSessionLocked([&]() { SearchOrder = std::move(NewSearchOrder); }); 1238 } 1239 1240 void VSO::addToSearchOrder(VSO &V) { 1241 ES.runSessionLocked([&]() { SearchOrder.push_back(&V); }); 1242 } 1243 1244 void VSO::replaceInSearchOrder(VSO &OldV, VSO &NewV) { 1245 ES.runSessionLocked([&]() { 1246 auto I = std::find(SearchOrder.begin(), SearchOrder.end(), &OldV); 1247 1248 if (I != SearchOrder.end()) 1249 *I = &NewV; 1250 }); 1251 } 1252 1253 void VSO::removeFromSearchOrder(VSO &V) { 1254 ES.runSessionLocked([&]() { 1255 auto I = std::find(SearchOrder.begin(), SearchOrder.end(), &V); 1256 if (I != SearchOrder.end()) 1257 SearchOrder.erase(I); 1258 }); 1259 } 1260 1261 SymbolFlagsMap VSO::lookupFlags(const SymbolNameSet &Names) { 1262 return ES.runSessionLocked([&, this]() { 1263 SymbolFlagsMap Result; 1264 auto Unresolved = lookupFlagsImpl(Result, Names); 1265 if (FallbackDefinitionGenerator && !Unresolved.empty()) { 1266 auto FallbackDefs = FallbackDefinitionGenerator(*this, Unresolved); 1267 if (!FallbackDefs.empty()) { 1268 auto Unresolved2 = lookupFlagsImpl(Result, FallbackDefs); 1269 (void)Unresolved2; 1270 assert(Unresolved2.empty() && 1271 "All fallback defs should have been found by lookupFlagsImpl"); 1272 } 1273 }; 1274 return Result; 1275 }); 1276 } 1277 1278 SymbolNameSet VSO::lookupFlagsImpl(SymbolFlagsMap &Flags, 1279 const SymbolNameSet &Names) { 1280 SymbolNameSet Unresolved; 1281 1282 for (auto &Name : Names) { 1283 auto I = Symbols.find(Name); 1284 1285 if (I == Symbols.end()) { 1286 Unresolved.insert(Name); 1287 continue; 1288 } 1289 1290 assert(!Flags.count(Name) && "Symbol already present in Flags map"); 1291 Flags[Name] = JITSymbolFlags::stripTransientFlags(I->second.getFlags()); 1292 } 1293 1294 return Unresolved; 1295 } 1296 1297 void VSO::lodgeQuery(std::shared_ptr<AsynchronousSymbolQuery> &Q, 1298 SymbolNameSet &Unresolved, MaterializationUnitList &MUs) { 1299 assert(Q && "Query can not be null"); 1300 1301 lodgeQueryImpl(Q, Unresolved, MUs); 1302 if (FallbackDefinitionGenerator && !Unresolved.empty()) { 1303 auto FallbackDefs = FallbackDefinitionGenerator(*this, Unresolved); 1304 if (!FallbackDefs.empty()) { 1305 for (auto &D : FallbackDefs) 1306 Unresolved.erase(D); 1307 lodgeQueryImpl(Q, FallbackDefs, MUs); 1308 assert(FallbackDefs.empty() && 1309 "All fallback defs should have been found by lookupImpl"); 1310 } 1311 } 1312 } 1313 1314 void VSO::lodgeQueryImpl( 1315 std::shared_ptr<AsynchronousSymbolQuery> &Q, SymbolNameSet &Unresolved, 1316 std::vector<std::unique_ptr<MaterializationUnit>> &MUs) { 1317 for (auto I = Unresolved.begin(), E = Unresolved.end(); I != E;) { 1318 auto TmpI = I++; 1319 auto Name = *TmpI; 1320 1321 // Search for the name in Symbols. Skip it if not found. 1322 auto SymI = Symbols.find(Name); 1323 if (SymI == Symbols.end()) 1324 continue; 1325 1326 // If we found Name in V, remove it frome the Unresolved set and add it 1327 // to the added set. 1328 Unresolved.erase(TmpI); 1329 1330 // If the symbol has an address then resolve it. 1331 if (SymI->second.getAddress() != 0) 1332 Q->resolve(Name, SymI->second); 1333 1334 // If the symbol is lazy, get the MaterialiaztionUnit for it. 1335 if (SymI->second.getFlags().isLazy()) { 1336 assert(SymI->second.getAddress() == 0 && 1337 "Lazy symbol should not have a resolved address"); 1338 assert(!SymI->second.getFlags().isMaterializing() && 1339 "Materializing and lazy should not both be set"); 1340 auto UMII = UnmaterializedInfos.find(Name); 1341 assert(UMII != UnmaterializedInfos.end() && 1342 "Lazy symbol should have UnmaterializedInfo"); 1343 auto MU = std::move(UMII->second->MU); 1344 assert(MU != nullptr && "Materializer should not be null"); 1345 1346 // Move all symbols associated with this MaterializationUnit into 1347 // materializing state. 1348 for (auto &KV : MU->getSymbols()) { 1349 auto SymK = Symbols.find(KV.first); 1350 auto Flags = SymK->second.getFlags(); 1351 Flags &= ~JITSymbolFlags::Lazy; 1352 Flags |= JITSymbolFlags::Materializing; 1353 SymK->second.setFlags(Flags); 1354 UnmaterializedInfos.erase(KV.first); 1355 } 1356 1357 // Add MU to the list of MaterializationUnits to be materialized. 1358 MUs.push_back(std::move(MU)); 1359 } else if (!SymI->second.getFlags().isMaterializing()) { 1360 // The symbol is neither lazy nor materializing. Finalize it and 1361 // continue. 1362 Q->notifySymbolReady(); 1363 continue; 1364 } 1365 1366 // Add the query to the PendingQueries list. 1367 assert(SymI->second.getFlags().isMaterializing() && 1368 "By this line the symbol should be materializing"); 1369 auto &MI = MaterializingInfos[Name]; 1370 MI.PendingQueries.push_back(Q); 1371 Q->addQueryDependence(*this, Name); 1372 } 1373 } 1374 1375 SymbolNameSet VSO::legacyLookup(std::shared_ptr<AsynchronousSymbolQuery> Q, 1376 SymbolNameSet Names) { 1377 assert(Q && "Query can not be null"); 1378 1379 ES.runOutstandingMUs(); 1380 1381 LookupImplActionFlags ActionFlags = None; 1382 std::vector<std::unique_ptr<MaterializationUnit>> MUs; 1383 1384 SymbolNameSet Unresolved = std::move(Names); 1385 ES.runSessionLocked([&, this]() { 1386 ActionFlags = lookupImpl(Q, MUs, Unresolved); 1387 if (FallbackDefinitionGenerator && !Unresolved.empty()) { 1388 assert(ActionFlags == None && 1389 "ActionFlags set but unresolved symbols remain?"); 1390 auto FallbackDefs = FallbackDefinitionGenerator(*this, Unresolved); 1391 if (!FallbackDefs.empty()) { 1392 for (auto &D : FallbackDefs) 1393 Unresolved.erase(D); 1394 ActionFlags = lookupImpl(Q, MUs, FallbackDefs); 1395 assert(FallbackDefs.empty() && 1396 "All fallback defs should have been found by lookupImpl"); 1397 } 1398 } 1399 }); 1400 1401 assert((MUs.empty() || ActionFlags == None) && 1402 "If action flags are set, there should be no work to do (so no MUs)"); 1403 1404 if (ActionFlags & NotifyFullyResolved) 1405 Q->handleFullyResolved(); 1406 1407 if (ActionFlags & NotifyFullyReady) 1408 Q->handleFullyReady(); 1409 1410 // FIXME: Swap back to the old code below once RuntimeDyld works with 1411 // callbacks from asynchronous queries. 1412 // Add MUs to the OutstandingMUs list. 1413 { 1414 std::lock_guard<std::recursive_mutex> Lock(ES.OutstandingMUsMutex); 1415 for (auto &MU : MUs) 1416 ES.OutstandingMUs.push_back(make_pair(this, std::move(MU))); 1417 } 1418 ES.runOutstandingMUs(); 1419 1420 // Dispatch any required MaterializationUnits for materialization. 1421 // for (auto &MU : MUs) 1422 // ES.dispatchMaterialization(*this, std::move(MU)); 1423 1424 return Unresolved; 1425 } 1426 1427 VSO::LookupImplActionFlags 1428 VSO::lookupImpl(std::shared_ptr<AsynchronousSymbolQuery> &Q, 1429 std::vector<std::unique_ptr<MaterializationUnit>> &MUs, 1430 SymbolNameSet &Unresolved) { 1431 LookupImplActionFlags ActionFlags = None; 1432 1433 for (auto I = Unresolved.begin(), E = Unresolved.end(); I != E;) { 1434 auto TmpI = I++; 1435 auto Name = *TmpI; 1436 1437 // Search for the name in Symbols. Skip it if not found. 1438 auto SymI = Symbols.find(Name); 1439 if (SymI == Symbols.end()) 1440 continue; 1441 1442 // If we found Name in V, remove it frome the Unresolved set and add it 1443 // to the dependencies set. 1444 Unresolved.erase(TmpI); 1445 1446 // If the symbol has an address then resolve it. 1447 if (SymI->second.getAddress() != 0) { 1448 Q->resolve(Name, SymI->second); 1449 if (Q->isFullyResolved()) 1450 ActionFlags |= NotifyFullyResolved; 1451 } 1452 1453 // If the symbol is lazy, get the MaterialiaztionUnit for it. 1454 if (SymI->second.getFlags().isLazy()) { 1455 assert(SymI->second.getAddress() == 0 && 1456 "Lazy symbol should not have a resolved address"); 1457 assert(!SymI->second.getFlags().isMaterializing() && 1458 "Materializing and lazy should not both be set"); 1459 auto UMII = UnmaterializedInfos.find(Name); 1460 assert(UMII != UnmaterializedInfos.end() && 1461 "Lazy symbol should have UnmaterializedInfo"); 1462 auto MU = std::move(UMII->second->MU); 1463 assert(MU != nullptr && "Materializer should not be null"); 1464 1465 // Kick all symbols associated with this MaterializationUnit into 1466 // materializing state. 1467 for (auto &KV : MU->getSymbols()) { 1468 auto SymK = Symbols.find(KV.first); 1469 auto Flags = SymK->second.getFlags(); 1470 Flags &= ~JITSymbolFlags::Lazy; 1471 Flags |= JITSymbolFlags::Materializing; 1472 SymK->second.setFlags(Flags); 1473 UnmaterializedInfos.erase(KV.first); 1474 } 1475 1476 // Add MU to the list of MaterializationUnits to be materialized. 1477 MUs.push_back(std::move(MU)); 1478 } else if (!SymI->second.getFlags().isMaterializing()) { 1479 // The symbol is neither lazy nor materializing. Finalize it and 1480 // continue. 1481 Q->notifySymbolReady(); 1482 if (Q->isFullyReady()) 1483 ActionFlags |= NotifyFullyReady; 1484 continue; 1485 } 1486 1487 // Add the query to the PendingQueries list. 1488 assert(SymI->second.getFlags().isMaterializing() && 1489 "By this line the symbol should be materializing"); 1490 auto &MI = MaterializingInfos[Name]; 1491 MI.PendingQueries.push_back(Q); 1492 Q->addQueryDependence(*this, Name); 1493 } 1494 1495 return ActionFlags; 1496 } 1497 1498 void VSO::dump(raw_ostream &OS) { 1499 ES.runSessionLocked([&, this]() { 1500 OS << "VSO \"" << VSOName 1501 << "\" (ES: " << format("0x%016x", reinterpret_cast<uintptr_t>(&ES)) 1502 << "):\n" 1503 << "Symbol table:\n"; 1504 1505 for (auto &KV : Symbols) { 1506 OS << " \"" << *KV.first 1507 << "\": " << format("0x%016x", KV.second.getAddress()); 1508 if (KV.second.getFlags().isLazy() || 1509 KV.second.getFlags().isMaterializing()) { 1510 OS << " ("; 1511 if (KV.second.getFlags().isLazy()) { 1512 auto I = UnmaterializedInfos.find(KV.first); 1513 assert(I != UnmaterializedInfos.end() && 1514 "Lazy symbol should have UnmaterializedInfo"); 1515 OS << " Lazy (MU=" << I->second->MU.get() << ")"; 1516 } 1517 if (KV.second.getFlags().isMaterializing()) 1518 OS << " Materializing"; 1519 OS << " )\n"; 1520 } else 1521 OS << "\n"; 1522 } 1523 1524 if (!MaterializingInfos.empty()) 1525 OS << " MaterializingInfos entries:\n"; 1526 for (auto &KV : MaterializingInfos) { 1527 OS << " \"" << *KV.first << "\":\n" 1528 << " IsFinalized = " << (KV.second.IsFinalized ? "true" : "false") 1529 << "\n" 1530 << " " << KV.second.PendingQueries.size() 1531 << " pending queries: { "; 1532 for (auto &Q : KV.second.PendingQueries) 1533 OS << Q.get() << " "; 1534 OS << "}\n Dependants:\n"; 1535 for (auto &KV2 : KV.second.Dependants) 1536 OS << " " << KV2.first->getName() << ": " << KV2.second << "\n"; 1537 OS << " Unfinalized Dependencies:\n"; 1538 for (auto &KV2 : KV.second.UnfinalizedDependencies) 1539 OS << " " << KV2.first->getName() << ": " << KV2.second << "\n"; 1540 } 1541 }); 1542 } 1543 1544 VSO::VSO(ExecutionSessionBase &ES, std::string Name) 1545 : ES(ES), VSOName(std::move(Name)) { 1546 SearchOrder.push_back(this); 1547 } 1548 1549 Error VSO::defineImpl(MaterializationUnit &MU) { 1550 SymbolNameSet Duplicates; 1551 SymbolNameSet MUDefsOverridden; 1552 1553 struct ExistingDefOverriddenEntry { 1554 SymbolMap::iterator ExistingDefItr; 1555 JITSymbolFlags NewFlags; 1556 }; 1557 std::vector<ExistingDefOverriddenEntry> ExistingDefsOverridden; 1558 1559 for (auto &KV : MU.getSymbols()) { 1560 assert(!KV.second.isLazy() && "Lazy flag should be managed internally."); 1561 assert(!KV.second.isMaterializing() && 1562 "Materializing flags should be managed internally."); 1563 1564 SymbolMap::iterator EntryItr; 1565 bool Added; 1566 1567 auto NewFlags = KV.second; 1568 NewFlags |= JITSymbolFlags::Lazy; 1569 1570 std::tie(EntryItr, Added) = Symbols.insert( 1571 std::make_pair(KV.first, JITEvaluatedSymbol(0, NewFlags))); 1572 1573 if (!Added) { 1574 if (KV.second.isStrong()) { 1575 if (EntryItr->second.getFlags().isStrong() || 1576 (EntryItr->second.getFlags() & JITSymbolFlags::Materializing)) 1577 Duplicates.insert(KV.first); 1578 else 1579 ExistingDefsOverridden.push_back({EntryItr, NewFlags}); 1580 } else 1581 MUDefsOverridden.insert(KV.first); 1582 } 1583 } 1584 1585 if (!Duplicates.empty()) { 1586 // We need to remove the symbols we added. 1587 for (auto &KV : MU.getSymbols()) { 1588 if (Duplicates.count(KV.first)) 1589 continue; 1590 1591 bool Found = false; 1592 for (const auto &EDO : ExistingDefsOverridden) 1593 if (EDO.ExistingDefItr->first == KV.first) 1594 Found = true; 1595 1596 if (!Found) 1597 Symbols.erase(KV.first); 1598 } 1599 1600 // FIXME: Return all duplicates. 1601 return make_error<DuplicateDefinition>(**Duplicates.begin()); 1602 } 1603 1604 // Update flags on existing defs and call discard on their materializers. 1605 for (auto &EDO : ExistingDefsOverridden) { 1606 assert(EDO.ExistingDefItr->second.getFlags().isLazy() && 1607 !EDO.ExistingDefItr->second.getFlags().isMaterializing() && 1608 "Overridden existing def should be in the Lazy state"); 1609 1610 EDO.ExistingDefItr->second.setFlags(EDO.NewFlags); 1611 1612 auto UMII = UnmaterializedInfos.find(EDO.ExistingDefItr->first); 1613 assert(UMII != UnmaterializedInfos.end() && 1614 "Overridden existing def should have an UnmaterializedInfo"); 1615 1616 UMII->second->MU->doDiscard(*this, EDO.ExistingDefItr->first); 1617 } 1618 1619 // Discard overridden symbols povided by MU. 1620 for (auto &Sym : MUDefsOverridden) 1621 MU.doDiscard(*this, Sym); 1622 1623 return Error::success(); 1624 } 1625 1626 void VSO::detachQueryHelper(AsynchronousSymbolQuery &Q, 1627 const SymbolNameSet &QuerySymbols) { 1628 for (auto &QuerySymbol : QuerySymbols) { 1629 assert(MaterializingInfos.count(QuerySymbol) && 1630 "QuerySymbol does not have MaterializingInfo"); 1631 auto &MI = MaterializingInfos[QuerySymbol]; 1632 1633 auto IdenticalQuery = 1634 [&](const std::shared_ptr<AsynchronousSymbolQuery> &R) { 1635 return R.get() == &Q; 1636 }; 1637 1638 auto I = std::find_if(MI.PendingQueries.begin(), MI.PendingQueries.end(), 1639 IdenticalQuery); 1640 assert(I != MI.PendingQueries.end() && 1641 "Query Q should be in the PendingQueries list for QuerySymbol"); 1642 MI.PendingQueries.erase(I); 1643 } 1644 } 1645 1646 void VSO::transferFinalizedNodeDependencies( 1647 MaterializingInfo &DependantMI, const SymbolStringPtr &DependantName, 1648 MaterializingInfo &FinalizedMI) { 1649 for (auto &KV : FinalizedMI.UnfinalizedDependencies) { 1650 auto &DependencyVSO = *KV.first; 1651 SymbolNameSet *UnfinalizedDependenciesOnDependencyVSO = nullptr; 1652 1653 for (auto &DependencyName : KV.second) { 1654 auto &DependencyMI = DependencyVSO.MaterializingInfos[DependencyName]; 1655 1656 // Do not add self dependencies. 1657 if (&DependencyMI == &DependantMI) 1658 continue; 1659 1660 // If we haven't looked up the dependencies for DependencyVSO yet, do it 1661 // now and cache the result. 1662 if (!UnfinalizedDependenciesOnDependencyVSO) 1663 UnfinalizedDependenciesOnDependencyVSO = 1664 &DependantMI.UnfinalizedDependencies[&DependencyVSO]; 1665 1666 DependencyMI.Dependants[this].insert(DependantName); 1667 UnfinalizedDependenciesOnDependencyVSO->insert(DependencyName); 1668 } 1669 } 1670 } 1671 1672 VSO &ExecutionSession::createVSO(std::string Name) { 1673 return runSessionLocked([&, this]() -> VSO & { 1674 VSOs.push_back(std::unique_ptr<VSO>(new VSO(*this, std::move(Name)))); 1675 return *VSOs.back(); 1676 }); 1677 } 1678 1679 Expected<SymbolMap> lookup(const VSOList &VSOs, SymbolNameSet Names) { 1680 1681 if (VSOs.empty()) 1682 return SymbolMap(); 1683 1684 auto &ES = (*VSOs.begin())->getExecutionSession(); 1685 1686 return ES.lookup(VSOs, Names, NoDependenciesToRegister, true); 1687 } 1688 1689 /// Look up a symbol by searching a list of VSOs. 1690 Expected<JITEvaluatedSymbol> lookup(const VSOList &VSOs, SymbolStringPtr Name) { 1691 SymbolNameSet Names({Name}); 1692 if (auto ResultMap = lookup(VSOs, std::move(Names))) { 1693 assert(ResultMap->size() == 1 && "Unexpected number of results"); 1694 assert(ResultMap->count(Name) && "Missing result for symbol"); 1695 return std::move(ResultMap->begin()->second); 1696 } else 1697 return ResultMap.takeError(); 1698 } 1699 1700 MangleAndInterner::MangleAndInterner(ExecutionSessionBase &ES, 1701 const DataLayout &DL) 1702 : ES(ES), DL(DL) {} 1703 1704 SymbolStringPtr MangleAndInterner::operator()(StringRef Name) { 1705 std::string MangledName; 1706 { 1707 raw_string_ostream MangledNameStream(MangledName); 1708 Mangler::getNameWithPrefix(MangledNameStream, Name, DL); 1709 } 1710 return ES.getSymbolStringPool().intern(MangledName); 1711 } 1712 1713 } // End namespace orc. 1714 } // End namespace llvm. 1715