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