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