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 {
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 
472       assert(!Sym.getFlags().isLazy() && !Sym.getFlags().isMaterializing() &&
473              "Materializing flags should be managed internally");
474 
475       auto I = Symbols.find(Name);
476 
477       assert(I != Symbols.end() && "Symbol not found");
478       assert(!I->second.getFlags().isLazy() &&
479              I->second.getFlags().isMaterializing() &&
480              "Symbol should be materializing");
481       assert(I->second.getAddress() == 0 && "Symbol has already been resolved");
482 
483       assert(Sym.getFlags() ==
484                  JITSymbolFlags::stripTransientFlags(I->second.getFlags()) &&
485              "Resolved flags should match the declared flags");
486 
487       // Once resolved, symbols can never be weak.
488       JITSymbolFlags ResolvedFlags = Sym.getFlags();
489       ResolvedFlags &= ~JITSymbolFlags::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             DependantVSO.Symbols[DependantName].getFlags() &=
566                 JITSymbolFlags::Materializing;
567             DependantVSO.MaterializingInfos.erase(DependantMII);
568           }
569         }
570       }
571       MI.Dependants.clear();
572       MI.IsFinalized = true;
573 
574       if (MI.UnfinalizedDependencies.empty()) {
575         for (auto &Q : MI.PendingQueries) {
576           Q->notifySymbolReady();
577           if (Q->isFullyReady())
578             ReadyQueries.insert(Q);
579           Q->removeQueryDependence(*this, Name);
580         }
581         assert(Symbols.count(Name) &&
582                "Symbol has no entry in the Symbols table");
583         Symbols[Name].getFlags() &= ~JITSymbolFlags::Materializing;
584         MaterializingInfos.erase(MII);
585       }
586     }
587 
588     return ReadyQueries;
589   });
590 
591   for (auto &Q : FullyReadyQueries) {
592     assert(Q->isFullyReady() && "Q is not fully ready");
593     Q->handleFullyReady();
594   }
595 }
596 
597 void VSO::notifyFailed(const SymbolNameSet &FailedSymbols) {
598 
599   // FIXME: This should fail any transitively dependant symbols too.
600 
601   auto FailedQueriesToNotify = ES.runSessionLocked([&, this]() {
602     AsynchronousSymbolQuerySet FailedQueries;
603 
604     for (auto &Name : FailedSymbols) {
605       auto I = Symbols.find(Name);
606       assert(I != Symbols.end() && "Symbol not present in this VSO");
607       Symbols.erase(I);
608 
609       auto MII = MaterializingInfos.find(Name);
610 
611       // If we have not created a MaterializingInfo for this symbol yet then
612       // there is nobody to notify.
613       if (MII == MaterializingInfos.end())
614         continue;
615 
616       // Copy all the queries to the FailedQueries list, then abandon them.
617       // This has to be a copy, and the copy has to come before the abandon
618       // operation: Each Q.detach() call will reach back into this
619       // PendingQueries list to remove Q.
620       for (auto &Q : MII->second.PendingQueries)
621         FailedQueries.insert(Q);
622 
623       for (auto &Q : FailedQueries)
624         Q->detach();
625 
626       assert(MII->second.PendingQueries.empty() &&
627              "Queries remain after symbol was failed");
628 
629       MaterializingInfos.erase(MII);
630     }
631 
632     return FailedQueries;
633   });
634 
635   for (auto &Q : FailedQueriesToNotify)
636     Q->handleFailed(make_error<FailedToMaterialize>(FailedSymbols));
637 }
638 
639 SymbolNameSet VSO::lookupFlags(SymbolFlagsMap &Flags,
640                                const SymbolNameSet &Names) {
641   return ES.runSessionLocked([&, this]() {
642     SymbolNameSet Unresolved;
643 
644     for (auto &Name : Names) {
645       auto I = Symbols.find(Name);
646       if (I == Symbols.end()) {
647         Unresolved.insert(Name);
648         continue;
649       }
650 
651       assert(!Flags.count(Name) && "Symbol already present in Flags map");
652       Flags[Name] = JITSymbolFlags::stripTransientFlags(I->second.getFlags());
653     }
654 
655     return Unresolved;
656   });
657 }
658 
659 SymbolNameSet VSO::lookup(std::shared_ptr<AsynchronousSymbolQuery> Q,
660                           SymbolNameSet Names) {
661   SymbolNameSet Unresolved = std::move(Names);
662   std::vector<std::unique_ptr<MaterializationUnit>> MUs;
663 
664   ES.runSessionLocked([&, this]() {
665     for (auto I = Unresolved.begin(), E = Unresolved.end(); I != E;) {
666       auto TmpI = I++;
667       auto Name = *TmpI;
668 
669       // Search for the name in Symbols. Skip it if not found.
670       auto SymI = Symbols.find(Name);
671       if (SymI == Symbols.end())
672         continue;
673 
674       // If we found Name in V, remove it frome the Unresolved set and add it
675       // to the dependencies set.
676       Unresolved.erase(TmpI);
677 
678       // If the symbol has an address then resolve it.
679       if (SymI->second.getAddress() != 0)
680         Q->resolve(Name, SymI->second);
681 
682       // If the symbol is lazy, get the MaterialiaztionUnit for it.
683       if (SymI->second.getFlags().isLazy()) {
684         assert(SymI->second.getAddress() == 0 &&
685                "Lazy symbol should not have a resolved address");
686         assert(!SymI->second.getFlags().isMaterializing() &&
687                "Materializing and lazy should not both be set");
688         auto UMII = UnmaterializedInfos.find(Name);
689         assert(UMII != UnmaterializedInfos.end() &&
690                "Lazy symbol should have UnmaterializedInfo");
691         auto MU = std::move(UMII->second->MU);
692         assert(MU != nullptr && "Materializer should not be null");
693 
694         // Kick all symbols associated with this MaterializationUnit into
695         // materializing state.
696         for (auto &KV : MU->getSymbols()) {
697           auto SymK = Symbols.find(KV.first);
698           auto Flags = SymK->second.getFlags();
699           Flags &= ~JITSymbolFlags::Lazy;
700           Flags |= JITSymbolFlags::Materializing;
701           SymK->second.setFlags(Flags);
702           UnmaterializedInfos.erase(KV.first);
703         }
704 
705         // Add MU to the list of MaterializationUnits to be materialized.
706         MUs.push_back(std::move(MU));
707       } else if (!SymI->second.getFlags().isMaterializing()) {
708         // The symbol is neither lazy nor materializing. Finalize it and
709         // continue.
710         Q->notifySymbolReady();
711         continue;
712       }
713 
714       // Add the query to the PendingQueries list.
715       assert(SymI->second.getFlags().isMaterializing() &&
716              "By this line the symbol should be materializing");
717       auto &MI = MaterializingInfos[Name];
718       MI.PendingQueries.push_back(Q);
719       Q->addQueryDependence(*this, Name);
720     }
721   });
722 
723   if (Q->isFullyResolved())
724     Q->handleFullyResolved();
725 
726   if (Q->isFullyReady())
727     Q->handleFullyReady();
728 
729   // Dispatch any required MaterializationUnits for materialization.
730   for (auto &MU : MUs)
731     ES.dispatchMaterialization(*this, std::move(MU));
732 
733   return Unresolved;
734 }
735 
736 void VSO::dump(raw_ostream &OS) {
737   ES.runSessionLocked([&, this]() {
738     OS << "VSO \"" << VSOName
739        << "\" (ES: " << format("0x%016x", reinterpret_cast<uintptr_t>(&ES))
740        << "):\n"
741        << "Symbol table:\n";
742 
743     for (auto &KV : Symbols) {
744       OS << "    \"" << *KV.first << "\": " << KV.second.getAddress();
745       if (KV.second.getFlags().isLazy() ||
746           KV.second.getFlags().isMaterializing()) {
747         OS << " (";
748         if (KV.second.getFlags().isLazy()) {
749           auto I = UnmaterializedInfos.find(KV.first);
750           assert(I != UnmaterializedInfos.end() &&
751                  "Lazy symbol should have UnmaterializedInfo");
752           OS << " Lazy (MU=" << I->second->MU.get() << ")";
753         }
754         if (KV.second.getFlags().isMaterializing())
755           OS << " Materializing";
756         OS << " )\n";
757       } else
758         OS << "\n";
759     }
760 
761     if (!MaterializingInfos.empty())
762       OS << "  MaterializingInfos entries:\n";
763     for (auto &KV : MaterializingInfos) {
764       OS << "    \"" << *KV.first << "\":\n"
765          << "      IsFinalized = " << (KV.second.IsFinalized ? "true" : "false")
766          << "\n"
767          << "      " << KV.second.PendingQueries.size() << " pending queries.\n"
768          << "      Dependants:\n";
769       for (auto &KV2 : KV.second.Dependants)
770         OS << "        " << KV2.first->getName() << ": " << KV2.second << "\n";
771       OS << "      Unfinalized Dependencies:\n";
772       for (auto &KV2 : KV.second.UnfinalizedDependencies)
773         OS << "        " << KV2.first->getName() << ": " << KV2.second << "\n";
774     }
775   });
776 }
777 
778 Error VSO::defineImpl(MaterializationUnit &MU) {
779   SymbolNameSet Duplicates;
780   SymbolNameSet MUDefsOverridden;
781   std::vector<SymbolMap::iterator> ExistingDefsOverridden;
782   for (auto &KV : MU.getSymbols()) {
783     assert(!KV.second.isLazy() && "Lazy flag should be managed internally.");
784     assert(!KV.second.isMaterializing() &&
785            "Materializing flags should be managed internally.");
786 
787     SymbolMap::iterator EntryItr;
788     bool Added;
789 
790     auto NewFlags = KV.second;
791     NewFlags |= JITSymbolFlags::Lazy;
792 
793     std::tie(EntryItr, Added) = Symbols.insert(
794         std::make_pair(KV.first, JITEvaluatedSymbol(0, NewFlags)));
795 
796     if (!Added) {
797       if (KV.second.isStrong()) {
798         if (EntryItr->second.getFlags().isStrong())
799           Duplicates.insert(KV.first);
800         else
801           ExistingDefsOverridden.push_back(EntryItr);
802       } else
803         MUDefsOverridden.insert(KV.first);
804     }
805   }
806 
807   if (!Duplicates.empty()) {
808     // We need to remove the symbols we added.
809     for (auto &KV : MU.getSymbols()) {
810       if (Duplicates.count(KV.first) || Duplicates.count(KV.first))
811         continue;
812 
813       bool Found = false;
814       for (const auto &I : ExistingDefsOverridden)
815         if (I->first == KV.first)
816           Found = true;
817 
818       if (!Found)
819         Symbols.erase(KV.first);
820     }
821 
822     // FIXME: Return all duplicates.
823     return make_error<DuplicateDefinition>(**Duplicates.begin());
824   }
825 
826   // Update flags on existing defs and call discard on their materializers.
827   for (auto &ExistingDefItr : ExistingDefsOverridden) {
828     assert(ExistingDefItr->second.getFlags().isLazy() &&
829            !ExistingDefItr->second.getFlags().isMaterializing() &&
830            "Overridden existing def should be in the Lazy state");
831 
832     ExistingDefItr->second.getFlags() &= ~JITSymbolFlags::Weak;
833 
834     auto UMII = UnmaterializedInfos.find(ExistingDefItr->first);
835     assert(UMII != UnmaterializedInfos.end() &&
836            "Overridden existing def should have an UnmaterializedInfo");
837 
838     UMII->second->MU->doDiscard(*this, ExistingDefItr->first);
839   }
840 
841   // Discard overridden symbols povided by MU.
842   for (auto &Sym : MUDefsOverridden)
843     MU.doDiscard(*this, Sym);
844 
845   return Error::success();
846 }
847 
848 void VSO::detachQueryHelper(AsynchronousSymbolQuery &Q,
849                             const SymbolNameSet &QuerySymbols) {
850   for (auto &QuerySymbol : QuerySymbols) {
851     assert(MaterializingInfos.count(QuerySymbol) &&
852            "QuerySymbol does not have MaterializingInfo");
853     auto &MI = MaterializingInfos[QuerySymbol];
854 
855     auto IdenticalQuery =
856         [&](const std::shared_ptr<AsynchronousSymbolQuery> &R) {
857           return R.get() == &Q;
858         };
859 
860     auto I = std::find_if(MI.PendingQueries.begin(), MI.PendingQueries.end(),
861                           IdenticalQuery);
862     assert(I != MI.PendingQueries.end() &&
863            "Query Q should be in the PendingQueries list for QuerySymbol");
864     MI.PendingQueries.erase(I);
865   }
866 }
867 
868 void VSO::transferFinalizedNodeDependencies(
869     MaterializingInfo &DependantMI, const SymbolStringPtr &DependantName,
870     MaterializingInfo &FinalizedMI) {
871   for (auto &KV : FinalizedMI.UnfinalizedDependencies) {
872     auto &DependencyVSO = *KV.first;
873     SymbolNameSet *UnfinalizedDependenciesOnDependencyVSO = nullptr;
874 
875     for (auto &DependencyName : KV.second) {
876       auto &DependencyMI = DependencyVSO.MaterializingInfos[DependencyName];
877 
878       // Do not add self dependencies.
879       if (&DependencyMI == &DependantMI)
880         continue;
881 
882       // If we haven't looked up the dependencies for DependencyVSO yet, do it
883       // now and cache the result.
884       if (!UnfinalizedDependenciesOnDependencyVSO)
885         UnfinalizedDependenciesOnDependencyVSO =
886             &DependantMI.UnfinalizedDependencies[&DependencyVSO];
887 
888       DependencyMI.Dependants[this].insert(DependantName);
889       UnfinalizedDependenciesOnDependencyVSO->insert(DependencyName);
890     }
891   }
892 }
893 
894 VSO &ExecutionSession::createVSO(std::string Name) {
895   return runSessionLocked([&, this]() -> VSO & {
896       VSOs.push_back(std::unique_ptr<VSO>(new VSO(*this, std::move(Name))));
897     return *VSOs.back();
898   });
899 }
900 
901 Expected<SymbolMap> lookup(const VSO::VSOList &VSOs, SymbolNameSet Names) {
902 
903 #if LLVM_ENABLE_THREADS
904   // In the threaded case we use promises to return the results.
905   std::promise<SymbolMap> PromisedResult;
906   std::mutex ErrMutex;
907   Error ResolutionError = Error::success();
908   std::promise<void> PromisedReady;
909   Error ReadyError = Error::success();
910   auto OnResolve =
911       [&](Expected<AsynchronousSymbolQuery::ResolutionResult> Result) {
912         if (Result)
913           PromisedResult.set_value(std::move(Result->Symbols));
914         else {
915           {
916             ErrorAsOutParameter _(&ResolutionError);
917             std::lock_guard<std::mutex> Lock(ErrMutex);
918             ResolutionError = Result.takeError();
919           }
920           PromisedResult.set_value(SymbolMap());
921         }
922       };
923   auto OnReady = [&](Error Err) {
924     if (Err) {
925       ErrorAsOutParameter _(&ReadyError);
926       std::lock_guard<std::mutex> Lock(ErrMutex);
927       ReadyError = std::move(Err);
928     }
929     PromisedReady.set_value();
930   };
931 #else
932   SymbolMap Result;
933   Error ResolutionError = Error::success();
934   Error ReadyError = Error::success();
935 
936   auto OnResolve = [&](Expected<AsynchronousSymbolQuery::ResolutionResult> R) {
937     ErrorAsOutParameter _(&ResolutionError);
938     if (R)
939       Result = std::move(R->Symbols);
940     else
941       ResolutionError = R.takeError();
942   };
943   auto OnReady = [&](Error Err) {
944     ErrorAsOutParameter _(&ReadyError);
945     if (Err)
946       ReadyError = std::move(Err);
947   };
948 #endif
949 
950   auto Query = std::make_shared<AsynchronousSymbolQuery>(
951       Names, std::move(OnResolve), std::move(OnReady));
952   SymbolNameSet UnresolvedSymbols(std::move(Names));
953 
954   for (auto *V : VSOs) {
955     assert(V && "VSO pointers in VSOs list should be non-null");
956     if (UnresolvedSymbols.empty())
957       break;
958     UnresolvedSymbols = V->lookup(Query, UnresolvedSymbols);
959   }
960 
961   if (!UnresolvedSymbols.empty()) {
962     // If there are unresolved symbols then the query will never return.
963     // Fail it with ES.failQuery.
964     auto &ES = (*VSOs.begin())->getExecutionSession();
965     ES.failQuery(*Query,
966                  make_error<SymbolsNotFound>(std::move(UnresolvedSymbols)));
967   }
968 
969 #if LLVM_ENABLE_THREADS
970   auto ResultFuture = PromisedResult.get_future();
971   auto Result = ResultFuture.get();
972 
973   {
974     std::lock_guard<std::mutex> Lock(ErrMutex);
975     if (ResolutionError) {
976       // ReadyError will never be assigned. Consume the success value.
977       cantFail(std::move(ReadyError));
978       return std::move(ResolutionError);
979     }
980   }
981 
982   auto ReadyFuture = PromisedReady.get_future();
983   ReadyFuture.get();
984 
985   {
986     std::lock_guard<std::mutex> Lock(ErrMutex);
987     if (ReadyError)
988       return std::move(ReadyError);
989   }
990 
991   return std::move(Result);
992 
993 #else
994   if (ResolutionError) {
995     // ReadyError will never be assigned. Consume the success value.
996     cantFail(std::move(ReadyError));
997     return std::move(ResolutionError);
998   }
999 
1000   if (ReadyError)
1001     return std::move(ReadyError);
1002 
1003   return Result;
1004 #endif
1005 }
1006 
1007 /// Look up a symbol by searching a list of VSOs.
1008 Expected<JITEvaluatedSymbol> lookup(const VSO::VSOList &VSOs,
1009                                     SymbolStringPtr Name) {
1010   SymbolNameSet Names({Name});
1011   if (auto ResultMap = lookup(VSOs, std::move(Names))) {
1012     assert(ResultMap->size() == 1 && "Unexpected number of results");
1013     assert(ResultMap->count(Name) && "Missing result for symbol");
1014     return std::move(ResultMap->begin()->second);
1015   } else
1016     return ResultMap.takeError();
1017 }
1018 
1019 } // End namespace orc.
1020 } // End namespace llvm.
1021