1 //===--------- Core.cpp - Core ORC APIs (SymbolSource, 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/ExecutionEngine/Orc/OrcError.h"
12 
13 namespace llvm {
14 namespace orc {
15 
16 void SymbolSource::anchor() {}
17 
18 AsynchronousSymbolQuery::AsynchronousSymbolQuery(
19     const SymbolNameSet &Symbols, SymbolsResolvedCallback NotifySymbolsResolved,
20     SymbolsReadyCallback NotifySymbolsReady)
21     : NotifySymbolsResolved(std::move(NotifySymbolsResolved)),
22       NotifySymbolsReady(std::move(NotifySymbolsReady)) {
23   assert(this->NotifySymbolsResolved &&
24          "Symbols resolved callback must be set");
25   assert(this->NotifySymbolsReady && "Symbols ready callback must be set");
26   OutstandingResolutions = OutstandingFinalizations = Symbols.size();
27 }
28 
29 void AsynchronousSymbolQuery::setFailed(Error Err) {
30   OutstandingResolutions = OutstandingFinalizations = 0;
31   if (NotifySymbolsResolved)
32     NotifySymbolsResolved(std::move(Err));
33   else
34     NotifySymbolsReady(std::move(Err));
35 }
36 
37 void AsynchronousSymbolQuery::setDefinition(SymbolStringPtr Name,
38                                             JITEvaluatedSymbol Sym) {
39   // If OutstandingResolutions is zero we must have errored out already. Just
40   // ignore this.
41   if (OutstandingResolutions == 0)
42     return;
43 
44   assert(!Symbols.count(Name) && "Symbol has already been assigned an address");
45   Symbols.insert(std::make_pair(std::move(Name), std::move(Sym)));
46   --OutstandingResolutions;
47   if (OutstandingResolutions == 0) {
48     NotifySymbolsResolved(std::move(Symbols));
49     // Null out NotifySymbolsResolved to indicate that we've already called it.
50     NotifySymbolsResolved = {};
51   }
52 }
53 
54 void AsynchronousSymbolQuery::notifySymbolFinalized() {
55   // If OutstandingFinalizations is zero we must have errored out already. Just
56   // ignore this.
57   if (OutstandingFinalizations == 0)
58     return;
59 
60   assert(OutstandingFinalizations > 0 && "All symbols already finalized");
61   --OutstandingFinalizations;
62   if (OutstandingFinalizations == 0)
63     NotifySymbolsReady(Error::success());
64 }
65 
66 VSO::MaterializationInfo::MaterializationInfo(JITSymbolFlags Flags,
67                                               AsynchronousSymbolQuery &Query)
68     : Flags(std::move(Flags)), PendingResolution({&Query}) {}
69 
70 JITSymbolFlags VSO::MaterializationInfo::getFlags() const { return Flags; }
71 
72 JITTargetAddress VSO::MaterializationInfo::getAddress() const {
73   return Address;
74 }
75 
76 void VSO::MaterializationInfo::query(SymbolStringPtr Name,
77                                      AsynchronousSymbolQuery &Query) {
78   if (Address != 0) {
79     Query.setDefinition(Name, JITEvaluatedSymbol(Address, Flags));
80     PendingFinalization.push_back(&Query);
81   } else
82     PendingResolution.push_back(&Query);
83 }
84 
85 void VSO::MaterializationInfo::resolve(SymbolStringPtr Name,
86                                        JITEvaluatedSymbol Sym) {
87   // FIXME: Sanity check flags?
88   Flags = Sym.getFlags();
89   Address = Sym.getAddress();
90   for (auto *Query : PendingResolution) {
91     Query->setDefinition(Name, std::move(Sym));
92     PendingFinalization.push_back(Query);
93   }
94   PendingResolution = {};
95 }
96 
97 void VSO::MaterializationInfo::finalize() {
98   for (auto *Query : PendingFinalization)
99     Query->notifySymbolFinalized();
100   PendingFinalization = {};
101 }
102 
103 VSO::SymbolTableEntry::SymbolTableEntry(JITSymbolFlags Flags,
104                                         SymbolSource &Source)
105     : Flags(JITSymbolFlags::FlagNames(Flags | JITSymbolFlags::NotMaterialized)),
106       Source(&Source) {
107   // FIXME: Assert flag sanity.
108 }
109 
110 VSO::SymbolTableEntry::SymbolTableEntry(JITEvaluatedSymbol Sym)
111     : Flags(Sym.getFlags()), Address(Sym.getAddress()) {
112   // FIXME: Assert flag sanity.
113 }
114 
115 VSO::SymbolTableEntry::SymbolTableEntry(SymbolTableEntry &&Other)
116     : Flags(Other.Flags), Address(0) {
117   if (Flags.isMaterializing())
118     MatInfo = std::move(Other.MatInfo);
119   else
120     Source = Other.Source;
121 }
122 
123 VSO::SymbolTableEntry::~SymbolTableEntry() {
124   assert(!Flags.isMaterializing() &&
125          "Symbol table entry destroyed while symbol was being materialized");
126 }
127 
128 JITSymbolFlags VSO::SymbolTableEntry::getFlags() const { return Flags; }
129 
130 void VSO::SymbolTableEntry::replaceWithSource(VSO &V, SymbolStringPtr Name,
131                                               JITSymbolFlags Flags,
132                                               SymbolSource &NewSource) {
133   assert(!this->Flags.isMaterializing() &&
134          "Attempted to replace symbol with lazy definition during "
135          "materialization");
136   if (!this->Flags.isMaterialized())
137     Source->discard(V, Name);
138   this->Flags = Flags;
139   this->Source = &NewSource;
140 }
141 
142 SymbolSource *VSO::SymbolTableEntry::query(SymbolStringPtr Name,
143                                            AsynchronousSymbolQuery &Query) {
144   if (Flags.isMaterializing()) {
145     MatInfo->query(std::move(Name), Query);
146     return nullptr;
147   } else if (Flags.isMaterialized()) {
148     Query.setDefinition(std::move(Name), JITEvaluatedSymbol(Address, Flags));
149     Query.notifySymbolFinalized();
150     return nullptr;
151   }
152   SymbolSource *S = Source;
153   new (&MatInfo) std::unique_ptr<MaterializationInfo>(
154       llvm::make_unique<MaterializationInfo>(Flags, Query));
155   Flags |= JITSymbolFlags::Materializing;
156   return S;
157 }
158 
159 void VSO::SymbolTableEntry::resolve(VSO &V, SymbolStringPtr Name,
160                                     JITEvaluatedSymbol Sym) {
161   if (Flags.isMaterializing())
162     MatInfo->resolve(std::move(Name), std::move(Sym));
163   else {
164     // If there's a layer for this symbol.
165     if (!Flags.isMaterialized())
166       Source->discard(V, Name);
167 
168     // FIXME: Should we assert flag state here (flags must match except for
169     //        materialization state, overrides must be legal) or in the caller
170     //        in VSO?
171     Flags = Sym.getFlags();
172     Address = Sym.getAddress();
173   }
174 }
175 
176 void VSO::SymbolTableEntry::finalize() {
177   if (Flags.isMaterializing()) {
178     auto TmpMatInfo = std::move(MatInfo);
179     MatInfo.std::unique_ptr<MaterializationInfo>::~unique_ptr();
180     // FIXME: Assert flag sanity?
181     Flags = TmpMatInfo->getFlags();
182     Address = TmpMatInfo->getAddress();
183     TmpMatInfo->finalize();
184   }
185   assert(Flags.isMaterialized() && "Trying to finalize not-emitted symbol");
186 }
187 
188 VSO::RelativeLinkageStrength VSO::compareLinkage(Optional<JITSymbolFlags> Old,
189                                                  JITSymbolFlags New) {
190   if (Old == None)
191     return llvm::orc::VSO::NewDefinitionIsStronger;
192 
193   if (Old->isStrong()) {
194     if (New.isStrong())
195       return llvm::orc::VSO::DuplicateDefinition;
196     else
197       return llvm::orc::VSO::ExistingDefinitionIsStronger;
198   } else {
199     if (New.isStrong())
200       return llvm::orc::VSO::NewDefinitionIsStronger;
201     else
202       return llvm::orc::VSO::ExistingDefinitionIsStronger;
203   }
204 }
205 
206 VSO::RelativeLinkageStrength
207 VSO::compareLinkage(SymbolStringPtr Name, JITSymbolFlags NewFlags) const {
208   auto I = Symbols.find(Name);
209   return compareLinkage(I == Symbols.end()
210                             ? None
211                             : Optional<JITSymbolFlags>(I->second.getFlags()),
212                         NewFlags);
213 }
214 
215 Error VSO::define(SymbolMap NewSymbols) {
216   Error Err = Error::success();
217   for (auto &KV : NewSymbols) {
218     auto I = Symbols.find(KV.first);
219     auto LinkageResult = compareLinkage(
220         I == Symbols.end() ? None
221                            : Optional<JITSymbolFlags>(I->second.getFlags()),
222         KV.second.getFlags());
223 
224     // Silently discard weaker definitions.
225     if (LinkageResult == ExistingDefinitionIsStronger)
226       continue;
227 
228     // Report duplicate definition errors.
229     if (LinkageResult == DuplicateDefinition) {
230       Err = joinErrors(std::move(Err),
231                        make_error<orc::DuplicateDefinition>(*KV.first));
232       continue;
233     }
234 
235     if (I != Symbols.end()) {
236       I->second.resolve(*this, KV.first, std::move(KV.second));
237       I->second.finalize();
238     } else
239       Symbols.insert(std::make_pair(KV.first, std::move(KV.second)));
240   }
241   return Err;
242 }
243 
244 Error VSO::defineLazy(const SymbolFlagsMap &NewSymbols, SymbolSource &Source) {
245   Error Err = Error::success();
246   for (auto &KV : NewSymbols) {
247     auto I = Symbols.find(KV.first);
248 
249     auto LinkageResult = compareLinkage(
250         I == Symbols.end() ? None
251                            : Optional<JITSymbolFlags>(I->second.getFlags()),
252         KV.second);
253 
254     // Discard weaker definitions.
255     if (LinkageResult == ExistingDefinitionIsStronger)
256       Source.discard(*this, KV.first);
257 
258     // Report duplicate definition errors.
259     if (LinkageResult == DuplicateDefinition) {
260       Err = joinErrors(std::move(Err),
261                        make_error<orc::DuplicateDefinition>(*KV.first));
262       continue;
263     }
264 
265     if (I != Symbols.end())
266       I->second.replaceWithSource(*this, KV.first, KV.second, Source);
267     else
268       Symbols.emplace(
269           std::make_pair(KV.first, SymbolTableEntry(KV.second, Source)));
270   }
271   return Err;
272 }
273 
274 void VSO::resolve(SymbolMap SymbolValues) {
275   for (auto &KV : SymbolValues) {
276     auto I = Symbols.find(KV.first);
277     assert(I != Symbols.end() && "Resolving symbol not present in this dylib");
278     I->second.resolve(*this, KV.first, std::move(KV.second));
279   }
280 }
281 
282 void VSO::finalize(SymbolNameSet SymbolsToFinalize) {
283   for (auto &S : SymbolsToFinalize) {
284     auto I = Symbols.find(S);
285     assert(I != Symbols.end() && "Finalizing symbol not present in this dylib");
286     I->second.finalize();
287   }
288 }
289 
290 VSO::LookupResult VSO::lookup(AsynchronousSymbolQuery &Query,
291                               SymbolNameSet Names) {
292   SourceWorkMap MaterializationWork;
293 
294   for (SymbolNameSet::iterator I = Names.begin(), E = Names.end(); I != E;) {
295     auto Tmp = I;
296     ++I;
297     auto SymI = Symbols.find(*Tmp);
298 
299     // If the symbol isn't in this dylib then just continue.
300     // If it is, erase it from Names and proceed.
301     if (SymI == Symbols.end())
302       continue;
303     else
304       Names.erase(Tmp);
305 
306     // Forward the query to the given SymbolTableEntry, and if it return a
307     // layer to perform materialization with, add that to the
308     // MaterializationWork map.
309     if (auto *Source = SymI->second.query(SymI->first, Query))
310       MaterializationWork[Source].insert(SymI->first);
311   }
312 
313   return {std::move(MaterializationWork), std::move(Names)};
314 }
315 
316 VModuleKey ExecutionSession::allocateVModule() { return ++LastKey; }
317 
318 void ExecutionSession::releaseVModule(VModuleKey VMod) {
319   // FIXME: Recycle keys.
320 }
321 
322 } // End namespace orc.
323 } // End namespace llvm.
324