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/Support/Format.h" 14 15 #if LLVM_ENABLE_THREADS 16 #include <future> 17 #endif 18 19 namespace llvm { 20 namespace orc { 21 22 char FailedToMaterialize::ID = 0; 23 char SymbolsNotFound::ID = 0; 24 25 void MaterializationUnit::anchor() {} 26 void SymbolResolver::anchor() {} 27 28 raw_ostream &operator<<(raw_ostream &OS, const JITSymbolFlags &Flags) { 29 if (Flags.isWeak()) 30 OS << 'W'; 31 else if (Flags.isCommon()) 32 OS << 'C'; 33 else 34 OS << 'S'; 35 36 if (Flags.isExported()) 37 OS << 'E'; 38 else 39 OS << 'H'; 40 41 return OS; 42 } 43 44 raw_ostream &operator<<(raw_ostream &OS, const JITEvaluatedSymbol &Sym) { 45 OS << format("0x%016x", Sym.getAddress()) << " " << Sym.getFlags(); 46 return OS; 47 } 48 49 raw_ostream &operator<<(raw_ostream &OS, const SymbolMap::value_type &KV) { 50 OS << "\"" << *KV.first << "\": " << KV.second; 51 return OS; 52 } 53 54 raw_ostream &operator<<(raw_ostream &OS, const SymbolNameSet &Symbols) { 55 OS << "{"; 56 if (!Symbols.empty()) { 57 OS << " \"" << **Symbols.begin() << "\""; 58 for (auto &Sym : make_range(std::next(Symbols.begin()), Symbols.end())) 59 OS << ", \"" << *Sym << "\""; 60 } 61 OS << " }"; 62 return OS; 63 } 64 65 raw_ostream &operator<<(raw_ostream &OS, const SymbolMap &Symbols) { 66 OS << "{"; 67 if (!Symbols.empty()) { 68 OS << " {" << *Symbols.begin() << "}"; 69 for (auto &Sym : make_range(std::next(Symbols.begin()), Symbols.end())) 70 OS << ", {" << Sym << "}"; 71 } 72 OS << " }"; 73 return OS; 74 } 75 76 raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap &SymbolFlags) { 77 OS << "{"; 78 if (!SymbolFlags.empty()) { 79 OS << " {\"" << *SymbolFlags.begin()->first 80 << "\": " << SymbolFlags.begin()->second << "}"; 81 for (auto &KV : 82 make_range(std::next(SymbolFlags.begin()), SymbolFlags.end())) 83 OS << ", {\"" << *KV.first << "\": " << KV.second << "}"; 84 } 85 OS << " }"; 86 return OS; 87 } 88 89 raw_ostream &operator<<(raw_ostream &OS, const SymbolDependenceMap &Deps) { 90 OS << "{"; 91 if (!Deps.empty()) { 92 OS << " { " << Deps.begin()->first->getName() << ": " 93 << Deps.begin()->second << " }"; 94 for (auto &KV : make_range(std::next(Deps.begin()), Deps.end())) 95 OS << ", { " << KV.first->getName() << ": " << KV.second << " }"; 96 } 97 OS << " }"; 98 return OS; 99 } 100 101 FailedToMaterialize::FailedToMaterialize(SymbolNameSet Symbols) 102 : Symbols(std::move(Symbols)) { 103 assert(!this->Symbols.empty() && "Can not fail to resolve an empty set"); 104 } 105 106 std::error_code FailedToMaterialize::convertToErrorCode() const { 107 return orcError(OrcErrorCode::UnknownORCError); 108 } 109 110 void FailedToMaterialize::log(raw_ostream &OS) const { 111 OS << "Failed to materialize symbols: " << Symbols; 112 } 113 114 SymbolsNotFound::SymbolsNotFound(SymbolNameSet Symbols) 115 : Symbols(std::move(Symbols)) { 116 assert(!this->Symbols.empty() && "Can not fail to resolve an empty set"); 117 } 118 119 std::error_code SymbolsNotFound::convertToErrorCode() const { 120 return orcError(OrcErrorCode::UnknownORCError); 121 } 122 123 void SymbolsNotFound::log(raw_ostream &OS) const { 124 OS << "Symbols not found: " << Symbols; 125 } 126 127 void ExecutionSessionBase::failQuery(AsynchronousSymbolQuery &Q, Error Err) { 128 bool DeliveredError = true; 129 runSessionLocked([&]() -> void { 130 Q.detach(); 131 if (Q.canStillFail()) 132 Q.handleFailed(std::move(Err)); 133 else 134 DeliveredError = false; 135 }); 136 137 if (!DeliveredError) 138 reportError(std::move(Err)); 139 } 140 141 AsynchronousSymbolQuery::AsynchronousSymbolQuery( 142 const SymbolNameSet &Symbols, SymbolsResolvedCallback NotifySymbolsResolved, 143 SymbolsReadyCallback NotifySymbolsReady) 144 : NotifySymbolsResolved(std::move(NotifySymbolsResolved)), 145 NotifySymbolsReady(std::move(NotifySymbolsReady)) { 146 NotYetResolvedCount = NotYetReadyCount = Symbols.size(); 147 148 for (auto &S : Symbols) 149 ResolvedSymbols[S] = nullptr; 150 } 151 152 void AsynchronousSymbolQuery::resolve(const SymbolStringPtr &Name, 153 JITEvaluatedSymbol Sym) { 154 auto I = ResolvedSymbols.find(Name); 155 assert(I != ResolvedSymbols.end() && 156 "Resolving symbol outside the requested set"); 157 assert(I->second.getAddress() == 0 && "Redundantly resolving symbol Name"); 158 I->second = std::move(Sym); 159 --NotYetResolvedCount; 160 } 161 162 void AsynchronousSymbolQuery::handleFullyResolved() { 163 assert(NotYetResolvedCount == 0 && "Not fully resolved?"); 164 assert(NotifySymbolsResolved && 165 "NotifySymbolsResolved already called or error occurred"); 166 NotifySymbolsResolved( 167 ResolutionResult(std::move(ResolvedSymbols), QueryRegistrations)); 168 NotifySymbolsResolved = SymbolsResolvedCallback(); 169 } 170 171 void AsynchronousSymbolQuery::notifySymbolReady() { 172 assert(NotYetReadyCount != 0 && "All symbols already finalized"); 173 --NotYetReadyCount; 174 } 175 176 void AsynchronousSymbolQuery::handleFullyReady() { 177 assert(QueryRegistrations.empty() && 178 "Query is still registered with some symbols"); 179 assert(!NotifySymbolsResolved && "Resolution not applied yet"); 180 NotifySymbolsReady(Error::success()); 181 NotifySymbolsReady = SymbolsReadyCallback(); 182 } 183 184 bool AsynchronousSymbolQuery::canStillFail() { 185 return (NotifySymbolsResolved || NotifySymbolsReady); 186 } 187 188 void AsynchronousSymbolQuery::handleFailed(Error Err) { 189 assert(QueryRegistrations.empty() && ResolvedSymbols.empty() && 190 NotYetResolvedCount == 0 && NotYetReadyCount == 0 && 191 "Query should already have been abandoned"); 192 if (NotifySymbolsResolved) 193 NotifySymbolsResolved(std::move(Err)); 194 else { 195 assert(NotifySymbolsReady && "Failed after both callbacks issued?"); 196 NotifySymbolsReady(std::move(Err)); 197 NotifySymbolsReady = SymbolsReadyCallback(); 198 } 199 } 200 201 void AsynchronousSymbolQuery::addQueryDependence(VSO &V, SymbolStringPtr Name) { 202 bool Added = QueryRegistrations[&V].insert(std::move(Name)).second; 203 (void)Added; 204 assert(Added && "Duplicate dependence notification?"); 205 } 206 207 void AsynchronousSymbolQuery::removeQueryDependence( 208 VSO &V, const SymbolStringPtr &Name) { 209 auto QRI = QueryRegistrations.find(&V); 210 assert(QRI != QueryRegistrations.end() && "No dependencies registered for V"); 211 assert(QRI->second.count(Name) && "No dependency on Name in V"); 212 QRI->second.erase(Name); 213 if (QRI->second.empty()) 214 QueryRegistrations.erase(QRI); 215 } 216 217 void AsynchronousSymbolQuery::detach() { 218 ResolvedSymbols.clear(); 219 NotYetResolvedCount = 0; 220 NotYetReadyCount = 0; 221 for (auto &KV : QueryRegistrations) 222 KV.first->detachQueryHelper(*this, KV.second); 223 QueryRegistrations.clear(); 224 } 225 226 MaterializationResponsibility::MaterializationResponsibility( 227 VSO &V, SymbolFlagsMap SymbolFlags) 228 : V(V), SymbolFlags(std::move(SymbolFlags)) { 229 assert(!this->SymbolFlags.empty() && "Materializing nothing?"); 230 231 for (auto &KV : this->SymbolFlags) 232 KV.second |= JITSymbolFlags::Materializing; 233 } 234 235 MaterializationResponsibility::~MaterializationResponsibility() { 236 assert(SymbolFlags.empty() && 237 "All symbols should have been explicitly materialized or failed"); 238 } 239 240 SymbolNameSet MaterializationResponsibility::getRequestedSymbols() { 241 return V.getRequestedSymbols(SymbolFlags); 242 } 243 244 void MaterializationResponsibility::resolve(const SymbolMap &Symbols) { 245 for (auto &KV : Symbols) { 246 auto I = SymbolFlags.find(KV.first); 247 assert(I != SymbolFlags.end() && 248 "Resolving symbol outside this responsibility set"); 249 assert(I->second.isMaterializing() && "Duplicate resolution"); 250 I->second &= ~JITSymbolFlags::Materializing; 251 assert(KV.second.getFlags() == I->second && 252 "Resolving symbol with incorrect flags"); 253 } 254 255 V.resolve(Symbols); 256 } 257 258 void MaterializationResponsibility::finalize() { 259 #ifndef NDEBUG 260 for (auto &KV : SymbolFlags) 261 assert(!KV.second.isMaterializing() && 262 "Failed to resolve symbol before finalization"); 263 #endif // NDEBUG 264 265 V.finalize(SymbolFlags); 266 SymbolFlags.clear(); 267 } 268 269 Error MaterializationResponsibility::defineMaterializing( 270 const SymbolFlagsMap &NewSymbolFlags) { 271 // Add the given symbols to this responsibility object. 272 // It's ok if we hit a duplicate here: In that case the new version will be 273 // discarded, and the VSO::defineMaterializing method will return a duplicate 274 // symbol error. 275 for (auto &KV : NewSymbolFlags) { 276 auto I = SymbolFlags.insert(KV).first; 277 I->second |= JITSymbolFlags::Materializing; 278 } 279 280 return V.defineMaterializing(NewSymbolFlags); 281 } 282 283 void MaterializationResponsibility::failMaterialization() { 284 285 SymbolNameSet FailedSymbols; 286 for (auto &KV : SymbolFlags) 287 FailedSymbols.insert(KV.first); 288 289 V.notifyFailed(FailedSymbols); 290 SymbolFlags.clear(); 291 } 292 293 void MaterializationResponsibility::delegate( 294 std::unique_ptr<MaterializationUnit> MU) { 295 for (auto &KV : MU->getSymbols()) 296 SymbolFlags.erase(KV.first); 297 298 V.replace(std::move(MU)); 299 } 300 301 void MaterializationResponsibility::addDependencies( 302 const SymbolDependenceMap &Dependencies) { 303 V.addDependencies(SymbolFlags, Dependencies); 304 } 305 306 AbsoluteSymbolsMaterializationUnit::AbsoluteSymbolsMaterializationUnit( 307 SymbolMap Symbols) 308 : MaterializationUnit(extractFlags(Symbols)), Symbols(std::move(Symbols)) {} 309 310 void AbsoluteSymbolsMaterializationUnit::materialize( 311 MaterializationResponsibility R) { 312 R.resolve(Symbols); 313 R.finalize(); 314 } 315 316 void AbsoluteSymbolsMaterializationUnit::discard(const VSO &V, 317 SymbolStringPtr Name) { 318 assert(Symbols.count(Name) && "Symbol is not part of this MU"); 319 Symbols.erase(Name); 320 } 321 322 SymbolFlagsMap 323 AbsoluteSymbolsMaterializationUnit::extractFlags(const SymbolMap &Symbols) { 324 SymbolFlagsMap Flags; 325 for (const auto &KV : Symbols) 326 Flags[KV.first] = KV.second.getFlags(); 327 return Flags; 328 } 329 330 Error VSO::defineMaterializing(const SymbolFlagsMap &SymbolFlags) { 331 return ES.runSessionLocked([&]() -> Error { 332 std::vector<SymbolMap::iterator> AddedSyms; 333 334 for (auto &KV : SymbolFlags) { 335 SymbolMap::iterator EntryItr; 336 bool Added; 337 338 auto NewFlags = KV.second; 339 NewFlags |= JITSymbolFlags::Materializing; 340 341 std::tie(EntryItr, Added) = Symbols.insert( 342 std::make_pair(KV.first, JITEvaluatedSymbol(0, NewFlags))); 343 344 if (Added) 345 AddedSyms.push_back(EntryItr); 346 else { 347 // Remove any symbols already added. 348 for (auto &SI : AddedSyms) 349 Symbols.erase(SI); 350 351 // FIXME: Return all duplicates. 352 return make_error<DuplicateDefinition>(*KV.first); 353 } 354 } 355 356 return Error::success(); 357 }); 358 } 359 360 void VSO::replace(std::unique_ptr<MaterializationUnit> MU) { 361 assert(MU != nullptr && "Can not replace with a null MaterializationUnit"); 362 363 auto MustRunMU = 364 ES.runSessionLocked([&, this]() -> std::unique_ptr<MaterializationUnit> { 365 366 #ifndef NDEBUG 367 for (auto &KV : MU->getSymbols()) { 368 auto SymI = Symbols.find(KV.first); 369 assert(SymI != Symbols.end() && "Replacing unknown symbol"); 370 assert(!SymI->second.getFlags().isLazy() && 371 SymI->second.getFlags().isMaterializing() && 372 "Can not replace symbol that is not materializing"); 373 assert(UnmaterializedInfos.count(KV.first) == 0 && 374 "Symbol being replaced should have no UnmaterializedInfo"); 375 } 376 #endif // NDEBUG 377 378 // If any symbol has pending queries against it then we need to 379 // materialize MU immediately. 380 for (auto &KV : MU->getSymbols()) { 381 auto MII = MaterializingInfos.find(KV.first); 382 if (MII != MaterializingInfos.end()) { 383 if (!MII->second.PendingQueries.empty()) 384 return std::move(MU); 385 } 386 } 387 388 // Otherwise, make MU responsible for all the symbols. 389 auto UMI = std::make_shared<UnmaterializedInfo>(std::move(MU)); 390 for (auto &KV : UMI->MU->getSymbols()) { 391 assert(!KV.second.isLazy() && 392 "Lazy flag should be managed internally."); 393 assert(!KV.second.isMaterializing() && 394 "Materializing flags should be managed internally."); 395 396 auto SymI = Symbols.find(KV.first); 397 JITSymbolFlags ReplaceFlags = KV.second; 398 ReplaceFlags |= JITSymbolFlags::Lazy; 399 SymI->second = JITEvaluatedSymbol(SymI->second.getAddress(), 400 std::move(ReplaceFlags)); 401 UnmaterializedInfos[KV.first] = UMI; 402 } 403 404 return nullptr; 405 }); 406 407 if (MustRunMU) 408 ES.dispatchMaterialization(*this, std::move(MustRunMU)); 409 } 410 411 SymbolNameSet VSO::getRequestedSymbols(const SymbolFlagsMap &SymbolFlags) { 412 return ES.runSessionLocked([&]() { 413 SymbolNameSet RequestedSymbols; 414 415 for (auto &KV : SymbolFlags) { 416 assert(Symbols.count(KV.first) && "VSO does not cover this symbol?"); 417 assert(Symbols[KV.first].getFlags().isMaterializing() && 418 "getRequestedSymbols can only be called for materializing " 419 "symbols"); 420 auto I = MaterializingInfos.find(KV.first); 421 if (I == MaterializingInfos.end()) 422 continue; 423 424 if (!I->second.PendingQueries.empty()) 425 RequestedSymbols.insert(KV.first); 426 } 427 428 return RequestedSymbols; 429 }); 430 } 431 432 void VSO::addDependencies(const SymbolFlagsMap &Dependants, 433 const SymbolDependenceMap &Dependencies) { 434 ES.runSessionLocked([&, this]() { 435 for (auto &KV : Dependants) { 436 const auto &Name = KV.first; 437 assert(Symbols.count(Name) && "Name not in symbol table"); 438 assert((Symbols[Name].getFlags().isLazy() || 439 Symbols[Name].getFlags().isMaterializing()) && 440 "Symbol is not lazy or materializing"); 441 442 auto &MI = MaterializingInfos[Name]; 443 assert(!MI.IsFinalized && "Can not add dependencies to finalized symbol"); 444 445 for (auto &KV : Dependencies) { 446 assert(KV.first && "Null VSO in dependency?"); 447 auto &OtherVSO = *KV.first; 448 auto &DepsOnOtherVSO = MI.UnfinalizedDependencies[&OtherVSO]; 449 450 for (auto &OtherSymbol : KV.second) { 451 auto &OtherMI = OtherVSO.MaterializingInfos[OtherSymbol]; 452 453 if (OtherMI.IsFinalized) 454 transferFinalizedNodeDependencies(MI, Name, OtherMI); 455 else { 456 OtherMI.Dependants[this].insert(Name); 457 DepsOnOtherVSO.insert(OtherSymbol); 458 } 459 } 460 } 461 } 462 }); 463 } 464 465 void VSO::resolve(const SymbolMap &Resolved) { 466 auto FullyResolvedQueries = ES.runSessionLocked([&, this]() { 467 AsynchronousSymbolQuerySet FullyResolvedQueries; 468 for (const auto &KV : Resolved) { 469 auto &Name = KV.first; 470 auto Sym = KV.second; 471 472 assert(!Sym.getFlags().isLazy() && !Sym.getFlags().isMaterializing() && 473 "Materializing flags should be managed internally"); 474 475 auto I = Symbols.find(Name); 476 477 assert(I != Symbols.end() && "Symbol not found"); 478 assert(!I->second.getFlags().isLazy() && 479 I->second.getFlags().isMaterializing() && 480 "Symbol should be materializing"); 481 assert(I->second.getAddress() == 0 && "Symbol has already been resolved"); 482 483 assert(Sym.getFlags() == 484 JITSymbolFlags::stripTransientFlags(I->second.getFlags()) && 485 "Resolved flags should match the declared flags"); 486 487 // Once resolved, symbols can never be weak. 488 JITSymbolFlags ResolvedFlags = Sym.getFlags(); 489 ResolvedFlags &= ~JITSymbolFlags::Weak; 490 ResolvedFlags |= JITSymbolFlags::Materializing; 491 I->second = JITEvaluatedSymbol(Sym.getAddress(), ResolvedFlags); 492 493 auto &MI = MaterializingInfos[Name]; 494 for (auto &Q : MI.PendingQueries) { 495 Q->resolve(Name, Sym); 496 if (Q->isFullyResolved()) 497 FullyResolvedQueries.insert(Q); 498 } 499 } 500 501 return FullyResolvedQueries; 502 }); 503 504 for (auto &Q : FullyResolvedQueries) { 505 assert(Q->isFullyResolved() && "Q not fully resolved"); 506 Q->handleFullyResolved(); 507 } 508 } 509 510 void VSO::finalize(const SymbolFlagsMap &Finalized) { 511 auto FullyReadyQueries = ES.runSessionLocked([&, this]() { 512 AsynchronousSymbolQuerySet ReadyQueries; 513 514 for (const auto &KV : Finalized) { 515 const auto &Name = KV.first; 516 517 auto MII = MaterializingInfos.find(Name); 518 assert(MII != MaterializingInfos.end() && 519 "Missing MaterializingInfo entry"); 520 521 auto &MI = MII->second; 522 523 // For each dependant, transfer this node's unfinalized dependencies to 524 // it. If the dependant node is fully finalized then notify any pending 525 // queries. 526 for (auto &KV : MI.Dependants) { 527 auto &DependantVSO = *KV.first; 528 for (auto &DependantName : KV.second) { 529 auto DependantMII = 530 DependantVSO.MaterializingInfos.find(DependantName); 531 assert(DependantMII != DependantVSO.MaterializingInfos.end() && 532 "Dependant should have MaterializingInfo"); 533 534 auto &DependantMI = DependantMII->second; 535 536 // Remove the dependant's dependency on this node. 537 assert(DependantMI.UnfinalizedDependencies[this].count(Name) && 538 "Dependant does not count this symbol as a dependency?"); 539 DependantMI.UnfinalizedDependencies[this].erase(Name); 540 if (DependantMI.UnfinalizedDependencies[this].empty()) 541 DependantMI.UnfinalizedDependencies.erase(this); 542 543 // Transfer unfinalized dependencies from this node to the dependant. 544 DependantVSO.transferFinalizedNodeDependencies(DependantMI, 545 DependantName, MI); 546 547 // If the dependant is finalized and this node was the last of its 548 // unfinalized dependencies then notify any pending queries on the 549 // dependant node. 550 if (DependantMI.IsFinalized && 551 DependantMI.UnfinalizedDependencies.empty()) { 552 assert(DependantMI.Dependants.empty() && 553 "Dependants should be empty by now"); 554 for (auto &Q : DependantMI.PendingQueries) { 555 Q->notifySymbolReady(); 556 if (Q->isFullyReady()) 557 ReadyQueries.insert(Q); 558 Q->removeQueryDependence(DependantVSO, DependantName); 559 } 560 561 // If this dependant node was fully finalized we can erase its 562 // MaterializingInfo and update its materializing state. 563 assert(DependantVSO.Symbols.count(DependantName) && 564 "Dependant has no entry in the Symbols table"); 565 DependantVSO.Symbols[DependantName].getFlags() &= 566 JITSymbolFlags::Materializing; 567 DependantVSO.MaterializingInfos.erase(DependantMII); 568 } 569 } 570 } 571 MI.Dependants.clear(); 572 MI.IsFinalized = true; 573 574 if (MI.UnfinalizedDependencies.empty()) { 575 for (auto &Q : MI.PendingQueries) { 576 Q->notifySymbolReady(); 577 if (Q->isFullyReady()) 578 ReadyQueries.insert(Q); 579 Q->removeQueryDependence(*this, Name); 580 } 581 assert(Symbols.count(Name) && 582 "Symbol has no entry in the Symbols table"); 583 Symbols[Name].getFlags() &= ~JITSymbolFlags::Materializing; 584 MaterializingInfos.erase(MII); 585 } 586 } 587 588 return ReadyQueries; 589 }); 590 591 for (auto &Q : FullyReadyQueries) { 592 assert(Q->isFullyReady() && "Q is not fully ready"); 593 Q->handleFullyReady(); 594 } 595 } 596 597 void VSO::notifyFailed(const SymbolNameSet &FailedSymbols) { 598 599 // FIXME: This should fail any transitively dependant symbols too. 600 601 auto FailedQueriesToNotify = ES.runSessionLocked([&, this]() { 602 AsynchronousSymbolQuerySet FailedQueries; 603 604 for (auto &Name : FailedSymbols) { 605 auto I = Symbols.find(Name); 606 assert(I != Symbols.end() && "Symbol not present in this VSO"); 607 Symbols.erase(I); 608 609 auto MII = MaterializingInfos.find(Name); 610 611 // If we have not created a MaterializingInfo for this symbol yet then 612 // there is nobody to notify. 613 if (MII == MaterializingInfos.end()) 614 continue; 615 616 // Copy all the queries to the FailedQueries list, then abandon them. 617 // This has to be a copy, and the copy has to come before the abandon 618 // operation: Each Q.detach() call will reach back into this 619 // PendingQueries list to remove Q. 620 for (auto &Q : MII->second.PendingQueries) 621 FailedQueries.insert(Q); 622 623 for (auto &Q : FailedQueries) 624 Q->detach(); 625 626 assert(MII->second.PendingQueries.empty() && 627 "Queries remain after symbol was failed"); 628 629 MaterializingInfos.erase(MII); 630 } 631 632 return FailedQueries; 633 }); 634 635 for (auto &Q : FailedQueriesToNotify) 636 Q->handleFailed(make_error<FailedToMaterialize>(FailedSymbols)); 637 } 638 639 SymbolNameSet VSO::lookupFlags(SymbolFlagsMap &Flags, 640 const SymbolNameSet &Names) { 641 return ES.runSessionLocked([&, this]() { 642 SymbolNameSet Unresolved; 643 644 for (auto &Name : Names) { 645 auto I = Symbols.find(Name); 646 if (I == Symbols.end()) { 647 Unresolved.insert(Name); 648 continue; 649 } 650 651 assert(!Flags.count(Name) && "Symbol already present in Flags map"); 652 Flags[Name] = JITSymbolFlags::stripTransientFlags(I->second.getFlags()); 653 } 654 655 return Unresolved; 656 }); 657 } 658 659 SymbolNameSet VSO::lookup(std::shared_ptr<AsynchronousSymbolQuery> Q, 660 SymbolNameSet Names) { 661 SymbolNameSet Unresolved = std::move(Names); 662 std::vector<std::unique_ptr<MaterializationUnit>> MUs; 663 664 ES.runSessionLocked([&, this]() { 665 for (auto I = Unresolved.begin(), E = Unresolved.end(); I != E;) { 666 auto TmpI = I++; 667 auto Name = *TmpI; 668 669 // Search for the name in Symbols. Skip it if not found. 670 auto SymI = Symbols.find(Name); 671 if (SymI == Symbols.end()) 672 continue; 673 674 // If we found Name in V, remove it frome the Unresolved set and add it 675 // to the dependencies set. 676 Unresolved.erase(TmpI); 677 678 // If the symbol has an address then resolve it. 679 if (SymI->second.getAddress() != 0) 680 Q->resolve(Name, SymI->second); 681 682 // If the symbol is lazy, get the MaterialiaztionUnit for it. 683 if (SymI->second.getFlags().isLazy()) { 684 assert(SymI->second.getAddress() == 0 && 685 "Lazy symbol should not have a resolved address"); 686 assert(!SymI->second.getFlags().isMaterializing() && 687 "Materializing and lazy should not both be set"); 688 auto UMII = UnmaterializedInfos.find(Name); 689 assert(UMII != UnmaterializedInfos.end() && 690 "Lazy symbol should have UnmaterializedInfo"); 691 auto MU = std::move(UMII->second->MU); 692 assert(MU != nullptr && "Materializer should not be null"); 693 694 // Kick all symbols associated with this MaterializationUnit into 695 // materializing state. 696 for (auto &KV : MU->getSymbols()) { 697 auto SymK = Symbols.find(KV.first); 698 auto Flags = SymK->second.getFlags(); 699 Flags &= ~JITSymbolFlags::Lazy; 700 Flags |= JITSymbolFlags::Materializing; 701 SymK->second.setFlags(Flags); 702 UnmaterializedInfos.erase(KV.first); 703 } 704 705 // Add MU to the list of MaterializationUnits to be materialized. 706 MUs.push_back(std::move(MU)); 707 } else if (!SymI->second.getFlags().isMaterializing()) { 708 // The symbol is neither lazy nor materializing. Finalize it and 709 // continue. 710 Q->notifySymbolReady(); 711 continue; 712 } 713 714 // Add the query to the PendingQueries list. 715 assert(SymI->second.getFlags().isMaterializing() && 716 "By this line the symbol should be materializing"); 717 auto &MI = MaterializingInfos[Name]; 718 MI.PendingQueries.push_back(Q); 719 Q->addQueryDependence(*this, Name); 720 } 721 }); 722 723 if (Q->isFullyResolved()) 724 Q->handleFullyResolved(); 725 726 if (Q->isFullyReady()) 727 Q->handleFullyReady(); 728 729 // Dispatch any required MaterializationUnits for materialization. 730 for (auto &MU : MUs) 731 ES.dispatchMaterialization(*this, std::move(MU)); 732 733 return Unresolved; 734 } 735 736 void VSO::dump(raw_ostream &OS) { 737 ES.runSessionLocked([&, this]() { 738 OS << "VSO \"" << VSOName 739 << "\" (ES: " << format("0x%016x", reinterpret_cast<uintptr_t>(&ES)) 740 << "):\n" 741 << "Symbol table:\n"; 742 743 for (auto &KV : Symbols) { 744 OS << " \"" << *KV.first << "\": " << KV.second.getAddress(); 745 if (KV.second.getFlags().isLazy() || 746 KV.second.getFlags().isMaterializing()) { 747 OS << " ("; 748 if (KV.second.getFlags().isLazy()) { 749 auto I = UnmaterializedInfos.find(KV.first); 750 assert(I != UnmaterializedInfos.end() && 751 "Lazy symbol should have UnmaterializedInfo"); 752 OS << " Lazy (MU=" << I->second->MU.get() << ")"; 753 } 754 if (KV.second.getFlags().isMaterializing()) 755 OS << " Materializing"; 756 OS << " )\n"; 757 } else 758 OS << "\n"; 759 } 760 761 if (!MaterializingInfos.empty()) 762 OS << " MaterializingInfos entries:\n"; 763 for (auto &KV : MaterializingInfos) { 764 OS << " \"" << *KV.first << "\":\n" 765 << " IsFinalized = " << (KV.second.IsFinalized ? "true" : "false") 766 << "\n" 767 << " " << KV.second.PendingQueries.size() << " pending queries.\n" 768 << " Dependants:\n"; 769 for (auto &KV2 : KV.second.Dependants) 770 OS << " " << KV2.first->getName() << ": " << KV2.second << "\n"; 771 OS << " Unfinalized Dependencies:\n"; 772 for (auto &KV2 : KV.second.UnfinalizedDependencies) 773 OS << " " << KV2.first->getName() << ": " << KV2.second << "\n"; 774 } 775 }); 776 } 777 778 Error VSO::defineImpl(MaterializationUnit &MU) { 779 SymbolNameSet Duplicates; 780 SymbolNameSet MUDefsOverridden; 781 std::vector<SymbolMap::iterator> ExistingDefsOverridden; 782 for (auto &KV : MU.getSymbols()) { 783 assert(!KV.second.isLazy() && "Lazy flag should be managed internally."); 784 assert(!KV.second.isMaterializing() && 785 "Materializing flags should be managed internally."); 786 787 SymbolMap::iterator EntryItr; 788 bool Added; 789 790 auto NewFlags = KV.second; 791 NewFlags |= JITSymbolFlags::Lazy; 792 793 std::tie(EntryItr, Added) = Symbols.insert( 794 std::make_pair(KV.first, JITEvaluatedSymbol(0, NewFlags))); 795 796 if (!Added) { 797 if (KV.second.isStrong()) { 798 if (EntryItr->second.getFlags().isStrong()) 799 Duplicates.insert(KV.first); 800 else 801 ExistingDefsOverridden.push_back(EntryItr); 802 } else 803 MUDefsOverridden.insert(KV.first); 804 } 805 } 806 807 if (!Duplicates.empty()) { 808 // We need to remove the symbols we added. 809 for (auto &KV : MU.getSymbols()) { 810 if (Duplicates.count(KV.first) || Duplicates.count(KV.first)) 811 continue; 812 813 bool Found = false; 814 for (const auto &I : ExistingDefsOverridden) 815 if (I->first == KV.first) 816 Found = true; 817 818 if (!Found) 819 Symbols.erase(KV.first); 820 } 821 822 // FIXME: Return all duplicates. 823 return make_error<DuplicateDefinition>(**Duplicates.begin()); 824 } 825 826 // Update flags on existing defs and call discard on their materializers. 827 for (auto &ExistingDefItr : ExistingDefsOverridden) { 828 assert(ExistingDefItr->second.getFlags().isLazy() && 829 !ExistingDefItr->second.getFlags().isMaterializing() && 830 "Overridden existing def should be in the Lazy state"); 831 832 ExistingDefItr->second.getFlags() &= ~JITSymbolFlags::Weak; 833 834 auto UMII = UnmaterializedInfos.find(ExistingDefItr->first); 835 assert(UMII != UnmaterializedInfos.end() && 836 "Overridden existing def should have an UnmaterializedInfo"); 837 838 UMII->second->MU->doDiscard(*this, ExistingDefItr->first); 839 } 840 841 // Discard overridden symbols povided by MU. 842 for (auto &Sym : MUDefsOverridden) 843 MU.doDiscard(*this, Sym); 844 845 return Error::success(); 846 } 847 848 void VSO::detachQueryHelper(AsynchronousSymbolQuery &Q, 849 const SymbolNameSet &QuerySymbols) { 850 for (auto &QuerySymbol : QuerySymbols) { 851 assert(MaterializingInfos.count(QuerySymbol) && 852 "QuerySymbol does not have MaterializingInfo"); 853 auto &MI = MaterializingInfos[QuerySymbol]; 854 855 auto IdenticalQuery = 856 [&](const std::shared_ptr<AsynchronousSymbolQuery> &R) { 857 return R.get() == &Q; 858 }; 859 860 auto I = std::find_if(MI.PendingQueries.begin(), MI.PendingQueries.end(), 861 IdenticalQuery); 862 assert(I != MI.PendingQueries.end() && 863 "Query Q should be in the PendingQueries list for QuerySymbol"); 864 MI.PendingQueries.erase(I); 865 } 866 } 867 868 void VSO::transferFinalizedNodeDependencies( 869 MaterializingInfo &DependantMI, const SymbolStringPtr &DependantName, 870 MaterializingInfo &FinalizedMI) { 871 for (auto &KV : FinalizedMI.UnfinalizedDependencies) { 872 auto &DependencyVSO = *KV.first; 873 SymbolNameSet *UnfinalizedDependenciesOnDependencyVSO = nullptr; 874 875 for (auto &DependencyName : KV.second) { 876 auto &DependencyMI = DependencyVSO.MaterializingInfos[DependencyName]; 877 878 // Do not add self dependencies. 879 if (&DependencyMI == &DependantMI) 880 continue; 881 882 // If we haven't looked up the dependencies for DependencyVSO yet, do it 883 // now and cache the result. 884 if (!UnfinalizedDependenciesOnDependencyVSO) 885 UnfinalizedDependenciesOnDependencyVSO = 886 &DependantMI.UnfinalizedDependencies[&DependencyVSO]; 887 888 DependencyMI.Dependants[this].insert(DependantName); 889 UnfinalizedDependenciesOnDependencyVSO->insert(DependencyName); 890 } 891 } 892 } 893 894 VSO &ExecutionSession::createVSO(std::string Name) { 895 return runSessionLocked([&, this]() -> VSO & { 896 VSOs.push_back(std::unique_ptr<VSO>(new VSO(*this, std::move(Name)))); 897 return *VSOs.back(); 898 }); 899 } 900 901 Expected<SymbolMap> lookup(const VSO::VSOList &VSOs, SymbolNameSet Names) { 902 903 #if LLVM_ENABLE_THREADS 904 // In the threaded case we use promises to return the results. 905 std::promise<SymbolMap> PromisedResult; 906 std::mutex ErrMutex; 907 Error ResolutionError = Error::success(); 908 std::promise<void> PromisedReady; 909 Error ReadyError = Error::success(); 910 auto OnResolve = 911 [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) { 912 if (Result) 913 PromisedResult.set_value(std::move(Result->Symbols)); 914 else { 915 { 916 ErrorAsOutParameter _(&ResolutionError); 917 std::lock_guard<std::mutex> Lock(ErrMutex); 918 ResolutionError = Result.takeError(); 919 } 920 PromisedResult.set_value(SymbolMap()); 921 } 922 }; 923 auto OnReady = [&](Error Err) { 924 if (Err) { 925 ErrorAsOutParameter _(&ReadyError); 926 std::lock_guard<std::mutex> Lock(ErrMutex); 927 ReadyError = std::move(Err); 928 } 929 PromisedReady.set_value(); 930 }; 931 #else 932 SymbolMap Result; 933 Error ResolutionError = Error::success(); 934 Error ReadyError = Error::success(); 935 936 auto OnResolve = [&](Expected<AsynchronousSymbolQuery::ResolutionResult> R) { 937 ErrorAsOutParameter _(&ResolutionError); 938 if (R) 939 Result = std::move(R->Symbols); 940 else 941 ResolutionError = R.takeError(); 942 }; 943 auto OnReady = [&](Error Err) { 944 ErrorAsOutParameter _(&ReadyError); 945 if (Err) 946 ReadyError = std::move(Err); 947 }; 948 #endif 949 950 auto Query = std::make_shared<AsynchronousSymbolQuery>( 951 Names, std::move(OnResolve), std::move(OnReady)); 952 SymbolNameSet UnresolvedSymbols(std::move(Names)); 953 954 for (auto *V : VSOs) { 955 assert(V && "VSO pointers in VSOs list should be non-null"); 956 if (UnresolvedSymbols.empty()) 957 break; 958 UnresolvedSymbols = V->lookup(Query, UnresolvedSymbols); 959 } 960 961 if (!UnresolvedSymbols.empty()) { 962 // If there are unresolved symbols then the query will never return. 963 // Fail it with ES.failQuery. 964 auto &ES = (*VSOs.begin())->getExecutionSession(); 965 ES.failQuery(*Query, 966 make_error<SymbolsNotFound>(std::move(UnresolvedSymbols))); 967 } 968 969 #if LLVM_ENABLE_THREADS 970 auto ResultFuture = PromisedResult.get_future(); 971 auto Result = ResultFuture.get(); 972 973 { 974 std::lock_guard<std::mutex> Lock(ErrMutex); 975 if (ResolutionError) { 976 // ReadyError will never be assigned. Consume the success value. 977 cantFail(std::move(ReadyError)); 978 return std::move(ResolutionError); 979 } 980 } 981 982 auto ReadyFuture = PromisedReady.get_future(); 983 ReadyFuture.get(); 984 985 { 986 std::lock_guard<std::mutex> Lock(ErrMutex); 987 if (ReadyError) 988 return std::move(ReadyError); 989 } 990 991 return std::move(Result); 992 993 #else 994 if (ResolutionError) { 995 // ReadyError will never be assigned. Consume the success value. 996 cantFail(std::move(ReadyError)); 997 return std::move(ResolutionError); 998 } 999 1000 if (ReadyError) 1001 return std::move(ReadyError); 1002 1003 return Result; 1004 #endif 1005 } 1006 1007 /// Look up a symbol by searching a list of VSOs. 1008 Expected<JITEvaluatedSymbol> lookup(const VSO::VSOList &VSOs, 1009 SymbolStringPtr Name) { 1010 SymbolNameSet Names({Name}); 1011 if (auto ResultMap = lookup(VSOs, std::move(Names))) { 1012 assert(ResultMap->size() == 1 && "Unexpected number of results"); 1013 assert(ResultMap->count(Name) && "Missing result for symbol"); 1014 return std::move(ResultMap->begin()->second); 1015 } else 1016 return ResultMap.takeError(); 1017 } 1018 1019 } // End namespace orc. 1020 } // End namespace llvm. 1021