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 void MaterializationResponsibility::resolve(const SymbolMap &Symbols) { 241 for (auto &KV : Symbols) { 242 auto I = SymbolFlags.find(KV.first); 243 assert(I != SymbolFlags.end() && 244 "Resolving symbol outside this responsibility set"); 245 assert(I->second.isMaterializing() && "Duplicate resolution"); 246 I->second &= ~JITSymbolFlags::Materializing; 247 assert(KV.second.getFlags() == I->second && 248 "Resolving symbol with incorrect flags"); 249 } 250 251 V.resolve(Symbols); 252 } 253 254 void MaterializationResponsibility::finalize() { 255 #ifndef NDEBUG 256 for (auto &KV : SymbolFlags) 257 assert(!KV.second.isMaterializing() && 258 "Failed to resolve symbol before finalization"); 259 #endif // NDEBUG 260 261 V.finalize(SymbolFlags); 262 SymbolFlags.clear(); 263 } 264 265 Error MaterializationResponsibility::defineMaterializing( 266 const SymbolFlagsMap &NewSymbolFlags) { 267 // Add the given symbols to this responsibility object. 268 // It's ok if we hit a duplicate here: In that case the new version will be 269 // discarded, and the VSO::defineMaterializing method will return a duplicate 270 // symbol error. 271 for (auto &KV : NewSymbolFlags) { 272 auto I = SymbolFlags.insert(KV).first; 273 I->second |= JITSymbolFlags::Materializing; 274 } 275 276 return V.defineMaterializing(NewSymbolFlags); 277 } 278 279 void MaterializationResponsibility::failMaterialization() { 280 281 SymbolNameSet FailedSymbols; 282 for (auto &KV : SymbolFlags) 283 FailedSymbols.insert(KV.first); 284 285 V.notifyFailed(FailedSymbols); 286 SymbolFlags.clear(); 287 } 288 289 void MaterializationResponsibility::delegate( 290 std::unique_ptr<MaterializationUnit> MU) { 291 for (auto &KV : MU->getSymbols()) 292 SymbolFlags.erase(KV.first); 293 294 V.replace(std::move(MU)); 295 } 296 297 void MaterializationResponsibility::addDependencies( 298 const SymbolDependenceMap &Dependencies) { 299 V.addDependencies(SymbolFlags, Dependencies); 300 } 301 302 AbsoluteSymbolsMaterializationUnit::AbsoluteSymbolsMaterializationUnit( 303 SymbolMap Symbols) 304 : MaterializationUnit(extractFlags(Symbols)), Symbols(std::move(Symbols)) {} 305 306 void AbsoluteSymbolsMaterializationUnit::materialize( 307 MaterializationResponsibility R) { 308 R.resolve(Symbols); 309 R.finalize(); 310 } 311 312 void AbsoluteSymbolsMaterializationUnit::discard(const VSO &V, 313 SymbolStringPtr Name) { 314 assert(Symbols.count(Name) && "Symbol is not part of this MU"); 315 Symbols.erase(Name); 316 } 317 318 SymbolFlagsMap 319 AbsoluteSymbolsMaterializationUnit::extractFlags(const SymbolMap &Symbols) { 320 SymbolFlagsMap Flags; 321 for (const auto &KV : Symbols) 322 Flags[KV.first] = KV.second.getFlags(); 323 return Flags; 324 } 325 326 Error VSO::defineMaterializing(const SymbolFlagsMap &SymbolFlags) { 327 return ES.runSessionLocked([&]() -> Error { 328 std::vector<SymbolMap::iterator> AddedSyms; 329 330 for (auto &KV : SymbolFlags) { 331 SymbolMap::iterator EntryItr; 332 bool Added; 333 334 auto NewFlags = KV.second; 335 NewFlags |= JITSymbolFlags::Materializing; 336 337 std::tie(EntryItr, Added) = Symbols.insert( 338 std::make_pair(KV.first, JITEvaluatedSymbol(0, NewFlags))); 339 340 if (Added) 341 AddedSyms.push_back(EntryItr); 342 else { 343 // Remove any symbols already added. 344 for (auto &SI : AddedSyms) 345 Symbols.erase(SI); 346 347 // FIXME: Return all duplicates. 348 return make_error<DuplicateDefinition>(*KV.first); 349 } 350 } 351 352 return Error::success(); 353 }); 354 } 355 356 void VSO::replace(std::unique_ptr<MaterializationUnit> MU) { 357 assert(MU != nullptr && "Can not replace with a null MaterializationUnit"); 358 359 auto MustRunMU = 360 ES.runSessionLocked([&, this]() -> std::unique_ptr<MaterializationUnit> { 361 362 #ifndef NDEBUG 363 for (auto &KV : MU->getSymbols()) { 364 auto SymI = Symbols.find(KV.first); 365 assert(SymI != Symbols.end() && "Replacing unknown symbol"); 366 assert(!SymI->second.getFlags().isLazy() && 367 SymI->second.getFlags().isMaterializing() && 368 "Can not replace symbol that is not materializing"); 369 assert(UnmaterializedInfos.count(KV.first) == 0 && 370 "Symbol being replaced should have no UnmaterializedInfo"); 371 assert(MaterializingInfos.count(KV.first) && 372 "Symbol being replaced should have a MaterializingInfo"); 373 } 374 #endif // NDEBUG 375 376 // If any symbol has pending queries against it then we need to 377 // materialize MU immediately. 378 for (auto &KV : MU->getSymbols()) 379 if (!MaterializingInfos[KV.first].PendingQueries.empty()) 380 return std::move(MU); 381 382 // Otherwise, make MU responsible for all the symbols. 383 auto UMI = std::make_shared<UnmaterializedInfo>(std::move(MU)); 384 for (auto &KV : UMI->MU->getSymbols()) { 385 assert(!KV.second.isLazy() && 386 "Lazy flag should be managed internally."); 387 assert(!KV.second.isMaterializing() && 388 "Materializing flags should be managed internally."); 389 390 auto SymI = Symbols.find(KV.first); 391 SymI->second.getFlags() = KV.second; 392 SymI->second.getFlags() |= JITSymbolFlags::Lazy; 393 UnmaterializedInfos[KV.first] = UMI; 394 } 395 396 return nullptr; 397 }); 398 399 if (MustRunMU) 400 ES.dispatchMaterialization(*this, std::move(MustRunMU)); 401 } 402 403 void VSO::addDependencies(const SymbolFlagsMap &Dependants, 404 const SymbolDependenceMap &Dependencies) { 405 ES.runSessionLocked([&, this]() { 406 for (auto &KV : Dependants) { 407 const auto &Name = KV.first; 408 assert(Symbols.count(Name) && "Name not in symbol table"); 409 assert((Symbols[Name].getFlags().isLazy() || 410 Symbols[Name].getFlags().isMaterializing()) && 411 "Symbol is not lazy or materializing"); 412 413 auto &MI = MaterializingInfos[Name]; 414 assert(!MI.IsFinalized && "Can not add dependencies to finalized symbol"); 415 416 for (auto &KV : Dependencies) { 417 assert(KV.first && "Null VSO in dependency?"); 418 auto &OtherVSO = *KV.first; 419 auto &DepsOnOtherVSO = MI.UnfinalizedDependencies[&OtherVSO]; 420 421 for (auto &OtherSymbol : KV.second) { 422 auto &OtherMI = OtherVSO.MaterializingInfos[OtherSymbol]; 423 424 if (OtherMI.IsFinalized) 425 transferFinalizedNodeDependencies(MI, Name, OtherMI); 426 else { 427 OtherMI.Dependants[this].insert(Name); 428 DepsOnOtherVSO.insert(OtherSymbol); 429 } 430 } 431 } 432 } 433 }); 434 } 435 436 void VSO::resolve(const SymbolMap &Resolved) { 437 auto FullyResolvedQueries = ES.runSessionLocked([&, this]() { 438 AsynchronousSymbolQuerySet FullyResolvedQueries; 439 for (const auto &KV : Resolved) { 440 auto &Name = KV.first; 441 auto Sym = KV.second; 442 443 assert(!Sym.getFlags().isLazy() && !Sym.getFlags().isMaterializing() && 444 "Materializing flags should be managed internally"); 445 446 auto I = Symbols.find(Name); 447 448 assert(I != Symbols.end() && "Symbol not found"); 449 assert(!I->second.getFlags().isLazy() && 450 I->second.getFlags().isMaterializing() && 451 "Symbol should be materializing"); 452 assert(I->second.getAddress() == 0 && "Symbol has already been resolved"); 453 454 assert(Sym.getFlags() == 455 JITSymbolFlags::stripTransientFlags(I->second.getFlags()) && 456 "Resolved flags should match the declared flags"); 457 458 // Once resolved, symbols can never be weak. 459 JITSymbolFlags ResolvedFlags = Sym.getFlags(); 460 ResolvedFlags &= ~JITSymbolFlags::Weak; 461 ResolvedFlags |= JITSymbolFlags::Materializing; 462 I->second = JITEvaluatedSymbol(Sym.getAddress(), ResolvedFlags); 463 464 auto &MI = MaterializingInfos[Name]; 465 for (auto &Q : MI.PendingQueries) { 466 Q->resolve(Name, Sym); 467 if (Q->isFullyResolved()) 468 FullyResolvedQueries.insert(Q); 469 } 470 } 471 472 return FullyResolvedQueries; 473 }); 474 475 for (auto &Q : FullyResolvedQueries) { 476 assert(Q->isFullyResolved() && "Q not fully resolved"); 477 Q->handleFullyResolved(); 478 } 479 } 480 481 void VSO::finalize(const SymbolFlagsMap &Finalized) { 482 auto FullyReadyQueries = ES.runSessionLocked([&, this]() { 483 AsynchronousSymbolQuerySet ReadyQueries; 484 485 for (const auto &KV : Finalized) { 486 const auto &Name = KV.first; 487 488 auto MII = MaterializingInfos.find(Name); 489 assert(MII != MaterializingInfos.end() && 490 "Missing MaterializingInfo entry"); 491 492 auto &MI = MII->second; 493 494 // For each dependant, transfer this node's unfinalized dependencies to 495 // it. If the dependant node is fully finalized then notify any pending 496 // queries. 497 for (auto &KV : MI.Dependants) { 498 auto &DependantVSO = *KV.first; 499 for (auto &DependantName : KV.second) { 500 auto DependantMII = 501 DependantVSO.MaterializingInfos.find(DependantName); 502 assert(DependantMII != DependantVSO.MaterializingInfos.end() && 503 "Dependant should have MaterializingInfo"); 504 505 auto &DependantMI = DependantMII->second; 506 507 // Remove the dependant's dependency on this node. 508 assert(DependantMI.UnfinalizedDependencies[this].count(Name) && 509 "Dependant does not count this symbol as a dependency?"); 510 DependantMI.UnfinalizedDependencies[this].erase(Name); 511 if (DependantMI.UnfinalizedDependencies[this].empty()) 512 DependantMI.UnfinalizedDependencies.erase(this); 513 514 // Transfer unfinalized dependencies from this node to the dependant. 515 DependantVSO.transferFinalizedNodeDependencies(DependantMI, 516 DependantName, MI); 517 518 // If the dependant is finalized and this node was the last of its 519 // unfinalized dependencies then notify any pending queries on the 520 // dependant node. 521 if (DependantMI.IsFinalized && 522 DependantMI.UnfinalizedDependencies.empty()) { 523 assert(DependantMI.Dependants.empty() && 524 "Dependants should be empty by now"); 525 for (auto &Q : DependantMI.PendingQueries) { 526 Q->notifySymbolReady(); 527 if (Q->isFullyReady()) 528 ReadyQueries.insert(Q); 529 Q->removeQueryDependence(DependantVSO, DependantName); 530 } 531 532 // If this dependant node was fully finalized we can erase its 533 // MaterializingInfo and update its materializing state. 534 assert(DependantVSO.Symbols.count(DependantName) && 535 "Dependant has no entry in the Symbols table"); 536 DependantVSO.Symbols[DependantName].getFlags() &= 537 JITSymbolFlags::Materializing; 538 DependantVSO.MaterializingInfos.erase(DependantMII); 539 } 540 } 541 } 542 MI.Dependants.clear(); 543 MI.IsFinalized = true; 544 545 if (MI.UnfinalizedDependencies.empty()) { 546 for (auto &Q : MI.PendingQueries) { 547 Q->notifySymbolReady(); 548 if (Q->isFullyReady()) 549 ReadyQueries.insert(Q); 550 Q->removeQueryDependence(*this, Name); 551 } 552 assert(Symbols.count(Name) && 553 "Symbol has no entry in the Symbols table"); 554 Symbols[Name].getFlags() &= ~JITSymbolFlags::Materializing; 555 MaterializingInfos.erase(MII); 556 } 557 } 558 559 return ReadyQueries; 560 }); 561 562 for (auto &Q : FullyReadyQueries) { 563 assert(Q->isFullyReady() && "Q is not fully ready"); 564 Q->handleFullyReady(); 565 } 566 } 567 568 void VSO::notifyFailed(const SymbolNameSet &FailedSymbols) { 569 570 // FIXME: This should fail any transitively dependant symbols too. 571 572 auto FailedQueriesToNotify = ES.runSessionLocked([&, this]() { 573 AsynchronousSymbolQuerySet FailedQueries; 574 575 for (auto &Name : FailedSymbols) { 576 auto I = Symbols.find(Name); 577 assert(I != Symbols.end() && "Symbol not present in this VSO"); 578 Symbols.erase(I); 579 580 auto MII = MaterializingInfos.find(Name); 581 582 // If we have not created a MaterializingInfo for this symbol yet then 583 // there is nobody to notify. 584 if (MII == MaterializingInfos.end()) 585 continue; 586 587 // Copy all the queries to the FailedQueries list, then abandon them. 588 // This has to be a copy, and the copy has to come before the abandon 589 // operation: Each Q.detach() call will reach back into this 590 // PendingQueries list to remove Q. 591 for (auto &Q : MII->second.PendingQueries) 592 FailedQueries.insert(Q); 593 594 for (auto &Q : FailedQueries) 595 Q->detach(); 596 597 assert(MII->second.PendingQueries.empty() && 598 "Queries remain after symbol was failed"); 599 600 MaterializingInfos.erase(MII); 601 } 602 603 return FailedQueries; 604 }); 605 606 for (auto &Q : FailedQueriesToNotify) 607 Q->handleFailed(make_error<FailedToMaterialize>(FailedSymbols)); 608 } 609 610 SymbolNameSet VSO::lookupFlags(SymbolFlagsMap &Flags, 611 const SymbolNameSet &Names) { 612 return ES.runSessionLocked([&, this]() { 613 SymbolNameSet Unresolved; 614 615 for (auto &Name : Names) { 616 auto I = Symbols.find(Name); 617 if (I == Symbols.end()) { 618 Unresolved.insert(Name); 619 continue; 620 } 621 622 assert(!Flags.count(Name) && "Symbol already present in Flags map"); 623 Flags[Name] = JITSymbolFlags::stripTransientFlags(I->second.getFlags()); 624 } 625 626 return Unresolved; 627 }); 628 } 629 630 SymbolNameSet VSO::lookup(std::shared_ptr<AsynchronousSymbolQuery> Q, 631 SymbolNameSet Names) { 632 SymbolNameSet Unresolved = std::move(Names); 633 std::vector<std::unique_ptr<MaterializationUnit>> MUs; 634 635 ES.runSessionLocked([&, this]() { 636 for (auto I = Unresolved.begin(), E = Unresolved.end(); I != E;) { 637 auto TmpI = I++; 638 auto Name = *TmpI; 639 640 // Search for the name in Symbols. Skip it if not found. 641 auto SymI = Symbols.find(Name); 642 if (SymI == Symbols.end()) 643 continue; 644 645 // If we found Name in V, remove it frome the Unresolved set and add it 646 // to the dependencies set. 647 Unresolved.erase(TmpI); 648 649 // If the symbol has an address then resolve it. 650 if (SymI->second.getAddress() != 0) 651 Q->resolve(Name, SymI->second); 652 653 // If the symbol is lazy, get the MaterialiaztionUnit for it. 654 if (SymI->second.getFlags().isLazy()) { 655 assert(SymI->second.getAddress() == 0 && 656 "Lazy symbol should not have a resolved address"); 657 assert(!SymI->second.getFlags().isMaterializing() && 658 "Materializing and lazy should not both be set"); 659 auto UMII = UnmaterializedInfos.find(Name); 660 assert(UMII != UnmaterializedInfos.end() && 661 "Lazy symbol should have UnmaterializedInfo"); 662 auto MU = std::move(UMII->second->MU); 663 assert(MU != nullptr && "Materializer should not be null"); 664 665 // Kick all symbols associated with this MaterializationUnit into 666 // materializing state. 667 for (auto &KV : MU->getSymbols()) { 668 auto SymK = Symbols.find(KV.first); 669 auto Flags = SymK->second.getFlags(); 670 Flags &= ~JITSymbolFlags::Lazy; 671 Flags |= JITSymbolFlags::Materializing; 672 SymK->second.setFlags(Flags); 673 UnmaterializedInfos.erase(KV.first); 674 } 675 676 // Add MU to the list of MaterializationUnits to be materialized. 677 MUs.push_back(std::move(MU)); 678 } else if (!SymI->second.getFlags().isMaterializing()) { 679 // The symbol is neither lazy nor materializing. Finalize it and 680 // continue. 681 Q->notifySymbolReady(); 682 continue; 683 } 684 685 // Add the query to the PendingQueries list. 686 assert(SymI->second.getFlags().isMaterializing() && 687 "By this line the symbol should be materializing"); 688 auto &MI = MaterializingInfos[Name]; 689 MI.PendingQueries.push_back(Q); 690 Q->addQueryDependence(*this, Name); 691 } 692 }); 693 694 if (Q->isFullyResolved()) 695 Q->handleFullyResolved(); 696 697 if (Q->isFullyReady()) 698 Q->handleFullyReady(); 699 700 // Dispatch any required MaterializationUnits for materialization. 701 for (auto &MU : MUs) 702 ES.dispatchMaterialization(*this, std::move(MU)); 703 704 return Unresolved; 705 } 706 707 void VSO::dump(raw_ostream &OS) { 708 ES.runSessionLocked([&, this]() { 709 OS << "VSO \"" << VSOName 710 << "\" (ES: " << format("0x%016x", reinterpret_cast<uintptr_t>(&ES)) 711 << "):\n" 712 << "Symbol table:\n"; 713 714 for (auto &KV : Symbols) { 715 OS << " \"" << *KV.first << "\": " << KV.second.getAddress(); 716 if (KV.second.getFlags().isLazy() || 717 KV.second.getFlags().isMaterializing()) { 718 OS << " ("; 719 if (KV.second.getFlags().isLazy()) { 720 auto I = UnmaterializedInfos.find(KV.first); 721 assert(I != UnmaterializedInfos.end() && 722 "Lazy symbol should have UnmaterializedInfo"); 723 OS << " Lazy (MU=" << I->second->MU.get() << ")"; 724 } 725 if (KV.second.getFlags().isMaterializing()) 726 OS << " Materializing"; 727 OS << " )\n"; 728 } else 729 OS << "\n"; 730 } 731 732 if (!MaterializingInfos.empty()) 733 OS << " MaterializingInfos entries:\n"; 734 for (auto &KV : MaterializingInfos) { 735 OS << " \"" << *KV.first << "\":\n" 736 << " IsFinalized = " << (KV.second.IsFinalized ? "true" : "false") 737 << "\n" 738 << " " << KV.second.PendingQueries.size() << " pending queries.\n" 739 << " Dependants:\n"; 740 for (auto &KV2 : KV.second.Dependants) 741 OS << " " << KV2.first->getName() << ": " << KV2.second << "\n"; 742 OS << " Unfinalized Dependencies:\n"; 743 for (auto &KV2 : KV.second.UnfinalizedDependencies) 744 OS << " " << KV2.first->getName() << ": " << KV2.second << "\n"; 745 } 746 }); 747 } 748 749 Error VSO::defineImpl(MaterializationUnit &MU) { 750 SymbolNameSet Duplicates; 751 SymbolNameSet MUDefsOverridden; 752 std::vector<SymbolMap::iterator> ExistingDefsOverridden; 753 for (auto &KV : MU.getSymbols()) { 754 assert(!KV.second.isLazy() && "Lazy flag should be managed internally."); 755 assert(!KV.second.isMaterializing() && 756 "Materializing flags should be managed internally."); 757 758 SymbolMap::iterator EntryItr; 759 bool Added; 760 761 auto NewFlags = KV.second; 762 NewFlags |= JITSymbolFlags::Lazy; 763 764 std::tie(EntryItr, Added) = Symbols.insert( 765 std::make_pair(KV.first, JITEvaluatedSymbol(0, NewFlags))); 766 767 if (!Added) { 768 if (KV.second.isStrong()) { 769 if (EntryItr->second.getFlags().isStrong()) 770 Duplicates.insert(KV.first); 771 else 772 ExistingDefsOverridden.push_back(EntryItr); 773 } else 774 MUDefsOverridden.insert(KV.first); 775 } 776 } 777 778 if (!Duplicates.empty()) { 779 // We need to remove the symbols we added. 780 for (auto &KV : MU.getSymbols()) { 781 if (Duplicates.count(KV.first) || Duplicates.count(KV.first)) 782 continue; 783 784 bool Found = false; 785 for (const auto &I : ExistingDefsOverridden) 786 if (I->first == KV.first) 787 Found = true; 788 789 if (!Found) 790 Symbols.erase(KV.first); 791 } 792 793 // FIXME: Return all duplicates. 794 return make_error<DuplicateDefinition>(**Duplicates.begin()); 795 } 796 797 // Update flags on existing defs and call discard on their materializers. 798 for (auto &ExistingDefItr : ExistingDefsOverridden) { 799 assert(ExistingDefItr->second.getFlags().isLazy() && 800 !ExistingDefItr->second.getFlags().isMaterializing() && 801 "Overridden existing def should be in the Lazy state"); 802 803 ExistingDefItr->second.getFlags() &= ~JITSymbolFlags::Weak; 804 805 auto UMII = UnmaterializedInfos.find(ExistingDefItr->first); 806 assert(UMII != UnmaterializedInfos.end() && 807 "Overridden existing def should have an UnmaterializedInfo"); 808 809 UMII->second->MU->doDiscard(*this, ExistingDefItr->first); 810 } 811 812 // Discard overridden symbols povided by MU. 813 for (auto &Sym : MUDefsOverridden) 814 MU.doDiscard(*this, Sym); 815 816 return Error::success(); 817 } 818 819 void VSO::detachQueryHelper(AsynchronousSymbolQuery &Q, 820 const SymbolNameSet &QuerySymbols) { 821 for (auto &QuerySymbol : QuerySymbols) { 822 assert(MaterializingInfos.count(QuerySymbol) && 823 "QuerySymbol does not have MaterializingInfo"); 824 auto &MI = MaterializingInfos[QuerySymbol]; 825 826 auto IdenticalQuery = 827 [&](const std::shared_ptr<AsynchronousSymbolQuery> &R) { 828 return R.get() == &Q; 829 }; 830 831 auto I = std::find_if(MI.PendingQueries.begin(), MI.PendingQueries.end(), 832 IdenticalQuery); 833 assert(I != MI.PendingQueries.end() && 834 "Query Q should be in the PendingQueries list for QuerySymbol"); 835 MI.PendingQueries.erase(I); 836 } 837 } 838 839 void VSO::transferFinalizedNodeDependencies( 840 MaterializingInfo &DependantMI, const SymbolStringPtr &DependantName, 841 MaterializingInfo &FinalizedMI) { 842 for (auto &KV : FinalizedMI.UnfinalizedDependencies) { 843 auto &DependencyVSO = *KV.first; 844 SymbolNameSet *UnfinalizedDependenciesOnDependencyVSO = nullptr; 845 846 for (auto &DependencyName : KV.second) { 847 auto &DependencyMI = DependencyVSO.MaterializingInfos[DependencyName]; 848 849 // Do not add self dependencies. 850 if (&DependencyMI == &DependantMI) 851 continue; 852 853 // If we haven't looked up the dependencies for DependencyVSO yet, do it 854 // now and cache the result. 855 if (!UnfinalizedDependenciesOnDependencyVSO) 856 UnfinalizedDependenciesOnDependencyVSO = 857 &DependantMI.UnfinalizedDependencies[&DependencyVSO]; 858 859 DependencyMI.Dependants[this].insert(DependantName); 860 UnfinalizedDependenciesOnDependencyVSO->insert(DependencyName); 861 } 862 } 863 } 864 865 VSO &ExecutionSession::createVSO(std::string Name) { 866 return runSessionLocked([&, this]() -> VSO & { 867 VSOs.push_back(std::unique_ptr<VSO>(new VSO(*this, std::move(Name)))); 868 return *VSOs.back(); 869 }); 870 } 871 872 Expected<SymbolMap> lookup(const std::vector<VSO *> &VSOs, SymbolNameSet Names) { 873 #if LLVM_ENABLE_THREADS 874 // In the threaded case we use promises to return the results. 875 std::promise<SymbolMap> PromisedResult; 876 std::mutex ErrMutex; 877 Error ResolutionError = Error::success(); 878 std::promise<void> PromisedReady; 879 Error ReadyError = Error::success(); 880 auto OnResolve = 881 [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) { 882 if (Result) 883 PromisedResult.set_value(std::move(Result->Symbols)); 884 else { 885 { 886 ErrorAsOutParameter _(&ResolutionError); 887 std::lock_guard<std::mutex> Lock(ErrMutex); 888 ResolutionError = Result.takeError(); 889 } 890 PromisedResult.set_value(SymbolMap()); 891 } 892 }; 893 auto OnReady = [&](Error Err) { 894 if (Err) { 895 ErrorAsOutParameter _(&ReadyError); 896 std::lock_guard<std::mutex> Lock(ErrMutex); 897 ReadyError = std::move(Err); 898 } 899 PromisedReady.set_value(); 900 }; 901 #else 902 SymbolMap Result; 903 Error ResolutionError = Error::success(); 904 Error ReadyError = Error::success(); 905 906 auto OnResolve = [&](Expected<AsynchronousSymbolQuery::ResolutionResult> R) { 907 ErrorAsOutParameter _(&ResolutionError); 908 if (R) 909 Result = std::move(R->Symbols); 910 else 911 ResolutionError = R.takeError(); 912 }; 913 auto OnReady = [&](Error Err) { 914 ErrorAsOutParameter _(&ReadyError); 915 if (Err) 916 ReadyError = std::move(Err); 917 }; 918 #endif 919 920 auto Query = std::make_shared<AsynchronousSymbolQuery>( 921 Names, std::move(OnResolve), std::move(OnReady)); 922 SymbolNameSet UnresolvedSymbols(std::move(Names)); 923 924 for (auto *V : VSOs) { 925 assert(V && "VSO pointers in VSOs list should be non-null"); 926 if (UnresolvedSymbols.empty()) 927 break; 928 UnresolvedSymbols = V->lookup(Query, UnresolvedSymbols); 929 } 930 931 if (!UnresolvedSymbols.empty()) { 932 // If there are unresolved symbols then the query will never return. 933 // Fail it with ES.failQuery. 934 auto &ES = (*VSOs.begin())->getExecutionSession(); 935 ES.failQuery(*Query, 936 make_error<SymbolsNotFound>(std::move(UnresolvedSymbols))); 937 } 938 939 #if LLVM_ENABLE_THREADS 940 auto ResultFuture = PromisedResult.get_future(); 941 auto Result = ResultFuture.get(); 942 943 { 944 std::lock_guard<std::mutex> Lock(ErrMutex); 945 if (ResolutionError) { 946 // ReadyError will never be assigned. Consume the success value. 947 cantFail(std::move(ReadyError)); 948 return std::move(ResolutionError); 949 } 950 } 951 952 auto ReadyFuture = PromisedReady.get_future(); 953 ReadyFuture.get(); 954 955 { 956 std::lock_guard<std::mutex> Lock(ErrMutex); 957 if (ReadyError) 958 return std::move(ReadyError); 959 } 960 961 return std::move(Result); 962 963 #else 964 if (ResolutionError) { 965 // ReadyError will never be assigned. Consume the success value. 966 cantFail(std::move(ReadyError)); 967 return std::move(ResolutionError); 968 } 969 970 if (ReadyError) 971 return std::move(ReadyError); 972 973 return Result; 974 #endif 975 } 976 977 /// Look up a symbol by searching a list of VSOs. 978 Expected<JITEvaluatedSymbol> lookup(const std::vector<VSO *> VSOs, 979 SymbolStringPtr Name) { 980 SymbolNameSet Names({Name}); 981 if (auto ResultMap = lookup(VSOs, std::move(Names))) { 982 assert(ResultMap->size() == 1 && "Unexpected number of results"); 983 assert(ResultMap->count(Name) && "Missing result for symbol"); 984 return std::move(ResultMap->begin()->second); 985 } else 986 return ResultMap.takeError(); 987 } 988 989 } // End namespace orc. 990 } // End namespace llvm. 991