3238 lines · cpp
1//===--- Core.cpp - Core ORC APIs (MaterializationUnit, JITDylib, etc.) ---===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/ExecutionEngine/Orc/Core.h"10 11#include "llvm/ADT/STLExtras.h"12#include "llvm/Config/llvm-config.h"13#include "llvm/ExecutionEngine/Orc/DebugUtils.h"14#include "llvm/ExecutionEngine/Orc/Shared/OrcError.h"15#include "llvm/Support/FormatVariadic.h"16#include "llvm/Support/MSVCErrorWorkarounds.h"17#include "llvm/Support/raw_ostream.h"18 19#include <condition_variable>20#include <future>21#include <optional>22 23#define DEBUG_TYPE "orc"24 25namespace llvm {26namespace orc {27 28char ResourceTrackerDefunct::ID = 0;29char FailedToMaterialize::ID = 0;30char SymbolsNotFound::ID = 0;31char SymbolsCouldNotBeRemoved::ID = 0;32char MissingSymbolDefinitions::ID = 0;33char UnexpectedSymbolDefinitions::ID = 0;34char UnsatisfiedSymbolDependencies::ID = 0;35char MaterializationTask::ID = 0;36char LookupTask::ID = 0;37 38RegisterDependenciesFunction NoDependenciesToRegister =39 RegisterDependenciesFunction();40 41void MaterializationUnit::anchor() {}42 43ResourceTracker::ResourceTracker(JITDylibSP JD) {44 assert((reinterpret_cast<uintptr_t>(JD.get()) & 0x1) == 0 &&45 "JITDylib must be two byte aligned");46 JD->Retain();47 JDAndFlag.store(reinterpret_cast<uintptr_t>(JD.get()));48}49 50ResourceTracker::~ResourceTracker() {51 getJITDylib().getExecutionSession().destroyResourceTracker(*this);52 getJITDylib().Release();53}54 55Error ResourceTracker::remove() {56 return getJITDylib().getExecutionSession().removeResourceTracker(*this);57}58 59void ResourceTracker::transferTo(ResourceTracker &DstRT) {60 getJITDylib().getExecutionSession().transferResourceTracker(DstRT, *this);61}62 63void ResourceTracker::makeDefunct() {64 uintptr_t Val = JDAndFlag.load();65 Val |= 0x1U;66 JDAndFlag.store(Val);67}68 69ResourceManager::~ResourceManager() = default;70 71ResourceTrackerDefunct::ResourceTrackerDefunct(ResourceTrackerSP RT)72 : RT(std::move(RT)) {}73 74std::error_code ResourceTrackerDefunct::convertToErrorCode() const {75 return orcError(OrcErrorCode::UnknownORCError);76}77 78void ResourceTrackerDefunct::log(raw_ostream &OS) const {79 OS << "Resource tracker " << (void *)RT.get() << " became defunct";80}81 82FailedToMaterialize::FailedToMaterialize(83 std::shared_ptr<SymbolStringPool> SSP,84 std::shared_ptr<SymbolDependenceMap> Symbols)85 : SSP(std::move(SSP)), Symbols(std::move(Symbols)) {86 assert(this->SSP && "String pool cannot be null");87 assert(!this->Symbols->empty() && "Can not fail to resolve an empty set");88 89 // FIXME: Use a new dep-map type for FailedToMaterialize errors so that we90 // don't have to manually retain/release.91 for (auto &[JD, Syms] : *this->Symbols)92 JD->Retain();93}94 95FailedToMaterialize::~FailedToMaterialize() {96 for (auto &[JD, Syms] : *Symbols)97 JD->Release();98}99 100std::error_code FailedToMaterialize::convertToErrorCode() const {101 return orcError(OrcErrorCode::UnknownORCError);102}103 104void FailedToMaterialize::log(raw_ostream &OS) const {105 OS << "Failed to materialize symbols: " << *Symbols;106}107 108UnsatisfiedSymbolDependencies::UnsatisfiedSymbolDependencies(109 std::shared_ptr<SymbolStringPool> SSP, JITDylibSP JD,110 SymbolNameSet FailedSymbols, SymbolDependenceMap BadDeps,111 std::string Explanation)112 : SSP(std::move(SSP)), JD(std::move(JD)),113 FailedSymbols(std::move(FailedSymbols)), BadDeps(std::move(BadDeps)),114 Explanation(std::move(Explanation)) {}115 116std::error_code UnsatisfiedSymbolDependencies::convertToErrorCode() const {117 return orcError(OrcErrorCode::UnknownORCError);118}119 120void UnsatisfiedSymbolDependencies::log(raw_ostream &OS) const {121 OS << "In " << JD->getName() << ", failed to materialize " << FailedSymbols122 << ", due to unsatisfied dependencies " << BadDeps;123 if (!Explanation.empty())124 OS << " (" << Explanation << ")";125}126 127SymbolsNotFound::SymbolsNotFound(std::shared_ptr<SymbolStringPool> SSP,128 SymbolNameSet Symbols)129 : SSP(std::move(SSP)) {130 llvm::append_range(this->Symbols, Symbols);131 assert(!this->Symbols.empty() && "Can not fail to resolve an empty set");132}133 134SymbolsNotFound::SymbolsNotFound(std::shared_ptr<SymbolStringPool> SSP,135 SymbolNameVector Symbols)136 : SSP(std::move(SSP)), Symbols(std::move(Symbols)) {137 assert(!this->Symbols.empty() && "Can not fail to resolve an empty set");138}139 140std::error_code SymbolsNotFound::convertToErrorCode() const {141 return orcError(OrcErrorCode::UnknownORCError);142}143 144void SymbolsNotFound::log(raw_ostream &OS) const {145 OS << "Symbols not found: " << Symbols;146}147 148SymbolsCouldNotBeRemoved::SymbolsCouldNotBeRemoved(149 std::shared_ptr<SymbolStringPool> SSP, SymbolNameSet Symbols)150 : SSP(std::move(SSP)), Symbols(std::move(Symbols)) {151 assert(!this->Symbols.empty() && "Can not fail to resolve an empty set");152}153 154std::error_code SymbolsCouldNotBeRemoved::convertToErrorCode() const {155 return orcError(OrcErrorCode::UnknownORCError);156}157 158void SymbolsCouldNotBeRemoved::log(raw_ostream &OS) const {159 OS << "Symbols could not be removed: " << Symbols;160}161 162std::error_code MissingSymbolDefinitions::convertToErrorCode() const {163 return orcError(OrcErrorCode::MissingSymbolDefinitions);164}165 166void MissingSymbolDefinitions::log(raw_ostream &OS) const {167 OS << "Missing definitions in module " << ModuleName168 << ": " << Symbols;169}170 171std::error_code UnexpectedSymbolDefinitions::convertToErrorCode() const {172 return orcError(OrcErrorCode::UnexpectedSymbolDefinitions);173}174 175void UnexpectedSymbolDefinitions::log(raw_ostream &OS) const {176 OS << "Unexpected definitions in module " << ModuleName177 << ": " << Symbols;178}179 180void SymbolInstance::lookupAsync(LookupAsyncOnCompleteFn OnComplete) const {181 JD->getExecutionSession().lookup(182 LookupKind::Static, {{JD.get(), JITDylibLookupFlags::MatchAllSymbols}},183 SymbolLookupSet(Name), SymbolState::Ready,184 [OnComplete = std::move(OnComplete)185#ifndef NDEBUG186 ,187 Name = this->Name // Captured for the assert below only.188#endif // NDEBUG189 ](Expected<SymbolMap> Result) mutable {190 if (Result) {191 assert(Result->size() == 1 && "Unexpected number of results");192 assert(Result->count(Name) &&193 "Result does not contain expected symbol");194 OnComplete(Result->begin()->second);195 } else196 OnComplete(Result.takeError());197 },198 NoDependenciesToRegister);199}200 201AsynchronousSymbolQuery::AsynchronousSymbolQuery(202 const SymbolLookupSet &Symbols, SymbolState RequiredState,203 SymbolsResolvedCallback NotifyComplete)204 : NotifyComplete(std::move(NotifyComplete)), RequiredState(RequiredState) {205 assert(RequiredState >= SymbolState::Resolved &&206 "Cannot query for a symbols that have not reached the resolve state "207 "yet");208 209 OutstandingSymbolsCount = Symbols.size();210 211 for (auto &[Name, Flags] : Symbols)212 ResolvedSymbols[Name] = ExecutorSymbolDef();213}214 215void AsynchronousSymbolQuery::notifySymbolMetRequiredState(216 const SymbolStringPtr &Name, ExecutorSymbolDef Sym) {217 auto I = ResolvedSymbols.find(Name);218 assert(I != ResolvedSymbols.end() &&219 "Resolving symbol outside the requested set");220 assert(I->second == ExecutorSymbolDef() &&221 "Redundantly resolving symbol Name");222 223 // If this is a materialization-side-effects-only symbol then drop it,224 // otherwise update its map entry with its resolved address.225 if (Sym.getFlags().hasMaterializationSideEffectsOnly())226 ResolvedSymbols.erase(I);227 else228 I->second = std::move(Sym);229 --OutstandingSymbolsCount;230}231 232void AsynchronousSymbolQuery::handleComplete(ExecutionSession &ES) {233 assert(OutstandingSymbolsCount == 0 &&234 "Symbols remain, handleComplete called prematurely");235 236 class RunQueryCompleteTask : public Task {237 public:238 RunQueryCompleteTask(SymbolMap ResolvedSymbols,239 SymbolsResolvedCallback NotifyComplete)240 : ResolvedSymbols(std::move(ResolvedSymbols)),241 NotifyComplete(std::move(NotifyComplete)) {}242 void printDescription(raw_ostream &OS) override {243 OS << "Execute query complete callback for " << ResolvedSymbols;244 }245 void run() override { NotifyComplete(std::move(ResolvedSymbols)); }246 247 private:248 SymbolMap ResolvedSymbols;249 SymbolsResolvedCallback NotifyComplete;250 };251 252 auto T = std::make_unique<RunQueryCompleteTask>(std::move(ResolvedSymbols),253 std::move(NotifyComplete));254 NotifyComplete = SymbolsResolvedCallback();255 ES.dispatchTask(std::move(T));256}257 258void AsynchronousSymbolQuery::handleFailed(Error Err) {259 assert(QueryRegistrations.empty() && ResolvedSymbols.empty() &&260 OutstandingSymbolsCount == 0 &&261 "Query should already have been abandoned");262 NotifyComplete(std::move(Err));263 NotifyComplete = SymbolsResolvedCallback();264}265 266void AsynchronousSymbolQuery::addQueryDependence(JITDylib &JD,267 SymbolStringPtr Name) {268 bool Added = QueryRegistrations[&JD].insert(std::move(Name)).second;269 (void)Added;270 assert(Added && "Duplicate dependence notification?");271}272 273void AsynchronousSymbolQuery::removeQueryDependence(274 JITDylib &JD, const SymbolStringPtr &Name) {275 auto QRI = QueryRegistrations.find(&JD);276 assert(QRI != QueryRegistrations.end() &&277 "No dependencies registered for JD");278 assert(QRI->second.count(Name) && "No dependency on Name in JD");279 QRI->second.erase(Name);280 if (QRI->second.empty())281 QueryRegistrations.erase(QRI);282}283 284void AsynchronousSymbolQuery::dropSymbol(const SymbolStringPtr &Name) {285 auto I = ResolvedSymbols.find(Name);286 assert(I != ResolvedSymbols.end() &&287 "Redundant removal of weakly-referenced symbol");288 ResolvedSymbols.erase(I);289 --OutstandingSymbolsCount;290}291 292void AsynchronousSymbolQuery::detach() {293 ResolvedSymbols.clear();294 OutstandingSymbolsCount = 0;295 for (auto &[JD, Syms] : QueryRegistrations)296 JD->detachQueryHelper(*this, Syms);297 QueryRegistrations.clear();298}299 300ReExportsMaterializationUnit::ReExportsMaterializationUnit(301 JITDylib *SourceJD, JITDylibLookupFlags SourceJDLookupFlags,302 SymbolAliasMap Aliases)303 : MaterializationUnit(extractFlags(Aliases)), SourceJD(SourceJD),304 SourceJDLookupFlags(SourceJDLookupFlags), Aliases(std::move(Aliases)) {}305 306StringRef ReExportsMaterializationUnit::getName() const {307 return "<Reexports>";308}309 310void ReExportsMaterializationUnit::materialize(311 std::unique_ptr<MaterializationResponsibility> R) {312 313 auto &ES = R->getTargetJITDylib().getExecutionSession();314 JITDylib &TgtJD = R->getTargetJITDylib();315 JITDylib &SrcJD = SourceJD ? *SourceJD : TgtJD;316 317 // Find the set of requested aliases and aliasees. Return any unrequested318 // aliases back to the JITDylib so as to not prematurely materialize any319 // aliasees.320 auto RequestedSymbols = R->getRequestedSymbols();321 SymbolAliasMap RequestedAliases;322 323 for (auto &Name : RequestedSymbols) {324 auto I = Aliases.find(Name);325 assert(I != Aliases.end() && "Symbol not found in aliases map?");326 RequestedAliases[Name] = std::move(I->second);327 Aliases.erase(I);328 }329 330 LLVM_DEBUG({331 ES.runSessionLocked([&]() {332 dbgs() << "materializing reexports: target = " << TgtJD.getName()333 << ", source = " << SrcJD.getName() << " " << RequestedAliases334 << "\n";335 });336 });337 338 if (!Aliases.empty()) {339 auto Err = SourceJD ? R->replace(reexports(*SourceJD, std::move(Aliases),340 SourceJDLookupFlags))341 : R->replace(symbolAliases(std::move(Aliases)));342 343 if (Err) {344 // FIXME: Should this be reported / treated as failure to materialize?345 // Or should this be treated as a sanctioned bailing-out?346 ES.reportError(std::move(Err));347 R->failMaterialization();348 return;349 }350 }351 352 // The OnResolveInfo struct will hold the aliases and responsibility for each353 // query in the list.354 struct OnResolveInfo {355 OnResolveInfo(std::unique_ptr<MaterializationResponsibility> R,356 SymbolAliasMap Aliases)357 : R(std::move(R)), Aliases(std::move(Aliases)) {}358 359 std::unique_ptr<MaterializationResponsibility> R;360 SymbolAliasMap Aliases;361 std::vector<SymbolDependenceGroup> SDGs;362 };363 364 // Build a list of queries to issue. In each round we build a query for the365 // largest set of aliases that we can resolve without encountering a chain of366 // aliases (e.g. Foo -> Bar, Bar -> Baz). Such a chain would deadlock as the367 // query would be waiting on a symbol that it itself had to resolve. Creating368 // a new query for each link in such a chain eliminates the possibility of369 // deadlock. In practice chains are likely to be rare, and this algorithm will370 // usually result in a single query to issue.371 372 std::vector<std::pair<SymbolLookupSet, std::shared_ptr<OnResolveInfo>>>373 QueryInfos;374 while (!RequestedAliases.empty()) {375 SymbolNameSet ResponsibilitySymbols;376 SymbolLookupSet QuerySymbols;377 SymbolAliasMap QueryAliases;378 379 // Collect as many aliases as we can without including a chain.380 for (auto &KV : RequestedAliases) {381 // Chain detected. Skip this symbol for this round.382 if (&SrcJD == &TgtJD && (QueryAliases.count(KV.second.Aliasee) ||383 RequestedAliases.count(KV.second.Aliasee)))384 continue;385 386 ResponsibilitySymbols.insert(KV.first);387 QuerySymbols.add(KV.second.Aliasee,388 KV.second.AliasFlags.hasMaterializationSideEffectsOnly()389 ? SymbolLookupFlags::WeaklyReferencedSymbol390 : SymbolLookupFlags::RequiredSymbol);391 QueryAliases[KV.first] = std::move(KV.second);392 }393 394 // Remove the aliases collected this round from the RequestedAliases map.395 for (auto &KV : QueryAliases)396 RequestedAliases.erase(KV.first);397 398 assert(!QuerySymbols.empty() && "Alias cycle detected!");399 400 auto NewR = R->delegate(ResponsibilitySymbols);401 if (!NewR) {402 ES.reportError(NewR.takeError());403 R->failMaterialization();404 return;405 }406 407 auto QueryInfo = std::make_shared<OnResolveInfo>(std::move(*NewR),408 std::move(QueryAliases));409 QueryInfos.push_back(410 make_pair(std::move(QuerySymbols), std::move(QueryInfo)));411 }412 413 // Issue the queries.414 while (!QueryInfos.empty()) {415 auto QuerySymbols = std::move(QueryInfos.back().first);416 auto QueryInfo = std::move(QueryInfos.back().second);417 418 QueryInfos.pop_back();419 420 auto RegisterDependencies = [QueryInfo,421 &SrcJD](const SymbolDependenceMap &Deps) {422 // If there were no materializing symbols, just bail out.423 if (Deps.empty())424 return;425 426 // Otherwise the only deps should be on SrcJD.427 assert(Deps.size() == 1 && Deps.count(&SrcJD) &&428 "Unexpected dependencies for reexports");429 430 auto &SrcJDDeps = Deps.find(&SrcJD)->second;431 432 for (auto &[Alias, AliasInfo] : QueryInfo->Aliases)433 if (SrcJDDeps.count(AliasInfo.Aliasee))434 QueryInfo->SDGs.push_back({{Alias}, {{&SrcJD, {AliasInfo.Aliasee}}}});435 };436 437 auto OnComplete = [QueryInfo](Expected<SymbolMap> Result) {438 auto &ES = QueryInfo->R->getTargetJITDylib().getExecutionSession();439 if (Result) {440 SymbolMap ResolutionMap;441 for (auto &KV : QueryInfo->Aliases) {442 assert((KV.second.AliasFlags.hasMaterializationSideEffectsOnly() ||443 Result->count(KV.second.Aliasee)) &&444 "Result map missing entry?");445 // Don't try to resolve materialization-side-effects-only symbols.446 if (KV.second.AliasFlags.hasMaterializationSideEffectsOnly())447 continue;448 449 ResolutionMap[KV.first] = {(*Result)[KV.second.Aliasee].getAddress(),450 KV.second.AliasFlags};451 }452 if (auto Err = QueryInfo->R->notifyResolved(ResolutionMap)) {453 ES.reportError(std::move(Err));454 QueryInfo->R->failMaterialization();455 return;456 }457 if (auto Err = QueryInfo->R->notifyEmitted(QueryInfo->SDGs)) {458 ES.reportError(std::move(Err));459 QueryInfo->R->failMaterialization();460 return;461 }462 } else {463 ES.reportError(Result.takeError());464 QueryInfo->R->failMaterialization();465 }466 };467 468 ES.lookup(LookupKind::Static,469 JITDylibSearchOrder({{&SrcJD, SourceJDLookupFlags}}),470 QuerySymbols, SymbolState::Resolved, std::move(OnComplete),471 std::move(RegisterDependencies));472 }473}474 475void ReExportsMaterializationUnit::discard(const JITDylib &JD,476 const SymbolStringPtr &Name) {477 assert(Aliases.count(Name) &&478 "Symbol not covered by this MaterializationUnit");479 Aliases.erase(Name);480}481 482MaterializationUnit::Interface483ReExportsMaterializationUnit::extractFlags(const SymbolAliasMap &Aliases) {484 SymbolFlagsMap SymbolFlags;485 for (auto &KV : Aliases)486 SymbolFlags[KV.first] = KV.second.AliasFlags;487 488 return MaterializationUnit::Interface(std::move(SymbolFlags), nullptr);489}490 491Expected<SymbolAliasMap> buildSimpleReexportsAliasMap(JITDylib &SourceJD,492 SymbolNameSet Symbols) {493 SymbolLookupSet LookupSet(Symbols);494 auto Flags = SourceJD.getExecutionSession().lookupFlags(495 LookupKind::Static, {{&SourceJD, JITDylibLookupFlags::MatchAllSymbols}},496 SymbolLookupSet(std::move(Symbols)));497 498 if (!Flags)499 return Flags.takeError();500 501 SymbolAliasMap Result;502 for (auto &Name : Symbols) {503 assert(Flags->count(Name) && "Missing entry in flags map");504 Result[Name] = SymbolAliasMapEntry(Name, (*Flags)[Name]);505 }506 507 return Result;508}509 510class InProgressLookupState {511public:512 // FIXME: Reduce the number of SymbolStringPtrs here. See513 // https://github.com/llvm/llvm-project/issues/55576.514 515 InProgressLookupState(LookupKind K, JITDylibSearchOrder SearchOrder,516 SymbolLookupSet LookupSet, SymbolState RequiredState)517 : K(K), SearchOrder(std::move(SearchOrder)),518 LookupSet(std::move(LookupSet)), RequiredState(RequiredState) {519 DefGeneratorCandidates = this->LookupSet;520 }521 virtual ~InProgressLookupState() = default;522 virtual void complete(std::unique_ptr<InProgressLookupState> IPLS) = 0;523 virtual void fail(Error Err) = 0;524 525 LookupKind K;526 JITDylibSearchOrder SearchOrder;527 SymbolLookupSet LookupSet;528 SymbolState RequiredState;529 530 size_t CurSearchOrderIndex = 0;531 bool NewJITDylib = true;532 SymbolLookupSet DefGeneratorCandidates;533 SymbolLookupSet DefGeneratorNonCandidates;534 535 enum {536 NotInGenerator, // Not currently using a generator.537 ResumedForGenerator, // Resumed after being auto-suspended before generator.538 InGenerator // Currently using generator.539 } GenState = NotInGenerator;540 std::vector<std::weak_ptr<DefinitionGenerator>> CurDefGeneratorStack;541};542 543class InProgressLookupFlagsState : public InProgressLookupState {544public:545 InProgressLookupFlagsState(546 LookupKind K, JITDylibSearchOrder SearchOrder, SymbolLookupSet LookupSet,547 unique_function<void(Expected<SymbolFlagsMap>)> OnComplete)548 : InProgressLookupState(K, std::move(SearchOrder), std::move(LookupSet),549 SymbolState::NeverSearched),550 OnComplete(std::move(OnComplete)) {}551 552 void complete(std::unique_ptr<InProgressLookupState> IPLS) override {553 auto &ES = SearchOrder.front().first->getExecutionSession();554 ES.OL_completeLookupFlags(std::move(IPLS), std::move(OnComplete));555 }556 557 void fail(Error Err) override { OnComplete(std::move(Err)); }558 559private:560 unique_function<void(Expected<SymbolFlagsMap>)> OnComplete;561};562 563class InProgressFullLookupState : public InProgressLookupState {564public:565 InProgressFullLookupState(LookupKind K, JITDylibSearchOrder SearchOrder,566 SymbolLookupSet LookupSet,567 SymbolState RequiredState,568 std::shared_ptr<AsynchronousSymbolQuery> Q,569 RegisterDependenciesFunction RegisterDependencies)570 : InProgressLookupState(K, std::move(SearchOrder), std::move(LookupSet),571 RequiredState),572 Q(std::move(Q)), RegisterDependencies(std::move(RegisterDependencies)) {573 }574 575 void complete(std::unique_ptr<InProgressLookupState> IPLS) override {576 auto &ES = SearchOrder.front().first->getExecutionSession();577 ES.OL_completeLookup(std::move(IPLS), std::move(Q),578 std::move(RegisterDependencies));579 }580 581 void fail(Error Err) override {582 Q->detach();583 Q->handleFailed(std::move(Err));584 }585 586private:587 std::shared_ptr<AsynchronousSymbolQuery> Q;588 RegisterDependenciesFunction RegisterDependencies;589};590 591ReexportsGenerator::ReexportsGenerator(JITDylib &SourceJD,592 JITDylibLookupFlags SourceJDLookupFlags,593 SymbolPredicate Allow)594 : SourceJD(SourceJD), SourceJDLookupFlags(SourceJDLookupFlags),595 Allow(std::move(Allow)) {}596 597Error ReexportsGenerator::tryToGenerate(LookupState &LS, LookupKind K,598 JITDylib &JD,599 JITDylibLookupFlags JDLookupFlags,600 const SymbolLookupSet &LookupSet) {601 assert(&JD != &SourceJD && "Cannot re-export from the same dylib");602 603 // Use lookupFlags to find the subset of symbols that match our lookup.604 auto Flags = JD.getExecutionSession().lookupFlags(605 K, {{&SourceJD, JDLookupFlags}}, LookupSet);606 if (!Flags)607 return Flags.takeError();608 609 // Create an alias map.610 orc::SymbolAliasMap AliasMap;611 for (auto &KV : *Flags)612 if (!Allow || Allow(KV.first))613 AliasMap[KV.first] = SymbolAliasMapEntry(KV.first, KV.second);614 615 if (AliasMap.empty())616 return Error::success();617 618 // Define the re-exports.619 return JD.define(reexports(SourceJD, AliasMap, SourceJDLookupFlags));620}621 622LookupState::LookupState(std::unique_ptr<InProgressLookupState> IPLS)623 : IPLS(std::move(IPLS)) {}624 625void LookupState::reset(InProgressLookupState *IPLS) { this->IPLS.reset(IPLS); }626 627LookupState::LookupState() = default;628LookupState::LookupState(LookupState &&) = default;629LookupState &LookupState::operator=(LookupState &&) = default;630LookupState::~LookupState() = default;631 632void LookupState::continueLookup(Error Err) {633 assert(IPLS && "Cannot call continueLookup on empty LookupState");634 auto &ES = IPLS->SearchOrder.begin()->first->getExecutionSession();635 ES.OL_applyQueryPhase1(std::move(IPLS), std::move(Err));636}637 638DefinitionGenerator::~DefinitionGenerator() {639 std::deque<LookupState> LookupsToFail;640 {641 std::lock_guard<std::mutex> Lock(M);642 std::swap(PendingLookups, LookupsToFail);643 InUse = false;644 }645 646 for (auto &LS : LookupsToFail)647 LS.continueLookup(make_error<StringError>(648 "Query waiting on DefinitionGenerator that was destroyed",649 inconvertibleErrorCode()));650}651 652JITDylib::~JITDylib() {653 LLVM_DEBUG(dbgs() << "Destroying JITDylib " << getName() << "\n");654}655 656Error JITDylib::clear() {657 std::vector<ResourceTrackerSP> TrackersToRemove;658 ES.runSessionLocked([&]() {659 assert(State != Closed && "JD is defunct");660 for (auto &KV : TrackerSymbols)661 TrackersToRemove.push_back(KV.first);662 TrackersToRemove.push_back(getDefaultResourceTracker());663 });664 665 Error Err = Error::success();666 for (auto &RT : TrackersToRemove)667 Err = joinErrors(std::move(Err), RT->remove());668 return Err;669}670 671ResourceTrackerSP JITDylib::getDefaultResourceTracker() {672 return ES.runSessionLocked([this] {673 assert(State != Closed && "JD is defunct");674 if (!DefaultTracker)675 DefaultTracker = new ResourceTracker(this);676 return DefaultTracker;677 });678}679 680ResourceTrackerSP JITDylib::createResourceTracker() {681 return ES.runSessionLocked([this] {682 assert(State == Open && "JD is defunct");683 ResourceTrackerSP RT = new ResourceTracker(this);684 return RT;685 });686}687 688void JITDylib::removeGenerator(DefinitionGenerator &G) {689 // DefGenerator moved into TmpDG to ensure that it's destroyed outside the690 // session lock (since it may have to send errors to pending queries).691 std::shared_ptr<DefinitionGenerator> TmpDG;692 693 ES.runSessionLocked([&] {694 assert(State == Open && "JD is defunct");695 auto I = llvm::find_if(DefGenerators,696 [&](const std::shared_ptr<DefinitionGenerator> &H) {697 return H.get() == &G;698 });699 assert(I != DefGenerators.end() && "Generator not found");700 TmpDG = std::move(*I);701 DefGenerators.erase(I);702 });703}704 705Expected<SymbolFlagsMap>706JITDylib::defineMaterializing(MaterializationResponsibility &FromMR,707 SymbolFlagsMap SymbolFlags) {708 709 return ES.runSessionLocked([&]() -> Expected<SymbolFlagsMap> {710 if (FromMR.RT->isDefunct())711 return make_error<ResourceTrackerDefunct>(FromMR.RT);712 713 std::vector<NonOwningSymbolStringPtr> AddedSyms;714 std::vector<NonOwningSymbolStringPtr> RejectedWeakDefs;715 716 for (auto &[Name, Flags] : SymbolFlags) {717 auto EntryItr = Symbols.find(Name);718 719 // If the entry already exists...720 if (EntryItr != Symbols.end()) {721 722 // If this is a strong definition then error out.723 if (!Flags.isWeak()) {724 // Remove any symbols already added.725 for (auto &S : AddedSyms)726 Symbols.erase(Symbols.find_as(S));727 728 // FIXME: Return all duplicates.729 return make_error<DuplicateDefinition>(730 std::string(*Name), "defineMaterializing operation");731 }732 733 // Otherwise just make a note to discard this symbol after the loop.734 RejectedWeakDefs.push_back(NonOwningSymbolStringPtr(Name));735 continue;736 } else737 EntryItr =738 Symbols.insert(std::make_pair(Name, SymbolTableEntry(Flags))).first;739 740 AddedSyms.push_back(NonOwningSymbolStringPtr(Name));741 EntryItr->second.setState(SymbolState::Materializing);742 }743 744 // Remove any rejected weak definitions from the SymbolFlags map.745 while (!RejectedWeakDefs.empty()) {746 SymbolFlags.erase(SymbolFlags.find_as(RejectedWeakDefs.back()));747 RejectedWeakDefs.pop_back();748 }749 750 return SymbolFlags;751 });752}753 754Error JITDylib::replace(MaterializationResponsibility &FromMR,755 std::unique_ptr<MaterializationUnit> MU) {756 assert(MU != nullptr && "Can not replace with a null MaterializationUnit");757 std::unique_ptr<MaterializationUnit> MustRunMU;758 std::unique_ptr<MaterializationResponsibility> MustRunMR;759 760 auto Err =761 ES.runSessionLocked([&, this]() -> Error {762 if (FromMR.RT->isDefunct())763 return make_error<ResourceTrackerDefunct>(std::move(FromMR.RT));764 765#ifndef NDEBUG766 for (auto &KV : MU->getSymbols()) {767 auto SymI = Symbols.find(KV.first);768 assert(SymI != Symbols.end() && "Replacing unknown symbol");769 assert(SymI->second.getState() == SymbolState::Materializing &&770 "Can not replace a symbol that ha is not materializing");771 assert(!SymI->second.hasMaterializerAttached() &&772 "Symbol should not have materializer attached already");773 assert(UnmaterializedInfos.count(KV.first) == 0 &&774 "Symbol being replaced should have no UnmaterializedInfo");775 }776#endif // NDEBUG777 778 // If the tracker is defunct we need to bail out immediately.779 780 // If any symbol has pending queries against it then we need to781 // materialize MU immediately.782 for (auto &KV : MU->getSymbols()) {783 auto MII = MaterializingInfos.find(KV.first);784 if (MII != MaterializingInfos.end()) {785 if (MII->second.hasQueriesPending()) {786 MustRunMR = ES.createMaterializationResponsibility(787 *FromMR.RT, std::move(MU->SymbolFlags),788 std::move(MU->InitSymbol));789 MustRunMU = std::move(MU);790 return Error::success();791 }792 }793 }794 795 // Otherwise, make MU responsible for all the symbols.796 auto UMI = std::make_shared<UnmaterializedInfo>(std::move(MU),797 FromMR.RT.get());798 for (auto &KV : UMI->MU->getSymbols()) {799 auto SymI = Symbols.find(KV.first);800 assert(SymI->second.getState() == SymbolState::Materializing &&801 "Can not replace a symbol that is not materializing");802 assert(!SymI->second.hasMaterializerAttached() &&803 "Can not replace a symbol that has a materializer attached");804 assert(UnmaterializedInfos.count(KV.first) == 0 &&805 "Unexpected materializer entry in map");806 SymI->second.setAddress(SymI->second.getAddress());807 SymI->second.setMaterializerAttached(true);808 809 auto &UMIEntry = UnmaterializedInfos[KV.first];810 assert((!UMIEntry || !UMIEntry->MU) &&811 "Replacing symbol with materializer still attached");812 UMIEntry = UMI;813 }814 815 return Error::success();816 });817 818 if (Err)819 return Err;820 821 if (MustRunMU) {822 assert(MustRunMR && "MustRunMU set implies MustRunMR set");823 ES.dispatchTask(std::make_unique<MaterializationTask>(824 std::move(MustRunMU), std::move(MustRunMR)));825 } else {826 assert(!MustRunMR && "MustRunMU unset implies MustRunMR unset");827 }828 829 return Error::success();830}831 832Expected<std::unique_ptr<MaterializationResponsibility>>833JITDylib::delegate(MaterializationResponsibility &FromMR,834 SymbolFlagsMap SymbolFlags, SymbolStringPtr InitSymbol) {835 836 return ES.runSessionLocked(837 [&]() -> Expected<std::unique_ptr<MaterializationResponsibility>> {838 if (FromMR.RT->isDefunct())839 return make_error<ResourceTrackerDefunct>(std::move(FromMR.RT));840 841 return ES.createMaterializationResponsibility(842 *FromMR.RT, std::move(SymbolFlags), std::move(InitSymbol));843 });844}845 846SymbolNameSet847JITDylib::getRequestedSymbols(const SymbolFlagsMap &SymbolFlags) const {848 return ES.runSessionLocked([&]() {849 SymbolNameSet RequestedSymbols;850 851 for (auto &KV : SymbolFlags) {852 assert(Symbols.count(KV.first) && "JITDylib does not cover this symbol?");853 assert(Symbols.find(KV.first)->second.getState() !=854 SymbolState::NeverSearched &&855 Symbols.find(KV.first)->second.getState() != SymbolState::Ready &&856 "getRequestedSymbols can only be called for symbols that have "857 "started materializing");858 auto I = MaterializingInfos.find(KV.first);859 if (I == MaterializingInfos.end())860 continue;861 862 if (I->second.hasQueriesPending())863 RequestedSymbols.insert(KV.first);864 }865 866 return RequestedSymbols;867 });868}869 870Error JITDylib::resolve(MaterializationResponsibility &MR,871 const SymbolMap &Resolved) {872 AsynchronousSymbolQuerySet CompletedQueries;873 874 if (auto Err = ES.runSessionLocked([&, this]() -> Error {875 if (MR.RT->isDefunct())876 return make_error<ResourceTrackerDefunct>(MR.RT);877 878 if (State != Open)879 return make_error<StringError>("JITDylib " + getName() +880 " is defunct",881 inconvertibleErrorCode());882 883 struct WorklistEntry {884 SymbolTable::iterator SymI;885 ExecutorSymbolDef ResolvedSym;886 };887 888 SymbolNameSet SymbolsInErrorState;889 std::vector<WorklistEntry> Worklist;890 Worklist.reserve(Resolved.size());891 892 // Build worklist and check for any symbols in the error state.893 for (const auto &KV : Resolved) {894 895 assert(!KV.second.getFlags().hasError() &&896 "Resolution result can not have error flag set");897 898 auto SymI = Symbols.find(KV.first);899 900 assert(SymI != Symbols.end() && "Symbol not found");901 assert(!SymI->second.hasMaterializerAttached() &&902 "Resolving symbol with materializer attached?");903 assert(SymI->second.getState() == SymbolState::Materializing &&904 "Symbol should be materializing");905 assert(SymI->second.getAddress() == ExecutorAddr() &&906 "Symbol has already been resolved");907 908 if (SymI->second.getFlags().hasError())909 SymbolsInErrorState.insert(KV.first);910 else {911 if (SymI->second.getFlags() & JITSymbolFlags::Common) {912 [[maybe_unused]] auto WeakOrCommon =913 JITSymbolFlags::Weak | JITSymbolFlags::Common;914 assert((KV.second.getFlags() & WeakOrCommon) &&915 "Common symbols must be resolved as common or weak");916 assert((KV.second.getFlags() & ~WeakOrCommon) ==917 (SymI->second.getFlags() & ~JITSymbolFlags::Common) &&918 "Resolving symbol with incorrect flags");919 920 } else921 assert(KV.second.getFlags() == SymI->second.getFlags() &&922 "Resolved flags should match the declared flags");923 924 Worklist.push_back(925 {SymI, {KV.second.getAddress(), SymI->second.getFlags()}});926 }927 }928 929 // If any symbols were in the error state then bail out.930 if (!SymbolsInErrorState.empty()) {931 auto FailedSymbolsDepMap = std::make_shared<SymbolDependenceMap>();932 (*FailedSymbolsDepMap)[this] = std::move(SymbolsInErrorState);933 return make_error<FailedToMaterialize>(934 getExecutionSession().getSymbolStringPool(),935 std::move(FailedSymbolsDepMap));936 }937 938 while (!Worklist.empty()) {939 auto SymI = Worklist.back().SymI;940 auto ResolvedSym = Worklist.back().ResolvedSym;941 Worklist.pop_back();942 943 auto &Name = SymI->first;944 945 // Resolved symbols can not be weak: discard the weak flag.946 JITSymbolFlags ResolvedFlags = ResolvedSym.getFlags();947 SymI->second.setAddress(ResolvedSym.getAddress());948 SymI->second.setFlags(ResolvedFlags);949 SymI->second.setState(SymbolState::Resolved);950 951 auto MII = MaterializingInfos.find(Name);952 if (MII == MaterializingInfos.end())953 continue;954 955 auto &MI = MII->second;956 for (auto &Q : MI.takeQueriesMeeting(SymbolState::Resolved)) {957 Q->notifySymbolMetRequiredState(Name, ResolvedSym);958 if (Q->isComplete())959 CompletedQueries.insert(std::move(Q));960 }961 }962 963 return Error::success();964 }))965 return Err;966 967 // Otherwise notify all the completed queries.968 for (auto &Q : CompletedQueries) {969 assert(Q->isComplete() && "Q not completed");970 Q->handleComplete(ES);971 }972 973 return Error::success();974}975 976void JITDylib::unlinkMaterializationResponsibility(977 MaterializationResponsibility &MR) {978 ES.runSessionLocked([&]() {979 auto I = TrackerMRs.find(MR.RT.get());980 assert(I != TrackerMRs.end() && "No MRs in TrackerMRs list for RT");981 assert(I->second.count(&MR) && "MR not in TrackerMRs list for RT");982 I->second.erase(&MR);983 if (I->second.empty())984 TrackerMRs.erase(MR.RT.get());985 });986}987 988void JITDylib::shrinkMaterializationInfoMemory() {989 // DenseMap::erase never shrinks its storage; use clear to heuristically free990 // memory since we may have long-lived JDs after linking is done.991 992 if (UnmaterializedInfos.empty())993 UnmaterializedInfos.clear();994 995 if (MaterializingInfos.empty())996 MaterializingInfos.clear();997}998 999void JITDylib::setLinkOrder(JITDylibSearchOrder NewLinkOrder,1000 bool LinkAgainstThisJITDylibFirst) {1001 ES.runSessionLocked([&]() {1002 assert(State == Open && "JD is defunct");1003 if (LinkAgainstThisJITDylibFirst) {1004 LinkOrder.clear();1005 if (NewLinkOrder.empty() || NewLinkOrder.front().first != this)1006 LinkOrder.push_back(1007 std::make_pair(this, JITDylibLookupFlags::MatchAllSymbols));1008 llvm::append_range(LinkOrder, NewLinkOrder);1009 } else1010 LinkOrder = std::move(NewLinkOrder);1011 });1012}1013 1014void JITDylib::addToLinkOrder(const JITDylibSearchOrder &NewLinks) {1015 ES.runSessionLocked([&]() {1016 for (auto &KV : NewLinks) {1017 // Skip elements of NewLinks that are already in the link order.1018 if (llvm::is_contained(LinkOrder, KV))1019 continue;1020 1021 LinkOrder.push_back(std::move(KV));1022 }1023 });1024}1025 1026void JITDylib::addToLinkOrder(JITDylib &JD, JITDylibLookupFlags JDLookupFlags) {1027 ES.runSessionLocked([&]() { LinkOrder.push_back({&JD, JDLookupFlags}); });1028}1029 1030void JITDylib::replaceInLinkOrder(JITDylib &OldJD, JITDylib &NewJD,1031 JITDylibLookupFlags JDLookupFlags) {1032 ES.runSessionLocked([&]() {1033 assert(State == Open && "JD is defunct");1034 for (auto &KV : LinkOrder)1035 if (KV.first == &OldJD) {1036 KV = {&NewJD, JDLookupFlags};1037 break;1038 }1039 });1040}1041 1042void JITDylib::removeFromLinkOrder(JITDylib &JD) {1043 ES.runSessionLocked([&]() {1044 assert(State == Open && "JD is defunct");1045 auto I = llvm::find_if(LinkOrder,1046 [&](const JITDylibSearchOrder::value_type &KV) {1047 return KV.first == &JD;1048 });1049 if (I != LinkOrder.end())1050 LinkOrder.erase(I);1051 });1052}1053 1054Error JITDylib::remove(const SymbolNameSet &Names) {1055 return ES.runSessionLocked([&]() -> Error {1056 assert(State == Open && "JD is defunct");1057 using SymbolMaterializerItrPair =1058 std::pair<SymbolTable::iterator, UnmaterializedInfosMap::iterator>;1059 std::vector<SymbolMaterializerItrPair> SymbolsToRemove;1060 SymbolNameSet Missing;1061 SymbolNameSet Materializing;1062 1063 for (auto &Name : Names) {1064 auto I = Symbols.find(Name);1065 1066 // Note symbol missing.1067 if (I == Symbols.end()) {1068 Missing.insert(Name);1069 continue;1070 }1071 1072 // Note symbol materializing.1073 if (I->second.getState() != SymbolState::NeverSearched &&1074 I->second.getState() != SymbolState::Ready) {1075 Materializing.insert(Name);1076 continue;1077 }1078 1079 auto UMII = I->second.hasMaterializerAttached()1080 ? UnmaterializedInfos.find(Name)1081 : UnmaterializedInfos.end();1082 SymbolsToRemove.push_back(std::make_pair(I, UMII));1083 }1084 1085 // If any of the symbols are not defined, return an error.1086 if (!Missing.empty())1087 return make_error<SymbolsNotFound>(ES.getSymbolStringPool(),1088 std::move(Missing));1089 1090 // If any of the symbols are currently materializing, return an error.1091 if (!Materializing.empty())1092 return make_error<SymbolsCouldNotBeRemoved>(ES.getSymbolStringPool(),1093 std::move(Materializing));1094 1095 // Remove the symbols.1096 for (auto &SymbolMaterializerItrPair : SymbolsToRemove) {1097 auto UMII = SymbolMaterializerItrPair.second;1098 1099 // If there is a materializer attached, call discard.1100 if (UMII != UnmaterializedInfos.end()) {1101 UMII->second->MU->doDiscard(*this, UMII->first);1102 UnmaterializedInfos.erase(UMII);1103 }1104 1105 auto SymI = SymbolMaterializerItrPair.first;1106 Symbols.erase(SymI);1107 }1108 1109 shrinkMaterializationInfoMemory();1110 1111 return Error::success();1112 });1113}1114 1115void JITDylib::dump(raw_ostream &OS) {1116 ES.runSessionLocked([&, this]() {1117 OS << "JITDylib \"" << getName() << "\" (ES: "1118 << format("0x%016" PRIx64, reinterpret_cast<uintptr_t>(&ES))1119 << ", State = ";1120 switch (State) {1121 case Open:1122 OS << "Open";1123 break;1124 case Closing:1125 OS << "Closing";1126 break;1127 case Closed:1128 OS << "Closed";1129 break;1130 }1131 OS << ")\n";1132 if (State == Closed)1133 return;1134 OS << "Link order: " << LinkOrder << "\n"1135 << "Symbol table:\n";1136 1137 // Sort symbols so we get a deterministic order and can check them in tests.1138 std::vector<std::pair<SymbolStringPtr, SymbolTableEntry *>> SymbolsSorted;1139 for (auto &KV : Symbols)1140 SymbolsSorted.emplace_back(KV.first, &KV.second);1141 std::sort(SymbolsSorted.begin(), SymbolsSorted.end(),1142 [](const auto &L, const auto &R) { return *L.first < *R.first; });1143 1144 for (auto &KV : SymbolsSorted) {1145 OS << " \"" << *KV.first << "\": ";1146 if (auto Addr = KV.second->getAddress())1147 OS << Addr;1148 else1149 OS << "<not resolved> ";1150 1151 OS << " " << KV.second->getFlags() << " " << KV.second->getState();1152 1153 if (KV.second->hasMaterializerAttached()) {1154 OS << " (Materializer ";1155 auto I = UnmaterializedInfos.find(KV.first);1156 assert(I != UnmaterializedInfos.end() &&1157 "Lazy symbol should have UnmaterializedInfo");1158 OS << I->second->MU.get() << ", " << I->second->MU->getName() << ")\n";1159 } else1160 OS << "\n";1161 }1162 1163 if (!MaterializingInfos.empty())1164 OS << " MaterializingInfos entries:\n";1165 for (auto &KV : MaterializingInfos) {1166 OS << " \"" << *KV.first << "\":\n"1167 << " " << KV.second.pendingQueries().size()1168 << " pending queries: { ";1169 for (const auto &Q : KV.second.pendingQueries())1170 OS << Q.get() << " (" << Q->getRequiredState() << ") ";1171 OS << "}\n";1172 }1173 });1174}1175 1176void JITDylib::MaterializingInfo::addQuery(1177 std::shared_ptr<AsynchronousSymbolQuery> Q) {1178 1179 auto I = llvm::lower_bound(1180 llvm::reverse(PendingQueries), Q->getRequiredState(),1181 [](const std::shared_ptr<AsynchronousSymbolQuery> &V, SymbolState S) {1182 return V->getRequiredState() <= S;1183 });1184 PendingQueries.insert(I.base(), std::move(Q));1185}1186 1187void JITDylib::MaterializingInfo::removeQuery(1188 const AsynchronousSymbolQuery &Q) {1189 // FIXME: Implement 'find_as' for shared_ptr<T>/T*.1190 auto I = llvm::find_if(1191 PendingQueries, [&Q](const std::shared_ptr<AsynchronousSymbolQuery> &V) {1192 return V.get() == &Q;1193 });1194 if (I != PendingQueries.end())1195 PendingQueries.erase(I);1196}1197 1198JITDylib::AsynchronousSymbolQueryList1199JITDylib::MaterializingInfo::takeQueriesMeeting(SymbolState RequiredState) {1200 AsynchronousSymbolQueryList Result;1201 while (!PendingQueries.empty()) {1202 if (PendingQueries.back()->getRequiredState() > RequiredState)1203 break;1204 1205 Result.push_back(std::move(PendingQueries.back()));1206 PendingQueries.pop_back();1207 }1208 1209 return Result;1210}1211 1212JITDylib::JITDylib(ExecutionSession &ES, std::string Name)1213 : JITLinkDylib(std::move(Name)), ES(ES) {1214 LinkOrder.push_back({this, JITDylibLookupFlags::MatchAllSymbols});1215}1216 1217JITDylib::RemoveTrackerResult JITDylib::IL_removeTracker(ResourceTracker &RT) {1218 // Note: Should be called under the session lock.1219 assert(State != Closed && "JD is defunct");1220 1221 SymbolNameVector SymbolsToRemove;1222 SymbolNameVector SymbolsToFail;1223 1224 if (&RT == DefaultTracker.get()) {1225 SymbolNameSet TrackedSymbols;1226 for (auto &KV : TrackerSymbols)1227 TrackedSymbols.insert_range(KV.second);1228 1229 for (auto &KV : Symbols) {1230 auto &Sym = KV.first;1231 if (!TrackedSymbols.count(Sym))1232 SymbolsToRemove.push_back(Sym);1233 }1234 1235 DefaultTracker.reset();1236 } else {1237 /// Check for a non-default tracker.1238 auto I = TrackerSymbols.find(&RT);1239 if (I != TrackerSymbols.end()) {1240 SymbolsToRemove = std::move(I->second);1241 TrackerSymbols.erase(I);1242 }1243 // ... if not found this tracker was already defunct. Nothing to do.1244 }1245 1246 for (auto &Sym : SymbolsToRemove) {1247 assert(Symbols.count(Sym) && "Symbol not in symbol table");1248 1249 // If there is a MaterializingInfo then collect any queries to fail.1250 auto MII = MaterializingInfos.find(Sym);1251 if (MII != MaterializingInfos.end())1252 SymbolsToFail.push_back(Sym);1253 }1254 1255 auto [QueriesToFail, FailedSymbols] =1256 ES.IL_failSymbols(*this, std::move(SymbolsToFail));1257 1258 std::vector<std::unique_ptr<MaterializationUnit>> DefunctMUs;1259 1260 // Removed symbols should be taken out of the table altogether.1261 for (auto &Sym : SymbolsToRemove) {1262 auto I = Symbols.find(Sym);1263 assert(I != Symbols.end() && "Symbol not present in table");1264 1265 // Remove Materializer if present.1266 if (I->second.hasMaterializerAttached()) {1267 // FIXME: Should this discard the symbols?1268 auto J = UnmaterializedInfos.find(Sym);1269 assert(J != UnmaterializedInfos.end() &&1270 "Symbol table indicates MU present, but no UMI record");1271 if (J->second->MU)1272 DefunctMUs.push_back(std::move(J->second->MU));1273 UnmaterializedInfos.erase(J);1274 } else {1275 assert(!UnmaterializedInfos.count(Sym) &&1276 "Symbol has materializer attached");1277 }1278 1279 Symbols.erase(I);1280 }1281 1282 shrinkMaterializationInfoMemory();1283 1284 return {std::move(QueriesToFail), std::move(FailedSymbols),1285 std::move(DefunctMUs)};1286}1287 1288void JITDylib::transferTracker(ResourceTracker &DstRT, ResourceTracker &SrcRT) {1289 assert(State != Closed && "JD is defunct");1290 assert(&DstRT != &SrcRT && "No-op transfers shouldn't call transferTracker");1291 assert(&DstRT.getJITDylib() == this && "DstRT is not for this JITDylib");1292 assert(&SrcRT.getJITDylib() == this && "SrcRT is not for this JITDylib");1293 1294 // Update trackers for any not-yet materialized units.1295 for (auto &KV : UnmaterializedInfos) {1296 if (KV.second->RT == &SrcRT)1297 KV.second->RT = &DstRT;1298 }1299 1300 // Update trackers for any active materialization responsibilities.1301 {1302 auto I = TrackerMRs.find(&SrcRT);1303 if (I != TrackerMRs.end()) {1304 auto &SrcMRs = I->second;1305 auto &DstMRs = TrackerMRs[&DstRT];1306 for (auto *MR : SrcMRs)1307 MR->RT = &DstRT;1308 if (DstMRs.empty())1309 DstMRs = std::move(SrcMRs);1310 else1311 DstMRs.insert_range(SrcMRs);1312 // Erase SrcRT entry in TrackerMRs. Use &SrcRT key rather than iterator I1313 // for this, since I may have been invalidated by 'TrackerMRs[&DstRT]'.1314 TrackerMRs.erase(&SrcRT);1315 }1316 }1317 1318 // If we're transfering to the default tracker we just need to delete the1319 // tracked symbols for the source tracker.1320 if (&DstRT == DefaultTracker.get()) {1321 TrackerSymbols.erase(&SrcRT);1322 return;1323 }1324 1325 // If we're transferring from the default tracker we need to find all1326 // currently untracked symbols.1327 if (&SrcRT == DefaultTracker.get()) {1328 assert(!TrackerSymbols.count(&SrcRT) &&1329 "Default tracker should not appear in TrackerSymbols");1330 1331 SymbolNameVector SymbolsToTrack;1332 1333 SymbolNameSet CurrentlyTrackedSymbols;1334 for (auto &KV : TrackerSymbols)1335 CurrentlyTrackedSymbols.insert_range(KV.second);1336 1337 for (auto &KV : Symbols) {1338 auto &Sym = KV.first;1339 if (!CurrentlyTrackedSymbols.count(Sym))1340 SymbolsToTrack.push_back(Sym);1341 }1342 1343 TrackerSymbols[&DstRT] = std::move(SymbolsToTrack);1344 return;1345 }1346 1347 auto &DstTrackedSymbols = TrackerSymbols[&DstRT];1348 1349 // Finally if neither SrtRT or DstRT are the default tracker then1350 // just append DstRT's tracked symbols to SrtRT's.1351 auto SI = TrackerSymbols.find(&SrcRT);1352 if (SI == TrackerSymbols.end())1353 return;1354 1355 DstTrackedSymbols.reserve(DstTrackedSymbols.size() + SI->second.size());1356 for (auto &Sym : SI->second)1357 DstTrackedSymbols.push_back(std::move(Sym));1358 TrackerSymbols.erase(SI);1359}1360 1361Error JITDylib::defineImpl(MaterializationUnit &MU) {1362 LLVM_DEBUG({ dbgs() << " " << MU.getSymbols() << "\n"; });1363 1364 SymbolNameSet Duplicates;1365 std::vector<SymbolStringPtr> ExistingDefsOverridden;1366 std::vector<SymbolStringPtr> MUDefsOverridden;1367 1368 for (const auto &KV : MU.getSymbols()) {1369 auto I = Symbols.find(KV.first);1370 1371 if (I != Symbols.end()) {1372 if (KV.second.isStrong()) {1373 if (I->second.getFlags().isStrong() ||1374 I->second.getState() > SymbolState::NeverSearched)1375 Duplicates.insert(KV.first);1376 else {1377 assert(I->second.getState() == SymbolState::NeverSearched &&1378 "Overridden existing def should be in the never-searched "1379 "state");1380 ExistingDefsOverridden.push_back(KV.first);1381 }1382 } else1383 MUDefsOverridden.push_back(KV.first);1384 }1385 }1386 1387 // If there were any duplicate definitions then bail out.1388 if (!Duplicates.empty()) {1389 LLVM_DEBUG(1390 { dbgs() << " Error: Duplicate symbols " << Duplicates << "\n"; });1391 return make_error<DuplicateDefinition>(std::string(**Duplicates.begin()),1392 MU.getName().str());1393 }1394 1395 // Discard any overridden defs in this MU.1396 LLVM_DEBUG({1397 if (!MUDefsOverridden.empty())1398 dbgs() << " Defs in this MU overridden: " << MUDefsOverridden << "\n";1399 });1400 for (auto &S : MUDefsOverridden)1401 MU.doDiscard(*this, S);1402 1403 // Discard existing overridden defs.1404 LLVM_DEBUG({1405 if (!ExistingDefsOverridden.empty())1406 dbgs() << " Existing defs overridden by this MU: " << MUDefsOverridden1407 << "\n";1408 });1409 for (auto &S : ExistingDefsOverridden) {1410 1411 auto UMII = UnmaterializedInfos.find(S);1412 assert(UMII != UnmaterializedInfos.end() &&1413 "Overridden existing def should have an UnmaterializedInfo");1414 UMII->second->MU->doDiscard(*this, S);1415 }1416 1417 // Finally, add the defs from this MU.1418 for (auto &KV : MU.getSymbols()) {1419 auto &SymEntry = Symbols[KV.first];1420 SymEntry.setFlags(KV.second);1421 SymEntry.setState(SymbolState::NeverSearched);1422 SymEntry.setMaterializerAttached(true);1423 }1424 1425 return Error::success();1426}1427 1428void JITDylib::installMaterializationUnit(1429 std::unique_ptr<MaterializationUnit> MU, ResourceTracker &RT) {1430 1431 /// defineImpl succeeded.1432 if (&RT != DefaultTracker.get()) {1433 auto &TS = TrackerSymbols[&RT];1434 TS.reserve(TS.size() + MU->getSymbols().size());1435 for (auto &KV : MU->getSymbols())1436 TS.push_back(KV.first);1437 }1438 1439 auto UMI = std::make_shared<UnmaterializedInfo>(std::move(MU), &RT);1440 for (auto &KV : UMI->MU->getSymbols())1441 UnmaterializedInfos[KV.first] = UMI;1442}1443 1444void JITDylib::detachQueryHelper(AsynchronousSymbolQuery &Q,1445 const SymbolNameSet &QuerySymbols) {1446 for (auto &QuerySymbol : QuerySymbols) {1447 auto MII = MaterializingInfos.find(QuerySymbol);1448 if (MII != MaterializingInfos.end())1449 MII->second.removeQuery(Q);1450 }1451}1452 1453Platform::~Platform() = default;1454 1455Expected<DenseMap<JITDylib *, SymbolMap>> Platform::lookupInitSymbols(1456 ExecutionSession &ES,1457 const DenseMap<JITDylib *, SymbolLookupSet> &InitSyms) {1458 1459 DenseMap<JITDylib *, SymbolMap> CompoundResult;1460 Error CompoundErr = Error::success();1461 std::mutex LookupMutex;1462 std::condition_variable CV;1463 uint64_t Count = InitSyms.size();1464 1465 LLVM_DEBUG({1466 dbgs() << "Issuing init-symbol lookup:\n";1467 for (auto &KV : InitSyms)1468 dbgs() << " " << KV.first->getName() << ": " << KV.second << "\n";1469 });1470 1471 for (auto &KV : InitSyms) {1472 auto *JD = KV.first;1473 auto Names = std::move(KV.second);1474 ES.lookup(1475 LookupKind::Static,1476 JITDylibSearchOrder({{JD, JITDylibLookupFlags::MatchAllSymbols}}),1477 std::move(Names), SymbolState::Ready,1478 [&, JD](Expected<SymbolMap> Result) {1479 {1480 std::lock_guard<std::mutex> Lock(LookupMutex);1481 --Count;1482 if (Result) {1483 assert(!CompoundResult.count(JD) &&1484 "Duplicate JITDylib in lookup?");1485 CompoundResult[JD] = std::move(*Result);1486 } else1487 CompoundErr =1488 joinErrors(std::move(CompoundErr), Result.takeError());1489 }1490 CV.notify_one();1491 },1492 NoDependenciesToRegister);1493 }1494 1495 std::unique_lock<std::mutex> Lock(LookupMutex);1496 CV.wait(Lock, [&] { return Count == 0; });1497 1498 if (CompoundErr)1499 return std::move(CompoundErr);1500 1501 return std::move(CompoundResult);1502}1503 1504void Platform::lookupInitSymbolsAsync(1505 unique_function<void(Error)> OnComplete, ExecutionSession &ES,1506 const DenseMap<JITDylib *, SymbolLookupSet> &InitSyms) {1507 1508 class TriggerOnComplete {1509 public:1510 using OnCompleteFn = unique_function<void(Error)>;1511 TriggerOnComplete(OnCompleteFn OnComplete)1512 : OnComplete(std::move(OnComplete)) {}1513 ~TriggerOnComplete() { OnComplete(std::move(LookupResult)); }1514 void reportResult(Error Err) {1515 std::lock_guard<std::mutex> Lock(ResultMutex);1516 LookupResult = joinErrors(std::move(LookupResult), std::move(Err));1517 }1518 1519 private:1520 std::mutex ResultMutex;1521 Error LookupResult{Error::success()};1522 OnCompleteFn OnComplete;1523 };1524 1525 LLVM_DEBUG({1526 dbgs() << "Issuing init-symbol lookup:\n";1527 for (auto &KV : InitSyms)1528 dbgs() << " " << KV.first->getName() << ": " << KV.second << "\n";1529 });1530 1531 auto TOC = std::make_shared<TriggerOnComplete>(std::move(OnComplete));1532 1533 for (auto &KV : InitSyms) {1534 auto *JD = KV.first;1535 auto Names = std::move(KV.second);1536 ES.lookup(1537 LookupKind::Static,1538 JITDylibSearchOrder({{JD, JITDylibLookupFlags::MatchAllSymbols}}),1539 std::move(Names), SymbolState::Ready,1540 [TOC](Expected<SymbolMap> Result) {1541 TOC->reportResult(Result.takeError());1542 },1543 NoDependenciesToRegister);1544 }1545}1546 1547MaterializationTask::~MaterializationTask() {1548 // If this task wasn't run then fail materialization.1549 if (MR)1550 MR->failMaterialization();1551}1552 1553void MaterializationTask::printDescription(raw_ostream &OS) {1554 OS << "Materialization task: " << MU->getName() << " in "1555 << MR->getTargetJITDylib().getName();1556}1557 1558void MaterializationTask::run() {1559 assert(MU && "MU should not be null");1560 assert(MR && "MR should not be null");1561 MU->materialize(std::move(MR));1562}1563 1564void LookupTask::printDescription(raw_ostream &OS) { OS << "Lookup task"; }1565 1566void LookupTask::run() { LS.continueLookup(Error::success()); }1567 1568ExecutionSession::ExecutionSession(std::unique_ptr<ExecutorProcessControl> EPC)1569 : EPC(std::move(EPC)) {1570 // Associated EPC and this.1571 this->EPC->ES = this;1572}1573 1574ExecutionSession::~ExecutionSession() {1575 // You must call endSession prior to destroying the session.1576 assert(!SessionOpen &&1577 "Session still open. Did you forget to call endSession?");1578}1579 1580Error ExecutionSession::endSession() {1581 LLVM_DEBUG(dbgs() << "Ending ExecutionSession " << this << "\n");1582 1583 auto JDsToRemove = runSessionLocked([&] {1584 1585#ifdef EXPENSIVE_CHECKS1586 verifySessionState("Entering ExecutionSession::endSession");1587#endif1588 1589 SessionOpen = false;1590 return JDs;1591 });1592 1593 std::reverse(JDsToRemove.begin(), JDsToRemove.end());1594 1595 auto Err = removeJITDylibs(std::move(JDsToRemove));1596 1597 Err = joinErrors(std::move(Err), EPC->disconnect());1598 1599 return Err;1600}1601 1602void ExecutionSession::registerResourceManager(ResourceManager &RM) {1603 runSessionLocked([&] { ResourceManagers.push_back(&RM); });1604}1605 1606void ExecutionSession::deregisterResourceManager(ResourceManager &RM) {1607 runSessionLocked([&] {1608 assert(!ResourceManagers.empty() && "No managers registered");1609 if (ResourceManagers.back() == &RM)1610 ResourceManagers.pop_back();1611 else {1612 auto I = llvm::find(ResourceManagers, &RM);1613 assert(I != ResourceManagers.end() && "RM not registered");1614 ResourceManagers.erase(I);1615 }1616 });1617}1618 1619JITDylib *ExecutionSession::getJITDylibByName(StringRef Name) {1620 return runSessionLocked([&, this]() -> JITDylib * {1621 for (auto &JD : JDs)1622 if (JD->getName() == Name)1623 return JD.get();1624 return nullptr;1625 });1626}1627 1628JITDylib &ExecutionSession::createBareJITDylib(std::string Name) {1629 assert(!getJITDylibByName(Name) && "JITDylib with that name already exists");1630 return runSessionLocked([&, this]() -> JITDylib & {1631 assert(SessionOpen && "Cannot create JITDylib after session is closed");1632 JDs.push_back(new JITDylib(*this, std::move(Name)));1633 return *JDs.back();1634 });1635}1636 1637Expected<JITDylib &> ExecutionSession::createJITDylib(std::string Name) {1638 auto &JD = createBareJITDylib(Name);1639 if (P)1640 if (auto Err = P->setupJITDylib(JD))1641 return std::move(Err);1642 return JD;1643}1644 1645Error ExecutionSession::removeJITDylibs(std::vector<JITDylibSP> JDsToRemove) {1646 // Set JD to 'Closing' state and remove JD from the ExecutionSession.1647 runSessionLocked([&] {1648 for (auto &JD : JDsToRemove) {1649 assert(JD->State == JITDylib::Open && "JD already closed");1650 JD->State = JITDylib::Closing;1651 auto I = llvm::find(JDs, JD);1652 assert(I != JDs.end() && "JD does not appear in session JDs");1653 JDs.erase(I);1654 }1655 });1656 1657 // Clear JITDylibs and notify the platform.1658 Error Err = Error::success();1659 for (auto JD : JDsToRemove) {1660 Err = joinErrors(std::move(Err), JD->clear());1661 if (P)1662 Err = joinErrors(std::move(Err), P->teardownJITDylib(*JD));1663 }1664 1665 // Set JD to closed state. Clear remaining data structures.1666 runSessionLocked([&] {1667 for (auto &JD : JDsToRemove) {1668 assert(JD->State == JITDylib::Closing && "JD should be closing");1669 JD->State = JITDylib::Closed;1670 assert(JD->Symbols.empty() && "JD.Symbols is not empty after clear");1671 assert(JD->UnmaterializedInfos.empty() &&1672 "JD.UnmaterializedInfos is not empty after clear");1673 assert(JD->MaterializingInfos.empty() &&1674 "JD.MaterializingInfos is not empty after clear");1675 assert(JD->TrackerSymbols.empty() &&1676 "TrackerSymbols is not empty after clear");1677 JD->DefGenerators.clear();1678 JD->LinkOrder.clear();1679 }1680 });1681 1682 return Err;1683}1684 1685Expected<std::vector<JITDylibSP>>1686JITDylib::getDFSLinkOrder(ArrayRef<JITDylibSP> JDs) {1687 if (JDs.empty())1688 return std::vector<JITDylibSP>();1689 1690 auto &ES = JDs.front()->getExecutionSession();1691 return ES.runSessionLocked([&]() -> Expected<std::vector<JITDylibSP>> {1692 DenseSet<JITDylib *> Visited;1693 std::vector<JITDylibSP> Result;1694 1695 for (auto &JD : JDs) {1696 1697 if (JD->State != Open)1698 return make_error<StringError>(1699 "Error building link order: " + JD->getName() + " is defunct",1700 inconvertibleErrorCode());1701 if (Visited.count(JD.get()))1702 continue;1703 1704 SmallVector<JITDylibSP, 64> WorkStack;1705 WorkStack.push_back(JD);1706 Visited.insert(JD.get());1707 1708 while (!WorkStack.empty()) {1709 Result.push_back(std::move(WorkStack.back()));1710 WorkStack.pop_back();1711 1712 for (auto &KV : llvm::reverse(Result.back()->LinkOrder)) {1713 auto &JD = *KV.first;1714 if (!Visited.insert(&JD).second)1715 continue;1716 WorkStack.push_back(&JD);1717 }1718 }1719 }1720 return Result;1721 });1722}1723 1724Expected<std::vector<JITDylibSP>>1725JITDylib::getReverseDFSLinkOrder(ArrayRef<JITDylibSP> JDs) {1726 auto Result = getDFSLinkOrder(JDs);1727 if (Result)1728 std::reverse(Result->begin(), Result->end());1729 return Result;1730}1731 1732Expected<std::vector<JITDylibSP>> JITDylib::getDFSLinkOrder() {1733 return getDFSLinkOrder({this});1734}1735 1736Expected<std::vector<JITDylibSP>> JITDylib::getReverseDFSLinkOrder() {1737 return getReverseDFSLinkOrder({this});1738}1739 1740void ExecutionSession::lookupFlags(1741 LookupKind K, JITDylibSearchOrder SearchOrder, SymbolLookupSet LookupSet,1742 unique_function<void(Expected<SymbolFlagsMap>)> OnComplete) {1743 1744 OL_applyQueryPhase1(std::make_unique<InProgressLookupFlagsState>(1745 K, std::move(SearchOrder), std::move(LookupSet),1746 std::move(OnComplete)),1747 Error::success());1748}1749 1750Expected<SymbolFlagsMap>1751ExecutionSession::lookupFlags(LookupKind K, JITDylibSearchOrder SearchOrder,1752 SymbolLookupSet LookupSet) {1753 1754 std::promise<MSVCPExpected<SymbolFlagsMap>> ResultP;1755 OL_applyQueryPhase1(std::make_unique<InProgressLookupFlagsState>(1756 K, std::move(SearchOrder), std::move(LookupSet),1757 [&ResultP](Expected<SymbolFlagsMap> Result) {1758 ResultP.set_value(std::move(Result));1759 }),1760 Error::success());1761 1762 auto ResultF = ResultP.get_future();1763 return ResultF.get();1764}1765 1766void ExecutionSession::lookup(1767 LookupKind K, const JITDylibSearchOrder &SearchOrder,1768 SymbolLookupSet Symbols, SymbolState RequiredState,1769 SymbolsResolvedCallback NotifyComplete,1770 RegisterDependenciesFunction RegisterDependencies) {1771 1772 LLVM_DEBUG({1773 runSessionLocked([&]() {1774 dbgs() << "Looking up " << Symbols << " in " << SearchOrder1775 << " (required state: " << RequiredState << ")\n";1776 });1777 });1778 1779 // lookup can be re-entered recursively if running on a single thread. Run any1780 // outstanding MUs in case this query depends on them, otherwise this lookup1781 // will starve waiting for a result from an MU that is stuck in the queue.1782 dispatchOutstandingMUs();1783 1784 auto Unresolved = std::move(Symbols);1785 auto Q = std::make_shared<AsynchronousSymbolQuery>(Unresolved, RequiredState,1786 std::move(NotifyComplete));1787 1788 auto IPLS = std::make_unique<InProgressFullLookupState>(1789 K, SearchOrder, std::move(Unresolved), RequiredState, std::move(Q),1790 std::move(RegisterDependencies));1791 1792 OL_applyQueryPhase1(std::move(IPLS), Error::success());1793}1794 1795Expected<SymbolMap>1796ExecutionSession::lookup(const JITDylibSearchOrder &SearchOrder,1797 SymbolLookupSet Symbols, LookupKind K,1798 SymbolState RequiredState,1799 RegisterDependenciesFunction RegisterDependencies) {1800#if LLVM_ENABLE_THREADS1801 // In the threaded case we use promises to return the results.1802 std::promise<MSVCPExpected<SymbolMap>> PromisedResult;1803 1804 auto NotifyComplete = [&](Expected<SymbolMap> R) {1805 PromisedResult.set_value(std::move(R));1806 };1807 1808#else1809 SymbolMap Result;1810 Error ResolutionError = Error::success();1811 1812 auto NotifyComplete = [&](Expected<SymbolMap> R) {1813 ErrorAsOutParameter _(ResolutionError);1814 if (R)1815 Result = std::move(*R);1816 else1817 ResolutionError = R.takeError();1818 };1819#endif1820 1821 // Perform the asynchronous lookup.1822 lookup(K, SearchOrder, std::move(Symbols), RequiredState,1823 std::move(NotifyComplete), RegisterDependencies);1824 1825#if LLVM_ENABLE_THREADS1826 return PromisedResult.get_future().get();1827#else1828 if (ResolutionError)1829 return std::move(ResolutionError);1830 1831 return Result;1832#endif1833}1834 1835Expected<ExecutorSymbolDef>1836ExecutionSession::lookup(const JITDylibSearchOrder &SearchOrder,1837 SymbolStringPtr Name, SymbolState RequiredState) {1838 SymbolLookupSet Names({Name});1839 1840 if (auto ResultMap = lookup(SearchOrder, std::move(Names), LookupKind::Static,1841 RequiredState, NoDependenciesToRegister)) {1842 assert(ResultMap->size() == 1 && "Unexpected number of results");1843 assert(ResultMap->count(Name) && "Missing result for symbol");1844 return std::move(ResultMap->begin()->second);1845 } else1846 return ResultMap.takeError();1847}1848 1849Expected<ExecutorSymbolDef>1850ExecutionSession::lookup(ArrayRef<JITDylib *> SearchOrder, SymbolStringPtr Name,1851 SymbolState RequiredState) {1852 return lookup(makeJITDylibSearchOrder(SearchOrder), Name, RequiredState);1853}1854 1855Expected<ExecutorSymbolDef>1856ExecutionSession::lookup(ArrayRef<JITDylib *> SearchOrder, StringRef Name,1857 SymbolState RequiredState) {1858 return lookup(SearchOrder, intern(Name), RequiredState);1859}1860 1861Error ExecutionSession::registerJITDispatchHandlers(1862 JITDylib &JD, JITDispatchHandlerAssociationMap WFs) {1863 1864 auto TagSyms = lookup({{&JD, JITDylibLookupFlags::MatchAllSymbols}},1865 SymbolLookupSet::fromMapKeys(1866 WFs, SymbolLookupFlags::WeaklyReferencedSymbol));1867 if (!TagSyms)1868 return TagSyms.takeError();1869 1870 // Associate tag addresses with implementations.1871 std::lock_guard<std::mutex> Lock(JITDispatchHandlersMutex);1872 1873 // Check that no tags are being overwritten.1874 for (auto &[TagName, TagSym] : *TagSyms) {1875 auto TagAddr = TagSym.getAddress();1876 if (JITDispatchHandlers.count(TagAddr))1877 return make_error<StringError>("Tag " + formatv("{0:x}", TagAddr) +1878 " (for " + *TagName +1879 ") already registered",1880 inconvertibleErrorCode());1881 }1882 1883 // At this point we're guaranteed to succeed. Install the handlers.1884 for (auto &[TagName, TagSym] : *TagSyms) {1885 auto TagAddr = TagSym.getAddress();1886 auto I = WFs.find(TagName);1887 assert(I != WFs.end() && I->second &&1888 "JITDispatchHandler implementation missing");1889 JITDispatchHandlers[TagAddr] =1890 std::make_shared<JITDispatchHandlerFunction>(std::move(I->second));1891 LLVM_DEBUG({1892 dbgs() << "Associated function tag \"" << *TagName << "\" ("1893 << formatv("{0:x}", TagAddr) << ") with handler\n";1894 });1895 }1896 1897 return Error::success();1898}1899 1900void ExecutionSession::runJITDispatchHandler(SendResultFunction SendResult,1901 ExecutorAddr HandlerFnTagAddr,1902 ArrayRef<char> ArgBuffer) {1903 1904 std::shared_ptr<JITDispatchHandlerFunction> F;1905 {1906 std::lock_guard<std::mutex> Lock(JITDispatchHandlersMutex);1907 auto I = JITDispatchHandlers.find(HandlerFnTagAddr);1908 if (I != JITDispatchHandlers.end())1909 F = I->second;1910 }1911 1912 if (F)1913 (*F)(std::move(SendResult), ArgBuffer.data(), ArgBuffer.size());1914 else1915 SendResult(shared::WrapperFunctionResult::createOutOfBandError(1916 ("No function registered for tag " +1917 formatv("{0:x16}", HandlerFnTagAddr))1918 .str()));1919}1920 1921void ExecutionSession::dump(raw_ostream &OS) {1922 runSessionLocked([this, &OS]() {1923 for (auto &JD : JDs)1924 JD->dump(OS);1925 });1926}1927 1928#ifdef EXPENSIVE_CHECKS1929bool ExecutionSession::verifySessionState(Twine Phase) {1930 return runSessionLocked([&]() {1931 bool AllOk = true;1932 1933 for (auto &JD : JDs) {1934 1935 auto LogFailure = [&]() -> raw_fd_ostream & {1936 auto &Stream = errs();1937 if (AllOk)1938 Stream << "ERROR: Bad ExecutionSession state detected " << Phase1939 << "\n";1940 Stream << " In JITDylib " << JD->getName() << ", ";1941 AllOk = false;1942 return Stream;1943 };1944 1945 if (JD->State != JITDylib::Open) {1946 LogFailure()1947 << "state is not Open, but JD is in ExecutionSession list.";1948 }1949 1950 // Check symbol table.1951 // 1. If the entry state isn't resolved then check that no address has1952 // been set.1953 // 2. Check that if the hasMaterializerAttached flag is set then there is1954 // an UnmaterializedInfo entry, and vice-versa.1955 for (auto &[Sym, Entry] : JD->Symbols) {1956 // Check that unresolved symbols have null addresses.1957 if (Entry.getState() < SymbolState::Resolved) {1958 if (Entry.getAddress()) {1959 LogFailure() << "symbol " << Sym << " has state "1960 << Entry.getState()1961 << " (not-yet-resolved) but non-null address "1962 << Entry.getAddress() << ".\n";1963 }1964 }1965 1966 // Check that the hasMaterializerAttached flag is correct.1967 auto UMIItr = JD->UnmaterializedInfos.find(Sym);1968 if (Entry.hasMaterializerAttached()) {1969 if (UMIItr == JD->UnmaterializedInfos.end()) {1970 LogFailure() << "symbol " << Sym1971 << " entry claims materializer attached, but "1972 "UnmaterializedInfos has no corresponding entry.\n";1973 }1974 } else if (UMIItr != JD->UnmaterializedInfos.end()) {1975 LogFailure()1976 << "symbol " << Sym1977 << " entry claims no materializer attached, but "1978 "UnmaterializedInfos has an unexpected entry for it.\n";1979 }1980 }1981 1982 // Check that every UnmaterializedInfo entry has a corresponding entry1983 // in the Symbols table.1984 for (auto &[Sym, UMI] : JD->UnmaterializedInfos) {1985 auto SymItr = JD->Symbols.find(Sym);1986 if (SymItr == JD->Symbols.end()) {1987 LogFailure()1988 << "symbol " << Sym1989 << " has UnmaterializedInfos entry, but no Symbols entry.\n";1990 }1991 }1992 1993 // Check consistency of the MaterializingInfos table.1994 for (auto &[Sym, MII] : JD->MaterializingInfos) {1995 1996 auto SymItr = JD->Symbols.find(Sym);1997 if (SymItr == JD->Symbols.end()) {1998 // If there's no Symbols entry for this MaterializingInfos entry then1999 // report that.2000 LogFailure()2001 << "symbol " << Sym2002 << " has MaterializingInfos entry, but no Symbols entry.\n";2003 } else {2004 // Otherwise check consistency between Symbols and MaterializingInfos.2005 2006 // Ready symbols should not have MaterializingInfos.2007 if (SymItr->second.getState() == SymbolState::Ready) {2008 LogFailure()2009 << "symbol " << Sym2010 << " is in Ready state, should not have MaterializingInfo.\n";2011 }2012 2013 // Pending queries should be for subsequent states.2014 auto CurState = static_cast<SymbolState>(2015 static_cast<std::underlying_type_t<SymbolState>>(2016 SymItr->second.getState()) + 1);2017 for (auto &Q : MII.PendingQueries) {2018 if (Q->getRequiredState() != CurState) {2019 if (Q->getRequiredState() > CurState)2020 CurState = Q->getRequiredState();2021 else2022 LogFailure() << "symbol " << Sym2023 << " has stale or misordered queries.\n";2024 }2025 }2026 }2027 }2028 }2029 2030 return AllOk;2031 });2032}2033#endif // EXPENSIVE_CHECKS2034 2035void ExecutionSession::dispatchOutstandingMUs() {2036 LLVM_DEBUG(dbgs() << "Dispatching MaterializationUnits...\n");2037 while (true) {2038 std::optional<std::pair<std::unique_ptr<MaterializationUnit>,2039 std::unique_ptr<MaterializationResponsibility>>>2040 JMU;2041 2042 {2043 std::lock_guard<std::recursive_mutex> Lock(OutstandingMUsMutex);2044 if (!OutstandingMUs.empty()) {2045 JMU.emplace(std::move(OutstandingMUs.back()));2046 OutstandingMUs.pop_back();2047 }2048 }2049 2050 if (!JMU)2051 break;2052 2053 assert(JMU->first && "No MU?");2054 LLVM_DEBUG(dbgs() << " Dispatching \"" << JMU->first->getName() << "\"\n");2055 dispatchTask(std::make_unique<MaterializationTask>(std::move(JMU->first),2056 std::move(JMU->second)));2057 }2058 LLVM_DEBUG(dbgs() << "Done dispatching MaterializationUnits.\n");2059}2060 2061Error ExecutionSession::removeResourceTracker(ResourceTracker &RT) {2062 LLVM_DEBUG({2063 dbgs() << "In " << RT.getJITDylib().getName() << " removing tracker "2064 << formatv("{0:x}", RT.getKeyUnsafe()) << "\n";2065 });2066 std::vector<ResourceManager *> CurrentResourceManagers;2067 2068 JITDylib::RemoveTrackerResult R;2069 2070 runSessionLocked([&] {2071 CurrentResourceManagers = ResourceManagers;2072 RT.makeDefunct();2073 R = RT.getJITDylib().IL_removeTracker(RT);2074 });2075 2076 // Release any defunct MaterializationUnits.2077 R.DefunctMUs.clear();2078 2079 Error Err = Error::success();2080 2081 auto &JD = RT.getJITDylib();2082 for (auto *L : reverse(CurrentResourceManagers))2083 Err = joinErrors(std::move(Err),2084 L->handleRemoveResources(JD, RT.getKeyUnsafe()));2085 2086 for (auto &Q : R.QueriesToFail)2087 Q->handleFailed(make_error<FailedToMaterialize>(getSymbolStringPool(),2088 R.FailedSymbols));2089 2090 return Err;2091}2092 2093void ExecutionSession::transferResourceTracker(ResourceTracker &DstRT,2094 ResourceTracker &SrcRT) {2095 LLVM_DEBUG({2096 dbgs() << "In " << SrcRT.getJITDylib().getName()2097 << " transfering resources from tracker "2098 << formatv("{0:x}", SrcRT.getKeyUnsafe()) << " to tracker "2099 << formatv("{0:x}", DstRT.getKeyUnsafe()) << "\n";2100 });2101 2102 // No-op transfers are allowed and do not invalidate the source.2103 if (&DstRT == &SrcRT)2104 return;2105 2106 assert(&DstRT.getJITDylib() == &SrcRT.getJITDylib() &&2107 "Can't transfer resources between JITDylibs");2108 runSessionLocked([&]() {2109 SrcRT.makeDefunct();2110 auto &JD = DstRT.getJITDylib();2111 JD.transferTracker(DstRT, SrcRT);2112 for (auto *L : reverse(ResourceManagers))2113 L->handleTransferResources(JD, DstRT.getKeyUnsafe(),2114 SrcRT.getKeyUnsafe());2115 });2116}2117 2118void ExecutionSession::destroyResourceTracker(ResourceTracker &RT) {2119 runSessionLocked([&]() {2120 LLVM_DEBUG({2121 dbgs() << "In " << RT.getJITDylib().getName() << " destroying tracker "2122 << formatv("{0:x}", RT.getKeyUnsafe()) << "\n";2123 });2124 if (!RT.isDefunct())2125 transferResourceTracker(*RT.getJITDylib().getDefaultResourceTracker(),2126 RT);2127 });2128}2129 2130Error ExecutionSession::IL_updateCandidatesFor(2131 JITDylib &JD, JITDylibLookupFlags JDLookupFlags,2132 SymbolLookupSet &Candidates, SymbolLookupSet *NonCandidates) {2133 return Candidates.forEachWithRemoval(2134 [&](const SymbolStringPtr &Name,2135 SymbolLookupFlags SymLookupFlags) -> Expected<bool> {2136 /// Search for the symbol. If not found then continue without2137 /// removal.2138 auto SymI = JD.Symbols.find(Name);2139 if (SymI == JD.Symbols.end())2140 return false;2141 2142 // If this is a non-exported symbol and we're matching exported2143 // symbols only then remove this symbol from the candidates list.2144 //2145 // If we're tracking non-candidates then add this to the non-candidate2146 // list.2147 if (!SymI->second.getFlags().isExported() &&2148 JDLookupFlags == JITDylibLookupFlags::MatchExportedSymbolsOnly) {2149 if (NonCandidates)2150 NonCandidates->add(Name, SymLookupFlags);2151 return true;2152 }2153 2154 // If we match against a materialization-side-effects only symbol2155 // then make sure it is weakly-referenced. Otherwise bail out with2156 // an error.2157 // FIXME: Use a "materialization-side-effects-only symbols must be2158 // weakly referenced" specific error here to reduce confusion.2159 if (SymI->second.getFlags().hasMaterializationSideEffectsOnly() &&2160 SymLookupFlags != SymbolLookupFlags::WeaklyReferencedSymbol)2161 return make_error<SymbolsNotFound>(getSymbolStringPool(),2162 SymbolNameVector({Name}));2163 2164 // If we matched against this symbol but it is in the error state2165 // then bail out and treat it as a failure to materialize.2166 if (SymI->second.getFlags().hasError()) {2167 auto FailedSymbolsMap = std::make_shared<SymbolDependenceMap>();2168 (*FailedSymbolsMap)[&JD] = {Name};2169 return make_error<FailedToMaterialize>(getSymbolStringPool(),2170 std::move(FailedSymbolsMap));2171 }2172 2173 // Otherwise this is a match. Remove it from the candidate set.2174 return true;2175 });2176}2177 2178void ExecutionSession::OL_resumeLookupAfterGeneration(2179 InProgressLookupState &IPLS) {2180 2181 assert(IPLS.GenState != InProgressLookupState::NotInGenerator &&2182 "Should not be called for not-in-generator lookups");2183 IPLS.GenState = InProgressLookupState::NotInGenerator;2184 2185 LookupState LS;2186 2187 if (auto DG = IPLS.CurDefGeneratorStack.back().lock()) {2188 IPLS.CurDefGeneratorStack.pop_back();2189 std::lock_guard<std::mutex> Lock(DG->M);2190 2191 // If there are no pending lookups then mark the generator as free and2192 // return.2193 if (DG->PendingLookups.empty()) {2194 DG->InUse = false;2195 return;2196 }2197 2198 // Otherwise resume the next lookup.2199 LS = std::move(DG->PendingLookups.front());2200 DG->PendingLookups.pop_front();2201 }2202 2203 if (LS.IPLS) {2204 LS.IPLS->GenState = InProgressLookupState::ResumedForGenerator;2205 dispatchTask(std::make_unique<LookupTask>(std::move(LS)));2206 }2207}2208 2209void ExecutionSession::OL_applyQueryPhase1(2210 std::unique_ptr<InProgressLookupState> IPLS, Error Err) {2211 2212 LLVM_DEBUG({2213 dbgs() << "Entering OL_applyQueryPhase1:\n"2214 << " Lookup kind: " << IPLS->K << "\n"2215 << " Search order: " << IPLS->SearchOrder2216 << ", Current index = " << IPLS->CurSearchOrderIndex2217 << (IPLS->NewJITDylib ? " (entering new JITDylib)" : "") << "\n"2218 << " Lookup set: " << IPLS->LookupSet << "\n"2219 << " Definition generator candidates: "2220 << IPLS->DefGeneratorCandidates << "\n"2221 << " Definition generator non-candidates: "2222 << IPLS->DefGeneratorNonCandidates << "\n";2223 });2224 2225 if (IPLS->GenState == InProgressLookupState::InGenerator)2226 OL_resumeLookupAfterGeneration(*IPLS);2227 2228 assert(IPLS->GenState != InProgressLookupState::InGenerator &&2229 "Lookup should not be in InGenerator state here");2230 2231 // FIXME: We should attach the query as we go: This provides a result in a2232 // single pass in the common case where all symbols have already reached the2233 // required state. The query could be detached again in the 'fail' method on2234 // IPLS. Phase 2 would be reduced to collecting and dispatching the MUs.2235 2236 while (IPLS->CurSearchOrderIndex != IPLS->SearchOrder.size()) {2237 2238 // If we've been handed an error or received one back from a generator then2239 // fail the query. We don't need to unlink: At this stage the query hasn't2240 // actually been lodged.2241 if (Err)2242 return IPLS->fail(std::move(Err));2243 2244 // Get the next JITDylib and lookup flags.2245 auto &KV = IPLS->SearchOrder[IPLS->CurSearchOrderIndex];2246 auto &JD = *KV.first;2247 auto JDLookupFlags = KV.second;2248 2249 LLVM_DEBUG({2250 dbgs() << "Visiting \"" << JD.getName() << "\" (" << JDLookupFlags2251 << ") with lookup set " << IPLS->LookupSet << ":\n";2252 });2253 2254 // If we've just reached a new JITDylib then perform some setup.2255 if (IPLS->NewJITDylib) {2256 // Add any non-candidates from the last JITDylib (if any) back on to the2257 // list of definition candidates for this JITDylib, reset definition2258 // non-candidates to the empty set.2259 SymbolLookupSet Tmp;2260 std::swap(IPLS->DefGeneratorNonCandidates, Tmp);2261 IPLS->DefGeneratorCandidates.append(std::move(Tmp));2262 2263 LLVM_DEBUG({2264 dbgs() << " First time visiting " << JD.getName()2265 << ", resetting candidate sets and building generator stack\n";2266 });2267 2268 // Build the definition generator stack for this JITDylib.2269 runSessionLocked([&] {2270 IPLS->CurDefGeneratorStack.reserve(JD.DefGenerators.size());2271 llvm::append_range(IPLS->CurDefGeneratorStack,2272 reverse(JD.DefGenerators));2273 });2274 2275 // Flag that we've done our initialization.2276 IPLS->NewJITDylib = false;2277 }2278 2279 // Remove any generation candidates that are already defined (and match) in2280 // this JITDylib.2281 runSessionLocked([&] {2282 // Update the list of candidates (and non-candidates) for definition2283 // generation.2284 LLVM_DEBUG(dbgs() << " Updating candidate set...\n");2285 Err = IL_updateCandidatesFor(2286 JD, JDLookupFlags, IPLS->DefGeneratorCandidates,2287 JD.DefGenerators.empty() ? nullptr2288 : &IPLS->DefGeneratorNonCandidates);2289 LLVM_DEBUG({2290 dbgs() << " Remaining candidates = " << IPLS->DefGeneratorCandidates2291 << "\n";2292 });2293 2294 // If this lookup was resumed after auto-suspension but all candidates2295 // have already been generated (by some previous call to the generator)2296 // treat the lookup as if it had completed generation.2297 if (IPLS->GenState == InProgressLookupState::ResumedForGenerator &&2298 IPLS->DefGeneratorCandidates.empty())2299 OL_resumeLookupAfterGeneration(*IPLS);2300 });2301 2302 // If we encountered an error while filtering generation candidates then2303 // bail out.2304 if (Err)2305 return IPLS->fail(std::move(Err));2306 2307 /// Apply any definition generators on the stack.2308 LLVM_DEBUG({2309 if (IPLS->CurDefGeneratorStack.empty())2310 LLVM_DEBUG(dbgs() << " No generators to run for this JITDylib.\n");2311 else if (IPLS->DefGeneratorCandidates.empty())2312 LLVM_DEBUG(dbgs() << " No candidates to generate.\n");2313 else2314 dbgs() << " Running " << IPLS->CurDefGeneratorStack.size()2315 << " remaining generators for "2316 << IPLS->DefGeneratorCandidates.size() << " candidates\n";2317 });2318 while (!IPLS->CurDefGeneratorStack.empty() &&2319 !IPLS->DefGeneratorCandidates.empty()) {2320 auto DG = IPLS->CurDefGeneratorStack.back().lock();2321 2322 if (!DG)2323 return IPLS->fail(make_error<StringError>(2324 "DefinitionGenerator removed while lookup in progress",2325 inconvertibleErrorCode()));2326 2327 // At this point the lookup is in either the NotInGenerator state, or in2328 // the ResumedForGenerator state.2329 // If this lookup is in the NotInGenerator state then check whether the2330 // generator is in use. If the generator is not in use then move the2331 // lookup to the InGenerator state and continue. If the generator is2332 // already in use then just add this lookup to the pending lookups list2333 // and bail out.2334 // If this lookup is in the ResumedForGenerator state then just move it2335 // to InGenerator and continue.2336 if (IPLS->GenState == InProgressLookupState::NotInGenerator) {2337 std::lock_guard<std::mutex> Lock(DG->M);2338 if (DG->InUse) {2339 DG->PendingLookups.push_back(std::move(IPLS));2340 return;2341 }2342 DG->InUse = true;2343 }2344 2345 IPLS->GenState = InProgressLookupState::InGenerator;2346 2347 auto K = IPLS->K;2348 auto &LookupSet = IPLS->DefGeneratorCandidates;2349 2350 // Run the generator. If the generator takes ownership of QA then this2351 // will break the loop.2352 {2353 LLVM_DEBUG(dbgs() << " Attempting to generate " << LookupSet << "\n");2354 LookupState LS(std::move(IPLS));2355 Err = DG->tryToGenerate(LS, K, JD, JDLookupFlags, LookupSet);2356 IPLS = std::move(LS.IPLS);2357 }2358 2359 // If the lookup returned then pop the generator stack and unblock the2360 // next lookup on this generator (if any).2361 if (IPLS)2362 OL_resumeLookupAfterGeneration(*IPLS);2363 2364 // If there was an error then fail the query.2365 if (Err) {2366 LLVM_DEBUG({2367 dbgs() << " Error attempting to generate " << LookupSet << "\n";2368 });2369 assert(IPLS && "LS cannot be retained if error is returned");2370 return IPLS->fail(std::move(Err));2371 }2372 2373 // Otherwise if QA was captured then break the loop.2374 if (!IPLS) {2375 LLVM_DEBUG(2376 { dbgs() << " LookupState captured. Exiting phase1 for now.\n"; });2377 return;2378 }2379 2380 // Otherwise if we're continuing around the loop then update candidates2381 // for the next round.2382 runSessionLocked([&] {2383 LLVM_DEBUG(dbgs() << " Updating candidate set post-generation\n");2384 Err = IL_updateCandidatesFor(2385 JD, JDLookupFlags, IPLS->DefGeneratorCandidates,2386 JD.DefGenerators.empty() ? nullptr2387 : &IPLS->DefGeneratorNonCandidates);2388 });2389 2390 // If updating candidates failed then fail the query.2391 if (Err) {2392 LLVM_DEBUG(dbgs() << " Error encountered while updating candidates\n");2393 return IPLS->fail(std::move(Err));2394 }2395 }2396 2397 if (IPLS->DefGeneratorCandidates.empty() &&2398 IPLS->DefGeneratorNonCandidates.empty()) {2399 // Early out if there are no remaining symbols.2400 LLVM_DEBUG(dbgs() << "All symbols matched.\n");2401 IPLS->CurSearchOrderIndex = IPLS->SearchOrder.size();2402 break;2403 } else {2404 // If we get here then we've moved on to the next JITDylib with candidates2405 // remaining.2406 LLVM_DEBUG(dbgs() << "Phase 1 moving to next JITDylib.\n");2407 ++IPLS->CurSearchOrderIndex;2408 IPLS->NewJITDylib = true;2409 }2410 }2411 2412 // Remove any weakly referenced candidates that could not be found/generated.2413 IPLS->DefGeneratorCandidates.remove_if(2414 [](const SymbolStringPtr &Name, SymbolLookupFlags SymLookupFlags) {2415 return SymLookupFlags == SymbolLookupFlags::WeaklyReferencedSymbol;2416 });2417 2418 // If we get here then we've finished searching all JITDylibs.2419 // If we matched all symbols then move to phase 2, otherwise fail the query2420 // with a SymbolsNotFound error.2421 if (IPLS->DefGeneratorCandidates.empty()) {2422 LLVM_DEBUG(dbgs() << "Phase 1 succeeded.\n");2423 IPLS->complete(std::move(IPLS));2424 } else {2425 LLVM_DEBUG(dbgs() << "Phase 1 failed with unresolved symbols.\n");2426 IPLS->fail(make_error<SymbolsNotFound>(2427 getSymbolStringPool(), IPLS->DefGeneratorCandidates.getSymbolNames()));2428 }2429}2430 2431void ExecutionSession::OL_completeLookup(2432 std::unique_ptr<InProgressLookupState> IPLS,2433 std::shared_ptr<AsynchronousSymbolQuery> Q,2434 RegisterDependenciesFunction RegisterDependencies) {2435 2436 LLVM_DEBUG({2437 dbgs() << "Entering OL_completeLookup:\n"2438 << " Lookup kind: " << IPLS->K << "\n"2439 << " Search order: " << IPLS->SearchOrder2440 << ", Current index = " << IPLS->CurSearchOrderIndex2441 << (IPLS->NewJITDylib ? " (entering new JITDylib)" : "") << "\n"2442 << " Lookup set: " << IPLS->LookupSet << "\n"2443 << " Definition generator candidates: "2444 << IPLS->DefGeneratorCandidates << "\n"2445 << " Definition generator non-candidates: "2446 << IPLS->DefGeneratorNonCandidates << "\n";2447 });2448 2449 bool QueryComplete = false;2450 DenseMap<JITDylib *, JITDylib::UnmaterializedInfosList> CollectedUMIs;2451 2452 auto LodgingErr = runSessionLocked([&]() -> Error {2453 for (auto &KV : IPLS->SearchOrder) {2454 auto &JD = *KV.first;2455 auto JDLookupFlags = KV.second;2456 LLVM_DEBUG({2457 dbgs() << "Visiting \"" << JD.getName() << "\" (" << JDLookupFlags2458 << ") with lookup set " << IPLS->LookupSet << ":\n";2459 });2460 2461 auto Err = IPLS->LookupSet.forEachWithRemoval(2462 [&](const SymbolStringPtr &Name,2463 SymbolLookupFlags SymLookupFlags) -> Expected<bool> {2464 LLVM_DEBUG({2465 dbgs() << " Attempting to match \"" << Name << "\" ("2466 << SymLookupFlags << ")... ";2467 });2468 2469 /// Search for the symbol. If not found then continue without2470 /// removal.2471 auto SymI = JD.Symbols.find(Name);2472 if (SymI == JD.Symbols.end()) {2473 LLVM_DEBUG(dbgs() << "skipping: not present\n");2474 return false;2475 }2476 2477 // If this is a non-exported symbol and we're matching exported2478 // symbols only then skip this symbol without removal.2479 if (!SymI->second.getFlags().isExported() &&2480 JDLookupFlags ==2481 JITDylibLookupFlags::MatchExportedSymbolsOnly) {2482 LLVM_DEBUG(dbgs() << "skipping: not exported\n");2483 return false;2484 }2485 2486 // If we match against a materialization-side-effects only symbol2487 // then make sure it is weakly-referenced. Otherwise bail out with2488 // an error.2489 // FIXME: Use a "materialization-side-effects-only symbols must be2490 // weakly referenced" specific error here to reduce confusion.2491 if (SymI->second.getFlags().hasMaterializationSideEffectsOnly() &&2492 SymLookupFlags != SymbolLookupFlags::WeaklyReferencedSymbol) {2493 LLVM_DEBUG({2494 dbgs() << "error: "2495 "required, but symbol is has-side-effects-only\n";2496 });2497 return make_error<SymbolsNotFound>(getSymbolStringPool(),2498 SymbolNameVector({Name}));2499 }2500 2501 // If we matched against this symbol but it is in the error state2502 // then bail out and treat it as a failure to materialize.2503 if (SymI->second.getFlags().hasError()) {2504 LLVM_DEBUG(dbgs() << "error: symbol is in error state\n");2505 auto FailedSymbolsMap = std::make_shared<SymbolDependenceMap>();2506 (*FailedSymbolsMap)[&JD] = {Name};2507 return make_error<FailedToMaterialize>(2508 getSymbolStringPool(), std::move(FailedSymbolsMap));2509 }2510 2511 // Otherwise this is a match.2512 2513 // If this symbol is already in the required state then notify the2514 // query, remove the symbol and continue.2515 if (SymI->second.getState() >= Q->getRequiredState()) {2516 LLVM_DEBUG(dbgs()2517 << "matched, symbol already in required state\n");2518 Q->notifySymbolMetRequiredState(Name, SymI->second.getSymbol());2519 2520 // If this symbol is in anything other than the Ready state then2521 // we need to track the dependence.2522 if (SymI->second.getState() != SymbolState::Ready)2523 Q->addQueryDependence(JD, Name);2524 2525 return true;2526 }2527 2528 // Otherwise this symbol does not yet meet the required state. Check2529 // whether it has a materializer attached, and if so prepare to run2530 // it.2531 if (SymI->second.hasMaterializerAttached()) {2532 assert(SymI->second.getAddress() == ExecutorAddr() &&2533 "Symbol not resolved but already has address?");2534 auto UMII = JD.UnmaterializedInfos.find(Name);2535 assert(UMII != JD.UnmaterializedInfos.end() &&2536 "Lazy symbol should have UnmaterializedInfo");2537 2538 auto UMI = UMII->second;2539 assert(UMI->MU && "Materializer should not be null");2540 assert(UMI->RT && "Tracker should not be null");2541 LLVM_DEBUG({2542 dbgs() << "matched, preparing to dispatch MU@" << UMI->MU.get()2543 << " (" << UMI->MU->getName() << ")\n";2544 });2545 2546 // Move all symbols associated with this MaterializationUnit into2547 // materializing state.2548 for (auto &KV : UMI->MU->getSymbols()) {2549 auto SymK = JD.Symbols.find(KV.first);2550 assert(SymK != JD.Symbols.end() &&2551 "No entry for symbol covered by MaterializationUnit");2552 SymK->second.setMaterializerAttached(false);2553 SymK->second.setState(SymbolState::Materializing);2554 JD.UnmaterializedInfos.erase(KV.first);2555 }2556 2557 // Add MU to the list of MaterializationUnits to be materialized.2558 CollectedUMIs[&JD].push_back(std::move(UMI));2559 } else2560 LLVM_DEBUG(dbgs() << "matched, registering query");2561 2562 // Add the query to the PendingQueries list and continue, deleting2563 // the element from the lookup set.2564 assert(SymI->second.getState() != SymbolState::NeverSearched &&2565 SymI->second.getState() != SymbolState::Ready &&2566 "By this line the symbol should be materializing");2567 auto &MI = JD.MaterializingInfos[Name];2568 MI.addQuery(Q);2569 Q->addQueryDependence(JD, Name);2570 2571 return true;2572 });2573 2574 JD.shrinkMaterializationInfoMemory();2575 2576 // Handle failure.2577 if (Err) {2578 2579 LLVM_DEBUG({2580 dbgs() << "Lookup failed. Detaching query and replacing MUs.\n";2581 });2582 2583 // Detach the query.2584 Q->detach();2585 2586 // Replace the MUs.2587 for (auto &KV : CollectedUMIs) {2588 auto &JD = *KV.first;2589 for (auto &UMI : KV.second)2590 for (auto &KV2 : UMI->MU->getSymbols()) {2591 assert(!JD.UnmaterializedInfos.count(KV2.first) &&2592 "Unexpected materializer in map");2593 auto SymI = JD.Symbols.find(KV2.first);2594 assert(SymI != JD.Symbols.end() && "Missing symbol entry");2595 assert(SymI->second.getState() == SymbolState::Materializing &&2596 "Can not replace symbol that is not materializing");2597 assert(!SymI->second.hasMaterializerAttached() &&2598 "MaterializerAttached flag should not be set");2599 SymI->second.setMaterializerAttached(true);2600 JD.UnmaterializedInfos[KV2.first] = UMI;2601 }2602 }2603 2604 return Err;2605 }2606 }2607 2608 LLVM_DEBUG(dbgs() << "Stripping unmatched weakly-referenced symbols\n");2609 IPLS->LookupSet.forEachWithRemoval(2610 [&](const SymbolStringPtr &Name, SymbolLookupFlags SymLookupFlags) {2611 if (SymLookupFlags == SymbolLookupFlags::WeaklyReferencedSymbol) {2612 Q->dropSymbol(Name);2613 return true;2614 } else2615 return false;2616 });2617 2618 if (!IPLS->LookupSet.empty()) {2619 LLVM_DEBUG(dbgs() << "Failing due to unresolved symbols\n");2620 return make_error<SymbolsNotFound>(getSymbolStringPool(),2621 IPLS->LookupSet.getSymbolNames());2622 }2623 2624 // Record whether the query completed.2625 QueryComplete = Q->isComplete();2626 2627 LLVM_DEBUG({2628 dbgs() << "Query successfully "2629 << (QueryComplete ? "completed" : "lodged") << "\n";2630 });2631 2632 // Move the collected MUs to the OutstandingMUs list.2633 if (!CollectedUMIs.empty()) {2634 std::lock_guard<std::recursive_mutex> Lock(OutstandingMUsMutex);2635 2636 LLVM_DEBUG(dbgs() << "Adding MUs to dispatch:\n");2637 for (auto &KV : CollectedUMIs) {2638 LLVM_DEBUG({2639 auto &JD = *KV.first;2640 dbgs() << " For " << JD.getName() << ": Adding " << KV.second.size()2641 << " MUs.\n";2642 });2643 for (auto &UMI : KV.second) {2644 auto MR = createMaterializationResponsibility(2645 *UMI->RT, std::move(UMI->MU->SymbolFlags),2646 std::move(UMI->MU->InitSymbol));2647 OutstandingMUs.push_back(2648 std::make_pair(std::move(UMI->MU), std::move(MR)));2649 }2650 }2651 } else2652 LLVM_DEBUG(dbgs() << "No MUs to dispatch.\n");2653 2654 if (RegisterDependencies && !Q->QueryRegistrations.empty()) {2655 LLVM_DEBUG(dbgs() << "Registering dependencies\n");2656 RegisterDependencies(Q->QueryRegistrations);2657 } else2658 LLVM_DEBUG(dbgs() << "No dependencies to register\n");2659 2660 return Error::success();2661 });2662 2663 if (LodgingErr) {2664 LLVM_DEBUG(dbgs() << "Failing query\n");2665 Q->detach();2666 Q->handleFailed(std::move(LodgingErr));2667 return;2668 }2669 2670 if (QueryComplete) {2671 LLVM_DEBUG(dbgs() << "Completing query\n");2672 Q->handleComplete(*this);2673 }2674 2675 dispatchOutstandingMUs();2676}2677 2678void ExecutionSession::OL_completeLookupFlags(2679 std::unique_ptr<InProgressLookupState> IPLS,2680 unique_function<void(Expected<SymbolFlagsMap>)> OnComplete) {2681 2682 auto Result = runSessionLocked([&]() -> Expected<SymbolFlagsMap> {2683 LLVM_DEBUG({2684 dbgs() << "Entering OL_completeLookupFlags:\n"2685 << " Lookup kind: " << IPLS->K << "\n"2686 << " Search order: " << IPLS->SearchOrder2687 << ", Current index = " << IPLS->CurSearchOrderIndex2688 << (IPLS->NewJITDylib ? " (entering new JITDylib)" : "") << "\n"2689 << " Lookup set: " << IPLS->LookupSet << "\n"2690 << " Definition generator candidates: "2691 << IPLS->DefGeneratorCandidates << "\n"2692 << " Definition generator non-candidates: "2693 << IPLS->DefGeneratorNonCandidates << "\n";2694 });2695 2696 SymbolFlagsMap Result;2697 2698 // Attempt to find flags for each symbol.2699 for (auto &KV : IPLS->SearchOrder) {2700 auto &JD = *KV.first;2701 auto JDLookupFlags = KV.second;2702 LLVM_DEBUG({2703 dbgs() << "Visiting \"" << JD.getName() << "\" (" << JDLookupFlags2704 << ") with lookup set " << IPLS->LookupSet << ":\n";2705 });2706 2707 IPLS->LookupSet.forEachWithRemoval([&](const SymbolStringPtr &Name,2708 SymbolLookupFlags SymLookupFlags) {2709 LLVM_DEBUG({2710 dbgs() << " Attempting to match \"" << Name << "\" ("2711 << SymLookupFlags << ")... ";2712 });2713 2714 // Search for the symbol. If not found then continue without removing2715 // from the lookup set.2716 auto SymI = JD.Symbols.find(Name);2717 if (SymI == JD.Symbols.end()) {2718 LLVM_DEBUG(dbgs() << "skipping: not present\n");2719 return false;2720 }2721 2722 // If this is a non-exported symbol then it doesn't match. Skip it.2723 if (!SymI->second.getFlags().isExported() &&2724 JDLookupFlags == JITDylibLookupFlags::MatchExportedSymbolsOnly) {2725 LLVM_DEBUG(dbgs() << "skipping: not exported\n");2726 return false;2727 }2728 2729 LLVM_DEBUG({2730 dbgs() << "matched, \"" << Name << "\" -> " << SymI->second.getFlags()2731 << "\n";2732 });2733 Result[Name] = SymI->second.getFlags();2734 return true;2735 });2736 }2737 2738 // Remove any weakly referenced symbols that haven't been resolved.2739 IPLS->LookupSet.remove_if(2740 [](const SymbolStringPtr &Name, SymbolLookupFlags SymLookupFlags) {2741 return SymLookupFlags == SymbolLookupFlags::WeaklyReferencedSymbol;2742 });2743 2744 if (!IPLS->LookupSet.empty()) {2745 LLVM_DEBUG(dbgs() << "Failing due to unresolved symbols\n");2746 return make_error<SymbolsNotFound>(getSymbolStringPool(),2747 IPLS->LookupSet.getSymbolNames());2748 }2749 2750 LLVM_DEBUG(dbgs() << "Succeded, result = " << Result << "\n");2751 return Result;2752 });2753 2754 // Run the callback on the result.2755 LLVM_DEBUG(dbgs() << "Sending result to handler.\n");2756 OnComplete(std::move(Result));2757}2758 2759void ExecutionSession::OL_destroyMaterializationResponsibility(2760 MaterializationResponsibility &MR) {2761 2762 assert(MR.SymbolFlags.empty() &&2763 "All symbols should have been explicitly materialized or failed");2764 MR.JD.unlinkMaterializationResponsibility(MR);2765}2766 2767SymbolNameSet ExecutionSession::OL_getRequestedSymbols(2768 const MaterializationResponsibility &MR) {2769 return MR.JD.getRequestedSymbols(MR.SymbolFlags);2770}2771 2772Error ExecutionSession::OL_notifyResolved(MaterializationResponsibility &MR,2773 const SymbolMap &Symbols) {2774 LLVM_DEBUG({2775 dbgs() << "In " << MR.JD.getName() << " resolving " << Symbols << "\n";2776 });2777#ifndef NDEBUG2778 for (auto &KV : Symbols) {2779 auto I = MR.SymbolFlags.find(KV.first);2780 assert(I != MR.SymbolFlags.end() &&2781 "Resolving symbol outside this responsibility set");2782 assert(!I->second.hasMaterializationSideEffectsOnly() &&2783 "Can't resolve materialization-side-effects-only symbol");2784 if (I->second & JITSymbolFlags::Common) {2785 auto WeakOrCommon = JITSymbolFlags::Weak | JITSymbolFlags::Common;2786 assert((KV.second.getFlags() & WeakOrCommon) &&2787 "Common symbols must be resolved as common or weak");2788 assert((KV.second.getFlags() & ~WeakOrCommon) ==2789 (I->second & ~JITSymbolFlags::Common) &&2790 "Resolving symbol with incorrect flags");2791 } else2792 assert(KV.second.getFlags() == I->second &&2793 "Resolving symbol with incorrect flags");2794 }2795#endif2796 2797 return MR.JD.resolve(MR, Symbols);2798}2799 2800WaitingOnGraph::ExternalState2801ExecutionSession::IL_getSymbolState(JITDylib *JD,2802 NonOwningSymbolStringPtr Name) {2803 if (JD->State != JITDylib::Open)2804 return WaitingOnGraph::ExternalState::Failed;2805 2806 auto I = JD->Symbols.find_as(Name);2807 2808 // FIXME: Can we eliminate this possibility if we support query binding?2809 if (I == JD->Symbols.end())2810 return WaitingOnGraph::ExternalState::Failed;2811 2812 if (I->second.getFlags().hasError())2813 return WaitingOnGraph::ExternalState::Failed;2814 2815 if (I->second.getState() == SymbolState::Ready)2816 return WaitingOnGraph::ExternalState::Ready;2817 2818 return WaitingOnGraph::ExternalState::None;2819}2820 2821template <typename UpdateSymbolFn, typename UpdateQueryFn>2822void ExecutionSession::IL_collectQueries(2823 JITDylib::AsynchronousSymbolQuerySet &Qs,2824 WaitingOnGraph::ContainerElementsMap &QualifiedSymbols,2825 UpdateSymbolFn &&UpdateSymbol, UpdateQueryFn &&UpdateQuery) {2826 2827 for (auto &[JD, Symbols] : QualifiedSymbols) {2828 // IL_emit and JITDylib removal are synchronized by the session lock.2829 // Since JITDylib removal removes any contained nodes from the2830 // WaitingOnGraph, we should be able to assert that all nodes in the2831 // WaitingOnGraph have not been removed.2832 assert(JD->State == JITDylib::Open &&2833 "WaitingOnGraph includes definition in defunct JITDylib");2834 for (auto &Symbol : Symbols) {2835 // Update symbol table.2836 auto I = JD->Symbols.find_as(Symbol);2837 assert(I != JD->Symbols.end() &&2838 "Failed Symbol missing from JD symbol table");2839 auto &Entry = I->second;2840 UpdateSymbol(Entry);2841 2842 // Collect queries.2843 auto J = JD->MaterializingInfos.find_as(Symbol);2844 if (J != JD->MaterializingInfos.end()) {2845 for (auto &Q : J->second.takeAllPendingQueries()) {2846 UpdateQuery(*Q, *JD, Symbol, Entry);2847 Qs.insert(std::move(Q));2848 }2849 JD->MaterializingInfos.erase(J);2850 }2851 }2852 }2853}2854 2855Expected<ExecutionSession::EmitQueries>2856ExecutionSession::IL_emit(MaterializationResponsibility &MR,2857 WaitingOnGraph::SimplifyResult SR) {2858 2859 if (MR.RT->isDefunct())2860 return make_error<ResourceTrackerDefunct>(MR.RT);2861 2862 auto &TargetJD = MR.getTargetJITDylib();2863 if (TargetJD.State != JITDylib::Open)2864 return make_error<StringError>("JITDylib " + TargetJD.getName() +2865 " is defunct",2866 inconvertibleErrorCode());2867 2868#ifdef EXPENSIVE_CHECKS2869 verifySessionState("entering ExecutionSession::IL_emit");2870#endif2871 2872 auto ER = G.emit(std::move(SR),2873 [this](JITDylib *JD, NonOwningSymbolStringPtr Name) {2874 return IL_getSymbolState(JD, Name);2875 });2876 2877 EmitQueries EQ;2878 2879 // Handle failed queries.2880 for (auto &SN : ER.Failed)2881 IL_collectQueries(2882 EQ.Failed, SN->defs(),2883 [](JITDylib::SymbolTableEntry &E) {2884 E.setFlags(E.getFlags() = JITSymbolFlags::HasError);2885 },2886 [&](AsynchronousSymbolQuery &Q, JITDylib &JD,2887 NonOwningSymbolStringPtr Name, JITDylib::SymbolTableEntry &E) {2888 auto &FS = EQ.FailedSymsForQuery[&Q];2889 if (!FS)2890 FS = std::make_shared<SymbolDependenceMap>();2891 (*FS)[&JD].insert(SymbolStringPtr(Name));2892 });2893 2894 for (auto &FQ : EQ.Failed)2895 FQ->detach();2896 2897 for (auto &SN : ER.Ready)2898 IL_collectQueries(2899 EQ.Completed, SN->defs(),2900 [](JITDylib::SymbolTableEntry &E) { E.setState(SymbolState::Ready); },2901 [](AsynchronousSymbolQuery &Q, JITDylib &JD,2902 NonOwningSymbolStringPtr Name, JITDylib::SymbolTableEntry &E) {2903 Q.notifySymbolMetRequiredState(SymbolStringPtr(Name), E.getSymbol());2904 });2905 2906 // std::erase_if is not available in C++17, and llvm::erase_if does not work2907 // here.2908 for (auto it = EQ.Completed.begin(), end = EQ.Completed.end(); it != end;) {2909 if ((*it)->isComplete()) {2910 ++it;2911 } else {2912 it = EQ.Completed.erase(it);2913 }2914 }2915 2916#ifdef EXPENSIVE_CHECKS2917 verifySessionState("exiting ExecutionSession::IL_emit");2918#endif2919 2920 return std::move(EQ);2921}2922 2923Error ExecutionSession::OL_notifyEmitted(2924 MaterializationResponsibility &MR,2925 ArrayRef<SymbolDependenceGroup> DepGroups) {2926 LLVM_DEBUG({2927 dbgs() << "In " << MR.JD.getName() << " emitting " << MR.SymbolFlags2928 << "\n";2929 if (!DepGroups.empty()) {2930 dbgs() << " Initial dependencies:\n";2931 for (auto &SDG : DepGroups) {2932 dbgs() << " Symbols: " << SDG.Symbols2933 << ", Dependencies: " << SDG.Dependencies << "\n";2934 }2935 }2936 });2937 2938#ifndef NDEBUG2939 SymbolNameSet Visited;2940 for (auto &DG : DepGroups) {2941 for (auto &Sym : DG.Symbols) {2942 assert(MR.SymbolFlags.count(Sym) &&2943 "DG contains dependence for symbol outside this MR");2944 assert(Visited.insert(Sym).second &&2945 "DG contains duplicate entries for Name");2946 }2947 }2948#endif // NDEBUG2949 2950 std::vector<std::unique_ptr<WaitingOnGraph::SuperNode>> SNs;2951 WaitingOnGraph::ContainerElementsMap Residual;2952 {2953 auto &JDResidual = Residual[&MR.getTargetJITDylib()];2954 for (auto &[Name, Flags] : MR.getSymbols())2955 JDResidual.insert(NonOwningSymbolStringPtr(Name));2956 2957 for (auto &SDG : DepGroups) {2958 WaitingOnGraph::ContainerElementsMap Defs;2959 assert(!SDG.Symbols.empty());2960 auto &JDDefs = Defs[&MR.getTargetJITDylib()];2961 for (auto &Def : SDG.Symbols) {2962 JDDefs.insert(NonOwningSymbolStringPtr(Def));2963 JDResidual.erase(NonOwningSymbolStringPtr(Def));2964 }2965 WaitingOnGraph::ContainerElementsMap Deps;2966 if (!SDG.Dependencies.empty()) {2967 for (auto &[JD, Syms] : SDG.Dependencies) {2968 auto &JDDeps = Deps[JD];2969 for (auto &Dep : Syms)2970 JDDeps.insert(NonOwningSymbolStringPtr(Dep));2971 }2972 }2973 SNs.push_back(std::make_unique<WaitingOnGraph::SuperNode>(2974 std::move(Defs), std::move(Deps)));2975 }2976 if (!JDResidual.empty())2977 SNs.push_back(std::make_unique<WaitingOnGraph::SuperNode>(2978 std::move(Residual), WaitingOnGraph::ContainerElementsMap()));2979 }2980 2981 auto SR = WaitingOnGraph::simplify(std::move(SNs));2982 2983 LLVM_DEBUG({2984 dbgs() << " Simplified dependencies:\n";2985 for (auto &SN : SR.superNodes()) {2986 2987 auto SortedLibs = [](WaitingOnGraph::ContainerElementsMap &C) {2988 std::vector<JITDylib *> JDs;2989 for (auto &[JD, _] : C)2990 JDs.push_back(JD);2991 llvm::sort(JDs, [](const JITDylib *LHS, const JITDylib *RHS) {2992 return LHS->getName() < RHS->getName();2993 });2994 return JDs;2995 };2996 2997 auto SortedNames = [](WaitingOnGraph::ElementSet &Elems) {2998 std::vector<NonOwningSymbolStringPtr> Names(Elems.begin(), Elems.end());2999 llvm::sort(Names, [](const NonOwningSymbolStringPtr &LHS,3000 const NonOwningSymbolStringPtr &RHS) {3001 return *LHS < *RHS;3002 });3003 return Names;3004 };3005 3006 dbgs() << " Defs: {";3007 for (auto *JD : SortedLibs(SN->defs())) {3008 dbgs() << " (" << JD->getName() << ", [";3009 for (auto &Sym : SortedNames(SN->defs()[JD]))3010 dbgs() << " " << Sym;3011 dbgs() << " ])";3012 }3013 dbgs() << " }, Deps: {";3014 for (auto *JD : SortedLibs(SN->deps())) {3015 dbgs() << " (" << JD->getName() << ", [";3016 for (auto &Sym : SortedNames(SN->deps()[JD]))3017 dbgs() << " " << Sym;3018 dbgs() << " ])";3019 }3020 dbgs() << " }\n";3021 }3022 });3023 auto EmitQueries =3024 runSessionLocked([&]() { return IL_emit(MR, std::move(SR)); });3025 3026 // On error bail out.3027 if (!EmitQueries)3028 return EmitQueries.takeError();3029 3030 // Otherwise notify failed queries, and any updated queries that have been3031 // completed.3032 3033 // FIXME: Get rid of error return from notifyEmitted.3034 SymbolDependenceMap BadDeps;3035 {3036 for (auto &FQ : EmitQueries->Failed) {3037 FQ->detach();3038 assert(EmitQueries->FailedSymsForQuery.count(FQ.get()) &&3039 "Missing failed symbols for query");3040 auto FailedSyms = std::move(EmitQueries->FailedSymsForQuery[FQ.get()]);3041 for (auto &[JD, Syms] : *FailedSyms) {3042 auto &BadDepsForJD = BadDeps[JD];3043 for (auto &Sym : Syms)3044 BadDepsForJD.insert(Sym);3045 }3046 FQ->handleFailed(make_error<FailedToMaterialize>(getSymbolStringPool(),3047 std::move(FailedSyms)));3048 }3049 }3050 3051 for (auto &UQ : EmitQueries->Completed)3052 UQ->handleComplete(*this);3053 3054 // If there are any bad dependencies then return an error.3055 if (!BadDeps.empty()) {3056 SymbolNameSet BadNames;3057 // Note: The name set calculated here is bogus: it includes all symbols in3058 // the MR, not just the ones that failed. We want to remove the error3059 // return path from notifyEmitted anyway, so this is just a brief3060 // placeholder to maintain (roughly) the current error behavior.3061 for (auto &[Name, Flags] : MR.getSymbols())3062 BadNames.insert(Name);3063 MR.SymbolFlags.clear();3064 return make_error<UnsatisfiedSymbolDependencies>(3065 getSymbolStringPool(), &MR.getTargetJITDylib(), std::move(BadNames),3066 std::move(BadDeps), "dependencies removed or in error state");3067 }3068 3069 MR.SymbolFlags.clear();3070 return Error::success();3071}3072 3073Error ExecutionSession::OL_defineMaterializing(3074 MaterializationResponsibility &MR, SymbolFlagsMap NewSymbolFlags) {3075 3076 LLVM_DEBUG({3077 dbgs() << "In " << MR.JD.getName() << " defining materializing symbols "3078 << NewSymbolFlags << "\n";3079 });3080 if (auto AcceptedDefs =3081 MR.JD.defineMaterializing(MR, std::move(NewSymbolFlags))) {3082 // Add all newly accepted symbols to this responsibility object.3083 for (auto &KV : *AcceptedDefs)3084 MR.SymbolFlags.insert(KV);3085 return Error::success();3086 } else3087 return AcceptedDefs.takeError();3088}3089 3090std::pair<JITDylib::AsynchronousSymbolQuerySet,3091 std::shared_ptr<SymbolDependenceMap>>3092ExecutionSession::IL_failSymbols(JITDylib &JD,3093 const SymbolNameVector &SymbolsToFail) {3094 3095#ifdef EXPENSIVE_CHECKS3096 verifySessionState("entering ExecutionSession::IL_failSymbols");3097#endif3098 3099 JITDylib::AsynchronousSymbolQuerySet FailedQueries;3100 auto Fail = [&](JITDylib *FailJD, NonOwningSymbolStringPtr FailSym) {3101 auto I = FailJD->Symbols.find_as(FailSym);3102 assert(I != FailJD->Symbols.end());3103 I->second.setFlags(I->second.getFlags() | JITSymbolFlags::HasError);3104 auto J = FailJD->MaterializingInfos.find_as(FailSym);3105 if (J != FailJD->MaterializingInfos.end()) {3106 for (auto &Q : J->second.takeAllPendingQueries())3107 FailedQueries.insert(std::move(Q));3108 FailJD->MaterializingInfos.erase(J);3109 }3110 };3111 3112 auto FailedSymbolsMap = std::make_shared<SymbolDependenceMap>();3113 3114 {3115 auto &FailedSymsForJD = (*FailedSymbolsMap)[&JD];3116 for (auto &Sym : SymbolsToFail) {3117 FailedSymsForJD.insert(Sym);3118 Fail(&JD, NonOwningSymbolStringPtr(Sym));3119 }3120 }3121 3122 WaitingOnGraph::ContainerElementsMap ToFail;3123 auto &JDToFail = ToFail[&JD];3124 for (auto &Sym : SymbolsToFail)3125 JDToFail.insert(NonOwningSymbolStringPtr(Sym));3126 3127 auto FailedSNs = G.fail(ToFail);3128 3129 for (auto &SN : FailedSNs) {3130 for (auto &[FailJD, Defs] : SN->defs()) {3131 auto &FailedSymsForFailJD = (*FailedSymbolsMap)[FailJD];3132 for (auto &Def : Defs) {3133 FailedSymsForFailJD.insert(SymbolStringPtr(Def));3134 Fail(FailJD, Def);3135 }3136 }3137 }3138 3139 // Detach all failed queries.3140 for (auto &Q : FailedQueries)3141 Q->detach();3142 3143#ifdef EXPENSIVE_CHECKS3144 verifySessionState("exiting ExecutionSession::IL_failSymbols");3145#endif3146 3147 return std::make_pair(std::move(FailedQueries), std::move(FailedSymbolsMap));3148}3149 3150void ExecutionSession::OL_notifyFailed(MaterializationResponsibility &MR) {3151 3152 LLVM_DEBUG({3153 dbgs() << "In " << MR.JD.getName() << " failing materialization for "3154 << MR.SymbolFlags << "\n";3155 });3156 3157 if (MR.SymbolFlags.empty())3158 return;3159 3160 SymbolNameVector SymbolsToFail;3161 for (auto &[Name, Flags] : MR.SymbolFlags)3162 SymbolsToFail.push_back(Name);3163 MR.SymbolFlags.clear();3164 3165 JITDylib::AsynchronousSymbolQuerySet FailedQueries;3166 std::shared_ptr<SymbolDependenceMap> FailedSymbols;3167 3168 std::tie(FailedQueries, FailedSymbols) = runSessionLocked([&]() {3169 // If the tracker is defunct then there's nothing to do here.3170 if (MR.RT->isDefunct())3171 return std::pair<JITDylib::AsynchronousSymbolQuerySet,3172 std::shared_ptr<SymbolDependenceMap>>();3173 return IL_failSymbols(MR.getTargetJITDylib(), SymbolsToFail);3174 });3175 3176 for (auto &Q : FailedQueries) {3177 Q->detach();3178 Q->handleFailed(3179 make_error<FailedToMaterialize>(getSymbolStringPool(), FailedSymbols));3180 }3181}3182 3183Error ExecutionSession::OL_replace(MaterializationResponsibility &MR,3184 std::unique_ptr<MaterializationUnit> MU) {3185 for (auto &KV : MU->getSymbols()) {3186 assert(MR.SymbolFlags.count(KV.first) &&3187 "Replacing definition outside this responsibility set");3188 MR.SymbolFlags.erase(KV.first);3189 }3190 3191 if (MU->getInitializerSymbol() == MR.InitSymbol)3192 MR.InitSymbol = nullptr;3193 3194 LLVM_DEBUG(MR.JD.getExecutionSession().runSessionLocked([&]() {3195 dbgs() << "In " << MR.JD.getName() << " replacing symbols with " << *MU3196 << "\n";3197 }););3198 3199 return MR.JD.replace(MR, std::move(MU));3200}3201 3202Expected<std::unique_ptr<MaterializationResponsibility>>3203ExecutionSession::OL_delegate(MaterializationResponsibility &MR,3204 const SymbolNameSet &Symbols) {3205 3206 SymbolStringPtr DelegatedInitSymbol;3207 SymbolFlagsMap DelegatedFlags;3208 3209 for (auto &Name : Symbols) {3210 auto I = MR.SymbolFlags.find(Name);3211 assert(I != MR.SymbolFlags.end() &&3212 "Symbol is not tracked by this MaterializationResponsibility "3213 "instance");3214 3215 DelegatedFlags[Name] = std::move(I->second);3216 if (Name == MR.InitSymbol)3217 std::swap(MR.InitSymbol, DelegatedInitSymbol);3218 3219 MR.SymbolFlags.erase(I);3220 }3221 3222 return MR.JD.delegate(MR, std::move(DelegatedFlags),3223 std::move(DelegatedInitSymbol));3224}3225 3226#ifndef NDEBUG3227void ExecutionSession::dumpDispatchInfo(Task &T) {3228 runSessionLocked([&]() {3229 dbgs() << "Dispatching: ";3230 T.printDescription(dbgs());3231 dbgs() << "\n";3232 });3233}3234#endif // NDEBUG3235 3236} // End namespace orc.3237} // End namespace llvm.3238