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/ExecutionEngine/Orc/OrcError.h" 12 #include "llvm/Support/Format.h" 13 14 #if LLVM_ENABLE_THREADS 15 #include <future> 16 #endif 17 18 namespace llvm { 19 namespace orc { 20 21 char FailedToMaterialize::ID = 0; 22 char FailedToResolve::ID = 0; 23 char FailedToFinalize::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 FailedToResolve::FailedToResolve(SymbolNameSet Symbols) 90 : Symbols(std::move(Symbols)) { 91 assert(!this->Symbols.empty() && "Can not fail to resolve an empty set"); 92 } 93 94 std::error_code FailedToResolve::convertToErrorCode() const { 95 return orcError(OrcErrorCode::UnknownORCError); 96 } 97 98 void FailedToResolve::log(raw_ostream &OS) const { 99 OS << "Failed to resolve symbols: " << Symbols; 100 } 101 102 FailedToFinalize::FailedToFinalize(SymbolNameSet Symbols) 103 : Symbols(std::move(Symbols)) { 104 assert(!this->Symbols.empty() && "Can not fail to finalize an empty set"); 105 } 106 107 std::error_code FailedToFinalize::convertToErrorCode() const { 108 return orcError(OrcErrorCode::UnknownORCError); 109 } 110 111 void FailedToFinalize::log(raw_ostream &OS) const { 112 OS << "Failed to finalize symbols: " << Symbols; 113 } 114 115 AsynchronousSymbolQuery::AsynchronousSymbolQuery( 116 const SymbolNameSet &Symbols, SymbolsResolvedCallback NotifySymbolsResolved, 117 SymbolsReadyCallback NotifySymbolsReady) 118 : NotifySymbolsResolved(std::move(NotifySymbolsResolved)), 119 NotifySymbolsReady(std::move(NotifySymbolsReady)) { 120 assert(this->NotifySymbolsResolved && 121 "Symbols resolved callback must be set"); 122 assert(this->NotifySymbolsReady && "Symbols ready callback must be set"); 123 OutstandingResolutions = OutstandingFinalizations = Symbols.size(); 124 } 125 126 void AsynchronousSymbolQuery::notifyFailed(Error Err) { 127 if (OutstandingResolutions != 0) 128 NotifySymbolsResolved(std::move(Err)); 129 else if (OutstandingFinalizations != 0) 130 NotifySymbolsReady(std::move(Err)); 131 else 132 consumeError(std::move(Err)); 133 OutstandingResolutions = OutstandingFinalizations = 0; 134 } 135 136 void AsynchronousSymbolQuery::resolve(SymbolStringPtr Name, 137 JITEvaluatedSymbol Sym) { 138 // If OutstandingResolutions is zero we must have errored out already. Just 139 // ignore this. 140 if (OutstandingResolutions == 0) 141 return; 142 143 assert(!Symbols.count(Name) && "Symbol has already been assigned an address"); 144 Symbols.insert(std::make_pair(std::move(Name), std::move(Sym))); 145 --OutstandingResolutions; 146 if (OutstandingResolutions == 0) 147 NotifySymbolsResolved(std::move(Symbols)); 148 } 149 150 void AsynchronousSymbolQuery::finalizeSymbol() { 151 // If OutstandingFinalizations is zero we must have errored out already. Just 152 // ignore this. 153 if (OutstandingFinalizations == 0) 154 return; 155 156 assert(OutstandingFinalizations > 0 && "All symbols already finalized"); 157 --OutstandingFinalizations; 158 if (OutstandingFinalizations == 0) 159 NotifySymbolsReady(Error::success()); 160 } 161 162 VSO::UnmaterializedInfo::UnmaterializedInfo( 163 size_t SymbolsRemaining, std::unique_ptr<MaterializationUnit> MU) 164 : SymbolsRemaining(SymbolsRemaining), MU(std::move(MU)) {} 165 166 VSO::SymbolTableEntry::SymbolTableEntry(JITSymbolFlags Flags, 167 UnmaterializedInfoIterator UMII) 168 : Flags(Flags), UMII(std::move(UMII)) { 169 // We *don't* expect isLazy to be set here. That's for the VSO to do. 170 assert(!Flags.isLazy() && "Initial flags include lazy?"); 171 assert(!Flags.isMaterializing() && "Initial flags include materializing"); 172 this->Flags |= JITSymbolFlags::Lazy; 173 } 174 175 VSO::SymbolTableEntry::SymbolTableEntry(JITEvaluatedSymbol Sym) 176 : Flags(Sym.getFlags()), Address(Sym.getAddress()) { 177 assert(!Flags.isLazy() && !Flags.isMaterializing() && 178 "This constructor is for final symbols only"); 179 } 180 181 VSO::SymbolTableEntry::SymbolTableEntry(SymbolTableEntry &&Other) 182 : Flags(Other.Flags), Address(0) { 183 if (this->Flags.isLazy()) 184 UMII = std::move(Other.UMII); 185 else 186 Address = Other.Address; 187 } 188 189 VSO::SymbolTableEntry &VSO::SymbolTableEntry:: 190 operator=(SymbolTableEntry &&Other) { 191 destroy(); 192 Flags = std::move(Other.Flags); 193 if (Other.Flags.isLazy()) { 194 UMII = std::move(Other.UMII); 195 } else 196 Address = Other.Address; 197 return *this; 198 } 199 200 VSO::SymbolTableEntry::~SymbolTableEntry() { destroy(); } 201 202 void VSO::SymbolTableEntry::replaceWith(VSO &V, SymbolStringPtr Name, 203 JITEvaluatedSymbol Sym) { 204 assert(!Flags.isMaterializing() && 205 "Attempting to replace definition during materialization?"); 206 if (Flags.isLazy()) { 207 if (UMII->MU) 208 UMII->MU->discard(V, Name); 209 V.detach(UMII); 210 } 211 destroy(); 212 Flags = Sym.getFlags(); 213 Address = Sym.getAddress(); 214 } 215 216 void VSO::SymbolTableEntry::replaceWith(VSO &V, SymbolStringPtr Name, 217 JITSymbolFlags NewFlags, 218 UnmaterializedInfoIterator NewUMII) { 219 assert(!Flags.isMaterializing() && 220 "Attempting to replace definition during materialization?"); 221 if (Flags.isLazy()) { 222 if (UMII->MU) 223 UMII->MU->discard(V, Name); 224 V.detach(UMII); 225 } 226 destroy(); 227 Flags = NewFlags; 228 UMII = std::move(NewUMII); 229 } 230 231 std::unique_ptr<MaterializationUnit> 232 VSO::SymbolTableEntry::initMaterialize(VSO &V) { 233 assert(Flags.isLazy() && "Can't materialize non-lazy symbol"); 234 auto TmpMU = std::move(UMII->MU); 235 V.detach(UMII); 236 destroy(); 237 Flags &= ~JITSymbolFlags::Lazy; 238 Flags |= JITSymbolFlags::Materializing; 239 Address = 0; 240 return TmpMU; 241 } 242 243 void VSO::SymbolTableEntry::resolve(VSO &V, JITEvaluatedSymbol Sym) { 244 if (Flags.isLazy()) { 245 assert(!UMII->MU && "Resolving with MaterializationUnit still attached?"); 246 V.detach(UMII); 247 } 248 destroy(); 249 Flags = Sym.getFlags(); 250 Flags |= JITSymbolFlags::Materializing; 251 Address = Sym.getAddress(); 252 } 253 254 void VSO::SymbolTableEntry::finalize() { 255 assert(Flags.isMaterializing() && !Flags.isLazy() && 256 "Symbol should be in materializing state"); 257 Flags &= ~JITSymbolFlags::Materializing; 258 } 259 260 void VSO::SymbolTableEntry::destroy() { 261 if (Flags.isLazy()) 262 UMII.~UnmaterializedInfoIterator(); 263 } 264 265 void VSO::detach(UnmaterializedInfoIterator UMII) { 266 assert(UMII->SymbolsRemaining > 0 && 267 "Detaching from empty UnmaterializedInfo?"); 268 --UMII->SymbolsRemaining; 269 if (UMII->SymbolsRemaining == 0) 270 UnmaterializedInfos.erase(UMII); 271 } 272 273 VSO::RelativeLinkageStrength VSO::compareLinkage(Optional<JITSymbolFlags> Old, 274 JITSymbolFlags New) { 275 if (Old == None) 276 return llvm::orc::VSO::NewDefinitionIsStronger; 277 278 if (Old->isStrong()) { 279 if (New.isStrong()) 280 return llvm::orc::VSO::DuplicateDefinition; 281 else 282 return llvm::orc::VSO::ExistingDefinitionIsStronger; 283 } else { 284 if (New.isStrong()) 285 return llvm::orc::VSO::NewDefinitionIsStronger; 286 else 287 return llvm::orc::VSO::ExistingDefinitionIsStronger; 288 } 289 } 290 291 VSO::RelativeLinkageStrength 292 VSO::compareLinkage(SymbolStringPtr Name, JITSymbolFlags NewFlags) const { 293 auto I = Symbols.find(Name); 294 return compareLinkage( 295 I == Symbols.end() ? None : Optional<JITSymbolFlags>(I->second.Flags), 296 NewFlags); 297 } 298 299 Error VSO::define(SymbolMap NewSymbols) { 300 Error Err = Error::success(); 301 for (auto &KV : NewSymbols) { 302 auto I = Symbols.find(KV.first); 303 auto LinkageResult = compareLinkage( 304 I == Symbols.end() ? None : Optional<JITSymbolFlags>(I->second.Flags), 305 KV.second.getFlags()); 306 307 // Silently discard weaker definitions. 308 if (LinkageResult == ExistingDefinitionIsStronger) 309 continue; 310 311 // Report duplicate definition errors. 312 if (LinkageResult == DuplicateDefinition) { 313 Err = joinErrors(std::move(Err), 314 make_error<orc::DuplicateDefinition>(*KV.first)); 315 continue; 316 } 317 318 if (I != Symbols.end()) 319 I->second.replaceWith(*this, I->first, KV.second); 320 else 321 Symbols.insert(std::make_pair(KV.first, std::move(KV.second))); 322 } 323 return Err; 324 } 325 326 Error VSO::defineLazy(std::unique_ptr<MaterializationUnit> MU) { 327 328 auto NewSymbols = MU->getSymbols(); 329 330 auto UMII = UnmaterializedInfos.insert( 331 UnmaterializedInfos.end(), 332 UnmaterializedInfo(NewSymbols.size(), std::move(MU))); 333 334 Error Err = Error::success(); 335 for (auto &KV : NewSymbols) { 336 auto I = Symbols.find(KV.first); 337 338 assert(I == Symbols.end() || 339 !I->second.Flags.isMaterializing() && 340 "Attempt to replace materializing symbol definition"); 341 342 auto LinkageResult = compareLinkage( 343 I == Symbols.end() ? None : Optional<JITSymbolFlags>(I->second.Flags), 344 KV.second); 345 346 // Discard weaker definitions. 347 if (LinkageResult == ExistingDefinitionIsStronger) { 348 UMII->MU->discard(*this, KV.first); 349 detach(UMII); 350 continue; 351 } 352 353 // Report duplicate definition errors. 354 if (LinkageResult == DuplicateDefinition) { 355 Err = joinErrors(std::move(Err), 356 make_error<orc::DuplicateDefinition>(*KV.first)); 357 // Duplicate definitions are discarded, so remove the duplicates from 358 // materializer. 359 detach(UMII); 360 continue; 361 } 362 363 // Existing definition was weaker. Replace it. 364 if (I != Symbols.end()) 365 I->second.replaceWith(*this, KV.first, KV.second, UMII); 366 else 367 Symbols.insert( 368 std::make_pair(KV.first, SymbolTableEntry(KV.second, UMII))); 369 } 370 371 return Err; 372 } 373 374 void VSO::resolve(const SymbolMap &SymbolValues) { 375 for (auto &KV : SymbolValues) { 376 auto I = Symbols.find(KV.first); 377 assert(I != Symbols.end() && "Resolving symbol not present in this dylib"); 378 I->second.resolve(*this, KV.second); 379 380 auto J = MaterializingInfos.find(KV.first); 381 if (J == MaterializingInfos.end()) 382 continue; 383 384 assert(J->second.PendingFinalization.empty() && 385 "Queries already pending finalization?"); 386 for (auto &Q : J->second.PendingResolution) 387 Q->resolve(KV.first, KV.second); 388 J->second.PendingFinalization = std::move(J->second.PendingResolution); 389 J->second.PendingResolution = MaterializingInfo::QueryList(); 390 } 391 } 392 393 void VSO::notifyResolutionFailed(const SymbolNameSet &Names) { 394 assert(!Names.empty() && "Failed to resolve empty set?"); 395 396 std::map<std::shared_ptr<AsynchronousSymbolQuery>, SymbolNameSet> 397 QueriesToFail; 398 399 for (auto &S : Names) { 400 auto I = Symbols.find(S); 401 assert(I != Symbols.end() && "Symbol not present in this VSO"); 402 403 auto J = MaterializingInfos.find(S); 404 if (J != MaterializingInfos.end()) { 405 assert(J->second.PendingFinalization.empty() && 406 "Failed during resolution, but queries pending finalization?"); 407 for (auto &Q : J->second.PendingResolution) 408 QueriesToFail[Q].insert(S); 409 MaterializingInfos.erase(J); 410 } 411 Symbols.erase(I); 412 } 413 414 for (auto &KV : QueriesToFail) 415 KV.first->notifyFailed(make_error<FailedToResolve>(std::move(KV.second))); 416 } 417 418 void VSO::finalize(const SymbolNameSet &SymbolsToFinalize) { 419 for (auto &S : SymbolsToFinalize) { 420 auto I = Symbols.find(S); 421 assert(I != Symbols.end() && "Finalizing symbol not present in this dylib"); 422 423 auto J = MaterializingInfos.find(S); 424 if (J != MaterializingInfos.end()) { 425 assert(J->second.PendingResolution.empty() && 426 "Queries still pending resolution?"); 427 for (auto &Q : J->second.PendingFinalization) 428 Q->finalizeSymbol(); 429 MaterializingInfos.erase(J); 430 } 431 I->second.finalize(); 432 } 433 } 434 435 void VSO::notifyFinalizationFailed(const SymbolNameSet &Names) { 436 assert(!Names.empty() && "Failed to finalize empty set?"); 437 438 std::map<std::shared_ptr<AsynchronousSymbolQuery>, SymbolNameSet> 439 QueriesToFail; 440 441 for (auto &S : Names) { 442 auto I = Symbols.find(S); 443 assert(I != Symbols.end() && "Symbol not present in this VSO"); 444 assert((I->second.Flags & JITSymbolFlags::Materializing) && 445 "Failed to finalize symbol that was not materializing"); 446 447 auto J = MaterializingInfos.find(S); 448 if (J != MaterializingInfos.end()) { 449 assert(J->second.PendingResolution.empty() && 450 "Failed during finalization, but queries pending resolution?"); 451 for (auto &Q : J->second.PendingFinalization) 452 QueriesToFail[Q].insert(S); 453 MaterializingInfos.erase(J); 454 } 455 Symbols.erase(I); 456 } 457 458 for (auto &KV : QueriesToFail) 459 KV.first->notifyFailed(make_error<FailedToFinalize>(std::move(KV.second))); 460 } 461 462 SymbolNameSet VSO::lookupFlags(SymbolFlagsMap &Flags, SymbolNameSet Names) { 463 464 for (SymbolNameSet::iterator I = Names.begin(), E = Names.end(); I != E;) { 465 auto Tmp = I++; 466 auto SymI = Symbols.find(*Tmp); 467 468 // If the symbol isn't in this dylib then just continue. 469 if (SymI == Symbols.end()) 470 continue; 471 472 Names.erase(Tmp); 473 474 Flags[SymI->first] = 475 JITSymbolFlags::stripTransientFlags(SymI->second.Flags); 476 } 477 478 return Names; 479 } 480 481 VSO::LookupResult VSO::lookup(std::shared_ptr<AsynchronousSymbolQuery> Query, 482 SymbolNameSet Names) { 483 MaterializationUnitList MaterializationUnits; 484 485 for (SymbolNameSet::iterator I = Names.begin(), E = Names.end(); I != E;) { 486 auto Tmp = I++; 487 auto SymI = Symbols.find(*Tmp); 488 489 // If the symbol isn't in this dylib then just continue. 490 if (SymI == Symbols.end()) 491 continue; 492 493 // The symbol is in the VSO. Erase it from Names and proceed. 494 Names.erase(Tmp); 495 496 // If this symbol has not been materialized yet, move it to materializing, 497 // then fall through to the materializing case below. 498 if (SymI->second.Flags.isLazy()) { 499 if (auto MU = SymI->second.initMaterialize(*this)) 500 MaterializationUnits.push_back(std::move(MU)); 501 } 502 503 // If this symbol already has a fully materialized value, just use it. 504 if (!SymI->second.Flags.isMaterializing()) { 505 Query->resolve(SymI->first, JITEvaluatedSymbol(SymI->second.Address, 506 SymI->second.Flags)); 507 Query->finalizeSymbol(); 508 continue; 509 } 510 511 // If this symbol is materializing, then get (or create) its 512 // MaterializingInfo struct and appaend the query. 513 auto J = MaterializingInfos.find(SymI->first); 514 if (J == MaterializingInfos.end()) 515 J = MaterializingInfos 516 .insert(std::make_pair(SymI->first, MaterializingInfo())) 517 .first; 518 519 if (SymI->second.Address) { 520 auto Sym = JITEvaluatedSymbol(SymI->second.Address, SymI->second.Flags); 521 Query->resolve(SymI->first, Sym); 522 assert(J->second.PendingResolution.empty() && 523 "Queries still pending resolution on resolved symbol?"); 524 J->second.PendingFinalization.push_back(Query); 525 } else { 526 assert(J->second.PendingFinalization.empty() && 527 "Queries pendiing finalization on unresolved symbol?"); 528 J->second.PendingResolution.push_back(Query); 529 } 530 } 531 532 return {std::move(MaterializationUnits), std::move(Names)}; 533 } 534 535 Expected<SymbolMap> lookup(const std::vector<VSO *> &VSOs, SymbolNameSet Names, 536 MaterializationDispatcher DispatchMaterialization) { 537 #if LLVM_ENABLE_THREADS 538 // In the threaded case we use promises to return the results. 539 std::promise<SymbolMap> PromisedResult; 540 std::mutex ErrMutex; 541 Error ResolutionError = Error::success(); 542 std::promise<void> PromisedReady; 543 Error ReadyError = Error::success(); 544 auto OnResolve = [&](Expected<SymbolMap> Result) { 545 if (Result) 546 PromisedResult.set_value(std::move(*Result)); 547 else { 548 { 549 ErrorAsOutParameter _(&ResolutionError); 550 std::lock_guard<std::mutex> Lock(ErrMutex); 551 ResolutionError = Result.takeError(); 552 } 553 PromisedResult.set_value(SymbolMap()); 554 } 555 }; 556 auto OnReady = [&](Error Err) { 557 if (Err) { 558 ErrorAsOutParameter _(&ReadyError); 559 std::lock_guard<std::mutex> Lock(ErrMutex); 560 ReadyError = std::move(Err); 561 } 562 PromisedReady.set_value(); 563 }; 564 #else 565 SymbolMap Result; 566 Error ResolutionError = Error::success(); 567 Error ReadyError = Error::success(); 568 569 auto OnResolve = [&](Expected<SymbolMap> R) { 570 ErrorAsOutParameter _(&ResolutionError); 571 if (R) 572 Result = std::move(*R); 573 else 574 ResolutionError = R.takeError(); 575 }; 576 auto OnReady = [&](Error Err) { 577 ErrorAsOutParameter _(&ReadyError); 578 if (Err) 579 ReadyError = std::move(Err); 580 }; 581 #endif 582 583 auto Query = std::make_shared<AsynchronousSymbolQuery>( 584 Names, std::move(OnResolve), std::move(OnReady)); 585 SymbolNameSet UnresolvedSymbols(std::move(Names)); 586 587 for (auto *V : VSOs) { 588 589 if (UnresolvedSymbols.empty()) 590 break; 591 592 assert(V && "VSO pointers in VSOs list should be non-null"); 593 auto LR = V->lookup(Query, UnresolvedSymbols); 594 UnresolvedSymbols = std::move(LR.UnresolvedSymbols); 595 596 for (auto &MU : LR.MaterializationUnits) 597 DispatchMaterialization(*V, std::move(MU)); 598 } 599 600 #if LLVM_ENABLE_THREADS 601 auto ResultFuture = PromisedResult.get_future(); 602 auto Result = ResultFuture.get(); 603 604 { 605 std::lock_guard<std::mutex> Lock(ErrMutex); 606 if (ResolutionError) { 607 // ReadyError will never be assigned. Consume the success value. 608 cantFail(std::move(ReadyError)); 609 return std::move(ResolutionError); 610 } 611 } 612 613 auto ReadyFuture = PromisedReady.get_future(); 614 ReadyFuture.get(); 615 616 { 617 std::lock_guard<std::mutex> Lock(ErrMutex); 618 if (ReadyError) 619 return std::move(ReadyError); 620 } 621 622 return std::move(Result); 623 624 #else 625 if (ResolutionError) { 626 // ReadyError will never be assigned. Consume the success value. 627 cantFail(std::move(ReadyError)); 628 return std::move(ResolutionError); 629 } 630 631 if (ReadyError) 632 return std::move(ReadyError); 633 634 return Result; 635 #endif 636 } 637 638 /// @brief Look up a symbol by searching a list of VSOs. 639 Expected<JITEvaluatedSymbol> 640 lookup(const std::vector<VSO *> VSOs, SymbolStringPtr Name, 641 MaterializationDispatcher DispatchMaterialization) { 642 SymbolNameSet Names({Name}); 643 if (auto ResultMap = 644 lookup(VSOs, std::move(Names), std::move(DispatchMaterialization))) { 645 assert(ResultMap->size() == 1 && "Unexpected number of results"); 646 assert(ResultMap->count(Name) && "Missing result for symbol"); 647 return ResultMap->begin()->second; 648 } else 649 return ResultMap.takeError(); 650 } 651 652 void ExecutionSession::logErrorsToStdErr(Error Err) { 653 logAllUnhandledErrors(std::move(Err), errs(), "JIT session error: "); 654 } 655 656 } // End namespace orc. 657 } // End namespace llvm. 658