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