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
9 #include "llvm/ExecutionEngine/Orc/Core.h"
10 #include "llvm/Config/llvm-config.h"
11 #include "llvm/ExecutionEngine/Orc/OrcError.h"
12 #include "llvm/IR/Mangler.h"
13 #include "llvm/Support/CommandLine.h"
14 #include "llvm/Support/Debug.h"
15 #include "llvm/Support/Format.h"
16
17 #if LLVM_ENABLE_THREADS
18 #include <future>
19 #endif
20
21 #define DEBUG_TYPE "orc"
22
23 using namespace llvm;
24
25 namespace {
26
27 #ifndef NDEBUG
28
29 cl::opt<bool> PrintHidden("debug-orc-print-hidden", cl::init(true),
30 cl::desc("debug print hidden symbols defined by "
31 "materialization units"),
32 cl::Hidden);
33
34 cl::opt<bool> PrintCallable("debug-orc-print-callable", cl::init(true),
35 cl::desc("debug print callable symbols defined by "
36 "materialization units"),
37 cl::Hidden);
38
39 cl::opt<bool> PrintData("debug-orc-print-data", cl::init(true),
40 cl::desc("debug print data symbols defined by "
41 "materialization units"),
42 cl::Hidden);
43
44 #endif // NDEBUG
45
46 // SetPrinter predicate that prints every element.
47 template <typename T> struct PrintAll {
operator ()__anon98ece18b0111::PrintAll48 bool operator()(const T &E) { return true; }
49 };
50
anyPrintSymbolOptionSet()51 bool anyPrintSymbolOptionSet() {
52 #ifndef NDEBUG
53 return PrintHidden || PrintCallable || PrintData;
54 #else
55 return false;
56 #endif // NDEBUG
57 }
58
flagsMatchCLOpts(const JITSymbolFlags & Flags)59 bool flagsMatchCLOpts(const JITSymbolFlags &Flags) {
60 #ifndef NDEBUG
61 // Bail out early if this is a hidden symbol and we're not printing hiddens.
62 if (!PrintHidden && !Flags.isExported())
63 return false;
64
65 // Return true if this is callable and we're printing callables.
66 if (PrintCallable && Flags.isCallable())
67 return true;
68
69 // Return true if this is data and we're printing data.
70 if (PrintData && !Flags.isCallable())
71 return true;
72
73 // otherwise return false.
74 return false;
75 #else
76 return false;
77 #endif // NDEBUG
78 }
79
80 // Prints a set of items, filtered by an user-supplied predicate.
81 template <typename Set, typename Pred = PrintAll<typename Set::value_type>>
82 class SetPrinter {
83 public:
SetPrinter(const Set & S,Pred ShouldPrint=Pred ())84 SetPrinter(const Set &S, Pred ShouldPrint = Pred())
85 : S(S), ShouldPrint(std::move(ShouldPrint)) {}
86
printTo(llvm::raw_ostream & OS) const87 void printTo(llvm::raw_ostream &OS) const {
88 bool PrintComma = false;
89 OS << "{";
90 for (auto &E : S) {
91 if (ShouldPrint(E)) {
92 if (PrintComma)
93 OS << ',';
94 OS << ' ' << E;
95 PrintComma = true;
96 }
97 }
98 OS << " }";
99 }
100
101 private:
102 const Set &S;
103 mutable Pred ShouldPrint;
104 };
105
106 template <typename Set, typename Pred>
printSet(const Set & S,Pred P=Pred ())107 SetPrinter<Set, Pred> printSet(const Set &S, Pred P = Pred()) {
108 return SetPrinter<Set, Pred>(S, std::move(P));
109 }
110
111 // Render a SetPrinter by delegating to its printTo method.
112 template <typename Set, typename Pred>
operator <<(llvm::raw_ostream & OS,const SetPrinter<Set,Pred> & Printer)113 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
114 const SetPrinter<Set, Pred> &Printer) {
115 Printer.printTo(OS);
116 return OS;
117 }
118
119 struct PrintSymbolFlagsMapElemsMatchingCLOpts {
operator ()__anon98ece18b0111::PrintSymbolFlagsMapElemsMatchingCLOpts120 bool operator()(const orc::SymbolFlagsMap::value_type &KV) {
121 return flagsMatchCLOpts(KV.second);
122 }
123 };
124
125 struct PrintSymbolMapElemsMatchingCLOpts {
operator ()__anon98ece18b0111::PrintSymbolMapElemsMatchingCLOpts126 bool operator()(const orc::SymbolMap::value_type &KV) {
127 return flagsMatchCLOpts(KV.second.getFlags());
128 }
129 };
130
131 } // end anonymous namespace
132
133 namespace llvm {
134 namespace orc {
135
136 char FailedToMaterialize::ID = 0;
137 char SymbolsNotFound::ID = 0;
138 char SymbolsCouldNotBeRemoved::ID = 0;
139
140 RegisterDependenciesFunction NoDependenciesToRegister =
141 RegisterDependenciesFunction();
142
anchor()143 void MaterializationUnit::anchor() {}
144
operator <<(raw_ostream & OS,const SymbolStringPtr & Sym)145 raw_ostream &operator<<(raw_ostream &OS, const SymbolStringPtr &Sym) {
146 return OS << *Sym;
147 }
148
operator <<(raw_ostream & OS,const SymbolNameSet & Symbols)149 raw_ostream &operator<<(raw_ostream &OS, const SymbolNameSet &Symbols) {
150 return OS << printSet(Symbols, PrintAll<SymbolStringPtr>());
151 }
152
operator <<(raw_ostream & OS,const JITSymbolFlags & Flags)153 raw_ostream &operator<<(raw_ostream &OS, const JITSymbolFlags &Flags) {
154 if (Flags.isCallable())
155 OS << "[Callable]";
156 else
157 OS << "[Data]";
158 if (Flags.isWeak())
159 OS << "[Weak]";
160 else if (Flags.isCommon())
161 OS << "[Common]";
162
163 if (!Flags.isExported())
164 OS << "[Hidden]";
165
166 return OS;
167 }
168
operator <<(raw_ostream & OS,const JITEvaluatedSymbol & Sym)169 raw_ostream &operator<<(raw_ostream &OS, const JITEvaluatedSymbol &Sym) {
170 return OS << format("0x%016" PRIx64, Sym.getAddress()) << " "
171 << Sym.getFlags();
172 }
173
operator <<(raw_ostream & OS,const SymbolFlagsMap::value_type & KV)174 raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap::value_type &KV) {
175 return OS << "(\"" << KV.first << "\", " << KV.second << ")";
176 }
177
operator <<(raw_ostream & OS,const SymbolMap::value_type & KV)178 raw_ostream &operator<<(raw_ostream &OS, const SymbolMap::value_type &KV) {
179 return OS << "(\"" << KV.first << "\": " << KV.second << ")";
180 }
181
operator <<(raw_ostream & OS,const SymbolFlagsMap & SymbolFlags)182 raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap &SymbolFlags) {
183 return OS << printSet(SymbolFlags, PrintSymbolFlagsMapElemsMatchingCLOpts());
184 }
185
operator <<(raw_ostream & OS,const SymbolMap & Symbols)186 raw_ostream &operator<<(raw_ostream &OS, const SymbolMap &Symbols) {
187 return OS << printSet(Symbols, PrintSymbolMapElemsMatchingCLOpts());
188 }
189
operator <<(raw_ostream & OS,const SymbolDependenceMap::value_type & KV)190 raw_ostream &operator<<(raw_ostream &OS,
191 const SymbolDependenceMap::value_type &KV) {
192 return OS << "(" << KV.first << ", " << KV.second << ")";
193 }
194
operator <<(raw_ostream & OS,const SymbolDependenceMap & Deps)195 raw_ostream &operator<<(raw_ostream &OS, const SymbolDependenceMap &Deps) {
196 return OS << printSet(Deps, PrintAll<SymbolDependenceMap::value_type>());
197 }
198
operator <<(raw_ostream & OS,const MaterializationUnit & MU)199 raw_ostream &operator<<(raw_ostream &OS, const MaterializationUnit &MU) {
200 OS << "MU@" << &MU << " (\"" << MU.getName() << "\"";
201 if (anyPrintSymbolOptionSet())
202 OS << ", " << MU.getSymbols();
203 return OS << ")";
204 }
205
operator <<(raw_ostream & OS,const JITDylibSearchList & JDs)206 raw_ostream &operator<<(raw_ostream &OS, const JITDylibSearchList &JDs) {
207 OS << "[";
208 if (!JDs.empty()) {
209 assert(JDs.front().first && "JITDylibList entries must not be null");
210 OS << " (\"" << JDs.front().first->getName() << "\", "
211 << (JDs.front().second ? "true" : "false") << ")";
212 for (auto &KV : make_range(std::next(JDs.begin()), JDs.end())) {
213 assert(KV.first && "JITDylibList entries must not be null");
214 OS << ", (\"" << KV.first->getName() << "\", "
215 << (KV.second ? "true" : "false") << ")";
216 }
217 }
218 OS << " ]";
219 return OS;
220 }
221
operator <<(raw_ostream & OS,const SymbolAliasMap & Aliases)222 raw_ostream &operator<<(raw_ostream &OS, const SymbolAliasMap &Aliases) {
223 OS << "{";
224 for (auto &KV : Aliases)
225 OS << " " << *KV.first << ": " << KV.second.Aliasee << " "
226 << KV.second.AliasFlags;
227 OS << " }\n";
228 return OS;
229 }
230
operator <<(raw_ostream & OS,const SymbolState & S)231 raw_ostream &operator<<(raw_ostream &OS, const SymbolState &S) {
232 switch (S) {
233 case SymbolState::Invalid:
234 return OS << "Invalid";
235 case SymbolState::NeverSearched:
236 return OS << "Never-Searched";
237 case SymbolState::Materializing:
238 return OS << "Materializing";
239 case SymbolState::Resolved:
240 return OS << "Resolved";
241 case SymbolState::Ready:
242 return OS << "Ready";
243 }
244 llvm_unreachable("Invalid state");
245 }
246
FailedToMaterialize(SymbolNameSet Symbols)247 FailedToMaterialize::FailedToMaterialize(SymbolNameSet Symbols)
248 : Symbols(std::move(Symbols)) {
249 assert(!this->Symbols.empty() && "Can not fail to resolve an empty set");
250 }
251
convertToErrorCode() const252 std::error_code FailedToMaterialize::convertToErrorCode() const {
253 return orcError(OrcErrorCode::UnknownORCError);
254 }
255
log(raw_ostream & OS) const256 void FailedToMaterialize::log(raw_ostream &OS) const {
257 OS << "Failed to materialize symbols: " << Symbols;
258 }
259
SymbolsNotFound(SymbolNameSet Symbols)260 SymbolsNotFound::SymbolsNotFound(SymbolNameSet Symbols)
261 : Symbols(std::move(Symbols)) {
262 assert(!this->Symbols.empty() && "Can not fail to resolve an empty set");
263 }
264
convertToErrorCode() const265 std::error_code SymbolsNotFound::convertToErrorCode() const {
266 return orcError(OrcErrorCode::UnknownORCError);
267 }
268
log(raw_ostream & OS) const269 void SymbolsNotFound::log(raw_ostream &OS) const {
270 OS << "Symbols not found: " << Symbols;
271 }
272
SymbolsCouldNotBeRemoved(SymbolNameSet Symbols)273 SymbolsCouldNotBeRemoved::SymbolsCouldNotBeRemoved(SymbolNameSet Symbols)
274 : Symbols(std::move(Symbols)) {
275 assert(!this->Symbols.empty() && "Can not fail to resolve an empty set");
276 }
277
convertToErrorCode() const278 std::error_code SymbolsCouldNotBeRemoved::convertToErrorCode() const {
279 return orcError(OrcErrorCode::UnknownORCError);
280 }
281
log(raw_ostream & OS) const282 void SymbolsCouldNotBeRemoved::log(raw_ostream &OS) const {
283 OS << "Symbols could not be removed: " << Symbols;
284 }
285
AsynchronousSymbolQuery(const SymbolNameSet & Symbols,SymbolState RequiredState,SymbolsResolvedCallback NotifyComplete)286 AsynchronousSymbolQuery::AsynchronousSymbolQuery(
287 const SymbolNameSet &Symbols, SymbolState RequiredState,
288 SymbolsResolvedCallback NotifyComplete)
289 : NotifyComplete(std::move(NotifyComplete)), RequiredState(RequiredState) {
290 assert(RequiredState >= SymbolState::Resolved &&
291 "Cannot query for a symbols that have not reached the resolve state "
292 "yet");
293
294 OutstandingSymbolsCount = Symbols.size();
295
296 for (auto &S : Symbols)
297 ResolvedSymbols[S] = nullptr;
298 }
299
notifySymbolMetRequiredState(const SymbolStringPtr & Name,JITEvaluatedSymbol Sym)300 void AsynchronousSymbolQuery::notifySymbolMetRequiredState(
301 const SymbolStringPtr &Name, JITEvaluatedSymbol Sym) {
302 auto I = ResolvedSymbols.find(Name);
303 assert(I != ResolvedSymbols.end() &&
304 "Resolving symbol outside the requested set");
305 assert(I->second.getAddress() == 0 && "Redundantly resolving symbol Name");
306 I->second = std::move(Sym);
307 --OutstandingSymbolsCount;
308 }
309
handleComplete()310 void AsynchronousSymbolQuery::handleComplete() {
311 assert(OutstandingSymbolsCount == 0 &&
312 "Symbols remain, handleComplete called prematurely");
313
314 auto TmpNotifyComplete = std::move(NotifyComplete);
315 NotifyComplete = SymbolsResolvedCallback();
316 TmpNotifyComplete(std::move(ResolvedSymbols));
317 }
318
canStillFail()319 bool AsynchronousSymbolQuery::canStillFail() { return !!NotifyComplete; }
320
handleFailed(Error Err)321 void AsynchronousSymbolQuery::handleFailed(Error Err) {
322 assert(QueryRegistrations.empty() && ResolvedSymbols.empty() &&
323 OutstandingSymbolsCount == 0 &&
324 "Query should already have been abandoned");
325 NotifyComplete(std::move(Err));
326 NotifyComplete = SymbolsResolvedCallback();
327 }
328
addQueryDependence(JITDylib & JD,SymbolStringPtr Name)329 void AsynchronousSymbolQuery::addQueryDependence(JITDylib &JD,
330 SymbolStringPtr Name) {
331 bool Added = QueryRegistrations[&JD].insert(std::move(Name)).second;
332 (void)Added;
333 assert(Added && "Duplicate dependence notification?");
334 }
335
removeQueryDependence(JITDylib & JD,const SymbolStringPtr & Name)336 void AsynchronousSymbolQuery::removeQueryDependence(
337 JITDylib &JD, const SymbolStringPtr &Name) {
338 auto QRI = QueryRegistrations.find(&JD);
339 assert(QRI != QueryRegistrations.end() &&
340 "No dependencies registered for JD");
341 assert(QRI->second.count(Name) && "No dependency on Name in JD");
342 QRI->second.erase(Name);
343 if (QRI->second.empty())
344 QueryRegistrations.erase(QRI);
345 }
346
detach()347 void AsynchronousSymbolQuery::detach() {
348 ResolvedSymbols.clear();
349 OutstandingSymbolsCount = 0;
350 for (auto &KV : QueryRegistrations)
351 KV.first->detachQueryHelper(*this, KV.second);
352 QueryRegistrations.clear();
353 }
354
MaterializationResponsibility(JITDylib & JD,SymbolFlagsMap SymbolFlags,VModuleKey K)355 MaterializationResponsibility::MaterializationResponsibility(
356 JITDylib &JD, SymbolFlagsMap SymbolFlags, VModuleKey K)
357 : JD(JD), SymbolFlags(std::move(SymbolFlags)), K(std::move(K)) {
358 assert(!this->SymbolFlags.empty() && "Materializing nothing?");
359 }
360
~MaterializationResponsibility()361 MaterializationResponsibility::~MaterializationResponsibility() {
362 assert(SymbolFlags.empty() &&
363 "All symbols should have been explicitly materialized or failed");
364 }
365
getRequestedSymbols() const366 SymbolNameSet MaterializationResponsibility::getRequestedSymbols() const {
367 return JD.getRequestedSymbols(SymbolFlags);
368 }
369
notifyResolved(const SymbolMap & Symbols)370 void MaterializationResponsibility::notifyResolved(const SymbolMap &Symbols) {
371 LLVM_DEBUG({
372 dbgs() << "In " << JD.getName() << " resolving " << Symbols << "\n";
373 });
374 #ifndef NDEBUG
375 for (auto &KV : Symbols) {
376 auto I = SymbolFlags.find(KV.first);
377 assert(I != SymbolFlags.end() &&
378 "Resolving symbol outside this responsibility set");
379 if (I->second.isWeak())
380 assert(I->second == (KV.second.getFlags() | JITSymbolFlags::Weak) &&
381 "Resolving symbol with incorrect flags");
382 else
383 assert(I->second == KV.second.getFlags() &&
384 "Resolving symbol with incorrect flags");
385 }
386 #endif
387
388 JD.resolve(Symbols);
389 }
390
notifyEmitted()391 void MaterializationResponsibility::notifyEmitted() {
392
393 LLVM_DEBUG({
394 dbgs() << "In " << JD.getName() << " emitting " << SymbolFlags << "\n";
395 });
396
397 JD.emit(SymbolFlags);
398 SymbolFlags.clear();
399 }
400
defineMaterializing(const SymbolFlagsMap & NewSymbolFlags)401 Error MaterializationResponsibility::defineMaterializing(
402 const SymbolFlagsMap &NewSymbolFlags) {
403 // Add the given symbols to this responsibility object.
404 // It's ok if we hit a duplicate here: In that case the new version will be
405 // discarded, and the JITDylib::defineMaterializing method will return a
406 // duplicate symbol error.
407 for (auto &KV : NewSymbolFlags)
408 SymbolFlags.insert(KV);
409
410 return JD.defineMaterializing(NewSymbolFlags);
411 }
412
failMaterialization()413 void MaterializationResponsibility::failMaterialization() {
414
415 LLVM_DEBUG({
416 dbgs() << "In " << JD.getName() << " failing materialization for "
417 << SymbolFlags << "\n";
418 });
419
420 SymbolNameSet FailedSymbols;
421 for (auto &KV : SymbolFlags)
422 FailedSymbols.insert(KV.first);
423
424 JD.notifyFailed(FailedSymbols);
425 SymbolFlags.clear();
426 }
427
replace(std::unique_ptr<MaterializationUnit> MU)428 void MaterializationResponsibility::replace(
429 std::unique_ptr<MaterializationUnit> MU) {
430 for (auto &KV : MU->getSymbols())
431 SymbolFlags.erase(KV.first);
432
433 LLVM_DEBUG(JD.getExecutionSession().runSessionLocked([&]() {
434 dbgs() << "In " << JD.getName() << " replacing symbols with " << *MU
435 << "\n";
436 }););
437
438 JD.replace(std::move(MU));
439 }
440
441 MaterializationResponsibility
delegate(const SymbolNameSet & Symbols,VModuleKey NewKey)442 MaterializationResponsibility::delegate(const SymbolNameSet &Symbols,
443 VModuleKey NewKey) {
444
445 if (NewKey == VModuleKey())
446 NewKey = K;
447
448 SymbolFlagsMap DelegatedFlags;
449
450 for (auto &Name : Symbols) {
451 auto I = SymbolFlags.find(Name);
452 assert(I != SymbolFlags.end() &&
453 "Symbol is not tracked by this MaterializationResponsibility "
454 "instance");
455
456 DelegatedFlags[Name] = std::move(I->second);
457 SymbolFlags.erase(I);
458 }
459
460 return MaterializationResponsibility(JD, std::move(DelegatedFlags),
461 std::move(NewKey));
462 }
463
addDependencies(const SymbolStringPtr & Name,const SymbolDependenceMap & Dependencies)464 void MaterializationResponsibility::addDependencies(
465 const SymbolStringPtr &Name, const SymbolDependenceMap &Dependencies) {
466 assert(SymbolFlags.count(Name) &&
467 "Symbol not covered by this MaterializationResponsibility instance");
468 JD.addDependencies(Name, Dependencies);
469 }
470
addDependenciesForAll(const SymbolDependenceMap & Dependencies)471 void MaterializationResponsibility::addDependenciesForAll(
472 const SymbolDependenceMap &Dependencies) {
473 for (auto &KV : SymbolFlags)
474 JD.addDependencies(KV.first, Dependencies);
475 }
476
AbsoluteSymbolsMaterializationUnit(SymbolMap Symbols,VModuleKey K)477 AbsoluteSymbolsMaterializationUnit::AbsoluteSymbolsMaterializationUnit(
478 SymbolMap Symbols, VModuleKey K)
479 : MaterializationUnit(extractFlags(Symbols), std::move(K)),
480 Symbols(std::move(Symbols)) {}
481
getName() const482 StringRef AbsoluteSymbolsMaterializationUnit::getName() const {
483 return "<Absolute Symbols>";
484 }
485
materialize(MaterializationResponsibility R)486 void AbsoluteSymbolsMaterializationUnit::materialize(
487 MaterializationResponsibility R) {
488 R.notifyResolved(Symbols);
489 R.notifyEmitted();
490 }
491
discard(const JITDylib & JD,const SymbolStringPtr & Name)492 void AbsoluteSymbolsMaterializationUnit::discard(const JITDylib &JD,
493 const SymbolStringPtr &Name) {
494 assert(Symbols.count(Name) && "Symbol is not part of this MU");
495 Symbols.erase(Name);
496 }
497
498 SymbolFlagsMap
extractFlags(const SymbolMap & Symbols)499 AbsoluteSymbolsMaterializationUnit::extractFlags(const SymbolMap &Symbols) {
500 SymbolFlagsMap Flags;
501 for (const auto &KV : Symbols)
502 Flags[KV.first] = KV.second.getFlags();
503 return Flags;
504 }
505
ReExportsMaterializationUnit(JITDylib * SourceJD,bool MatchNonExported,SymbolAliasMap Aliases,VModuleKey K)506 ReExportsMaterializationUnit::ReExportsMaterializationUnit(
507 JITDylib *SourceJD, bool MatchNonExported, SymbolAliasMap Aliases,
508 VModuleKey K)
509 : MaterializationUnit(extractFlags(Aliases), std::move(K)),
510 SourceJD(SourceJD), MatchNonExported(MatchNonExported),
511 Aliases(std::move(Aliases)) {}
512
getName() const513 StringRef ReExportsMaterializationUnit::getName() const {
514 return "<Reexports>";
515 }
516
materialize(MaterializationResponsibility R)517 void ReExportsMaterializationUnit::materialize(
518 MaterializationResponsibility R) {
519
520 auto &ES = R.getTargetJITDylib().getExecutionSession();
521 JITDylib &TgtJD = R.getTargetJITDylib();
522 JITDylib &SrcJD = SourceJD ? *SourceJD : TgtJD;
523
524 // Find the set of requested aliases and aliasees. Return any unrequested
525 // aliases back to the JITDylib so as to not prematurely materialize any
526 // aliasees.
527 auto RequestedSymbols = R.getRequestedSymbols();
528 SymbolAliasMap RequestedAliases;
529
530 for (auto &Name : RequestedSymbols) {
531 auto I = Aliases.find(Name);
532 assert(I != Aliases.end() && "Symbol not found in aliases map?");
533 RequestedAliases[Name] = std::move(I->second);
534 Aliases.erase(I);
535 }
536
537 LLVM_DEBUG({
538 ES.runSessionLocked([&]() {
539 dbgs() << "materializing reexports: target = " << TgtJD.getName()
540 << ", source = " << SrcJD.getName() << " " << RequestedAliases
541 << "\n";
542 });
543 });
544
545 if (!Aliases.empty()) {
546 if (SourceJD)
547 R.replace(reexports(*SourceJD, std::move(Aliases), MatchNonExported));
548 else
549 R.replace(symbolAliases(std::move(Aliases)));
550 }
551
552 // The OnResolveInfo struct will hold the aliases and responsibilty for each
553 // query in the list.
554 struct OnResolveInfo {
555 OnResolveInfo(MaterializationResponsibility R, SymbolAliasMap Aliases)
556 : R(std::move(R)), Aliases(std::move(Aliases)) {}
557
558 MaterializationResponsibility R;
559 SymbolAliasMap Aliases;
560 };
561
562 // Build a list of queries to issue. In each round we build the largest set of
563 // aliases that we can resolve without encountering a chain definition of the
564 // form Foo -> Bar, Bar -> Baz. Such a form would deadlock as the query would
565 // be waitin on a symbol that it itself had to resolve. Usually this will just
566 // involve one round and a single query.
567
568 std::vector<std::pair<SymbolNameSet, std::shared_ptr<OnResolveInfo>>>
569 QueryInfos;
570 while (!RequestedAliases.empty()) {
571 SymbolNameSet ResponsibilitySymbols;
572 SymbolNameSet QuerySymbols;
573 SymbolAliasMap QueryAliases;
574
575 // Collect as many aliases as we can without including a chain.
576 for (auto &KV : RequestedAliases) {
577 // Chain detected. Skip this symbol for this round.
578 if (&SrcJD == &TgtJD && (QueryAliases.count(KV.second.Aliasee) ||
579 RequestedAliases.count(KV.second.Aliasee)))
580 continue;
581
582 ResponsibilitySymbols.insert(KV.first);
583 QuerySymbols.insert(KV.second.Aliasee);
584 QueryAliases[KV.first] = std::move(KV.second);
585 }
586
587 // Remove the aliases collected this round from the RequestedAliases map.
588 for (auto &KV : QueryAliases)
589 RequestedAliases.erase(KV.first);
590
591 assert(!QuerySymbols.empty() && "Alias cycle detected!");
592
593 auto QueryInfo = std::make_shared<OnResolveInfo>(
594 R.delegate(ResponsibilitySymbols), std::move(QueryAliases));
595 QueryInfos.push_back(
596 make_pair(std::move(QuerySymbols), std::move(QueryInfo)));
597 }
598
599 // Issue the queries.
600 while (!QueryInfos.empty()) {
601 auto QuerySymbols = std::move(QueryInfos.back().first);
602 auto QueryInfo = std::move(QueryInfos.back().second);
603
604 QueryInfos.pop_back();
605
606 auto RegisterDependencies = [QueryInfo,
607 &SrcJD](const SymbolDependenceMap &Deps) {
608 // If there were no materializing symbols, just bail out.
609 if (Deps.empty())
610 return;
611
612 // Otherwise the only deps should be on SrcJD.
613 assert(Deps.size() == 1 && Deps.count(&SrcJD) &&
614 "Unexpected dependencies for reexports");
615
616 auto &SrcJDDeps = Deps.find(&SrcJD)->second;
617 SymbolDependenceMap PerAliasDepsMap;
618 auto &PerAliasDeps = PerAliasDepsMap[&SrcJD];
619
620 for (auto &KV : QueryInfo->Aliases)
621 if (SrcJDDeps.count(KV.second.Aliasee)) {
622 PerAliasDeps = {KV.second.Aliasee};
623 QueryInfo->R.addDependencies(KV.first, PerAliasDepsMap);
624 }
625 };
626
627 auto OnComplete = [QueryInfo](Expected<SymbolMap> Result) {
628 if (Result) {
629 SymbolMap ResolutionMap;
630 for (auto &KV : QueryInfo->Aliases) {
631 assert(Result->count(KV.second.Aliasee) &&
632 "Result map missing entry?");
633 ResolutionMap[KV.first] = JITEvaluatedSymbol(
634 (*Result)[KV.second.Aliasee].getAddress(), KV.second.AliasFlags);
635 }
636 QueryInfo->R.notifyResolved(ResolutionMap);
637 QueryInfo->R.notifyEmitted();
638 } else {
639 auto &ES = QueryInfo->R.getTargetJITDylib().getExecutionSession();
640 ES.reportError(Result.takeError());
641 QueryInfo->R.failMaterialization();
642 }
643 };
644
645 ES.lookup(JITDylibSearchList({{&SrcJD, MatchNonExported}}), QuerySymbols,
646 SymbolState::Resolved, std::move(OnComplete),
647 std::move(RegisterDependencies));
648 }
649 }
650
discard(const JITDylib & JD,const SymbolStringPtr & Name)651 void ReExportsMaterializationUnit::discard(const JITDylib &JD,
652 const SymbolStringPtr &Name) {
653 assert(Aliases.count(Name) &&
654 "Symbol not covered by this MaterializationUnit");
655 Aliases.erase(Name);
656 }
657
658 SymbolFlagsMap
extractFlags(const SymbolAliasMap & Aliases)659 ReExportsMaterializationUnit::extractFlags(const SymbolAliasMap &Aliases) {
660 SymbolFlagsMap SymbolFlags;
661 for (auto &KV : Aliases)
662 SymbolFlags[KV.first] = KV.second.AliasFlags;
663
664 return SymbolFlags;
665 }
666
667 Expected<SymbolAliasMap>
buildSimpleReexportsAliasMap(JITDylib & SourceJD,const SymbolNameSet & Symbols)668 buildSimpleReexportsAliasMap(JITDylib &SourceJD, const SymbolNameSet &Symbols) {
669 auto Flags = SourceJD.lookupFlags(Symbols);
670
671 if (!Flags)
672 return Flags.takeError();
673
674 if (Flags->size() != Symbols.size()) {
675 SymbolNameSet Unresolved = Symbols;
676 for (auto &KV : *Flags)
677 Unresolved.erase(KV.first);
678 return make_error<SymbolsNotFound>(std::move(Unresolved));
679 }
680
681 SymbolAliasMap Result;
682 for (auto &Name : Symbols) {
683 assert(Flags->count(Name) && "Missing entry in flags map");
684 Result[Name] = SymbolAliasMapEntry(Name, (*Flags)[Name]);
685 }
686
687 return Result;
688 }
689
ReexportsGenerator(JITDylib & SourceJD,bool MatchNonExported,SymbolPredicate Allow)690 ReexportsGenerator::ReexportsGenerator(JITDylib &SourceJD,
691 bool MatchNonExported,
692 SymbolPredicate Allow)
693 : SourceJD(SourceJD), MatchNonExported(MatchNonExported),
694 Allow(std::move(Allow)) {}
695
696 Expected<SymbolNameSet>
operator ()(JITDylib & JD,const SymbolNameSet & Names)697 ReexportsGenerator::operator()(JITDylib &JD, const SymbolNameSet &Names) {
698 orc::SymbolNameSet Added;
699 orc::SymbolAliasMap AliasMap;
700
701 auto Flags = SourceJD.lookupFlags(Names);
702
703 if (!Flags)
704 return Flags.takeError();
705
706 for (auto &KV : *Flags) {
707 if (Allow && !Allow(KV.first))
708 continue;
709 AliasMap[KV.first] = SymbolAliasMapEntry(KV.first, KV.second);
710 Added.insert(KV.first);
711 }
712
713 if (!Added.empty())
714 cantFail(JD.define(reexports(SourceJD, AliasMap, MatchNonExported)));
715
716 return Added;
717 }
718
defineMaterializing(const SymbolFlagsMap & SymbolFlags)719 Error JITDylib::defineMaterializing(const SymbolFlagsMap &SymbolFlags) {
720 return ES.runSessionLocked([&]() -> Error {
721 std::vector<SymbolTable::iterator> AddedSyms;
722
723 for (auto &KV : SymbolFlags) {
724 SymbolTable::iterator EntryItr;
725 bool Added;
726
727 std::tie(EntryItr, Added) =
728 Symbols.insert(std::make_pair(KV.first, SymbolTableEntry(KV.second)));
729
730 if (Added) {
731 AddedSyms.push_back(EntryItr);
732 EntryItr->second.setState(SymbolState::Materializing);
733 } else {
734 // Remove any symbols already added.
735 for (auto &SI : AddedSyms)
736 Symbols.erase(SI);
737
738 // FIXME: Return all duplicates.
739 return make_error<DuplicateDefinition>(*KV.first);
740 }
741 }
742
743 return Error::success();
744 });
745 }
746
replace(std::unique_ptr<MaterializationUnit> MU)747 void JITDylib::replace(std::unique_ptr<MaterializationUnit> MU) {
748 assert(MU != nullptr && "Can not replace with a null MaterializationUnit");
749
750 auto MustRunMU =
751 ES.runSessionLocked([&, this]() -> std::unique_ptr<MaterializationUnit> {
752
753 #ifndef NDEBUG
754 for (auto &KV : MU->getSymbols()) {
755 auto SymI = Symbols.find(KV.first);
756 assert(SymI != Symbols.end() && "Replacing unknown symbol");
757 assert(SymI->second.isInMaterializationPhase() &&
758 "Can not call replace on a symbol that is not materializing");
759 assert(!SymI->second.hasMaterializerAttached() &&
760 "Symbol should not have materializer attached already");
761 assert(UnmaterializedInfos.count(KV.first) == 0 &&
762 "Symbol being replaced should have no UnmaterializedInfo");
763 }
764 #endif // NDEBUG
765
766 // If any symbol has pending queries against it then we need to
767 // materialize MU immediately.
768 for (auto &KV : MU->getSymbols()) {
769 auto MII = MaterializingInfos.find(KV.first);
770 if (MII != MaterializingInfos.end()) {
771 if (MII->second.hasQueriesPending())
772 return std::move(MU);
773 }
774 }
775
776 // Otherwise, make MU responsible for all the symbols.
777 auto UMI = std::make_shared<UnmaterializedInfo>(std::move(MU));
778 for (auto &KV : UMI->MU->getSymbols()) {
779 auto SymI = Symbols.find(KV.first);
780 assert(SymI->second.getState() == SymbolState::Materializing &&
781 "Can not replace a symbol that is not materializing");
782 assert(!SymI->second.hasMaterializerAttached() &&
783 "Can not replace a symbol that has a materializer attached");
784 assert(UnmaterializedInfos.count(KV.first) == 0 &&
785 "Unexpected materializer entry in map");
786 SymI->second.setAddress(SymI->second.getAddress());
787 SymI->second.setMaterializerAttached(true);
788 UnmaterializedInfos[KV.first] = UMI;
789 }
790
791 return nullptr;
792 });
793
794 if (MustRunMU)
795 ES.dispatchMaterialization(*this, std::move(MustRunMU));
796 }
797
798 SymbolNameSet
getRequestedSymbols(const SymbolFlagsMap & SymbolFlags) const799 JITDylib::getRequestedSymbols(const SymbolFlagsMap &SymbolFlags) const {
800 return ES.runSessionLocked([&]() {
801 SymbolNameSet RequestedSymbols;
802
803 for (auto &KV : SymbolFlags) {
804 assert(Symbols.count(KV.first) && "JITDylib does not cover this symbol?");
805 assert(Symbols.find(KV.first)->second.isInMaterializationPhase() &&
806 "getRequestedSymbols can only be called for symbols that have "
807 "started materializing");
808 auto I = MaterializingInfos.find(KV.first);
809 if (I == MaterializingInfos.end())
810 continue;
811
812 if (I->second.hasQueriesPending())
813 RequestedSymbols.insert(KV.first);
814 }
815
816 return RequestedSymbols;
817 });
818 }
819
addDependencies(const SymbolStringPtr & Name,const SymbolDependenceMap & Dependencies)820 void JITDylib::addDependencies(const SymbolStringPtr &Name,
821 const SymbolDependenceMap &Dependencies) {
822 assert(Symbols.count(Name) && "Name not in symbol table");
823 assert(Symbols[Name].isInMaterializationPhase() &&
824 "Can not add dependencies for a symbol that is not materializing");
825
826 auto &MI = MaterializingInfos[Name];
827 assert(!MI.IsEmitted && "Can not add dependencies to an emitted symbol");
828
829 for (auto &KV : Dependencies) {
830 assert(KV.first && "Null JITDylib in dependency?");
831 auto &OtherJITDylib = *KV.first;
832 auto &DepsOnOtherJITDylib = MI.UnemittedDependencies[&OtherJITDylib];
833
834 for (auto &OtherSymbol : KV.second) {
835 #ifndef NDEBUG
836 // Assert that this symbol exists and has not been emitted already.
837 auto SymI = OtherJITDylib.Symbols.find(OtherSymbol);
838 assert(SymI != OtherJITDylib.Symbols.end() &&
839 (SymI->second.getState() != SymbolState::Ready &&
840 "Dependency on emitted symbol"));
841 #endif
842
843 auto &OtherMI = OtherJITDylib.MaterializingInfos[OtherSymbol];
844
845 if (OtherMI.IsEmitted)
846 transferEmittedNodeDependencies(MI, Name, OtherMI);
847 else if (&OtherJITDylib != this || OtherSymbol != Name) {
848 OtherMI.Dependants[this].insert(Name);
849 DepsOnOtherJITDylib.insert(OtherSymbol);
850 }
851 }
852
853 if (DepsOnOtherJITDylib.empty())
854 MI.UnemittedDependencies.erase(&OtherJITDylib);
855 }
856 }
857
resolve(const SymbolMap & Resolved)858 void JITDylib::resolve(const SymbolMap &Resolved) {
859 auto CompletedQueries = ES.runSessionLocked([&, this]() {
860 AsynchronousSymbolQuerySet CompletedQueries;
861 for (const auto &KV : Resolved) {
862 auto &Name = KV.first;
863 auto Sym = KV.second;
864
865 auto I = Symbols.find(Name);
866
867 assert(I != Symbols.end() && "Symbol not found");
868 assert(!I->second.hasMaterializerAttached() &&
869 "Resolving symbol with materializer attached?");
870 assert(I->second.getState() == SymbolState::Materializing &&
871 "Symbol should be materializing");
872 assert(I->second.getAddress() == 0 && "Symbol has already been resolved");
873
874 assert((Sym.getFlags() & ~JITSymbolFlags::Weak) ==
875 (I->second.getFlags() & ~JITSymbolFlags::Weak) &&
876 "Resolved flags should match the declared flags");
877
878 // Once resolved, symbols can never be weak.
879 JITSymbolFlags ResolvedFlags = Sym.getFlags();
880 ResolvedFlags &= ~JITSymbolFlags::Weak;
881 I->second.setAddress(Sym.getAddress());
882 I->second.setFlags(ResolvedFlags);
883 I->second.setState(SymbolState::Resolved);
884
885 auto &MI = MaterializingInfos[Name];
886 for (auto &Q : MI.takeQueriesMeeting(SymbolState::Resolved)) {
887 Q->notifySymbolMetRequiredState(Name, Sym);
888 if (Q->isComplete())
889 CompletedQueries.insert(std::move(Q));
890 }
891 }
892
893 return CompletedQueries;
894 });
895
896 for (auto &Q : CompletedQueries) {
897 assert(Q->isComplete() && "Q not completed");
898 Q->handleComplete();
899 }
900 }
901
emit(const SymbolFlagsMap & Emitted)902 void JITDylib::emit(const SymbolFlagsMap &Emitted) {
903 auto CompletedQueries = ES.runSessionLocked([&, this]() {
904 AsynchronousSymbolQuerySet CompletedQueries;
905
906 for (const auto &KV : Emitted) {
907 const auto &Name = KV.first;
908
909 auto MII = MaterializingInfos.find(Name);
910 assert(MII != MaterializingInfos.end() &&
911 "Missing MaterializingInfo entry");
912
913 auto &MI = MII->second;
914
915 // For each dependant, transfer this node's emitted dependencies to
916 // it. If the dependant node is ready (i.e. has no unemitted
917 // dependencies) then notify any pending queries.
918 for (auto &KV : MI.Dependants) {
919 auto &DependantJD = *KV.first;
920 for (auto &DependantName : KV.second) {
921 auto DependantMII =
922 DependantJD.MaterializingInfos.find(DependantName);
923 assert(DependantMII != DependantJD.MaterializingInfos.end() &&
924 "Dependant should have MaterializingInfo");
925
926 auto &DependantMI = DependantMII->second;
927
928 // Remove the dependant's dependency on this node.
929 assert(DependantMI.UnemittedDependencies[this].count(Name) &&
930 "Dependant does not count this symbol as a dependency?");
931 DependantMI.UnemittedDependencies[this].erase(Name);
932 if (DependantMI.UnemittedDependencies[this].empty())
933 DependantMI.UnemittedDependencies.erase(this);
934
935 // Transfer unemitted dependencies from this node to the dependant.
936 DependantJD.transferEmittedNodeDependencies(DependantMI,
937 DependantName, MI);
938
939 // If the dependant is emitted and this node was the last of its
940 // unemitted dependencies then the dependant node is now ready, so
941 // notify any pending queries on the dependant node.
942 if (DependantMI.IsEmitted &&
943 DependantMI.UnemittedDependencies.empty()) {
944 assert(DependantMI.Dependants.empty() &&
945 "Dependants should be empty by now");
946
947 // Since this dependant is now ready, we erase its MaterializingInfo
948 // and update its materializing state.
949 auto DependantSymI = DependantJD.Symbols.find(DependantName);
950 assert(DependantSymI != DependantJD.Symbols.end() &&
951 "Dependant has no entry in the Symbols table");
952 DependantSymI->second.setState(SymbolState::Ready);
953
954 for (auto &Q : DependantMI.takeQueriesMeeting(SymbolState::Ready)) {
955 Q->notifySymbolMetRequiredState(
956 DependantName, DependantSymI->second.getSymbol());
957 if (Q->isComplete())
958 CompletedQueries.insert(Q);
959 Q->removeQueryDependence(DependantJD, DependantName);
960 }
961
962 DependantJD.MaterializingInfos.erase(DependantMII);
963 }
964 }
965 }
966 MI.Dependants.clear();
967 MI.IsEmitted = true;
968
969 if (MI.UnemittedDependencies.empty()) {
970 auto SymI = Symbols.find(Name);
971 assert(SymI != Symbols.end() && "Symbol has no entry in Symbols table");
972 SymI->second.setState(SymbolState::Ready);
973 for (auto &Q : MI.takeQueriesMeeting(SymbolState::Ready)) {
974 Q->notifySymbolMetRequiredState(Name, SymI->second.getSymbol());
975 if (Q->isComplete())
976 CompletedQueries.insert(Q);
977 Q->removeQueryDependence(*this, Name);
978 }
979 MaterializingInfos.erase(MII);
980 }
981 }
982
983 return CompletedQueries;
984 });
985
986 for (auto &Q : CompletedQueries) {
987 assert(Q->isComplete() && "Q is not complete");
988 Q->handleComplete();
989 }
990 }
991
notifyFailed(const SymbolNameSet & FailedSymbols)992 void JITDylib::notifyFailed(const SymbolNameSet &FailedSymbols) {
993
994 // FIXME: This should fail any transitively dependant symbols too.
995
996 auto FailedQueriesToNotify = ES.runSessionLocked([&, this]() {
997 AsynchronousSymbolQuerySet FailedQueries;
998 std::vector<MaterializingInfosMap::iterator> MIIsToRemove;
999
1000 for (auto &Name : FailedSymbols) {
1001 auto I = Symbols.find(Name);
1002 assert(I != Symbols.end() && "Symbol not present in this JITDylib");
1003 Symbols.erase(I);
1004
1005 auto MII = MaterializingInfos.find(Name);
1006
1007 // If we have not created a MaterializingInfo for this symbol yet then
1008 // there is nobody to notify.
1009 if (MII == MaterializingInfos.end())
1010 continue;
1011
1012 // Remove this symbol from the dependants list of any dependencies.
1013 for (auto &KV : MII->second.UnemittedDependencies) {
1014 auto *DependencyJD = KV.first;
1015 auto &Dependencies = KV.second;
1016 for (auto &DependencyName : Dependencies) {
1017 auto DependencyMII =
1018 DependencyJD->MaterializingInfos.find(DependencyName);
1019 assert(DependencyMII != DependencyJD->MaterializingInfos.end() &&
1020 "Unemitted dependency must have a MaterializingInfo entry");
1021 assert(DependencyMII->second.Dependants.count(this) &&
1022 "Dependency's dependants list does not contain this JITDylib");
1023 assert(DependencyMII->second.Dependants[this].count(Name) &&
1024 "Dependency's dependants list does not contain dependant");
1025 DependencyMII->second.Dependants[this].erase(Name);
1026 }
1027 }
1028
1029 // Copy all the queries to the FailedQueries list, then abandon them.
1030 // This has to be a copy, and the copy has to come before the abandon
1031 // operation: Each Q.detach() call will reach back into this
1032 // PendingQueries list to remove Q.
1033 for (auto &Q : MII->second.pendingQueries())
1034 FailedQueries.insert(Q);
1035
1036 MIIsToRemove.push_back(std::move(MII));
1037 }
1038
1039 // Detach failed queries.
1040 for (auto &Q : FailedQueries)
1041 Q->detach();
1042
1043 // Remove the MaterializingInfos.
1044 for (auto &MII : MIIsToRemove) {
1045 assert(!MII->second.hasQueriesPending() &&
1046 "Queries remain after symbol was failed");
1047
1048 MaterializingInfos.erase(MII);
1049 }
1050
1051 return FailedQueries;
1052 });
1053
1054 for (auto &Q : FailedQueriesToNotify)
1055 Q->handleFailed(make_error<FailedToMaterialize>(FailedSymbols));
1056 }
1057
setSearchOrder(JITDylibSearchList NewSearchOrder,bool SearchThisJITDylibFirst,bool MatchNonExportedInThisDylib)1058 void JITDylib::setSearchOrder(JITDylibSearchList NewSearchOrder,
1059 bool SearchThisJITDylibFirst,
1060 bool MatchNonExportedInThisDylib) {
1061 if (SearchThisJITDylibFirst) {
1062 if (NewSearchOrder.empty() || NewSearchOrder.front().first != this)
1063 NewSearchOrder.insert(NewSearchOrder.begin(),
1064 {this, MatchNonExportedInThisDylib});
1065 }
1066
1067 ES.runSessionLocked([&]() { SearchOrder = std::move(NewSearchOrder); });
1068 }
1069
addToSearchOrder(JITDylib & JD,bool MatchNonExported)1070 void JITDylib::addToSearchOrder(JITDylib &JD, bool MatchNonExported) {
1071 ES.runSessionLocked([&]() {
1072 SearchOrder.push_back({&JD, MatchNonExported});
1073 });
1074 }
1075
replaceInSearchOrder(JITDylib & OldJD,JITDylib & NewJD,bool MatchNonExported)1076 void JITDylib::replaceInSearchOrder(JITDylib &OldJD, JITDylib &NewJD,
1077 bool MatchNonExported) {
1078 ES.runSessionLocked([&]() {
1079 auto I = std::find_if(SearchOrder.begin(), SearchOrder.end(),
1080 [&](const JITDylibSearchList::value_type &KV) {
1081 return KV.first == &OldJD;
1082 });
1083
1084 if (I != SearchOrder.end())
1085 *I = {&NewJD, MatchNonExported};
1086 });
1087 }
1088
removeFromSearchOrder(JITDylib & JD)1089 void JITDylib::removeFromSearchOrder(JITDylib &JD) {
1090 ES.runSessionLocked([&]() {
1091 auto I = std::find_if(SearchOrder.begin(), SearchOrder.end(),
1092 [&](const JITDylibSearchList::value_type &KV) {
1093 return KV.first == &JD;
1094 });
1095 if (I != SearchOrder.end())
1096 SearchOrder.erase(I);
1097 });
1098 }
1099
remove(const SymbolNameSet & Names)1100 Error JITDylib::remove(const SymbolNameSet &Names) {
1101 return ES.runSessionLocked([&]() -> Error {
1102 using SymbolMaterializerItrPair =
1103 std::pair<SymbolTable::iterator, UnmaterializedInfosMap::iterator>;
1104 std::vector<SymbolMaterializerItrPair> SymbolsToRemove;
1105 SymbolNameSet Missing;
1106 SymbolNameSet Materializing;
1107
1108 for (auto &Name : Names) {
1109 auto I = Symbols.find(Name);
1110
1111 // Note symbol missing.
1112 if (I == Symbols.end()) {
1113 Missing.insert(Name);
1114 continue;
1115 }
1116
1117 // Note symbol materializing.
1118 if (I->second.isInMaterializationPhase()) {
1119 Materializing.insert(Name);
1120 continue;
1121 }
1122
1123 auto UMII = I->second.hasMaterializerAttached()
1124 ? UnmaterializedInfos.find(Name)
1125 : UnmaterializedInfos.end();
1126 SymbolsToRemove.push_back(std::make_pair(I, UMII));
1127 }
1128
1129 // If any of the symbols are not defined, return an error.
1130 if (!Missing.empty())
1131 return make_error<SymbolsNotFound>(std::move(Missing));
1132
1133 // If any of the symbols are currently materializing, return an error.
1134 if (!Materializing.empty())
1135 return make_error<SymbolsCouldNotBeRemoved>(std::move(Materializing));
1136
1137 // Remove the symbols.
1138 for (auto &SymbolMaterializerItrPair : SymbolsToRemove) {
1139 auto UMII = SymbolMaterializerItrPair.second;
1140
1141 // If there is a materializer attached, call discard.
1142 if (UMII != UnmaterializedInfos.end()) {
1143 UMII->second->MU->doDiscard(*this, UMII->first);
1144 UnmaterializedInfos.erase(UMII);
1145 }
1146
1147 auto SymI = SymbolMaterializerItrPair.first;
1148 Symbols.erase(SymI);
1149 }
1150
1151 return Error::success();
1152 });
1153 }
1154
lookupFlags(const SymbolNameSet & Names)1155 Expected<SymbolFlagsMap> JITDylib::lookupFlags(const SymbolNameSet &Names) {
1156 return ES.runSessionLocked([&, this]() -> Expected<SymbolFlagsMap> {
1157 SymbolFlagsMap Result;
1158 auto Unresolved = lookupFlagsImpl(Result, Names);
1159 if (!Unresolved)
1160 return Unresolved.takeError();
1161
1162 if (DefGenerator && !Unresolved->empty()) {
1163 auto NewDefs = DefGenerator(*this, *Unresolved);
1164 if (!NewDefs)
1165 return NewDefs.takeError();
1166 if (!NewDefs->empty()) {
1167 auto Unresolved2 = lookupFlagsImpl(Result, *NewDefs);
1168 if (!Unresolved2)
1169 return Unresolved2.takeError();
1170 (void)Unresolved2;
1171 assert(Unresolved2->empty() &&
1172 "All fallback defs should have been found by lookupFlagsImpl");
1173 }
1174 };
1175 return Result;
1176 });
1177 }
1178
lookupFlagsImpl(SymbolFlagsMap & Flags,const SymbolNameSet & Names)1179 Expected<SymbolNameSet> JITDylib::lookupFlagsImpl(SymbolFlagsMap &Flags,
1180 const SymbolNameSet &Names) {
1181 SymbolNameSet Unresolved;
1182
1183 for (auto &Name : Names) {
1184 auto I = Symbols.find(Name);
1185 if (I != Symbols.end()) {
1186 assert(!Flags.count(Name) && "Symbol already present in Flags map");
1187 Flags[Name] = I->second.getFlags();
1188 } else
1189 Unresolved.insert(Name);
1190 }
1191
1192 return Unresolved;
1193 }
1194
lodgeQuery(std::shared_ptr<AsynchronousSymbolQuery> & Q,SymbolNameSet & Unresolved,bool MatchNonExported,MaterializationUnitList & MUs)1195 Error JITDylib::lodgeQuery(std::shared_ptr<AsynchronousSymbolQuery> &Q,
1196 SymbolNameSet &Unresolved, bool MatchNonExported,
1197 MaterializationUnitList &MUs) {
1198 assert(Q && "Query can not be null");
1199
1200 lodgeQueryImpl(Q, Unresolved, MatchNonExported, MUs);
1201 if (DefGenerator && !Unresolved.empty()) {
1202 auto NewDefs = DefGenerator(*this, Unresolved);
1203 if (!NewDefs)
1204 return NewDefs.takeError();
1205 if (!NewDefs->empty()) {
1206 for (auto &D : *NewDefs)
1207 Unresolved.erase(D);
1208 lodgeQueryImpl(Q, *NewDefs, MatchNonExported, MUs);
1209 assert(NewDefs->empty() &&
1210 "All fallback defs should have been found by lookupImpl");
1211 }
1212 }
1213
1214 return Error::success();
1215 }
1216
lodgeQueryImpl(std::shared_ptr<AsynchronousSymbolQuery> & Q,SymbolNameSet & Unresolved,bool MatchNonExported,std::vector<std::unique_ptr<MaterializationUnit>> & MUs)1217 void JITDylib::lodgeQueryImpl(
1218 std::shared_ptr<AsynchronousSymbolQuery> &Q, SymbolNameSet &Unresolved,
1219 bool MatchNonExported,
1220 std::vector<std::unique_ptr<MaterializationUnit>> &MUs) {
1221
1222 std::vector<SymbolStringPtr> ToRemove;
1223 for (auto Name : Unresolved) {
1224
1225 // Search for the name in Symbols. Skip it if not found.
1226 auto SymI = Symbols.find(Name);
1227 if (SymI == Symbols.end())
1228 continue;
1229
1230 // If this is a non exported symbol and we're skipping those then skip it.
1231 if (!SymI->second.getFlags().isExported() && !MatchNonExported)
1232 continue;
1233
1234 // If we matched against Name in JD, mark it to be removed from the
1235 // Unresolved set.
1236 ToRemove.push_back(Name);
1237
1238 // If this symbol already meets the required state for then notify the
1239 // query and continue.
1240 if (SymI->second.getState() >= Q->getRequiredState()) {
1241 Q->notifySymbolMetRequiredState(Name, SymI->second.getSymbol());
1242 continue;
1243 }
1244
1245 // Otherwise this symbol does not yet meet the required state. Check whether
1246 // it has a materializer attached, and if so prepare to run it.
1247 if (SymI->second.hasMaterializerAttached()) {
1248 assert(SymI->second.getAddress() == 0 &&
1249 "Symbol not resolved but already has address?");
1250 auto UMII = UnmaterializedInfos.find(Name);
1251 assert(UMII != UnmaterializedInfos.end() &&
1252 "Lazy symbol should have UnmaterializedInfo");
1253 auto MU = std::move(UMII->second->MU);
1254 assert(MU != nullptr && "Materializer should not be null");
1255
1256 // Move all symbols associated with this MaterializationUnit into
1257 // materializing state.
1258 for (auto &KV : MU->getSymbols()) {
1259 auto SymK = Symbols.find(KV.first);
1260 SymK->second.setMaterializerAttached(false);
1261 SymK->second.setState(SymbolState::Materializing);
1262 UnmaterializedInfos.erase(KV.first);
1263 }
1264
1265 // Add MU to the list of MaterializationUnits to be materialized.
1266 MUs.push_back(std::move(MU));
1267 }
1268
1269 // Add the query to the PendingQueries list.
1270 assert(SymI->second.isInMaterializationPhase() &&
1271 "By this line the symbol should be materializing");
1272 auto &MI = MaterializingInfos[Name];
1273 MI.addQuery(Q);
1274 Q->addQueryDependence(*this, Name);
1275 }
1276
1277 // Remove any symbols that we found.
1278 for (auto &Name : ToRemove)
1279 Unresolved.erase(Name);
1280 }
1281
1282 Expected<SymbolNameSet>
legacyLookup(std::shared_ptr<AsynchronousSymbolQuery> Q,SymbolNameSet Names)1283 JITDylib::legacyLookup(std::shared_ptr<AsynchronousSymbolQuery> Q,
1284 SymbolNameSet Names) {
1285 assert(Q && "Query can not be null");
1286
1287 ES.runOutstandingMUs();
1288
1289 bool QueryComplete = false;
1290 std::vector<std::unique_ptr<MaterializationUnit>> MUs;
1291
1292 SymbolNameSet Unresolved = std::move(Names);
1293 auto Err = ES.runSessionLocked([&, this]() -> Error {
1294 QueryComplete = lookupImpl(Q, MUs, Unresolved);
1295 if (DefGenerator && !Unresolved.empty()) {
1296 assert(!QueryComplete && "query complete but unresolved symbols remain?");
1297 auto NewDefs = DefGenerator(*this, Unresolved);
1298 if (!NewDefs)
1299 return NewDefs.takeError();
1300 if (!NewDefs->empty()) {
1301 for (auto &D : *NewDefs)
1302 Unresolved.erase(D);
1303 QueryComplete = lookupImpl(Q, MUs, *NewDefs);
1304 assert(NewDefs->empty() &&
1305 "All fallback defs should have been found by lookupImpl");
1306 }
1307 }
1308 return Error::success();
1309 });
1310
1311 if (Err)
1312 return std::move(Err);
1313
1314 assert((MUs.empty() || !QueryComplete) &&
1315 "If action flags are set, there should be no work to do (so no MUs)");
1316
1317 if (QueryComplete)
1318 Q->handleComplete();
1319
1320 // FIXME: Swap back to the old code below once RuntimeDyld works with
1321 // callbacks from asynchronous queries.
1322 // Add MUs to the OutstandingMUs list.
1323 {
1324 std::lock_guard<std::recursive_mutex> Lock(ES.OutstandingMUsMutex);
1325 for (auto &MU : MUs)
1326 ES.OutstandingMUs.push_back(make_pair(this, std::move(MU)));
1327 }
1328 ES.runOutstandingMUs();
1329
1330 // Dispatch any required MaterializationUnits for materialization.
1331 // for (auto &MU : MUs)
1332 // ES.dispatchMaterialization(*this, std::move(MU));
1333
1334 return Unresolved;
1335 }
1336
lookupImpl(std::shared_ptr<AsynchronousSymbolQuery> & Q,std::vector<std::unique_ptr<MaterializationUnit>> & MUs,SymbolNameSet & Unresolved)1337 bool JITDylib::lookupImpl(
1338 std::shared_ptr<AsynchronousSymbolQuery> &Q,
1339 std::vector<std::unique_ptr<MaterializationUnit>> &MUs,
1340 SymbolNameSet &Unresolved) {
1341 bool QueryComplete = false;
1342
1343 std::vector<SymbolStringPtr> ToRemove;
1344 for (auto Name : Unresolved) {
1345
1346 // Search for the name in Symbols. Skip it if not found.
1347 auto SymI = Symbols.find(Name);
1348 if (SymI == Symbols.end())
1349 continue;
1350
1351 // If we found Name, mark it to be removed from the Unresolved set.
1352 ToRemove.push_back(Name);
1353
1354 if (SymI->second.getState() >= Q->getRequiredState()) {
1355 Q->notifySymbolMetRequiredState(Name, SymI->second.getSymbol());
1356 if (Q->isComplete())
1357 QueryComplete = true;
1358 continue;
1359 }
1360
1361 // If the symbol is lazy, get the MaterialiaztionUnit for it.
1362 if (SymI->second.hasMaterializerAttached()) {
1363 assert(SymI->second.getAddress() == 0 &&
1364 "Lazy symbol should not have a resolved address");
1365 auto UMII = UnmaterializedInfos.find(Name);
1366 assert(UMII != UnmaterializedInfos.end() &&
1367 "Lazy symbol should have UnmaterializedInfo");
1368 auto MU = std::move(UMII->second->MU);
1369 assert(MU != nullptr && "Materializer should not be null");
1370
1371 // Kick all symbols associated with this MaterializationUnit into
1372 // materializing state.
1373 for (auto &KV : MU->getSymbols()) {
1374 auto SymK = Symbols.find(KV.first);
1375 assert(SymK != Symbols.end() && "Missing symbol table entry");
1376 SymK->second.setState(SymbolState::Materializing);
1377 SymK->second.setMaterializerAttached(false);
1378 UnmaterializedInfos.erase(KV.first);
1379 }
1380
1381 // Add MU to the list of MaterializationUnits to be materialized.
1382 MUs.push_back(std::move(MU));
1383 }
1384
1385 // Add the query to the PendingQueries list.
1386 assert(SymI->second.isInMaterializationPhase() &&
1387 "By this line the symbol should be materializing");
1388 auto &MI = MaterializingInfos[Name];
1389 MI.addQuery(Q);
1390 Q->addQueryDependence(*this, Name);
1391 }
1392
1393 // Remove any marked symbols from the Unresolved set.
1394 for (auto &Name : ToRemove)
1395 Unresolved.erase(Name);
1396
1397 return QueryComplete;
1398 }
1399
dump(raw_ostream & OS)1400 void JITDylib::dump(raw_ostream &OS) {
1401 ES.runSessionLocked([&, this]() {
1402 OS << "JITDylib \"" << JITDylibName << "\" (ES: "
1403 << format("0x%016" PRIx64, reinterpret_cast<uintptr_t>(&ES)) << "):\n"
1404 << "Search order: [";
1405 for (auto &KV : SearchOrder)
1406 OS << " (\"" << KV.first->getName() << "\", "
1407 << (KV.second ? "all" : "exported only") << ")";
1408 OS << " ]\n"
1409 << "Symbol table:\n";
1410
1411 for (auto &KV : Symbols) {
1412 OS << " \"" << *KV.first << "\": ";
1413 if (auto Addr = KV.second.getAddress())
1414 OS << format("0x%016" PRIx64, Addr) << ", " << KV.second.getFlags()
1415 << " ";
1416 else
1417 OS << "<not resolved> ";
1418
1419 OS << KV.second.getState();
1420
1421 if (KV.second.hasMaterializerAttached()) {
1422 OS << " (Materializer ";
1423 auto I = UnmaterializedInfos.find(KV.first);
1424 assert(I != UnmaterializedInfos.end() &&
1425 "Lazy symbol should have UnmaterializedInfo");
1426 OS << I->second->MU.get() << ")\n";
1427 } else
1428 OS << "\n";
1429 }
1430
1431 if (!MaterializingInfos.empty())
1432 OS << " MaterializingInfos entries:\n";
1433 for (auto &KV : MaterializingInfos) {
1434 OS << " \"" << *KV.first << "\":\n"
1435 << " IsEmitted = " << (KV.second.IsEmitted ? "true" : "false")
1436 << "\n"
1437 << " " << KV.second.pendingQueries().size()
1438 << " pending queries: { ";
1439 for (const auto &Q : KV.second.pendingQueries())
1440 OS << Q.get() << " (" << Q->getRequiredState() << ") ";
1441 OS << "}\n Dependants:\n";
1442 for (auto &KV2 : KV.second.Dependants)
1443 OS << " " << KV2.first->getName() << ": " << KV2.second << "\n";
1444 OS << " Unemitted Dependencies:\n";
1445 for (auto &KV2 : KV.second.UnemittedDependencies)
1446 OS << " " << KV2.first->getName() << ": " << KV2.second << "\n";
1447 }
1448 });
1449 }
1450
addQuery(std::shared_ptr<AsynchronousSymbolQuery> Q)1451 void JITDylib::MaterializingInfo::addQuery(
1452 std::shared_ptr<AsynchronousSymbolQuery> Q) {
1453
1454 auto I = std::lower_bound(
1455 PendingQueries.rbegin(), PendingQueries.rend(), Q->getRequiredState(),
1456 [](const std::shared_ptr<AsynchronousSymbolQuery> &V, SymbolState S) {
1457 return V->getRequiredState() <= S;
1458 });
1459 PendingQueries.insert(I.base(), std::move(Q));
1460 }
1461
removeQuery(const AsynchronousSymbolQuery & Q)1462 void JITDylib::MaterializingInfo::removeQuery(
1463 const AsynchronousSymbolQuery &Q) {
1464 // FIXME: Implement 'find_as' for shared_ptr<T>/T*.
1465 auto I =
1466 std::find_if(PendingQueries.begin(), PendingQueries.end(),
1467 [&Q](const std::shared_ptr<AsynchronousSymbolQuery> &V) {
1468 return V.get() == &Q;
1469 });
1470 assert(I != PendingQueries.end() &&
1471 "Query is not attached to this MaterializingInfo");
1472 PendingQueries.erase(I);
1473 }
1474
1475 JITDylib::AsynchronousSymbolQueryList
takeQueriesMeeting(SymbolState RequiredState)1476 JITDylib::MaterializingInfo::takeQueriesMeeting(SymbolState RequiredState) {
1477 AsynchronousSymbolQueryList Result;
1478 while (!PendingQueries.empty()) {
1479 if (PendingQueries.back()->getRequiredState() > RequiredState)
1480 break;
1481
1482 Result.push_back(std::move(PendingQueries.back()));
1483 PendingQueries.pop_back();
1484 }
1485
1486 return Result;
1487 }
1488
1489 JITDylib::AsynchronousSymbolQueryList
takeAllQueries()1490 JITDylib::MaterializingInfo::takeAllQueries() {
1491 AsynchronousSymbolQueryList Result;
1492 std::swap(Result, PendingQueries);
1493 return Result;
1494 }
1495
JITDylib(ExecutionSession & ES,std::string Name)1496 JITDylib::JITDylib(ExecutionSession &ES, std::string Name)
1497 : ES(ES), JITDylibName(std::move(Name)) {
1498 SearchOrder.push_back({this, true});
1499 }
1500
defineImpl(MaterializationUnit & MU)1501 Error JITDylib::defineImpl(MaterializationUnit &MU) {
1502 SymbolNameSet Duplicates;
1503 std::vector<SymbolStringPtr> ExistingDefsOverridden;
1504 std::vector<SymbolStringPtr> MUDefsOverridden;
1505
1506 for (const auto &KV : MU.getSymbols()) {
1507 auto I = Symbols.find(KV.first);
1508
1509 if (I != Symbols.end()) {
1510 if (KV.second.isStrong()) {
1511 if (I->second.getFlags().isStrong() ||
1512 I->second.getState() > SymbolState::NeverSearched)
1513 Duplicates.insert(KV.first);
1514 else {
1515 assert(I->second.getState() == SymbolState::NeverSearched &&
1516 "Overridden existing def should be in the never-searched "
1517 "state");
1518 ExistingDefsOverridden.push_back(KV.first);
1519 }
1520 } else
1521 MUDefsOverridden.push_back(KV.first);
1522 }
1523 }
1524
1525 // If there were any duplicate definitions then bail out.
1526 if (!Duplicates.empty())
1527 return make_error<DuplicateDefinition>(**Duplicates.begin());
1528
1529 // Discard any overridden defs in this MU.
1530 for (auto &S : MUDefsOverridden)
1531 MU.doDiscard(*this, S);
1532
1533 // Discard existing overridden defs.
1534 for (auto &S : ExistingDefsOverridden) {
1535
1536 auto UMII = UnmaterializedInfos.find(S);
1537 assert(UMII != UnmaterializedInfos.end() &&
1538 "Overridden existing def should have an UnmaterializedInfo");
1539 UMII->second->MU->doDiscard(*this, S);
1540 }
1541
1542 // Finally, add the defs from this MU.
1543 for (auto &KV : MU.getSymbols()) {
1544 auto &SymEntry = Symbols[KV.first];
1545 SymEntry.setFlags(KV.second);
1546 SymEntry.setState(SymbolState::NeverSearched);
1547 SymEntry.setMaterializerAttached(true);
1548 }
1549
1550 return Error::success();
1551 }
1552
detachQueryHelper(AsynchronousSymbolQuery & Q,const SymbolNameSet & QuerySymbols)1553 void JITDylib::detachQueryHelper(AsynchronousSymbolQuery &Q,
1554 const SymbolNameSet &QuerySymbols) {
1555 for (auto &QuerySymbol : QuerySymbols) {
1556 assert(MaterializingInfos.count(QuerySymbol) &&
1557 "QuerySymbol does not have MaterializingInfo");
1558 auto &MI = MaterializingInfos[QuerySymbol];
1559 MI.removeQuery(Q);
1560 }
1561 }
1562
transferEmittedNodeDependencies(MaterializingInfo & DependantMI,const SymbolStringPtr & DependantName,MaterializingInfo & EmittedMI)1563 void JITDylib::transferEmittedNodeDependencies(
1564 MaterializingInfo &DependantMI, const SymbolStringPtr &DependantName,
1565 MaterializingInfo &EmittedMI) {
1566 for (auto &KV : EmittedMI.UnemittedDependencies) {
1567 auto &DependencyJD = *KV.first;
1568 SymbolNameSet *UnemittedDependenciesOnDependencyJD = nullptr;
1569
1570 for (auto &DependencyName : KV.second) {
1571 auto &DependencyMI = DependencyJD.MaterializingInfos[DependencyName];
1572
1573 // Do not add self dependencies.
1574 if (&DependencyMI == &DependantMI)
1575 continue;
1576
1577 // If we haven't looked up the dependencies for DependencyJD yet, do it
1578 // now and cache the result.
1579 if (!UnemittedDependenciesOnDependencyJD)
1580 UnemittedDependenciesOnDependencyJD =
1581 &DependantMI.UnemittedDependencies[&DependencyJD];
1582
1583 DependencyMI.Dependants[this].insert(DependantName);
1584 UnemittedDependenciesOnDependencyJD->insert(DependencyName);
1585 }
1586 }
1587 }
1588
ExecutionSession(std::shared_ptr<SymbolStringPool> SSP)1589 ExecutionSession::ExecutionSession(std::shared_ptr<SymbolStringPool> SSP)
1590 : SSP(SSP ? std::move(SSP) : std::make_shared<SymbolStringPool>()) {
1591 // Construct the main dylib.
1592 JDs.push_back(std::unique_ptr<JITDylib>(new JITDylib(*this, "<main>")));
1593 }
1594
getMainJITDylib()1595 JITDylib &ExecutionSession::getMainJITDylib() {
1596 return runSessionLocked([this]() -> JITDylib & { return *JDs.front(); });
1597 }
1598
getJITDylibByName(StringRef Name)1599 JITDylib *ExecutionSession::getJITDylibByName(StringRef Name) {
1600 return runSessionLocked([&, this]() -> JITDylib * {
1601 for (auto &JD : JDs)
1602 if (JD->getName() == Name)
1603 return JD.get();
1604 return nullptr;
1605 });
1606 }
1607
createJITDylib(std::string Name,bool AddToMainDylibSearchOrder)1608 JITDylib &ExecutionSession::createJITDylib(std::string Name,
1609 bool AddToMainDylibSearchOrder) {
1610 assert(!getJITDylibByName(Name) && "JITDylib with that name already exists");
1611 return runSessionLocked([&, this]() -> JITDylib & {
1612 JDs.push_back(
1613 std::unique_ptr<JITDylib>(new JITDylib(*this, std::move(Name))));
1614 if (AddToMainDylibSearchOrder)
1615 JDs.front()->addToSearchOrder(*JDs.back());
1616 return *JDs.back();
1617 });
1618 }
1619
legacyFailQuery(AsynchronousSymbolQuery & Q,Error Err)1620 void ExecutionSession::legacyFailQuery(AsynchronousSymbolQuery &Q, Error Err) {
1621 assert(!!Err && "Error should be in failure state");
1622
1623 bool SendErrorToQuery;
1624 runSessionLocked([&]() {
1625 Q.detach();
1626 SendErrorToQuery = Q.canStillFail();
1627 });
1628
1629 if (SendErrorToQuery)
1630 Q.handleFailed(std::move(Err));
1631 else
1632 reportError(std::move(Err));
1633 }
1634
legacyLookup(LegacyAsyncLookupFunction AsyncLookup,SymbolNameSet Names,SymbolState RequiredState,RegisterDependenciesFunction RegisterDependencies)1635 Expected<SymbolMap> ExecutionSession::legacyLookup(
1636 LegacyAsyncLookupFunction AsyncLookup, SymbolNameSet Names,
1637 SymbolState RequiredState,
1638 RegisterDependenciesFunction RegisterDependencies) {
1639 #if LLVM_ENABLE_THREADS
1640 // In the threaded case we use promises to return the results.
1641 std::promise<SymbolMap> PromisedResult;
1642 Error ResolutionError = Error::success();
1643 auto NotifyComplete = [&](Expected<SymbolMap> R) {
1644 if (R)
1645 PromisedResult.set_value(std::move(*R));
1646 else {
1647 ErrorAsOutParameter _(&ResolutionError);
1648 ResolutionError = R.takeError();
1649 PromisedResult.set_value(SymbolMap());
1650 }
1651 };
1652 #else
1653 SymbolMap Result;
1654 Error ResolutionError = Error::success();
1655
1656 auto NotifyComplete = [&](Expected<SymbolMap> R) {
1657 ErrorAsOutParameter _(&ResolutionError);
1658 if (R)
1659 Result = std::move(*R);
1660 else
1661 ResolutionError = R.takeError();
1662 };
1663 #endif
1664
1665 auto Query = std::make_shared<AsynchronousSymbolQuery>(
1666 Names, RequiredState, std::move(NotifyComplete));
1667 // FIXME: This should be run session locked along with the registration code
1668 // and error reporting below.
1669 SymbolNameSet UnresolvedSymbols = AsyncLookup(Query, std::move(Names));
1670
1671 // If the query was lodged successfully then register the dependencies,
1672 // otherwise fail it with an error.
1673 if (UnresolvedSymbols.empty())
1674 RegisterDependencies(Query->QueryRegistrations);
1675 else {
1676 bool DeliverError = runSessionLocked([&]() {
1677 Query->detach();
1678 return Query->canStillFail();
1679 });
1680 auto Err = make_error<SymbolsNotFound>(std::move(UnresolvedSymbols));
1681 if (DeliverError)
1682 Query->handleFailed(std::move(Err));
1683 else
1684 reportError(std::move(Err));
1685 }
1686
1687 #if LLVM_ENABLE_THREADS
1688 auto ResultFuture = PromisedResult.get_future();
1689 auto Result = ResultFuture.get();
1690 if (ResolutionError)
1691 return std::move(ResolutionError);
1692 return std::move(Result);
1693
1694 #else
1695 if (ResolutionError)
1696 return std::move(ResolutionError);
1697
1698 return Result;
1699 #endif
1700 }
1701
lookup(const JITDylibSearchList & SearchOrder,SymbolNameSet Symbols,SymbolState RequiredState,SymbolsResolvedCallback NotifyComplete,RegisterDependenciesFunction RegisterDependencies)1702 void ExecutionSession::lookup(
1703 const JITDylibSearchList &SearchOrder, SymbolNameSet Symbols,
1704 SymbolState RequiredState, SymbolsResolvedCallback NotifyComplete,
1705 RegisterDependenciesFunction RegisterDependencies) {
1706
1707 LLVM_DEBUG({
1708 runSessionLocked([&]() {
1709 dbgs() << "Looking up " << Symbols << " in " << SearchOrder
1710 << " (required state: " << RequiredState << ")\n";
1711 });
1712 });
1713
1714 // lookup can be re-entered recursively if running on a single thread. Run any
1715 // outstanding MUs in case this query depends on them, otherwise this lookup
1716 // will starve waiting for a result from an MU that is stuck in the queue.
1717 runOutstandingMUs();
1718
1719 auto Unresolved = std::move(Symbols);
1720 std::map<JITDylib *, MaterializationUnitList> CollectedMUsMap;
1721 auto Q = std::make_shared<AsynchronousSymbolQuery>(Unresolved, RequiredState,
1722 std::move(NotifyComplete));
1723 bool QueryComplete = false;
1724
1725 auto LodgingErr = runSessionLocked([&]() -> Error {
1726 auto LodgeQuery = [&]() -> Error {
1727 for (auto &KV : SearchOrder) {
1728 assert(KV.first && "JITDylibList entries must not be null");
1729 assert(!CollectedMUsMap.count(KV.first) &&
1730 "JITDylibList should not contain duplicate entries");
1731
1732 auto &JD = *KV.first;
1733 auto MatchNonExported = KV.second;
1734 if (auto Err = JD.lodgeQuery(Q, Unresolved, MatchNonExported,
1735 CollectedMUsMap[&JD]))
1736 return Err;
1737 }
1738
1739 if (!Unresolved.empty())
1740 return make_error<SymbolsNotFound>(std::move(Unresolved));
1741
1742 return Error::success();
1743 };
1744
1745 if (auto Err = LodgeQuery()) {
1746 // Query failed.
1747
1748 // Disconnect the query from its dependencies.
1749 Q->detach();
1750
1751 // Replace the MUs.
1752 for (auto &KV : CollectedMUsMap)
1753 for (auto &MU : KV.second)
1754 KV.first->replace(std::move(MU));
1755
1756 return Err;
1757 }
1758
1759 // Query lodged successfully.
1760
1761 // Record whether this query is fully ready / resolved. We will use
1762 // this to call handleFullyResolved/handleFullyReady outside the session
1763 // lock.
1764 QueryComplete = Q->isComplete();
1765
1766 // Call the register dependencies function.
1767 if (RegisterDependencies && !Q->QueryRegistrations.empty())
1768 RegisterDependencies(Q->QueryRegistrations);
1769
1770 return Error::success();
1771 });
1772
1773 if (LodgingErr) {
1774 Q->handleFailed(std::move(LodgingErr));
1775 return;
1776 }
1777
1778 if (QueryComplete)
1779 Q->handleComplete();
1780
1781 // Move the MUs to the OutstandingMUs list, then materialize.
1782 {
1783 std::lock_guard<std::recursive_mutex> Lock(OutstandingMUsMutex);
1784
1785 for (auto &KV : CollectedMUsMap)
1786 for (auto &MU : KV.second)
1787 OutstandingMUs.push_back(std::make_pair(KV.first, std::move(MU)));
1788 }
1789
1790 runOutstandingMUs();
1791 }
1792
1793 Expected<SymbolMap>
lookup(const JITDylibSearchList & SearchOrder,const SymbolNameSet & Symbols,SymbolState RequiredState,RegisterDependenciesFunction RegisterDependencies)1794 ExecutionSession::lookup(const JITDylibSearchList &SearchOrder,
1795 const SymbolNameSet &Symbols,
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<SymbolMap> PromisedResult;
1801 Error ResolutionError = Error::success();
1802
1803 auto NotifyComplete = [&](Expected<SymbolMap> R) {
1804 if (R)
1805 PromisedResult.set_value(std::move(*R));
1806 else {
1807 ErrorAsOutParameter _(&ResolutionError);
1808 ResolutionError = R.takeError();
1809 PromisedResult.set_value(SymbolMap());
1810 }
1811 };
1812
1813 #else
1814 SymbolMap Result;
1815 Error ResolutionError = Error::success();
1816
1817 auto NotifyComplete = [&](Expected<SymbolMap> R) {
1818 ErrorAsOutParameter _(&ResolutionError);
1819 if (R)
1820 Result = std::move(*R);
1821 else
1822 ResolutionError = R.takeError();
1823 };
1824 #endif
1825
1826 // Perform the asynchronous lookup.
1827 lookup(SearchOrder, Symbols, RequiredState, NotifyComplete,
1828 RegisterDependencies);
1829
1830 #if LLVM_ENABLE_THREADS
1831 auto ResultFuture = PromisedResult.get_future();
1832 auto Result = ResultFuture.get();
1833
1834 if (ResolutionError)
1835 return std::move(ResolutionError);
1836
1837 return std::move(Result);
1838
1839 #else
1840 if (ResolutionError)
1841 return std::move(ResolutionError);
1842
1843 return Result;
1844 #endif
1845 }
1846
1847 Expected<JITEvaluatedSymbol>
lookup(const JITDylibSearchList & SearchOrder,SymbolStringPtr Name)1848 ExecutionSession::lookup(const JITDylibSearchList &SearchOrder,
1849 SymbolStringPtr Name) {
1850 SymbolNameSet Names({Name});
1851
1852 if (auto ResultMap = lookup(SearchOrder, std::move(Names), SymbolState::Ready,
1853 NoDependenciesToRegister)) {
1854 assert(ResultMap->size() == 1 && "Unexpected number of results");
1855 assert(ResultMap->count(Name) && "Missing result for symbol");
1856 return std::move(ResultMap->begin()->second);
1857 } else
1858 return ResultMap.takeError();
1859 }
1860
1861 Expected<JITEvaluatedSymbol>
lookup(ArrayRef<JITDylib * > SearchOrder,SymbolStringPtr Name)1862 ExecutionSession::lookup(ArrayRef<JITDylib *> SearchOrder,
1863 SymbolStringPtr Name) {
1864 SymbolNameSet Names({Name});
1865
1866 JITDylibSearchList FullSearchOrder;
1867 FullSearchOrder.reserve(SearchOrder.size());
1868 for (auto *JD : SearchOrder)
1869 FullSearchOrder.push_back({JD, false});
1870
1871 return lookup(FullSearchOrder, Name);
1872 }
1873
1874 Expected<JITEvaluatedSymbol>
lookup(ArrayRef<JITDylib * > SearchOrder,StringRef Name)1875 ExecutionSession::lookup(ArrayRef<JITDylib *> SearchOrder, StringRef Name) {
1876 return lookup(SearchOrder, intern(Name));
1877 }
1878
dump(raw_ostream & OS)1879 void ExecutionSession::dump(raw_ostream &OS) {
1880 runSessionLocked([this, &OS]() {
1881 for (auto &JD : JDs)
1882 JD->dump(OS);
1883 });
1884 }
1885
runOutstandingMUs()1886 void ExecutionSession::runOutstandingMUs() {
1887 while (1) {
1888 std::pair<JITDylib *, std::unique_ptr<MaterializationUnit>> JITDylibAndMU;
1889
1890 {
1891 std::lock_guard<std::recursive_mutex> Lock(OutstandingMUsMutex);
1892 if (!OutstandingMUs.empty()) {
1893 JITDylibAndMU = std::move(OutstandingMUs.back());
1894 OutstandingMUs.pop_back();
1895 }
1896 }
1897
1898 if (JITDylibAndMU.first) {
1899 assert(JITDylibAndMU.second && "JITDylib, but no MU?");
1900 dispatchMaterialization(*JITDylibAndMU.first,
1901 std::move(JITDylibAndMU.second));
1902 } else
1903 break;
1904 }
1905 }
1906
MangleAndInterner(ExecutionSession & ES,const DataLayout & DL)1907 MangleAndInterner::MangleAndInterner(ExecutionSession &ES, const DataLayout &DL)
1908 : ES(ES), DL(DL) {}
1909
operator ()(StringRef Name)1910 SymbolStringPtr MangleAndInterner::operator()(StringRef Name) {
1911 std::string MangledName;
1912 {
1913 raw_string_ostream MangledNameStream(MangledName);
1914 Mangler::getNameWithPrefix(MangledNameStream, Name, DL);
1915 }
1916 return ES.intern(MangledName);
1917 }
1918
1919 } // End namespace orc.
1920 } // End namespace llvm.
1921