1 //===----- Core.cpp - Core ORC APIs (MaterializationUnit, VSO, etc.) ------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "llvm/ExecutionEngine/Orc/Core.h"
11 #include "llvm/Config/llvm-config.h"
12 #include "llvm/ExecutionEngine/Orc/OrcError.h"
13 #include "llvm/Support/Format.h"
14 
15 #if LLVM_ENABLE_THREADS
16 #include <future>
17 #endif
18 
19 namespace llvm {
20 namespace orc {
21 
22 char FailedToMaterialize::ID = 0;
23 char SymbolsNotFound::ID = 0;
24 
25 void MaterializationUnit::anchor() {}
26 void SymbolResolver::anchor() {}
27 
28 raw_ostream &operator<<(raw_ostream &OS, const JITSymbolFlags &Flags) {
29   if (Flags.isWeak())
30     OS << 'W';
31   else if (Flags.isCommon())
32     OS << 'C';
33   else
34     OS << 'S';
35 
36   if (Flags.isExported())
37     OS << 'E';
38   else
39     OS << 'H';
40 
41   return OS;
42 }
43 
44 raw_ostream &operator<<(raw_ostream &OS, const JITEvaluatedSymbol &Sym) {
45   OS << format("0x%016x", Sym.getAddress()) << " " << Sym.getFlags();
46   return OS;
47 }
48 
49 raw_ostream &operator<<(raw_ostream &OS, const SymbolMap::value_type &KV) {
50   OS << "\"" << *KV.first << "\": " << KV.second;
51   return OS;
52 }
53 
54 raw_ostream &operator<<(raw_ostream &OS, const SymbolNameSet &Symbols) {
55   OS << "{";
56   if (!Symbols.empty()) {
57     OS << " \"" << **Symbols.begin() << "\"";
58     for (auto &Sym : make_range(std::next(Symbols.begin()), Symbols.end()))
59       OS << ", \"" << *Sym << "\"";
60   }
61   OS << " }";
62   return OS;
63 }
64 
65 raw_ostream &operator<<(raw_ostream &OS, const SymbolMap &Symbols) {
66   OS << "{";
67   if (!Symbols.empty()) {
68     OS << " {" << *Symbols.begin() << "}";
69     for (auto &Sym : make_range(std::next(Symbols.begin()), Symbols.end()))
70       OS << ", {" << Sym << "}";
71   }
72   OS << " }";
73   return OS;
74 }
75 
76 raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap &SymbolFlags) {
77   OS << "{";
78   if (!SymbolFlags.empty()) {
79     OS << " {\"" << *SymbolFlags.begin()->first
80        << "\": " << SymbolFlags.begin()->second << "}";
81     for (auto &KV :
82          make_range(std::next(SymbolFlags.begin()), SymbolFlags.end()))
83       OS << ", {\"" << *KV.first << "\": " << KV.second << "}";
84   }
85   OS << " }";
86   return OS;
87 }
88 
89 raw_ostream &operator<<(raw_ostream &OS, const SymbolDependenceMap &Deps) {
90   OS << "{";
91   if (!Deps.empty()) {
92     OS << " { " << Deps.begin()->first->getName() << ": "
93        << Deps.begin()->second << " }";
94     for (auto &KV : make_range(std::next(Deps.begin()), Deps.end()))
95       OS << ", { " << KV.first->getName() << ": " << KV.second << " }";
96   }
97   OS << " }";
98   return OS;
99 }
100 
101 FailedToMaterialize::FailedToMaterialize(SymbolNameSet Symbols)
102     : Symbols(std::move(Symbols)) {
103   assert(!this->Symbols.empty() && "Can not fail to resolve an empty set");
104 }
105 
106 std::error_code FailedToMaterialize::convertToErrorCode() const {
107   return orcError(OrcErrorCode::UnknownORCError);
108 }
109 
110 void FailedToMaterialize::log(raw_ostream &OS) const {
111   OS << "Failed to materialize symbols: " << Symbols;
112 }
113 
114 SymbolsNotFound::SymbolsNotFound(SymbolNameSet Symbols)
115     : Symbols(std::move(Symbols)) {
116   assert(!this->Symbols.empty() && "Can not fail to resolve an empty set");
117 }
118 
119 std::error_code SymbolsNotFound::convertToErrorCode() const {
120   return orcError(OrcErrorCode::UnknownORCError);
121 }
122 
123 void SymbolsNotFound::log(raw_ostream &OS) const {
124   OS << "Symbols not found: " << Symbols;
125 }
126 
127 void ExecutionSessionBase::failQuery(AsynchronousSymbolQuery &Q, Error Err) {
128   bool DeliveredError = true;
129   runSessionLocked([&]() -> void {
130     Q.detach();
131     if (Q.canStillFail())
132       Q.handleFailed(std::move(Err));
133     else
134       DeliveredError = false;
135   });
136 
137   if (!DeliveredError)
138     reportError(std::move(Err));
139 }
140 
141 AsynchronousSymbolQuery::AsynchronousSymbolQuery(
142     const SymbolNameSet &Symbols, SymbolsResolvedCallback NotifySymbolsResolved,
143     SymbolsReadyCallback NotifySymbolsReady)
144     : NotifySymbolsResolved(std::move(NotifySymbolsResolved)),
145       NotifySymbolsReady(std::move(NotifySymbolsReady)) {
146   NotYetResolvedCount = NotYetReadyCount = Symbols.size();
147 
148   for (auto &S : Symbols)
149     ResolvedSymbols[S] = nullptr;
150 }
151 
152 void AsynchronousSymbolQuery::resolve(const SymbolStringPtr &Name,
153                                       JITEvaluatedSymbol Sym) {
154   auto I = ResolvedSymbols.find(Name);
155   assert(I != ResolvedSymbols.end() &&
156          "Resolving symbol outside the requested set");
157   assert(I->second.getAddress() == 0 && "Redundantly resolving symbol Name");
158   I->second = std::move(Sym);
159   --NotYetResolvedCount;
160 }
161 
162 void AsynchronousSymbolQuery::handleFullyResolved() {
163   assert(NotYetResolvedCount == 0 && "Not fully resolved?");
164   assert(NotifySymbolsResolved &&
165          "NotifySymbolsResolved already called or error occurred");
166   NotifySymbolsResolved(
167       ResolutionResult(std::move(ResolvedSymbols), QueryRegistrations));
168   NotifySymbolsResolved = SymbolsResolvedCallback();
169 }
170 
171 void AsynchronousSymbolQuery::notifySymbolReady() {
172   assert(NotYetReadyCount != 0 && "All symbols already finalized");
173   --NotYetReadyCount;
174 }
175 
176 void AsynchronousSymbolQuery::handleFullyReady() {
177   assert(QueryRegistrations.empty() &&
178          "Query is still registered with some symbols");
179   assert(!NotifySymbolsResolved && "Resolution not applied yet");
180   NotifySymbolsReady(Error::success());
181   NotifySymbolsReady = SymbolsReadyCallback();
182 }
183 
184 bool AsynchronousSymbolQuery::canStillFail() {
185   return (NotifySymbolsResolved || NotifySymbolsReady);
186 }
187 
188 void AsynchronousSymbolQuery::handleFailed(Error Err) {
189   assert(QueryRegistrations.empty() && ResolvedSymbols.empty() &&
190          NotYetResolvedCount == 0 && NotYetReadyCount == 0 &&
191          "Query should already have been abandoned");
192   if (NotifySymbolsResolved)
193     NotifySymbolsResolved(std::move(Err));
194   else {
195     assert(NotifySymbolsReady && "Failed after both callbacks issued?");
196     NotifySymbolsReady(std::move(Err));
197     NotifySymbolsReady = SymbolsReadyCallback();
198   }
199 }
200 
201 void AsynchronousSymbolQuery::addQueryDependence(VSO &V, SymbolStringPtr Name) {
202   bool Added = QueryRegistrations[&V].insert(std::move(Name)).second;
203   (void)Added;
204   assert(Added && "Duplicate dependence notification?");
205 }
206 
207 void AsynchronousSymbolQuery::removeQueryDependence(
208     VSO &V, const SymbolStringPtr &Name) {
209   auto QRI = QueryRegistrations.find(&V);
210   assert(QRI != QueryRegistrations.end() && "No dependencies registered for V");
211   assert(QRI->second.count(Name) && "No dependency on Name in V");
212   QRI->second.erase(Name);
213   if (QRI->second.empty())
214     QueryRegistrations.erase(QRI);
215 }
216 
217 void AsynchronousSymbolQuery::detach() {
218   ResolvedSymbols.clear();
219   NotYetResolvedCount = 0;
220   NotYetReadyCount = 0;
221   for (auto &KV : QueryRegistrations)
222     KV.first->detachQueryHelper(*this, KV.second);
223   QueryRegistrations.clear();
224 }
225 
226 MaterializationResponsibility::MaterializationResponsibility(
227     VSO &V, SymbolFlagsMap SymbolFlags)
228     : V(V), SymbolFlags(std::move(SymbolFlags)) {
229   assert(!this->SymbolFlags.empty() && "Materializing nothing?");
230 
231   for (auto &KV : this->SymbolFlags)
232     KV.second |= JITSymbolFlags::Materializing;
233 }
234 
235 MaterializationResponsibility::~MaterializationResponsibility() {
236   assert(SymbolFlags.empty() &&
237          "All symbols should have been explicitly materialized or failed");
238 }
239 
240 void MaterializationResponsibility::resolve(const SymbolMap &Symbols) {
241   for (auto &KV : Symbols) {
242     auto I = SymbolFlags.find(KV.first);
243     assert(I != SymbolFlags.end() &&
244            "Resolving symbol outside this responsibility set");
245     assert(I->second.isMaterializing() && "Duplicate resolution");
246     I->second &= ~JITSymbolFlags::Materializing;
247     assert(KV.second.getFlags() == I->second &&
248            "Resolving symbol with incorrect flags");
249   }
250 
251   V.resolve(Symbols);
252 }
253 
254 void MaterializationResponsibility::finalize() {
255 #ifndef NDEBUG
256   for (auto &KV : SymbolFlags)
257     assert(!KV.second.isMaterializing() &&
258            "Failed to resolve symbol before finalization");
259 #endif // NDEBUG
260 
261   V.finalize(SymbolFlags);
262   SymbolFlags.clear();
263 }
264 
265 Error MaterializationResponsibility::defineMaterializing(
266     const SymbolFlagsMap &NewSymbolFlags) {
267   // Add the given symbols to this responsibility object.
268   // It's ok if we hit a duplicate here: In that case the new version will be
269   // discarded, and the VSO::defineMaterializing method will return a duplicate
270   // symbol error.
271   for (auto &KV : NewSymbolFlags) {
272     auto I = SymbolFlags.insert(KV).first;
273     I->second |= JITSymbolFlags::Materializing;
274   }
275 
276   return V.defineMaterializing(NewSymbolFlags);
277 }
278 
279 void MaterializationResponsibility::failMaterialization() {
280 
281   SymbolNameSet FailedSymbols;
282   for (auto &KV : SymbolFlags)
283     FailedSymbols.insert(KV.first);
284 
285   V.notifyFailed(FailedSymbols);
286   SymbolFlags.clear();
287 }
288 
289 void MaterializationResponsibility::delegate(
290     std::unique_ptr<MaterializationUnit> MU) {
291   for (auto &KV : MU->getSymbols())
292     SymbolFlags.erase(KV.first);
293 
294   V.replace(std::move(MU));
295 }
296 
297 void MaterializationResponsibility::addDependencies(
298     const SymbolDependenceMap &Dependencies) {
299   V.addDependencies(SymbolFlags, Dependencies);
300 }
301 
302 AbsoluteSymbolsMaterializationUnit::AbsoluteSymbolsMaterializationUnit(
303     SymbolMap Symbols)
304     : MaterializationUnit(extractFlags(Symbols)), Symbols(std::move(Symbols)) {}
305 
306 void AbsoluteSymbolsMaterializationUnit::materialize(
307     MaterializationResponsibility R) {
308   R.resolve(Symbols);
309   R.finalize();
310 }
311 
312 void AbsoluteSymbolsMaterializationUnit::discard(const VSO &V,
313                                                  SymbolStringPtr Name) {
314   assert(Symbols.count(Name) && "Symbol is not part of this MU");
315   Symbols.erase(Name);
316 }
317 
318 SymbolFlagsMap
319 AbsoluteSymbolsMaterializationUnit::extractFlags(const SymbolMap &Symbols) {
320   SymbolFlagsMap Flags;
321   for (const auto &KV : Symbols)
322     Flags[KV.first] = KV.second.getFlags();
323   return Flags;
324 }
325 
326 Error VSO::defineMaterializing(const SymbolFlagsMap &SymbolFlags) {
327   return ES.runSessionLocked([&]() -> Error {
328     std::vector<SymbolMap::iterator> AddedSyms;
329 
330     for (auto &KV : SymbolFlags) {
331       SymbolMap::iterator EntryItr;
332       bool Added;
333 
334       auto NewFlags = KV.second;
335       NewFlags |= JITSymbolFlags::Materializing;
336 
337       std::tie(EntryItr, Added) = Symbols.insert(
338           std::make_pair(KV.first, JITEvaluatedSymbol(0, NewFlags)));
339 
340       if (Added)
341         AddedSyms.push_back(EntryItr);
342       else {
343         // Remove any symbols already added.
344         for (auto &SI : AddedSyms)
345           Symbols.erase(SI);
346 
347         // FIXME: Return all duplicates.
348         return make_error<DuplicateDefinition>(*KV.first);
349       }
350     }
351 
352     return Error::success();
353   });
354 }
355 
356 void VSO::replace(std::unique_ptr<MaterializationUnit> MU) {
357   assert(MU != nullptr && "Can not replace with a null MaterializationUnit");
358 
359   auto MustRunMU =
360       ES.runSessionLocked([&, this]() -> std::unique_ptr<MaterializationUnit> {
361 
362 #ifndef NDEBUG
363         for (auto &KV : MU->getSymbols()) {
364           auto SymI = Symbols.find(KV.first);
365           assert(SymI != Symbols.end() && "Replacing unknown symbol");
366           assert(!SymI->second.getFlags().isLazy() &&
367                  SymI->second.getFlags().isMaterializing() &&
368                  "Can not replace symbol that is not materializing");
369           assert(UnmaterializedInfos.count(KV.first) == 0 &&
370                  "Symbol being replaced should have no UnmaterializedInfo");
371           assert(MaterializingInfos.count(KV.first) &&
372                  "Symbol being replaced should have a MaterializingInfo");
373         }
374 #endif // NDEBUG
375 
376         // If any symbol has pending queries against it then we need to
377         // materialize MU immediately.
378         for (auto &KV : MU->getSymbols())
379           if (!MaterializingInfos[KV.first].PendingQueries.empty())
380             return std::move(MU);
381 
382         // Otherwise, make MU responsible for all the symbols.
383         auto UMI = std::make_shared<UnmaterializedInfo>(std::move(MU));
384         for (auto &KV : UMI->MU->getSymbols()) {
385           assert(!KV.second.isLazy() &&
386                  "Lazy flag should be managed internally.");
387           assert(!KV.second.isMaterializing() &&
388                  "Materializing flags should be managed internally.");
389 
390           auto SymI = Symbols.find(KV.first);
391           SymI->second.getFlags() = KV.second;
392           SymI->second.getFlags() |= JITSymbolFlags::Lazy;
393           UnmaterializedInfos[KV.first] = UMI;
394         }
395 
396         return nullptr;
397       });
398 
399   if (MustRunMU)
400     ES.dispatchMaterialization(*this, std::move(MustRunMU));
401 }
402 
403 void VSO::addDependencies(const SymbolFlagsMap &Dependants,
404                           const SymbolDependenceMap &Dependencies) {
405   ES.runSessionLocked([&, this]() {
406     for (auto &KV : Dependants) {
407       const auto &Name = KV.first;
408       assert(Symbols.count(Name) && "Name not in symbol table");
409       assert((Symbols[Name].getFlags().isLazy() ||
410               Symbols[Name].getFlags().isMaterializing()) &&
411              "Symbol is not lazy or materializing");
412 
413       auto &MI = MaterializingInfos[Name];
414       assert(!MI.IsFinalized && "Can not add dependencies to finalized symbol");
415 
416       for (auto &KV : Dependencies) {
417         assert(KV.first && "Null VSO in dependency?");
418         auto &OtherVSO = *KV.first;
419         auto &DepsOnOtherVSO = MI.UnfinalizedDependencies[&OtherVSO];
420 
421         for (auto &OtherSymbol : KV.second) {
422           auto &OtherMI = OtherVSO.MaterializingInfos[OtherSymbol];
423 
424           if (OtherMI.IsFinalized)
425             transferFinalizedNodeDependencies(MI, Name, OtherMI);
426           else {
427             OtherMI.Dependants[this].insert(Name);
428             DepsOnOtherVSO.insert(OtherSymbol);
429           }
430         }
431       }
432     }
433   });
434 }
435 
436 void VSO::resolve(const SymbolMap &Resolved) {
437   auto FullyResolvedQueries = ES.runSessionLocked([&, this]() {
438     AsynchronousSymbolQuerySet FullyResolvedQueries;
439     for (const auto &KV : Resolved) {
440       auto &Name = KV.first;
441       auto Sym = KV.second;
442 
443       assert(!Sym.getFlags().isLazy() && !Sym.getFlags().isMaterializing() &&
444              "Materializing flags should be managed internally");
445 
446       auto I = Symbols.find(Name);
447 
448       assert(I != Symbols.end() && "Symbol not found");
449       assert(!I->second.getFlags().isLazy() &&
450              I->second.getFlags().isMaterializing() &&
451              "Symbol should be materializing");
452       assert(I->second.getAddress() == 0 && "Symbol has already been resolved");
453 
454       assert(Sym.getFlags() ==
455                  JITSymbolFlags::stripTransientFlags(I->second.getFlags()) &&
456              "Resolved flags should match the declared flags");
457 
458       // Once resolved, symbols can never be weak.
459       JITSymbolFlags ResolvedFlags = Sym.getFlags();
460       ResolvedFlags &= ~JITSymbolFlags::Weak;
461       ResolvedFlags |= JITSymbolFlags::Materializing;
462       I->second = JITEvaluatedSymbol(Sym.getAddress(), ResolvedFlags);
463 
464       auto &MI = MaterializingInfos[Name];
465       for (auto &Q : MI.PendingQueries) {
466         Q->resolve(Name, Sym);
467         if (Q->isFullyResolved())
468           FullyResolvedQueries.insert(Q);
469       }
470     }
471 
472     return FullyResolvedQueries;
473   });
474 
475   for (auto &Q : FullyResolvedQueries) {
476     assert(Q->isFullyResolved() && "Q not fully resolved");
477     Q->handleFullyResolved();
478   }
479 }
480 
481 void VSO::finalize(const SymbolFlagsMap &Finalized) {
482   auto FullyReadyQueries = ES.runSessionLocked([&, this]() {
483     AsynchronousSymbolQuerySet ReadyQueries;
484 
485     for (const auto &KV : Finalized) {
486       const auto &Name = KV.first;
487 
488       auto MII = MaterializingInfos.find(Name);
489       assert(MII != MaterializingInfos.end() &&
490              "Missing MaterializingInfo entry");
491 
492       auto &MI = MII->second;
493 
494       // For each dependant, transfer this node's unfinalized dependencies to
495       // it. If the dependant node is fully finalized then notify any pending
496       // queries.
497       for (auto &KV : MI.Dependants) {
498         auto &DependantVSO = *KV.first;
499         for (auto &DependantName : KV.second) {
500           auto DependantMII =
501               DependantVSO.MaterializingInfos.find(DependantName);
502           assert(DependantMII != DependantVSO.MaterializingInfos.end() &&
503                  "Dependant should have MaterializingInfo");
504 
505           auto &DependantMI = DependantMII->second;
506 
507           // Remove the dependant's dependency on this node.
508           assert(DependantMI.UnfinalizedDependencies[this].count(Name) &&
509                  "Dependant does not count this symbol as a dependency?");
510           DependantMI.UnfinalizedDependencies[this].erase(Name);
511           if (DependantMI.UnfinalizedDependencies[this].empty())
512             DependantMI.UnfinalizedDependencies.erase(this);
513 
514           // Transfer unfinalized dependencies from this node to the dependant.
515           DependantVSO.transferFinalizedNodeDependencies(DependantMI,
516                                                          DependantName, MI);
517 
518           // If the dependant is finalized and this node was the last of its
519           // unfinalized dependencies then notify any pending queries on the
520           // dependant node.
521           if (DependantMI.IsFinalized &&
522               DependantMI.UnfinalizedDependencies.empty()) {
523             assert(DependantMI.Dependants.empty() &&
524                    "Dependants should be empty by now");
525             for (auto &Q : DependantMI.PendingQueries) {
526               Q->notifySymbolReady();
527               if (Q->isFullyReady())
528                 ReadyQueries.insert(Q);
529               Q->removeQueryDependence(DependantVSO, DependantName);
530             }
531 
532             // If this dependant node was fully finalized we can erase its
533             // MaterializingInfo and update its materializing state.
534             assert(DependantVSO.Symbols.count(DependantName) &&
535                    "Dependant has no entry in the Symbols table");
536             DependantVSO.Symbols[DependantName].getFlags() &=
537                 JITSymbolFlags::Materializing;
538             DependantVSO.MaterializingInfos.erase(DependantMII);
539           }
540         }
541       }
542       MI.Dependants.clear();
543       MI.IsFinalized = true;
544 
545       if (MI.UnfinalizedDependencies.empty()) {
546         for (auto &Q : MI.PendingQueries) {
547           Q->notifySymbolReady();
548           if (Q->isFullyReady())
549             ReadyQueries.insert(Q);
550           Q->removeQueryDependence(*this, Name);
551         }
552         assert(Symbols.count(Name) &&
553                "Symbol has no entry in the Symbols table");
554         Symbols[Name].getFlags() &= ~JITSymbolFlags::Materializing;
555         MaterializingInfos.erase(MII);
556       }
557     }
558 
559     return ReadyQueries;
560   });
561 
562   for (auto &Q : FullyReadyQueries) {
563     assert(Q->isFullyReady() && "Q is not fully ready");
564     Q->handleFullyReady();
565   }
566 }
567 
568 void VSO::notifyFailed(const SymbolNameSet &FailedSymbols) {
569 
570   // FIXME: This should fail any transitively dependant symbols too.
571 
572   auto FailedQueriesToNotify = ES.runSessionLocked([&, this]() {
573     AsynchronousSymbolQuerySet FailedQueries;
574 
575     for (auto &Name : FailedSymbols) {
576       auto I = Symbols.find(Name);
577       assert(I != Symbols.end() && "Symbol not present in this VSO");
578       Symbols.erase(I);
579 
580       auto MII = MaterializingInfos.find(Name);
581 
582       // If we have not created a MaterializingInfo for this symbol yet then
583       // there is nobody to notify.
584       if (MII == MaterializingInfos.end())
585         continue;
586 
587       // Copy all the queries to the FailedQueries list, then abandon them.
588       // This has to be a copy, and the copy has to come before the abandon
589       // operation: Each Q.detach() call will reach back into this
590       // PendingQueries list to remove Q.
591       for (auto &Q : MII->second.PendingQueries)
592         FailedQueries.insert(Q);
593 
594       for (auto &Q : FailedQueries)
595         Q->detach();
596 
597       assert(MII->second.PendingQueries.empty() &&
598              "Queries remain after symbol was failed");
599 
600       MaterializingInfos.erase(MII);
601     }
602 
603     return FailedQueries;
604   });
605 
606   for (auto &Q : FailedQueriesToNotify)
607     Q->handleFailed(make_error<FailedToMaterialize>(FailedSymbols));
608 }
609 
610 SymbolNameSet VSO::lookupFlags(SymbolFlagsMap &Flags,
611                                const SymbolNameSet &Names) {
612   return ES.runSessionLocked([&, this]() {
613     SymbolNameSet Unresolved;
614 
615     for (auto &Name : Names) {
616       auto I = Symbols.find(Name);
617       if (I == Symbols.end()) {
618         Unresolved.insert(Name);
619         continue;
620       }
621 
622       assert(!Flags.count(Name) && "Symbol already present in Flags map");
623       Flags[Name] = JITSymbolFlags::stripTransientFlags(I->second.getFlags());
624     }
625 
626     return Unresolved;
627   });
628 }
629 
630 SymbolNameSet VSO::lookup(std::shared_ptr<AsynchronousSymbolQuery> Q,
631                           SymbolNameSet Names) {
632   SymbolNameSet Unresolved = std::move(Names);
633   std::vector<std::unique_ptr<MaterializationUnit>> MUs;
634 
635   ES.runSessionLocked([&, this]() {
636     for (auto I = Unresolved.begin(), E = Unresolved.end(); I != E;) {
637       auto TmpI = I++;
638       auto Name = *TmpI;
639 
640       // Search for the name in Symbols. Skip it if not found.
641       auto SymI = Symbols.find(Name);
642       if (SymI == Symbols.end())
643         continue;
644 
645       // If we found Name in V, remove it frome the Unresolved set and add it
646       // to the dependencies set.
647       Unresolved.erase(TmpI);
648 
649       // If the symbol has an address then resolve it.
650       if (SymI->second.getAddress() != 0)
651         Q->resolve(Name, SymI->second);
652 
653       // If the symbol is lazy, get the MaterialiaztionUnit for it.
654       if (SymI->second.getFlags().isLazy()) {
655         assert(SymI->second.getAddress() == 0 &&
656                "Lazy symbol should not have a resolved address");
657         assert(!SymI->second.getFlags().isMaterializing() &&
658                "Materializing and lazy should not both be set");
659         auto UMII = UnmaterializedInfos.find(Name);
660         assert(UMII != UnmaterializedInfos.end() &&
661                "Lazy symbol should have UnmaterializedInfo");
662         auto MU = std::move(UMII->second->MU);
663         assert(MU != nullptr && "Materializer should not be null");
664 
665         // Kick all symbols associated with this MaterializationUnit into
666         // materializing state.
667         for (auto &KV : MU->getSymbols()) {
668           auto SymK = Symbols.find(KV.first);
669           auto Flags = SymK->second.getFlags();
670           Flags &= ~JITSymbolFlags::Lazy;
671           Flags |= JITSymbolFlags::Materializing;
672           SymK->second.setFlags(Flags);
673           UnmaterializedInfos.erase(KV.first);
674         }
675 
676         // Add MU to the list of MaterializationUnits to be materialized.
677         MUs.push_back(std::move(MU));
678       } else if (!SymI->second.getFlags().isMaterializing()) {
679         // The symbol is neither lazy nor materializing. Finalize it and
680         // continue.
681         Q->notifySymbolReady();
682         continue;
683       }
684 
685       // Add the query to the PendingQueries list.
686       assert(SymI->second.getFlags().isMaterializing() &&
687              "By this line the symbol should be materializing");
688       auto &MI = MaterializingInfos[Name];
689       MI.PendingQueries.push_back(Q);
690       Q->addQueryDependence(*this, Name);
691     }
692   });
693 
694   if (Q->isFullyResolved())
695     Q->handleFullyResolved();
696 
697   if (Q->isFullyReady())
698     Q->handleFullyReady();
699 
700   // Dispatch any required MaterializationUnits for materialization.
701   for (auto &MU : MUs)
702     ES.dispatchMaterialization(*this, std::move(MU));
703 
704   return Unresolved;
705 }
706 
707 void VSO::dump(raw_ostream &OS) {
708   ES.runSessionLocked([&, this]() {
709     OS << "VSO \"" << VSOName
710        << "\" (ES: " << format("0x%016x", reinterpret_cast<uintptr_t>(&ES))
711        << "):\n"
712        << "Symbol table:\n";
713 
714     for (auto &KV : Symbols) {
715       OS << "    \"" << *KV.first << "\": " << KV.second.getAddress();
716       if (KV.second.getFlags().isLazy() ||
717           KV.second.getFlags().isMaterializing()) {
718         OS << " (";
719         if (KV.second.getFlags().isLazy()) {
720           auto I = UnmaterializedInfos.find(KV.first);
721           assert(I != UnmaterializedInfos.end() &&
722                  "Lazy symbol should have UnmaterializedInfo");
723           OS << " Lazy (MU=" << I->second->MU.get() << ")";
724         }
725         if (KV.second.getFlags().isMaterializing())
726           OS << " Materializing";
727         OS << " )\n";
728       } else
729         OS << "\n";
730     }
731 
732     if (!MaterializingInfos.empty())
733       OS << "  MaterializingInfos entries:\n";
734     for (auto &KV : MaterializingInfos) {
735       OS << "    \"" << *KV.first << "\":\n"
736          << "      IsFinalized = " << (KV.second.IsFinalized ? "true" : "false")
737          << "\n"
738          << "      " << KV.second.PendingQueries.size() << " pending queries.\n"
739          << "      Dependants:\n";
740       for (auto &KV2 : KV.second.Dependants)
741         OS << "        " << KV2.first->getName() << ": " << KV2.second << "\n";
742       OS << "      Unfinalized Dependencies:\n";
743       for (auto &KV2 : KV.second.UnfinalizedDependencies)
744         OS << "        " << KV2.first->getName() << ": " << KV2.second << "\n";
745     }
746   });
747 }
748 
749 Error VSO::defineImpl(MaterializationUnit &MU) {
750   SymbolNameSet Duplicates;
751   SymbolNameSet MUDefsOverridden;
752   std::vector<SymbolMap::iterator> ExistingDefsOverridden;
753   for (auto &KV : MU.getSymbols()) {
754     assert(!KV.second.isLazy() && "Lazy flag should be managed internally.");
755     assert(!KV.second.isMaterializing() &&
756            "Materializing flags should be managed internally.");
757 
758     SymbolMap::iterator EntryItr;
759     bool Added;
760 
761     auto NewFlags = KV.second;
762     NewFlags |= JITSymbolFlags::Lazy;
763 
764     std::tie(EntryItr, Added) = Symbols.insert(
765         std::make_pair(KV.first, JITEvaluatedSymbol(0, NewFlags)));
766 
767     if (!Added) {
768       if (KV.second.isStrong()) {
769         if (EntryItr->second.getFlags().isStrong())
770           Duplicates.insert(KV.first);
771         else
772           ExistingDefsOverridden.push_back(EntryItr);
773       } else
774         MUDefsOverridden.insert(KV.first);
775     }
776   }
777 
778   if (!Duplicates.empty()) {
779     // We need to remove the symbols we added.
780     for (auto &KV : MU.getSymbols()) {
781       if (Duplicates.count(KV.first) || Duplicates.count(KV.first))
782         continue;
783 
784       bool Found = false;
785       for (const auto &I : ExistingDefsOverridden)
786         if (I->first == KV.first)
787           Found = true;
788 
789       if (!Found)
790         Symbols.erase(KV.first);
791     }
792 
793     // FIXME: Return all duplicates.
794     return make_error<DuplicateDefinition>(**Duplicates.begin());
795   }
796 
797   // Update flags on existing defs and call discard on their materializers.
798   for (auto &ExistingDefItr : ExistingDefsOverridden) {
799     assert(ExistingDefItr->second.getFlags().isLazy() &&
800            !ExistingDefItr->second.getFlags().isMaterializing() &&
801            "Overridden existing def should be in the Lazy state");
802 
803     ExistingDefItr->second.getFlags() &= ~JITSymbolFlags::Weak;
804 
805     auto UMII = UnmaterializedInfos.find(ExistingDefItr->first);
806     assert(UMII != UnmaterializedInfos.end() &&
807            "Overridden existing def should have an UnmaterializedInfo");
808 
809     UMII->second->MU->doDiscard(*this, ExistingDefItr->first);
810   }
811 
812   // Discard overridden symbols povided by MU.
813   for (auto &Sym : MUDefsOverridden)
814     MU.doDiscard(*this, Sym);
815 
816   return Error::success();
817 }
818 
819 void VSO::detachQueryHelper(AsynchronousSymbolQuery &Q,
820                             const SymbolNameSet &QuerySymbols) {
821   for (auto &QuerySymbol : QuerySymbols) {
822     assert(MaterializingInfos.count(QuerySymbol) &&
823            "QuerySymbol does not have MaterializingInfo");
824     auto &MI = MaterializingInfos[QuerySymbol];
825 
826     auto IdenticalQuery =
827         [&](const std::shared_ptr<AsynchronousSymbolQuery> &R) {
828           return R.get() == &Q;
829         };
830 
831     auto I = std::find_if(MI.PendingQueries.begin(), MI.PendingQueries.end(),
832                           IdenticalQuery);
833     assert(I != MI.PendingQueries.end() &&
834            "Query Q should be in the PendingQueries list for QuerySymbol");
835     MI.PendingQueries.erase(I);
836   }
837 }
838 
839 void VSO::transferFinalizedNodeDependencies(
840     MaterializingInfo &DependantMI, const SymbolStringPtr &DependantName,
841     MaterializingInfo &FinalizedMI) {
842   for (auto &KV : FinalizedMI.UnfinalizedDependencies) {
843     auto &DependencyVSO = *KV.first;
844     SymbolNameSet *UnfinalizedDependenciesOnDependencyVSO = nullptr;
845 
846     for (auto &DependencyName : KV.second) {
847       auto &DependencyMI = DependencyVSO.MaterializingInfos[DependencyName];
848 
849       // Do not add self dependencies.
850       if (&DependencyMI == &DependantMI)
851         continue;
852 
853       // If we haven't looked up the dependencies for DependencyVSO yet, do it
854       // now and cache the result.
855       if (!UnfinalizedDependenciesOnDependencyVSO)
856         UnfinalizedDependenciesOnDependencyVSO =
857             &DependantMI.UnfinalizedDependencies[&DependencyVSO];
858 
859       DependencyMI.Dependants[this].insert(DependantName);
860       UnfinalizedDependenciesOnDependencyVSO->insert(DependencyName);
861     }
862   }
863 }
864 
865 VSO &ExecutionSession::createVSO(std::string Name) {
866   return runSessionLocked([&, this]() -> VSO & {
867       VSOs.push_back(std::unique_ptr<VSO>(new VSO(*this, std::move(Name))));
868     return *VSOs.back();
869   });
870 }
871 
872 Expected<SymbolMap> lookup(const std::vector<VSO *> &VSOs, SymbolNameSet Names) {
873 #if LLVM_ENABLE_THREADS
874   // In the threaded case we use promises to return the results.
875   std::promise<SymbolMap> PromisedResult;
876   std::mutex ErrMutex;
877   Error ResolutionError = Error::success();
878   std::promise<void> PromisedReady;
879   Error ReadyError = Error::success();
880   auto OnResolve =
881       [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) {
882         if (Result)
883           PromisedResult.set_value(std::move(Result->Symbols));
884         else {
885           {
886             ErrorAsOutParameter _(&ResolutionError);
887             std::lock_guard<std::mutex> Lock(ErrMutex);
888             ResolutionError = Result.takeError();
889           }
890           PromisedResult.set_value(SymbolMap());
891         }
892       };
893   auto OnReady = [&](Error Err) {
894     if (Err) {
895       ErrorAsOutParameter _(&ReadyError);
896       std::lock_guard<std::mutex> Lock(ErrMutex);
897       ReadyError = std::move(Err);
898     }
899     PromisedReady.set_value();
900   };
901 #else
902   SymbolMap Result;
903   Error ResolutionError = Error::success();
904   Error ReadyError = Error::success();
905 
906   auto OnResolve = [&](Expected<AsynchronousSymbolQuery::ResolutionResult> R) {
907     ErrorAsOutParameter _(&ResolutionError);
908     if (R)
909       Result = std::move(R->Symbols);
910     else
911       ResolutionError = R.takeError();
912   };
913   auto OnReady = [&](Error Err) {
914     ErrorAsOutParameter _(&ReadyError);
915     if (Err)
916       ReadyError = std::move(Err);
917   };
918 #endif
919 
920   auto Query = std::make_shared<AsynchronousSymbolQuery>(
921       Names, std::move(OnResolve), std::move(OnReady));
922   SymbolNameSet UnresolvedSymbols(std::move(Names));
923 
924   for (auto *V : VSOs) {
925     assert(V && "VSO pointers in VSOs list should be non-null");
926     if (UnresolvedSymbols.empty())
927       break;
928     UnresolvedSymbols = V->lookup(Query, UnresolvedSymbols);
929   }
930 
931   if (!UnresolvedSymbols.empty()) {
932     // If there are unresolved symbols then the query will never return.
933     // Fail it with ES.failQuery.
934     auto &ES = (*VSOs.begin())->getExecutionSession();
935     ES.failQuery(*Query,
936                  make_error<SymbolsNotFound>(std::move(UnresolvedSymbols)));
937   }
938 
939 #if LLVM_ENABLE_THREADS
940   auto ResultFuture = PromisedResult.get_future();
941   auto Result = ResultFuture.get();
942 
943   {
944     std::lock_guard<std::mutex> Lock(ErrMutex);
945     if (ResolutionError) {
946       // ReadyError will never be assigned. Consume the success value.
947       cantFail(std::move(ReadyError));
948       return std::move(ResolutionError);
949     }
950   }
951 
952   auto ReadyFuture = PromisedReady.get_future();
953   ReadyFuture.get();
954 
955   {
956     std::lock_guard<std::mutex> Lock(ErrMutex);
957     if (ReadyError)
958       return std::move(ReadyError);
959   }
960 
961   return std::move(Result);
962 
963 #else
964   if (ResolutionError) {
965     // ReadyError will never be assigned. Consume the success value.
966     cantFail(std::move(ReadyError));
967     return std::move(ResolutionError);
968   }
969 
970   if (ReadyError)
971     return std::move(ReadyError);
972 
973   return Result;
974 #endif
975 }
976 
977 /// Look up a symbol by searching a list of VSOs.
978 Expected<JITEvaluatedSymbol> lookup(const std::vector<VSO *> VSOs,
979                                     SymbolStringPtr Name) {
980   SymbolNameSet Names({Name});
981   if (auto ResultMap = lookup(VSOs, std::move(Names))) {
982     assert(ResultMap->size() == 1 && "Unexpected number of results");
983     assert(ResultMap->count(Name) && "Missing result for symbol");
984     return std::move(ResultMap->begin()->second);
985   } else
986     return ResultMap.takeError();
987 }
988 
989 } // End namespace orc.
990 } // End namespace llvm.
991