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 if (&OtherVSO != this || OtherSymbol != Name) { 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 JITSymbolFlags ResolvedFlags = Sym.getFlags(); 472 ResolvedFlags &= ~JITSymbolFlags::Weak; 473 474 assert(!Sym.getFlags().isLazy() && !Sym.getFlags().isMaterializing() && 475 "Materializing flags should be managed internally"); 476 477 auto I = Symbols.find(Name); 478 479 assert(I != Symbols.end() && "Symbol not found"); 480 assert(!I->second.getFlags().isLazy() && 481 I->second.getFlags().isMaterializing() && 482 "Symbol should be materializing"); 483 assert(I->second.getAddress() == 0 && "Symbol has already been resolved"); 484 485 assert(ResolvedFlags == 486 JITSymbolFlags::stripTransientFlags(I->second.getFlags()) && 487 "Resolved flags should match the declared flags"); 488 489 // Once resolved, symbols can never be 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 auto &DependantSym = DependantVSO.Symbols[DependantName]; 566 DependantSym.setFlags(static_cast<JITSymbolFlags::FlagNames>( 567 DependantSym.getFlags() & ~JITSymbolFlags::Materializing)); 568 DependantVSO.MaterializingInfos.erase(DependantMII); 569 } 570 } 571 } 572 MI.Dependants.clear(); 573 MI.IsFinalized = true; 574 575 if (MI.UnfinalizedDependencies.empty()) { 576 for (auto &Q : MI.PendingQueries) { 577 Q->notifySymbolReady(); 578 if (Q->isFullyReady()) 579 ReadyQueries.insert(Q); 580 Q->removeQueryDependence(*this, Name); 581 } 582 assert(Symbols.count(Name) && 583 "Symbol has no entry in the Symbols table"); 584 auto &Sym = Symbols[Name]; 585 Sym.setFlags(static_cast<JITSymbolFlags::FlagNames>( 586 Sym.getFlags() & ~JITSymbolFlags::Materializing)); 587 MaterializingInfos.erase(MII); 588 } 589 } 590 591 return ReadyQueries; 592 }); 593 594 for (auto &Q : FullyReadyQueries) { 595 assert(Q->isFullyReady() && "Q is not fully ready"); 596 Q->handleFullyReady(); 597 } 598 } 599 600 void VSO::notifyFailed(const SymbolNameSet &FailedSymbols) { 601 602 // FIXME: This should fail any transitively dependant symbols too. 603 604 auto FailedQueriesToNotify = ES.runSessionLocked([&, this]() { 605 AsynchronousSymbolQuerySet FailedQueries; 606 607 for (auto &Name : FailedSymbols) { 608 auto I = Symbols.find(Name); 609 assert(I != Symbols.end() && "Symbol not present in this VSO"); 610 Symbols.erase(I); 611 612 auto MII = MaterializingInfos.find(Name); 613 614 // If we have not created a MaterializingInfo for this symbol yet then 615 // there is nobody to notify. 616 if (MII == MaterializingInfos.end()) 617 continue; 618 619 // Copy all the queries to the FailedQueries list, then abandon them. 620 // This has to be a copy, and the copy has to come before the abandon 621 // operation: Each Q.detach() call will reach back into this 622 // PendingQueries list to remove Q. 623 for (auto &Q : MII->second.PendingQueries) 624 FailedQueries.insert(Q); 625 626 for (auto &Q : FailedQueries) 627 Q->detach(); 628 629 assert(MII->second.PendingQueries.empty() && 630 "Queries remain after symbol was failed"); 631 632 MaterializingInfos.erase(MII); 633 } 634 635 return FailedQueries; 636 }); 637 638 for (auto &Q : FailedQueriesToNotify) 639 Q->handleFailed(make_error<FailedToMaterialize>(FailedSymbols)); 640 } 641 642 SymbolNameSet VSO::lookupFlags(SymbolFlagsMap &Flags, 643 const SymbolNameSet &Names) { 644 return ES.runSessionLocked([&, this]() { 645 auto Unresolved = lookupFlagsImpl(Flags, Names); 646 if (FallbackDefinitionGenerator && !Unresolved.empty()) { 647 auto FallbackDefs = FallbackDefinitionGenerator(*this, Unresolved); 648 if (!FallbackDefs.empty()) { 649 auto Unresolved2 = lookupFlagsImpl(Flags, FallbackDefs); 650 (void)Unresolved2; 651 assert(Unresolved2.empty() && 652 "All fallback defs should have been found by lookupFlagsImpl"); 653 for (auto &D : FallbackDefs) 654 Unresolved.erase(D); 655 } 656 }; 657 return Unresolved; 658 }); 659 } 660 661 SymbolNameSet VSO::lookupFlagsImpl(SymbolFlagsMap &Flags, 662 const SymbolNameSet &Names) { 663 SymbolNameSet Unresolved; 664 665 for (auto &Name : Names) { 666 auto I = Symbols.find(Name); 667 668 if (I == Symbols.end()) { 669 Unresolved.insert(Name); 670 continue; 671 } 672 673 assert(!Flags.count(Name) && "Symbol already present in Flags map"); 674 Flags[Name] = JITSymbolFlags::stripTransientFlags(I->second.getFlags()); 675 } 676 677 return Unresolved; 678 } 679 680 SymbolNameSet VSO::lookup(std::shared_ptr<AsynchronousSymbolQuery> Q, 681 SymbolNameSet Names) { 682 assert(Q && "Query can not be null"); 683 684 std::vector<std::unique_ptr<MaterializationUnit>> MUs; 685 686 SymbolNameSet Unresolved = std::move(Names); 687 ES.runSessionLocked([&, this]() { 688 lookupImpl(Q, MUs, Unresolved); 689 if (FallbackDefinitionGenerator && !Unresolved.empty()) { 690 auto FallbackDefs = FallbackDefinitionGenerator(*this, Unresolved); 691 if (!FallbackDefs.empty()) { 692 for (auto &D : FallbackDefs) 693 Unresolved.erase(D); 694 lookupImpl(Q, MUs, FallbackDefs); 695 assert(FallbackDefs.empty() && 696 "All fallback defs should have been found by lookupImpl"); 697 } 698 } 699 }); 700 701 if (Q->isFullyResolved()) 702 Q->handleFullyResolved(); 703 704 if (Q->isFullyReady()) 705 Q->handleFullyReady(); 706 707 // Dispatch any required MaterializationUnits for materialization. 708 for (auto &MU : MUs) 709 ES.dispatchMaterialization(*this, std::move(MU)); 710 711 return Unresolved; 712 } 713 714 void VSO::lookupImpl(std::shared_ptr<AsynchronousSymbolQuery> &Q, 715 std::vector<std::unique_ptr<MaterializationUnit>> &MUs, 716 SymbolNameSet &Unresolved) { 717 for (auto I = Unresolved.begin(), E = Unresolved.end(); I != E;) { 718 auto TmpI = I++; 719 auto Name = *TmpI; 720 721 // Search for the name in Symbols. Skip it if not found. 722 auto SymI = Symbols.find(Name); 723 if (SymI == Symbols.end()) 724 continue; 725 726 // If we found Name in V, remove it frome the Unresolved set and add it 727 // to the dependencies set. 728 Unresolved.erase(TmpI); 729 730 // If the symbol has an address then resolve it. 731 if (SymI->second.getAddress() != 0) 732 Q->resolve(Name, SymI->second); 733 734 // If the symbol is lazy, get the MaterialiaztionUnit for it. 735 if (SymI->second.getFlags().isLazy()) { 736 assert(SymI->second.getAddress() == 0 && 737 "Lazy symbol should not have a resolved address"); 738 assert(!SymI->second.getFlags().isMaterializing() && 739 "Materializing and lazy should not both be set"); 740 auto UMII = UnmaterializedInfos.find(Name); 741 assert(UMII != UnmaterializedInfos.end() && 742 "Lazy symbol should have UnmaterializedInfo"); 743 auto MU = std::move(UMII->second->MU); 744 assert(MU != nullptr && "Materializer should not be null"); 745 746 // Kick all symbols associated with this MaterializationUnit into 747 // materializing state. 748 for (auto &KV : MU->getSymbols()) { 749 auto SymK = Symbols.find(KV.first); 750 auto Flags = SymK->second.getFlags(); 751 Flags &= ~JITSymbolFlags::Weak; 752 Flags &= ~JITSymbolFlags::Lazy; 753 Flags |= JITSymbolFlags::Materializing; 754 SymK->second.setFlags(Flags); 755 UnmaterializedInfos.erase(KV.first); 756 } 757 758 // Add MU to the list of MaterializationUnits to be materialized. 759 MUs.push_back(std::move(MU)); 760 } else if (!SymI->second.getFlags().isMaterializing()) { 761 // The symbol is neither lazy nor materializing. Finalize it and 762 // continue. 763 Q->notifySymbolReady(); 764 continue; 765 } 766 767 // Add the query to the PendingQueries list. 768 assert(SymI->second.getFlags().isMaterializing() && 769 "By this line the symbol should be materializing"); 770 auto &MI = MaterializingInfos[Name]; 771 MI.PendingQueries.push_back(Q); 772 Q->addQueryDependence(*this, Name); 773 } 774 } 775 776 void VSO::dump(raw_ostream &OS) { 777 ES.runSessionLocked([&, this]() { 778 OS << "VSO \"" << VSOName 779 << "\" (ES: " << format("0x%016x", reinterpret_cast<uintptr_t>(&ES)) 780 << "):\n" 781 << "Symbol table:\n"; 782 783 for (auto &KV : Symbols) { 784 OS << " \"" << *KV.first << "\": " << KV.second.getAddress(); 785 if (KV.second.getFlags().isLazy() || 786 KV.second.getFlags().isMaterializing()) { 787 OS << " ("; 788 if (KV.second.getFlags().isLazy()) { 789 auto I = UnmaterializedInfos.find(KV.first); 790 assert(I != UnmaterializedInfos.end() && 791 "Lazy symbol should have UnmaterializedInfo"); 792 OS << " Lazy (MU=" << I->second->MU.get() << ")"; 793 } 794 if (KV.second.getFlags().isMaterializing()) 795 OS << " Materializing"; 796 OS << " )\n"; 797 } else 798 OS << "\n"; 799 } 800 801 if (!MaterializingInfos.empty()) 802 OS << " MaterializingInfos entries:\n"; 803 for (auto &KV : MaterializingInfos) { 804 OS << " \"" << *KV.first << "\":\n" 805 << " IsFinalized = " << (KV.second.IsFinalized ? "true" : "false") 806 << "\n" 807 << " " << KV.second.PendingQueries.size() << " pending queries.\n" 808 << " Dependants:\n"; 809 for (auto &KV2 : KV.second.Dependants) 810 OS << " " << KV2.first->getName() << ": " << KV2.second << "\n"; 811 OS << " Unfinalized Dependencies:\n"; 812 for (auto &KV2 : KV.second.UnfinalizedDependencies) 813 OS << " " << KV2.first->getName() << ": " << KV2.second << "\n"; 814 } 815 }); 816 } 817 818 Error VSO::defineImpl(MaterializationUnit &MU) { 819 SymbolNameSet Duplicates; 820 SymbolNameSet MUDefsOverridden; 821 std::vector<SymbolMap::iterator> ExistingDefsOverridden; 822 for (auto &KV : MU.getSymbols()) { 823 assert(!KV.second.isLazy() && "Lazy flag should be managed internally."); 824 assert(!KV.second.isMaterializing() && 825 "Materializing flags should be managed internally."); 826 827 SymbolMap::iterator EntryItr; 828 bool Added; 829 830 auto NewFlags = KV.second; 831 NewFlags |= JITSymbolFlags::Lazy; 832 833 std::tie(EntryItr, Added) = Symbols.insert( 834 std::make_pair(KV.first, JITEvaluatedSymbol(0, NewFlags))); 835 836 if (!Added) { 837 if (KV.second.isStrong()) { 838 if (EntryItr->second.getFlags().isStrong()) 839 Duplicates.insert(KV.first); 840 else 841 ExistingDefsOverridden.push_back(EntryItr); 842 } else 843 MUDefsOverridden.insert(KV.first); 844 } 845 } 846 847 if (!Duplicates.empty()) { 848 // We need to remove the symbols we added. 849 for (auto &KV : MU.getSymbols()) { 850 if (Duplicates.count(KV.first) || Duplicates.count(KV.first)) 851 continue; 852 853 bool Found = false; 854 for (const auto &I : ExistingDefsOverridden) 855 if (I->first == KV.first) 856 Found = true; 857 858 if (!Found) 859 Symbols.erase(KV.first); 860 } 861 862 // FIXME: Return all duplicates. 863 return make_error<DuplicateDefinition>(**Duplicates.begin()); 864 } 865 866 // Update flags on existing defs and call discard on their materializers. 867 for (auto &ExistingDefItr : ExistingDefsOverridden) { 868 assert(ExistingDefItr->second.getFlags().isLazy() && 869 !ExistingDefItr->second.getFlags().isMaterializing() && 870 "Overridden existing def should be in the Lazy state"); 871 872 ExistingDefItr->second.getFlags() &= ~JITSymbolFlags::Weak; 873 874 auto UMII = UnmaterializedInfos.find(ExistingDefItr->first); 875 assert(UMII != UnmaterializedInfos.end() && 876 "Overridden existing def should have an UnmaterializedInfo"); 877 878 UMII->second->MU->doDiscard(*this, ExistingDefItr->first); 879 } 880 881 // Discard overridden symbols povided by MU. 882 for (auto &Sym : MUDefsOverridden) 883 MU.doDiscard(*this, Sym); 884 885 return Error::success(); 886 } 887 888 void VSO::detachQueryHelper(AsynchronousSymbolQuery &Q, 889 const SymbolNameSet &QuerySymbols) { 890 for (auto &QuerySymbol : QuerySymbols) { 891 assert(MaterializingInfos.count(QuerySymbol) && 892 "QuerySymbol does not have MaterializingInfo"); 893 auto &MI = MaterializingInfos[QuerySymbol]; 894 895 auto IdenticalQuery = 896 [&](const std::shared_ptr<AsynchronousSymbolQuery> &R) { 897 return R.get() == &Q; 898 }; 899 900 auto I = std::find_if(MI.PendingQueries.begin(), MI.PendingQueries.end(), 901 IdenticalQuery); 902 assert(I != MI.PendingQueries.end() && 903 "Query Q should be in the PendingQueries list for QuerySymbol"); 904 MI.PendingQueries.erase(I); 905 } 906 } 907 908 void VSO::transferFinalizedNodeDependencies( 909 MaterializingInfo &DependantMI, const SymbolStringPtr &DependantName, 910 MaterializingInfo &FinalizedMI) { 911 for (auto &KV : FinalizedMI.UnfinalizedDependencies) { 912 auto &DependencyVSO = *KV.first; 913 SymbolNameSet *UnfinalizedDependenciesOnDependencyVSO = nullptr; 914 915 for (auto &DependencyName : KV.second) { 916 auto &DependencyMI = DependencyVSO.MaterializingInfos[DependencyName]; 917 918 // Do not add self dependencies. 919 if (&DependencyMI == &DependantMI) 920 continue; 921 922 // If we haven't looked up the dependencies for DependencyVSO yet, do it 923 // now and cache the result. 924 if (!UnfinalizedDependenciesOnDependencyVSO) 925 UnfinalizedDependenciesOnDependencyVSO = 926 &DependantMI.UnfinalizedDependencies[&DependencyVSO]; 927 928 DependencyMI.Dependants[this].insert(DependantName); 929 UnfinalizedDependenciesOnDependencyVSO->insert(DependencyName); 930 } 931 } 932 } 933 934 VSO &ExecutionSession::createVSO(std::string Name) { 935 return runSessionLocked([&, this]() -> VSO & { 936 VSOs.push_back(std::unique_ptr<VSO>(new VSO(*this, std::move(Name)))); 937 return *VSOs.back(); 938 }); 939 } 940 941 Expected<SymbolMap> blockingLookup(ExecutionSessionBase &ES, 942 AsynchronousLookupFunction AsyncLookup, 943 SymbolNameSet Names, bool WaitUntilReady, 944 MaterializationResponsibility *MR) { 945 946 #if LLVM_ENABLE_THREADS 947 // In the threaded case we use promises to return the results. 948 std::promise<SymbolMap> PromisedResult; 949 std::mutex ErrMutex; 950 Error ResolutionError = Error::success(); 951 std::promise<void> PromisedReady; 952 Error ReadyError = Error::success(); 953 auto OnResolve = 954 [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) { 955 if (Result) { 956 if (MR) 957 MR->addDependencies(Result->Dependencies); 958 PromisedResult.set_value(std::move(Result->Symbols)); 959 } else { 960 { 961 ErrorAsOutParameter _(&ResolutionError); 962 std::lock_guard<std::mutex> Lock(ErrMutex); 963 ResolutionError = Result.takeError(); 964 } 965 PromisedResult.set_value(SymbolMap()); 966 } 967 }; 968 969 std::function<void(Error)> OnReady; 970 if (WaitUntilReady) { 971 OnReady = [&](Error Err) { 972 if (Err) { 973 ErrorAsOutParameter _(&ReadyError); 974 std::lock_guard<std::mutex> Lock(ErrMutex); 975 ReadyError = std::move(Err); 976 } 977 PromisedReady.set_value(); 978 }; 979 } else { 980 OnReady = [&](Error Err) { 981 if (Err) 982 ES.reportError(std::move(Err)); 983 }; 984 } 985 986 #else 987 SymbolMap Result; 988 Error ResolutionError = Error::success(); 989 Error ReadyError = Error::success(); 990 991 auto OnResolve = [&](Expected<AsynchronousSymbolQuery::ResolutionResult> R) { 992 ErrorAsOutParameter _(&ResolutionError); 993 if (R) { 994 if (MR) 995 MR->addDependencies(R->Dependencies); 996 Result = std::move(R->Symbols); 997 } else 998 ResolutionError = R.takeError(); 999 }; 1000 1001 std::function<void(Error)> OnReady; 1002 if (WaitUntilReady) { 1003 OnReady = [&](Error Err) { 1004 ErrorAsOutParameter _(&ReadyError); 1005 if (Err) 1006 ReadyError = std::move(Err); 1007 }; 1008 } else { 1009 OnReady = [&](Error Err) { 1010 if (Err) 1011 ES.reportError(std::move(Err)); 1012 }; 1013 } 1014 #endif 1015 1016 auto Query = std::make_shared<AsynchronousSymbolQuery>( 1017 Names, std::move(OnResolve), std::move(OnReady)); 1018 1019 SymbolNameSet UnresolvedSymbols = AsyncLookup(Query, std::move(Names)); 1020 1021 // If there are unresolved symbols then the query will never return. 1022 // Fail it with ES.failQuery. 1023 if (!UnresolvedSymbols.empty()) 1024 ES.failQuery(*Query, 1025 make_error<SymbolsNotFound>(std::move(UnresolvedSymbols))); 1026 1027 #if LLVM_ENABLE_THREADS 1028 auto ResultFuture = PromisedResult.get_future(); 1029 auto Result = ResultFuture.get(); 1030 1031 { 1032 std::lock_guard<std::mutex> Lock(ErrMutex); 1033 if (ResolutionError) { 1034 // ReadyError will never be assigned. Consume the success value. 1035 cantFail(std::move(ReadyError)); 1036 return std::move(ResolutionError); 1037 } 1038 } 1039 1040 if (WaitUntilReady) { 1041 auto ReadyFuture = PromisedReady.get_future(); 1042 ReadyFuture.get(); 1043 1044 { 1045 std::lock_guard<std::mutex> Lock(ErrMutex); 1046 if (ReadyError) 1047 return std::move(ReadyError); 1048 } 1049 } else 1050 cantFail(std::move(ReadyError)); 1051 1052 return std::move(Result); 1053 1054 #else 1055 if (ResolutionError) { 1056 // ReadyError will never be assigned. Consume the success value. 1057 cantFail(std::move(ReadyError)); 1058 return std::move(ResolutionError); 1059 } 1060 1061 if (ReadyError) 1062 return std::move(ReadyError); 1063 1064 return Result; 1065 #endif 1066 } 1067 1068 Expected<SymbolMap> lookup(const VSO::VSOList &VSOs, SymbolNameSet Names) { 1069 1070 if (VSOs.empty()) 1071 return SymbolMap(); 1072 1073 auto &ES = (*VSOs.begin())->getExecutionSession(); 1074 1075 auto LookupFn = [&](std::shared_ptr<AsynchronousSymbolQuery> Q, 1076 SymbolNameSet Unresolved) { 1077 for (auto *V : VSOs) { 1078 assert(V && "VSOs entries must not be null"); 1079 if (Unresolved.empty()) 1080 break; 1081 Unresolved = V->lookup(Q, std::move(Unresolved)); 1082 } 1083 return Unresolved; 1084 }; 1085 1086 return blockingLookup(ES, std::move(LookupFn), Names, true); 1087 } 1088 1089 /// Look up a symbol by searching a list of VSOs. 1090 Expected<JITEvaluatedSymbol> lookup(const VSO::VSOList &VSOs, 1091 SymbolStringPtr Name) { 1092 SymbolNameSet Names({Name}); 1093 if (auto ResultMap = lookup(VSOs, std::move(Names))) { 1094 assert(ResultMap->size() == 1 && "Unexpected number of results"); 1095 assert(ResultMap->count(Name) && "Missing result for symbol"); 1096 return std::move(ResultMap->begin()->second); 1097 } else 1098 return ResultMap.takeError(); 1099 } 1100 1101 } // End namespace orc. 1102 } // End namespace llvm. 1103