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