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