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 SymbolNameSet MaterializationResponsibility::getRequestedSymbols() {
241   return V.getRequestedSymbols(SymbolFlags);
242 }
243 
244 void MaterializationResponsibility::resolve(const SymbolMap &Symbols) {
245   for (auto &KV : Symbols) {
246     auto I = SymbolFlags.find(KV.first);
247     assert(I != SymbolFlags.end() &&
248            "Resolving symbol outside this responsibility set");
249     assert(I->second.isMaterializing() && "Duplicate resolution");
250     I->second &= ~JITSymbolFlags::Materializing;
251     assert(KV.second.getFlags() == I->second &&
252            "Resolving symbol with incorrect flags");
253   }
254 
255   V.resolve(Symbols);
256 }
257 
258 void MaterializationResponsibility::finalize() {
259 #ifndef NDEBUG
260   for (auto &KV : SymbolFlags)
261     assert(!KV.second.isMaterializing() &&
262            "Failed to resolve symbol before finalization");
263 #endif // NDEBUG
264 
265   V.finalize(SymbolFlags);
266   SymbolFlags.clear();
267 }
268 
269 Error MaterializationResponsibility::defineMaterializing(
270     const SymbolFlagsMap &NewSymbolFlags) {
271   // Add the given symbols to this responsibility object.
272   // It's ok if we hit a duplicate here: In that case the new version will be
273   // discarded, and the VSO::defineMaterializing method will return a duplicate
274   // symbol error.
275   for (auto &KV : NewSymbolFlags) {
276     auto I = SymbolFlags.insert(KV).first;
277     I->second |= JITSymbolFlags::Materializing;
278   }
279 
280   return V.defineMaterializing(NewSymbolFlags);
281 }
282 
283 void MaterializationResponsibility::failMaterialization() {
284 
285   SymbolNameSet FailedSymbols;
286   for (auto &KV : SymbolFlags)
287     FailedSymbols.insert(KV.first);
288 
289   V.notifyFailed(FailedSymbols);
290   SymbolFlags.clear();
291 }
292 
293 void MaterializationResponsibility::delegate(
294     std::unique_ptr<MaterializationUnit> MU) {
295   for (auto &KV : MU->getSymbols())
296     SymbolFlags.erase(KV.first);
297 
298   V.replace(std::move(MU));
299 }
300 
301 void MaterializationResponsibility::addDependencies(
302     const SymbolDependenceMap &Dependencies) {
303   V.addDependencies(SymbolFlags, Dependencies);
304 }
305 
306 AbsoluteSymbolsMaterializationUnit::AbsoluteSymbolsMaterializationUnit(
307     SymbolMap Symbols)
308     : MaterializationUnit(extractFlags(Symbols)), Symbols(std::move(Symbols)) {}
309 
310 void AbsoluteSymbolsMaterializationUnit::materialize(
311     MaterializationResponsibility R) {
312   R.resolve(Symbols);
313   R.finalize();
314 }
315 
316 void AbsoluteSymbolsMaterializationUnit::discard(const VSO &V,
317                                                  SymbolStringPtr Name) {
318   assert(Symbols.count(Name) && "Symbol is not part of this MU");
319   Symbols.erase(Name);
320 }
321 
322 SymbolFlagsMap
323 AbsoluteSymbolsMaterializationUnit::extractFlags(const SymbolMap &Symbols) {
324   SymbolFlagsMap Flags;
325   for (const auto &KV : Symbols)
326     Flags[KV.first] = KV.second.getFlags();
327   return Flags;
328 }
329 
330 Error VSO::defineMaterializing(const SymbolFlagsMap &SymbolFlags) {
331   return ES.runSessionLocked([&]() -> Error {
332     std::vector<SymbolMap::iterator> AddedSyms;
333 
334     for (auto &KV : SymbolFlags) {
335       SymbolMap::iterator EntryItr;
336       bool Added;
337 
338       auto NewFlags = KV.second;
339       NewFlags |= JITSymbolFlags::Materializing;
340 
341       std::tie(EntryItr, Added) = Symbols.insert(
342           std::make_pair(KV.first, JITEvaluatedSymbol(0, NewFlags)));
343 
344       if (Added)
345         AddedSyms.push_back(EntryItr);
346       else {
347         // Remove any symbols already added.
348         for (auto &SI : AddedSyms)
349           Symbols.erase(SI);
350 
351         // FIXME: Return all duplicates.
352         return make_error<DuplicateDefinition>(*KV.first);
353       }
354     }
355 
356     return Error::success();
357   });
358 }
359 
360 void VSO::replace(std::unique_ptr<MaterializationUnit> MU) {
361   assert(MU != nullptr && "Can not replace with a null MaterializationUnit");
362 
363   auto MustRunMU =
364       ES.runSessionLocked([&, this]() -> std::unique_ptr<MaterializationUnit> {
365 
366 #ifndef NDEBUG
367         for (auto &KV : MU->getSymbols()) {
368           auto SymI = Symbols.find(KV.first);
369           assert(SymI != Symbols.end() && "Replacing unknown symbol");
370           assert(!SymI->second.getFlags().isLazy() &&
371                  SymI->second.getFlags().isMaterializing() &&
372                  "Can not replace symbol that is not materializing");
373           assert(UnmaterializedInfos.count(KV.first) == 0 &&
374                  "Symbol being replaced should have no UnmaterializedInfo");
375         }
376 #endif // NDEBUG
377 
378         // If any symbol has pending queries against it then we need to
379         // materialize MU immediately.
380         for (auto &KV : MU->getSymbols()) {
381           auto MII = MaterializingInfos.find(KV.first);
382           if (MII != MaterializingInfos.end()) {
383             if (!MII->second.PendingQueries.empty())
384               return std::move(MU);
385           }
386         }
387 
388         // Otherwise, make MU responsible for all the symbols.
389         auto UMI = std::make_shared<UnmaterializedInfo>(std::move(MU));
390         for (auto &KV : UMI->MU->getSymbols()) {
391           assert(!KV.second.isLazy() &&
392                  "Lazy flag should be managed internally.");
393           assert(!KV.second.isMaterializing() &&
394                  "Materializing flags should be managed internally.");
395 
396           auto SymI = Symbols.find(KV.first);
397           JITSymbolFlags ReplaceFlags = KV.second;
398           ReplaceFlags |= JITSymbolFlags::Lazy;
399           SymI->second = JITEvaluatedSymbol(SymI->second.getAddress(),
400                                             std::move(ReplaceFlags));
401           UnmaterializedInfos[KV.first] = UMI;
402         }
403 
404         return nullptr;
405       });
406 
407   if (MustRunMU)
408     ES.dispatchMaterialization(*this, std::move(MustRunMU));
409 }
410 
411 SymbolNameSet VSO::getRequestedSymbols(const SymbolFlagsMap &SymbolFlags) {
412   return ES.runSessionLocked([&]() {
413     SymbolNameSet RequestedSymbols;
414 
415     for (auto &KV : SymbolFlags) {
416       assert(Symbols.count(KV.first) && "VSO does not cover this symbol?");
417       assert(Symbols[KV.first].getFlags().isMaterializing() &&
418              "getRequestedSymbols can only be called for materializing "
419              "symbols");
420       auto I = MaterializingInfos.find(KV.first);
421       if (I == MaterializingInfos.end())
422         continue;
423 
424       if (!I->second.PendingQueries.empty())
425         RequestedSymbols.insert(KV.first);
426     }
427 
428     return RequestedSymbols;
429   });
430 }
431 
432 void VSO::addDependencies(const SymbolFlagsMap &Dependants,
433                           const SymbolDependenceMap &Dependencies) {
434   ES.runSessionLocked([&, this]() {
435     for (auto &KV : Dependants) {
436       const auto &Name = KV.first;
437       assert(Symbols.count(Name) && "Name not in symbol table");
438       assert((Symbols[Name].getFlags().isLazy() ||
439               Symbols[Name].getFlags().isMaterializing()) &&
440              "Symbol is not lazy or materializing");
441 
442       auto &MI = MaterializingInfos[Name];
443       assert(!MI.IsFinalized && "Can not add dependencies to finalized symbol");
444 
445       for (auto &KV : Dependencies) {
446         assert(KV.first && "Null VSO in dependency?");
447         auto &OtherVSO = *KV.first;
448         auto &DepsOnOtherVSO = MI.UnfinalizedDependencies[&OtherVSO];
449 
450         for (auto &OtherSymbol : KV.second) {
451           auto &OtherMI = OtherVSO.MaterializingInfos[OtherSymbol];
452 
453           if (OtherMI.IsFinalized)
454             transferFinalizedNodeDependencies(MI, Name, OtherMI);
455           else if (&OtherVSO != this || OtherSymbol != Name) {
456             OtherMI.Dependants[this].insert(Name);
457             DepsOnOtherVSO.insert(OtherSymbol);
458           }
459         }
460       }
461     }
462   });
463 }
464 
465 void VSO::resolve(const SymbolMap &Resolved) {
466   auto FullyResolvedQueries = ES.runSessionLocked([&, this]() {
467     AsynchronousSymbolQuerySet FullyResolvedQueries;
468     for (const auto &KV : Resolved) {
469       auto &Name = KV.first;
470       auto Sym = KV.second;
471       JITSymbolFlags ResolvedFlags = Sym.getFlags();
472       ResolvedFlags &= ~JITSymbolFlags::Weak;
473 
474       assert(!Sym.getFlags().isLazy() && !Sym.getFlags().isMaterializing() &&
475              "Materializing flags should be managed internally");
476 
477       auto I = Symbols.find(Name);
478 
479       assert(I != Symbols.end() && "Symbol not found");
480       assert(!I->second.getFlags().isLazy() &&
481              I->second.getFlags().isMaterializing() &&
482              "Symbol should be materializing");
483       assert(I->second.getAddress() == 0 && "Symbol has already been resolved");
484 
485       assert(ResolvedFlags ==
486                  JITSymbolFlags::stripTransientFlags(I->second.getFlags()) &&
487              "Resolved flags should match the declared flags");
488 
489       // Once resolved, symbols can never be weak.
490       ResolvedFlags |= JITSymbolFlags::Materializing;
491       I->second = JITEvaluatedSymbol(Sym.getAddress(), ResolvedFlags);
492 
493       auto &MI = MaterializingInfos[Name];
494       for (auto &Q : MI.PendingQueries) {
495         Q->resolve(Name, Sym);
496         if (Q->isFullyResolved())
497           FullyResolvedQueries.insert(Q);
498       }
499     }
500 
501     return FullyResolvedQueries;
502   });
503 
504   for (auto &Q : FullyResolvedQueries) {
505     assert(Q->isFullyResolved() && "Q not fully resolved");
506     Q->handleFullyResolved();
507   }
508 }
509 
510 void VSO::finalize(const SymbolFlagsMap &Finalized) {
511   auto FullyReadyQueries = ES.runSessionLocked([&, this]() {
512     AsynchronousSymbolQuerySet ReadyQueries;
513 
514     for (const auto &KV : Finalized) {
515       const auto &Name = KV.first;
516 
517       auto MII = MaterializingInfos.find(Name);
518       assert(MII != MaterializingInfos.end() &&
519              "Missing MaterializingInfo entry");
520 
521       auto &MI = MII->second;
522 
523       // For each dependant, transfer this node's unfinalized dependencies to
524       // it. If the dependant node is fully finalized then notify any pending
525       // queries.
526       for (auto &KV : MI.Dependants) {
527         auto &DependantVSO = *KV.first;
528         for (auto &DependantName : KV.second) {
529           auto DependantMII =
530               DependantVSO.MaterializingInfos.find(DependantName);
531           assert(DependantMII != DependantVSO.MaterializingInfos.end() &&
532                  "Dependant should have MaterializingInfo");
533 
534           auto &DependantMI = DependantMII->second;
535 
536           // Remove the dependant's dependency on this node.
537           assert(DependantMI.UnfinalizedDependencies[this].count(Name) &&
538                  "Dependant does not count this symbol as a dependency?");
539           DependantMI.UnfinalizedDependencies[this].erase(Name);
540           if (DependantMI.UnfinalizedDependencies[this].empty())
541             DependantMI.UnfinalizedDependencies.erase(this);
542 
543           // Transfer unfinalized dependencies from this node to the dependant.
544           DependantVSO.transferFinalizedNodeDependencies(DependantMI,
545                                                          DependantName, MI);
546 
547           // If the dependant is finalized and this node was the last of its
548           // unfinalized dependencies then notify any pending queries on the
549           // dependant node.
550           if (DependantMI.IsFinalized &&
551               DependantMI.UnfinalizedDependencies.empty()) {
552             assert(DependantMI.Dependants.empty() &&
553                    "Dependants should be empty by now");
554             for (auto &Q : DependantMI.PendingQueries) {
555               Q->notifySymbolReady();
556               if (Q->isFullyReady())
557                 ReadyQueries.insert(Q);
558               Q->removeQueryDependence(DependantVSO, DependantName);
559             }
560 
561             // If this dependant node was fully finalized we can erase its
562             // MaterializingInfo and update its materializing state.
563             assert(DependantVSO.Symbols.count(DependantName) &&
564                    "Dependant has no entry in the Symbols table");
565             auto &DependantSym = DependantVSO.Symbols[DependantName];
566             DependantSym.setFlags(static_cast<JITSymbolFlags::FlagNames>(
567                 DependantSym.getFlags() & ~JITSymbolFlags::Materializing));
568             DependantVSO.MaterializingInfos.erase(DependantMII);
569           }
570         }
571       }
572       MI.Dependants.clear();
573       MI.IsFinalized = true;
574 
575       if (MI.UnfinalizedDependencies.empty()) {
576         for (auto &Q : MI.PendingQueries) {
577           Q->notifySymbolReady();
578           if (Q->isFullyReady())
579             ReadyQueries.insert(Q);
580           Q->removeQueryDependence(*this, Name);
581         }
582         assert(Symbols.count(Name) &&
583                "Symbol has no entry in the Symbols table");
584         auto &Sym = Symbols[Name];
585         Sym.setFlags(static_cast<JITSymbolFlags::FlagNames>(
586             Sym.getFlags() & ~JITSymbolFlags::Materializing));
587         MaterializingInfos.erase(MII);
588       }
589     }
590 
591     return ReadyQueries;
592   });
593 
594   for (auto &Q : FullyReadyQueries) {
595     assert(Q->isFullyReady() && "Q is not fully ready");
596     Q->handleFullyReady();
597   }
598 }
599 
600 void VSO::notifyFailed(const SymbolNameSet &FailedSymbols) {
601 
602   // FIXME: This should fail any transitively dependant symbols too.
603 
604   auto FailedQueriesToNotify = ES.runSessionLocked([&, this]() {
605     AsynchronousSymbolQuerySet FailedQueries;
606 
607     for (auto &Name : FailedSymbols) {
608       auto I = Symbols.find(Name);
609       assert(I != Symbols.end() && "Symbol not present in this VSO");
610       Symbols.erase(I);
611 
612       auto MII = MaterializingInfos.find(Name);
613 
614       // If we have not created a MaterializingInfo for this symbol yet then
615       // there is nobody to notify.
616       if (MII == MaterializingInfos.end())
617         continue;
618 
619       // Copy all the queries to the FailedQueries list, then abandon them.
620       // This has to be a copy, and the copy has to come before the abandon
621       // operation: Each Q.detach() call will reach back into this
622       // PendingQueries list to remove Q.
623       for (auto &Q : MII->second.PendingQueries)
624         FailedQueries.insert(Q);
625 
626       for (auto &Q : FailedQueries)
627         Q->detach();
628 
629       assert(MII->second.PendingQueries.empty() &&
630              "Queries remain after symbol was failed");
631 
632       MaterializingInfos.erase(MII);
633     }
634 
635     return FailedQueries;
636   });
637 
638   for (auto &Q : FailedQueriesToNotify)
639     Q->handleFailed(make_error<FailedToMaterialize>(FailedSymbols));
640 }
641 
642 SymbolNameSet VSO::lookupFlags(SymbolFlagsMap &Flags,
643                                const SymbolNameSet &Names) {
644   return ES.runSessionLocked([&, this]() {
645     auto Unresolved = lookupFlagsImpl(Flags, Names);
646     if (FallbackDefinitionGenerator && !Unresolved.empty()) {
647       auto FallbackDefs = FallbackDefinitionGenerator(*this, Unresolved);
648       if (!FallbackDefs.empty()) {
649         auto Unresolved2 = lookupFlagsImpl(Flags, FallbackDefs);
650         (void)Unresolved2;
651         assert(Unresolved2.empty() &&
652                "All fallback defs should have been found by lookupFlagsImpl");
653         for (auto &D : FallbackDefs)
654           Unresolved.erase(D);
655       }
656     };
657     return Unresolved;
658   });
659 }
660 
661 SymbolNameSet VSO::lookupFlagsImpl(SymbolFlagsMap &Flags,
662                                    const SymbolNameSet &Names) {
663   SymbolNameSet Unresolved;
664 
665   for (auto &Name : Names) {
666     auto I = Symbols.find(Name);
667 
668     if (I == Symbols.end()) {
669       Unresolved.insert(Name);
670       continue;
671     }
672 
673     assert(!Flags.count(Name) && "Symbol already present in Flags map");
674     Flags[Name] = JITSymbolFlags::stripTransientFlags(I->second.getFlags());
675   }
676 
677   return Unresolved;
678 }
679 
680 SymbolNameSet VSO::lookup(std::shared_ptr<AsynchronousSymbolQuery> Q,
681                           SymbolNameSet Names) {
682   assert(Q && "Query can not be null");
683 
684   std::vector<std::unique_ptr<MaterializationUnit>> MUs;
685 
686   SymbolNameSet Unresolved = std::move(Names);
687   ES.runSessionLocked([&, this]() {
688     lookupImpl(Q, MUs, Unresolved);
689     if (FallbackDefinitionGenerator && !Unresolved.empty()) {
690       auto FallbackDefs = FallbackDefinitionGenerator(*this, Unresolved);
691       if (!FallbackDefs.empty()) {
692         for (auto &D : FallbackDefs)
693           Unresolved.erase(D);
694         lookupImpl(Q, MUs, FallbackDefs);
695         assert(FallbackDefs.empty() &&
696                "All fallback defs should have been found by lookupImpl");
697       }
698     }
699   });
700 
701   if (Q->isFullyResolved())
702     Q->handleFullyResolved();
703 
704   if (Q->isFullyReady())
705     Q->handleFullyReady();
706 
707   // Dispatch any required MaterializationUnits for materialization.
708   for (auto &MU : MUs)
709     ES.dispatchMaterialization(*this, std::move(MU));
710 
711   return Unresolved;
712 }
713 
714 void VSO::lookupImpl(std::shared_ptr<AsynchronousSymbolQuery> &Q,
715                      std::vector<std::unique_ptr<MaterializationUnit>> &MUs,
716                      SymbolNameSet &Unresolved) {
717   for (auto I = Unresolved.begin(), E = Unresolved.end(); I != E;) {
718     auto TmpI = I++;
719     auto Name = *TmpI;
720 
721     // Search for the name in Symbols. Skip it if not found.
722     auto SymI = Symbols.find(Name);
723     if (SymI == Symbols.end())
724       continue;
725 
726     // If we found Name in V, remove it frome the Unresolved set and add it
727     // to the dependencies set.
728     Unresolved.erase(TmpI);
729 
730     // If the symbol has an address then resolve it.
731     if (SymI->second.getAddress() != 0)
732       Q->resolve(Name, SymI->second);
733 
734     // If the symbol is lazy, get the MaterialiaztionUnit for it.
735     if (SymI->second.getFlags().isLazy()) {
736       assert(SymI->second.getAddress() == 0 &&
737              "Lazy symbol should not have a resolved address");
738       assert(!SymI->second.getFlags().isMaterializing() &&
739              "Materializing and lazy should not both be set");
740       auto UMII = UnmaterializedInfos.find(Name);
741       assert(UMII != UnmaterializedInfos.end() &&
742              "Lazy symbol should have UnmaterializedInfo");
743       auto MU = std::move(UMII->second->MU);
744       assert(MU != nullptr && "Materializer should not be null");
745 
746       // Kick all symbols associated with this MaterializationUnit into
747       // materializing state.
748       for (auto &KV : MU->getSymbols()) {
749         auto SymK = Symbols.find(KV.first);
750         auto Flags = SymK->second.getFlags();
751         Flags &= ~JITSymbolFlags::Weak;
752         Flags &= ~JITSymbolFlags::Lazy;
753         Flags |= JITSymbolFlags::Materializing;
754         SymK->second.setFlags(Flags);
755         UnmaterializedInfos.erase(KV.first);
756       }
757 
758       // Add MU to the list of MaterializationUnits to be materialized.
759       MUs.push_back(std::move(MU));
760     } else if (!SymI->second.getFlags().isMaterializing()) {
761       // The symbol is neither lazy nor materializing. Finalize it and
762       // continue.
763       Q->notifySymbolReady();
764       continue;
765     }
766 
767     // Add the query to the PendingQueries list.
768     assert(SymI->second.getFlags().isMaterializing() &&
769            "By this line the symbol should be materializing");
770     auto &MI = MaterializingInfos[Name];
771     MI.PendingQueries.push_back(Q);
772     Q->addQueryDependence(*this, Name);
773   }
774 }
775 
776 void VSO::dump(raw_ostream &OS) {
777   ES.runSessionLocked([&, this]() {
778     OS << "VSO \"" << VSOName
779        << "\" (ES: " << format("0x%016x", reinterpret_cast<uintptr_t>(&ES))
780        << "):\n"
781        << "Symbol table:\n";
782 
783     for (auto &KV : Symbols) {
784       OS << "    \"" << *KV.first << "\": " << KV.second.getAddress();
785       if (KV.second.getFlags().isLazy() ||
786           KV.second.getFlags().isMaterializing()) {
787         OS << " (";
788         if (KV.second.getFlags().isLazy()) {
789           auto I = UnmaterializedInfos.find(KV.first);
790           assert(I != UnmaterializedInfos.end() &&
791                  "Lazy symbol should have UnmaterializedInfo");
792           OS << " Lazy (MU=" << I->second->MU.get() << ")";
793         }
794         if (KV.second.getFlags().isMaterializing())
795           OS << " Materializing";
796         OS << " )\n";
797       } else
798         OS << "\n";
799     }
800 
801     if (!MaterializingInfos.empty())
802       OS << "  MaterializingInfos entries:\n";
803     for (auto &KV : MaterializingInfos) {
804       OS << "    \"" << *KV.first << "\":\n"
805          << "      IsFinalized = " << (KV.second.IsFinalized ? "true" : "false")
806          << "\n"
807          << "      " << KV.second.PendingQueries.size() << " pending queries.\n"
808          << "      Dependants:\n";
809       for (auto &KV2 : KV.second.Dependants)
810         OS << "        " << KV2.first->getName() << ": " << KV2.second << "\n";
811       OS << "      Unfinalized Dependencies:\n";
812       for (auto &KV2 : KV.second.UnfinalizedDependencies)
813         OS << "        " << KV2.first->getName() << ": " << KV2.second << "\n";
814     }
815   });
816 }
817 
818 Error VSO::defineImpl(MaterializationUnit &MU) {
819   SymbolNameSet Duplicates;
820   SymbolNameSet MUDefsOverridden;
821   std::vector<SymbolMap::iterator> ExistingDefsOverridden;
822   for (auto &KV : MU.getSymbols()) {
823     assert(!KV.second.isLazy() && "Lazy flag should be managed internally.");
824     assert(!KV.second.isMaterializing() &&
825            "Materializing flags should be managed internally.");
826 
827     SymbolMap::iterator EntryItr;
828     bool Added;
829 
830     auto NewFlags = KV.second;
831     NewFlags |= JITSymbolFlags::Lazy;
832 
833     std::tie(EntryItr, Added) = Symbols.insert(
834         std::make_pair(KV.first, JITEvaluatedSymbol(0, NewFlags)));
835 
836     if (!Added) {
837       if (KV.second.isStrong()) {
838         if (EntryItr->second.getFlags().isStrong())
839           Duplicates.insert(KV.first);
840         else
841           ExistingDefsOverridden.push_back(EntryItr);
842       } else
843         MUDefsOverridden.insert(KV.first);
844     }
845   }
846 
847   if (!Duplicates.empty()) {
848     // We need to remove the symbols we added.
849     for (auto &KV : MU.getSymbols()) {
850       if (Duplicates.count(KV.first) || Duplicates.count(KV.first))
851         continue;
852 
853       bool Found = false;
854       for (const auto &I : ExistingDefsOverridden)
855         if (I->first == KV.first)
856           Found = true;
857 
858       if (!Found)
859         Symbols.erase(KV.first);
860     }
861 
862     // FIXME: Return all duplicates.
863     return make_error<DuplicateDefinition>(**Duplicates.begin());
864   }
865 
866   // Update flags on existing defs and call discard on their materializers.
867   for (auto &ExistingDefItr : ExistingDefsOverridden) {
868     assert(ExistingDefItr->second.getFlags().isLazy() &&
869            !ExistingDefItr->second.getFlags().isMaterializing() &&
870            "Overridden existing def should be in the Lazy state");
871 
872     ExistingDefItr->second.getFlags() &= ~JITSymbolFlags::Weak;
873 
874     auto UMII = UnmaterializedInfos.find(ExistingDefItr->first);
875     assert(UMII != UnmaterializedInfos.end() &&
876            "Overridden existing def should have an UnmaterializedInfo");
877 
878     UMII->second->MU->doDiscard(*this, ExistingDefItr->first);
879   }
880 
881   // Discard overridden symbols povided by MU.
882   for (auto &Sym : MUDefsOverridden)
883     MU.doDiscard(*this, Sym);
884 
885   return Error::success();
886 }
887 
888 void VSO::detachQueryHelper(AsynchronousSymbolQuery &Q,
889                             const SymbolNameSet &QuerySymbols) {
890   for (auto &QuerySymbol : QuerySymbols) {
891     assert(MaterializingInfos.count(QuerySymbol) &&
892            "QuerySymbol does not have MaterializingInfo");
893     auto &MI = MaterializingInfos[QuerySymbol];
894 
895     auto IdenticalQuery =
896         [&](const std::shared_ptr<AsynchronousSymbolQuery> &R) {
897           return R.get() == &Q;
898         };
899 
900     auto I = std::find_if(MI.PendingQueries.begin(), MI.PendingQueries.end(),
901                           IdenticalQuery);
902     assert(I != MI.PendingQueries.end() &&
903            "Query Q should be in the PendingQueries list for QuerySymbol");
904     MI.PendingQueries.erase(I);
905   }
906 }
907 
908 void VSO::transferFinalizedNodeDependencies(
909     MaterializingInfo &DependantMI, const SymbolStringPtr &DependantName,
910     MaterializingInfo &FinalizedMI) {
911   for (auto &KV : FinalizedMI.UnfinalizedDependencies) {
912     auto &DependencyVSO = *KV.first;
913     SymbolNameSet *UnfinalizedDependenciesOnDependencyVSO = nullptr;
914 
915     for (auto &DependencyName : KV.second) {
916       auto &DependencyMI = DependencyVSO.MaterializingInfos[DependencyName];
917 
918       // Do not add self dependencies.
919       if (&DependencyMI == &DependantMI)
920         continue;
921 
922       // If we haven't looked up the dependencies for DependencyVSO yet, do it
923       // now and cache the result.
924       if (!UnfinalizedDependenciesOnDependencyVSO)
925         UnfinalizedDependenciesOnDependencyVSO =
926             &DependantMI.UnfinalizedDependencies[&DependencyVSO];
927 
928       DependencyMI.Dependants[this].insert(DependantName);
929       UnfinalizedDependenciesOnDependencyVSO->insert(DependencyName);
930     }
931   }
932 }
933 
934 VSO &ExecutionSession::createVSO(std::string Name) {
935   return runSessionLocked([&, this]() -> VSO & {
936       VSOs.push_back(std::unique_ptr<VSO>(new VSO(*this, std::move(Name))));
937     return *VSOs.back();
938   });
939 }
940 
941 Expected<SymbolMap> blockingLookup(ExecutionSessionBase &ES,
942                                    AsynchronousLookupFunction AsyncLookup,
943                                    SymbolNameSet Names, bool WaitUntilReady,
944                                    MaterializationResponsibility *MR) {
945 
946 #if LLVM_ENABLE_THREADS
947   // In the threaded case we use promises to return the results.
948   std::promise<SymbolMap> PromisedResult;
949   std::mutex ErrMutex;
950   Error ResolutionError = Error::success();
951   std::promise<void> PromisedReady;
952   Error ReadyError = Error::success();
953   auto OnResolve =
954       [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) {
955         if (Result) {
956           if (MR)
957             MR->addDependencies(Result->Dependencies);
958           PromisedResult.set_value(std::move(Result->Symbols));
959         } else {
960           {
961             ErrorAsOutParameter _(&ResolutionError);
962             std::lock_guard<std::mutex> Lock(ErrMutex);
963             ResolutionError = Result.takeError();
964           }
965           PromisedResult.set_value(SymbolMap());
966         }
967       };
968 
969   std::function<void(Error)> OnReady;
970   if (WaitUntilReady) {
971     OnReady = [&](Error Err) {
972       if (Err) {
973         ErrorAsOutParameter _(&ReadyError);
974         std::lock_guard<std::mutex> Lock(ErrMutex);
975         ReadyError = std::move(Err);
976       }
977       PromisedReady.set_value();
978     };
979   } else {
980     OnReady = [&](Error Err) {
981       if (Err)
982         ES.reportError(std::move(Err));
983     };
984   }
985 
986 #else
987   SymbolMap Result;
988   Error ResolutionError = Error::success();
989   Error ReadyError = Error::success();
990 
991   auto OnResolve = [&](Expected<AsynchronousSymbolQuery::ResolutionResult> R) {
992     ErrorAsOutParameter _(&ResolutionError);
993     if (R) {
994       if (MR)
995         MR->addDependencies(R->Dependencies);
996       Result = std::move(R->Symbols);
997     } else
998       ResolutionError = R.takeError();
999   };
1000 
1001   std::function<void(Error)> OnReady;
1002   if (WaitUntilReady) {
1003     OnReady = [&](Error Err) {
1004       ErrorAsOutParameter _(&ReadyError);
1005       if (Err)
1006         ReadyError = std::move(Err);
1007     };
1008   } else {
1009     OnReady = [&](Error Err) {
1010       if (Err)
1011         ES.reportError(std::move(Err));
1012     };
1013   }
1014 #endif
1015 
1016   auto Query = std::make_shared<AsynchronousSymbolQuery>(
1017       Names, std::move(OnResolve), std::move(OnReady));
1018 
1019   SymbolNameSet UnresolvedSymbols = AsyncLookup(Query, std::move(Names));
1020 
1021   // If there are unresolved symbols then the query will never return.
1022   // Fail it with ES.failQuery.
1023   if (!UnresolvedSymbols.empty())
1024     ES.failQuery(*Query,
1025                  make_error<SymbolsNotFound>(std::move(UnresolvedSymbols)));
1026 
1027 #if LLVM_ENABLE_THREADS
1028   auto ResultFuture = PromisedResult.get_future();
1029   auto Result = ResultFuture.get();
1030 
1031   {
1032     std::lock_guard<std::mutex> Lock(ErrMutex);
1033     if (ResolutionError) {
1034       // ReadyError will never be assigned. Consume the success value.
1035       cantFail(std::move(ReadyError));
1036       return std::move(ResolutionError);
1037     }
1038   }
1039 
1040   if (WaitUntilReady) {
1041     auto ReadyFuture = PromisedReady.get_future();
1042     ReadyFuture.get();
1043 
1044     {
1045       std::lock_guard<std::mutex> Lock(ErrMutex);
1046       if (ReadyError)
1047         return std::move(ReadyError);
1048     }
1049   } else
1050     cantFail(std::move(ReadyError));
1051 
1052   return std::move(Result);
1053 
1054 #else
1055   if (ResolutionError) {
1056     // ReadyError will never be assigned. Consume the success value.
1057     cantFail(std::move(ReadyError));
1058     return std::move(ResolutionError);
1059   }
1060 
1061   if (ReadyError)
1062     return std::move(ReadyError);
1063 
1064   return Result;
1065 #endif
1066 }
1067 
1068 Expected<SymbolMap> lookup(const VSO::VSOList &VSOs, SymbolNameSet Names) {
1069 
1070   if (VSOs.empty())
1071     return SymbolMap();
1072 
1073   auto &ES = (*VSOs.begin())->getExecutionSession();
1074 
1075   auto LookupFn = [&](std::shared_ptr<AsynchronousSymbolQuery> Q,
1076                       SymbolNameSet Unresolved) {
1077     for (auto *V : VSOs) {
1078       assert(V && "VSOs entries must not be null");
1079       if (Unresolved.empty())
1080         break;
1081       Unresolved = V->lookup(Q, std::move(Unresolved));
1082     }
1083     return Unresolved;
1084   };
1085 
1086   return blockingLookup(ES, std::move(LookupFn), Names, true);
1087 }
1088 
1089 /// Look up a symbol by searching a list of VSOs.
1090 Expected<JITEvaluatedSymbol> lookup(const VSO::VSOList &VSOs,
1091                                     SymbolStringPtr Name) {
1092   SymbolNameSet Names({Name});
1093   if (auto ResultMap = lookup(VSOs, std::move(Names))) {
1094     assert(ResultMap->size() == 1 && "Unexpected number of results");
1095     assert(ResultMap->count(Name) && "Missing result for symbol");
1096     return std::move(ResultMap->begin()->second);
1097   } else
1098     return ResultMap.takeError();
1099 }
1100 
1101 } // End namespace orc.
1102 } // End namespace llvm.
1103