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