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