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