Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
14 | pmbaty | 1 | //===------ Core.h -- Core ORC APIs (Layer, JITDylib, etc.) -----*- C++ -*-===// |
2 | // |
||
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
||
4 | // See https://llvm.org/LICENSE.txt for license information. |
||
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
||
6 | // |
||
7 | //===----------------------------------------------------------------------===// |
||
8 | // |
||
9 | // Contains core ORC APIs. |
||
10 | // |
||
11 | //===----------------------------------------------------------------------===// |
||
12 | |||
13 | #ifndef LLVM_EXECUTIONENGINE_ORC_CORE_H |
||
14 | #define LLVM_EXECUTIONENGINE_ORC_CORE_H |
||
15 | |||
16 | #include "llvm/ADT/BitmaskEnum.h" |
||
17 | #include "llvm/ADT/DenseSet.h" |
||
18 | #include "llvm/ADT/FunctionExtras.h" |
||
19 | #include "llvm/ADT/IntrusiveRefCntPtr.h" |
||
20 | #include "llvm/ExecutionEngine/JITLink/JITLinkDylib.h" |
||
21 | #include "llvm/ExecutionEngine/JITSymbol.h" |
||
22 | #include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h" |
||
23 | #include "llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h" |
||
24 | #include "llvm/ExecutionEngine/Orc/TaskDispatch.h" |
||
25 | #include "llvm/Support/Debug.h" |
||
26 | #include "llvm/Support/ExtensibleRTTI.h" |
||
27 | |||
28 | #include <atomic> |
||
29 | #include <future> |
||
30 | #include <memory> |
||
31 | #include <vector> |
||
32 | |||
33 | namespace llvm { |
||
34 | namespace orc { |
||
35 | |||
36 | // Forward declare some classes. |
||
37 | class AsynchronousSymbolQuery; |
||
38 | class ExecutionSession; |
||
39 | class MaterializationUnit; |
||
40 | class MaterializationResponsibility; |
||
41 | class JITDylib; |
||
42 | class ResourceTracker; |
||
43 | class InProgressLookupState; |
||
44 | |||
45 | enum class SymbolState : uint8_t; |
||
46 | |||
47 | using ResourceTrackerSP = IntrusiveRefCntPtr<ResourceTracker>; |
||
48 | using JITDylibSP = IntrusiveRefCntPtr<JITDylib>; |
||
49 | |||
50 | using ResourceKey = uintptr_t; |
||
51 | |||
52 | /// API to remove / transfer ownership of JIT resources. |
||
53 | class ResourceTracker : public ThreadSafeRefCountedBase<ResourceTracker> { |
||
54 | private: |
||
55 | friend class ExecutionSession; |
||
56 | friend class JITDylib; |
||
57 | friend class MaterializationResponsibility; |
||
58 | |||
59 | public: |
||
60 | ResourceTracker(const ResourceTracker &) = delete; |
||
61 | ResourceTracker &operator=(const ResourceTracker &) = delete; |
||
62 | ResourceTracker(ResourceTracker &&) = delete; |
||
63 | ResourceTracker &operator=(ResourceTracker &&) = delete; |
||
64 | |||
65 | ~ResourceTracker(); |
||
66 | |||
67 | /// Return the JITDylib targeted by this tracker. |
||
68 | JITDylib &getJITDylib() const { |
||
69 | return *reinterpret_cast<JITDylib *>(JDAndFlag.load() & |
||
70 | ~static_cast<uintptr_t>(1)); |
||
71 | } |
||
72 | |||
73 | /// Runs the given callback under the session lock, passing in the associated |
||
74 | /// ResourceKey. This is the safe way to associate resources with trackers. |
||
75 | template <typename Func> Error withResourceKeyDo(Func &&F); |
||
76 | |||
77 | /// Remove all resources associated with this key. |
||
78 | Error remove(); |
||
79 | |||
80 | /// Transfer all resources associated with this key to the given |
||
81 | /// tracker, which must target the same JITDylib as this one. |
||
82 | void transferTo(ResourceTracker &DstRT); |
||
83 | |||
84 | /// Return true if this tracker has become defunct. |
||
85 | bool isDefunct() const { return JDAndFlag.load() & 0x1; } |
||
86 | |||
87 | /// Returns the key associated with this tracker. |
||
88 | /// This method should not be used except for debug logging: there is no |
||
89 | /// guarantee that the returned value will remain valid. |
||
90 | ResourceKey getKeyUnsafe() const { return reinterpret_cast<uintptr_t>(this); } |
||
91 | |||
92 | private: |
||
93 | ResourceTracker(JITDylibSP JD); |
||
94 | |||
95 | void makeDefunct(); |
||
96 | |||
97 | std::atomic_uintptr_t JDAndFlag; |
||
98 | }; |
||
99 | |||
100 | /// Listens for ResourceTracker operations. |
||
101 | class ResourceManager { |
||
102 | public: |
||
103 | virtual ~ResourceManager(); |
||
104 | virtual Error handleRemoveResources(JITDylib &JD, ResourceKey K) = 0; |
||
105 | virtual void handleTransferResources(JITDylib &JD, ResourceKey DstK, |
||
106 | ResourceKey SrcK) = 0; |
||
107 | }; |
||
108 | |||
109 | /// A set of symbol names (represented by SymbolStringPtrs for |
||
110 | // efficiency). |
||
111 | using SymbolNameSet = DenseSet<SymbolStringPtr>; |
||
112 | |||
113 | /// A vector of symbol names. |
||
114 | using SymbolNameVector = std::vector<SymbolStringPtr>; |
||
115 | |||
116 | /// A map from symbol names (as SymbolStringPtrs) to JITSymbols |
||
117 | /// (address/flags pairs). |
||
118 | using SymbolMap = DenseMap<SymbolStringPtr, JITEvaluatedSymbol>; |
||
119 | |||
120 | /// A map from symbol names (as SymbolStringPtrs) to JITSymbolFlags. |
||
121 | using SymbolFlagsMap = DenseMap<SymbolStringPtr, JITSymbolFlags>; |
||
122 | |||
123 | /// A map from JITDylibs to sets of symbols. |
||
124 | using SymbolDependenceMap = DenseMap<JITDylib *, SymbolNameSet>; |
||
125 | |||
126 | /// Lookup flags that apply to each dylib in the search order for a lookup. |
||
127 | /// |
||
128 | /// If MatchHiddenSymbolsOnly is used (the default) for a given dylib, then |
||
129 | /// only symbols in that Dylib's interface will be searched. If |
||
130 | /// MatchHiddenSymbols is used then symbols with hidden visibility will match |
||
131 | /// as well. |
||
132 | enum class JITDylibLookupFlags { MatchExportedSymbolsOnly, MatchAllSymbols }; |
||
133 | |||
134 | /// Lookup flags that apply to each symbol in a lookup. |
||
135 | /// |
||
136 | /// If RequiredSymbol is used (the default) for a given symbol then that symbol |
||
137 | /// must be found during the lookup or the lookup will fail returning a |
||
138 | /// SymbolNotFound error. If WeaklyReferencedSymbol is used and the given |
||
139 | /// symbol is not found then the query will continue, and no result for the |
||
140 | /// missing symbol will be present in the result (assuming the rest of the |
||
141 | /// lookup succeeds). |
||
142 | enum class SymbolLookupFlags { RequiredSymbol, WeaklyReferencedSymbol }; |
||
143 | |||
144 | /// Describes the kind of lookup being performed. The lookup kind is passed to |
||
145 | /// symbol generators (if they're invoked) to help them determine what |
||
146 | /// definitions to generate. |
||
147 | /// |
||
148 | /// Static -- Lookup is being performed as-if at static link time (e.g. |
||
149 | /// generators representing static archives should pull in new |
||
150 | /// definitions). |
||
151 | /// |
||
152 | /// DLSym -- Lookup is being performed as-if at runtime (e.g. generators |
||
153 | /// representing static archives should not pull in new definitions). |
||
154 | enum class LookupKind { Static, DLSym }; |
||
155 | |||
156 | /// A list of (JITDylib*, JITDylibLookupFlags) pairs to be used as a search |
||
157 | /// order during symbol lookup. |
||
158 | using JITDylibSearchOrder = |
||
159 | std::vector<std::pair<JITDylib *, JITDylibLookupFlags>>; |
||
160 | |||
161 | /// Convenience function for creating a search order from an ArrayRef of |
||
162 | /// JITDylib*, all with the same flags. |
||
163 | inline JITDylibSearchOrder makeJITDylibSearchOrder( |
||
164 | ArrayRef<JITDylib *> JDs, |
||
165 | JITDylibLookupFlags Flags = JITDylibLookupFlags::MatchExportedSymbolsOnly) { |
||
166 | JITDylibSearchOrder O; |
||
167 | O.reserve(JDs.size()); |
||
168 | for (auto *JD : JDs) |
||
169 | O.push_back(std::make_pair(JD, Flags)); |
||
170 | return O; |
||
171 | } |
||
172 | |||
173 | /// A set of symbols to look up, each associated with a SymbolLookupFlags |
||
174 | /// value. |
||
175 | /// |
||
176 | /// This class is backed by a vector and optimized for fast insertion, |
||
177 | /// deletion and iteration. It does not guarantee a stable order between |
||
178 | /// operations, and will not automatically detect duplicate elements (they |
||
179 | /// can be manually checked by calling the validate method). |
||
180 | class SymbolLookupSet { |
||
181 | public: |
||
182 | using value_type = std::pair<SymbolStringPtr, SymbolLookupFlags>; |
||
183 | using UnderlyingVector = std::vector<value_type>; |
||
184 | using iterator = UnderlyingVector::iterator; |
||
185 | using const_iterator = UnderlyingVector::const_iterator; |
||
186 | |||
187 | SymbolLookupSet() = default; |
||
188 | |||
189 | explicit SymbolLookupSet( |
||
190 | SymbolStringPtr Name, |
||
191 | SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) { |
||
192 | add(std::move(Name), Flags); |
||
193 | } |
||
194 | |||
195 | /// Construct a SymbolLookupSet from an initializer list of SymbolStringPtrs. |
||
196 | explicit SymbolLookupSet( |
||
197 | std::initializer_list<SymbolStringPtr> Names, |
||
198 | SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) { |
||
199 | Symbols.reserve(Names.size()); |
||
200 | for (const auto &Name : Names) |
||
201 | add(std::move(Name), Flags); |
||
202 | } |
||
203 | |||
204 | /// Construct a SymbolLookupSet from a SymbolNameSet with the given |
||
205 | /// Flags used for each value. |
||
206 | explicit SymbolLookupSet( |
||
207 | const SymbolNameSet &Names, |
||
208 | SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) { |
||
209 | Symbols.reserve(Names.size()); |
||
210 | for (const auto &Name : Names) |
||
211 | add(Name, Flags); |
||
212 | } |
||
213 | |||
214 | /// Construct a SymbolLookupSet from a vector of symbols with the given Flags |
||
215 | /// used for each value. |
||
216 | /// If the ArrayRef contains duplicates it is up to the client to remove these |
||
217 | /// before using this instance for lookup. |
||
218 | explicit SymbolLookupSet( |
||
219 | ArrayRef<SymbolStringPtr> Names, |
||
220 | SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) { |
||
221 | Symbols.reserve(Names.size()); |
||
222 | for (const auto &Name : Names) |
||
223 | add(Name, Flags); |
||
224 | } |
||
225 | |||
226 | /// Construct a SymbolLookupSet from DenseMap keys. |
||
227 | template <typename KeyT> |
||
228 | static SymbolLookupSet |
||
229 | fromMapKeys(const DenseMap<SymbolStringPtr, KeyT> &M, |
||
230 | SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) { |
||
231 | SymbolLookupSet Result; |
||
232 | Result.Symbols.reserve(M.size()); |
||
233 | for (const auto &KV : M) |
||
234 | Result.add(KV.first, Flags); |
||
235 | return Result; |
||
236 | } |
||
237 | |||
238 | /// Add an element to the set. The client is responsible for checking that |
||
239 | /// duplicates are not added. |
||
240 | SymbolLookupSet & |
||
241 | add(SymbolStringPtr Name, |
||
242 | SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) { |
||
243 | Symbols.push_back(std::make_pair(std::move(Name), Flags)); |
||
244 | return *this; |
||
245 | } |
||
246 | |||
247 | /// Quickly append one lookup set to another. |
||
248 | SymbolLookupSet &append(SymbolLookupSet Other) { |
||
249 | Symbols.reserve(Symbols.size() + Other.size()); |
||
250 | for (auto &KV : Other) |
||
251 | Symbols.push_back(std::move(KV)); |
||
252 | return *this; |
||
253 | } |
||
254 | |||
255 | bool empty() const { return Symbols.empty(); } |
||
256 | UnderlyingVector::size_type size() const { return Symbols.size(); } |
||
257 | iterator begin() { return Symbols.begin(); } |
||
258 | iterator end() { return Symbols.end(); } |
||
259 | const_iterator begin() const { return Symbols.begin(); } |
||
260 | const_iterator end() const { return Symbols.end(); } |
||
261 | |||
262 | /// Removes the Ith element of the vector, replacing it with the last element. |
||
263 | void remove(UnderlyingVector::size_type I) { |
||
264 | std::swap(Symbols[I], Symbols.back()); |
||
265 | Symbols.pop_back(); |
||
266 | } |
||
267 | |||
268 | /// Removes the element pointed to by the given iterator. This iterator and |
||
269 | /// all subsequent ones (including end()) are invalidated. |
||
270 | void remove(iterator I) { remove(I - begin()); } |
||
271 | |||
272 | /// Removes all elements matching the given predicate, which must be callable |
||
273 | /// as bool(const SymbolStringPtr &, SymbolLookupFlags Flags). |
||
274 | template <typename PredFn> void remove_if(PredFn &&Pred) { |
||
275 | UnderlyingVector::size_type I = 0; |
||
276 | while (I != Symbols.size()) { |
||
277 | const auto &Name = Symbols[I].first; |
||
278 | auto Flags = Symbols[I].second; |
||
279 | if (Pred(Name, Flags)) |
||
280 | remove(I); |
||
281 | else |
||
282 | ++I; |
||
283 | } |
||
284 | } |
||
285 | |||
286 | /// Loop over the elements of this SymbolLookupSet, applying the Body function |
||
287 | /// to each one. Body must be callable as |
||
288 | /// bool(const SymbolStringPtr &, SymbolLookupFlags). |
||
289 | /// If Body returns true then the element just passed in is removed from the |
||
290 | /// set. If Body returns false then the element is retained. |
||
291 | template <typename BodyFn> |
||
292 | auto forEachWithRemoval(BodyFn &&Body) -> std::enable_if_t< |
||
293 | std::is_same<decltype(Body(std::declval<const SymbolStringPtr &>(), |
||
294 | std::declval<SymbolLookupFlags>())), |
||
295 | bool>::value> { |
||
296 | UnderlyingVector::size_type I = 0; |
||
297 | while (I != Symbols.size()) { |
||
298 | const auto &Name = Symbols[I].first; |
||
299 | auto Flags = Symbols[I].second; |
||
300 | if (Body(Name, Flags)) |
||
301 | remove(I); |
||
302 | else |
||
303 | ++I; |
||
304 | } |
||
305 | } |
||
306 | |||
307 | /// Loop over the elements of this SymbolLookupSet, applying the Body function |
||
308 | /// to each one. Body must be callable as |
||
309 | /// Expected<bool>(const SymbolStringPtr &, SymbolLookupFlags). |
||
310 | /// If Body returns a failure value, the loop exits immediately. If Body |
||
311 | /// returns true then the element just passed in is removed from the set. If |
||
312 | /// Body returns false then the element is retained. |
||
313 | template <typename BodyFn> |
||
314 | auto forEachWithRemoval(BodyFn &&Body) -> std::enable_if_t< |
||
315 | std::is_same<decltype(Body(std::declval<const SymbolStringPtr &>(), |
||
316 | std::declval<SymbolLookupFlags>())), |
||
317 | Expected<bool>>::value, |
||
318 | Error> { |
||
319 | UnderlyingVector::size_type I = 0; |
||
320 | while (I != Symbols.size()) { |
||
321 | const auto &Name = Symbols[I].first; |
||
322 | auto Flags = Symbols[I].second; |
||
323 | auto Remove = Body(Name, Flags); |
||
324 | if (!Remove) |
||
325 | return Remove.takeError(); |
||
326 | if (*Remove) |
||
327 | remove(I); |
||
328 | else |
||
329 | ++I; |
||
330 | } |
||
331 | return Error::success(); |
||
332 | } |
||
333 | |||
334 | /// Construct a SymbolNameVector from this instance by dropping the Flags |
||
335 | /// values. |
||
336 | SymbolNameVector getSymbolNames() const { |
||
337 | SymbolNameVector Names; |
||
338 | Names.reserve(Symbols.size()); |
||
339 | for (const auto &KV : Symbols) |
||
340 | Names.push_back(KV.first); |
||
341 | return Names; |
||
342 | } |
||
343 | |||
344 | /// Sort the lookup set by pointer value. This sort is fast but sensitive to |
||
345 | /// allocation order and so should not be used where a consistent order is |
||
346 | /// required. |
||
347 | void sortByAddress() { llvm::sort(Symbols, llvm::less_first()); } |
||
348 | |||
349 | /// Sort the lookup set lexicographically. This sort is slow but the order |
||
350 | /// is unaffected by allocation order. |
||
351 | void sortByName() { |
||
352 | llvm::sort(Symbols, [](const value_type &LHS, const value_type &RHS) { |
||
353 | return *LHS.first < *RHS.first; |
||
354 | }); |
||
355 | } |
||
356 | |||
357 | /// Remove any duplicate elements. If a SymbolLookupSet is not duplicate-free |
||
358 | /// by construction, this method can be used to turn it into a proper set. |
||
359 | void removeDuplicates() { |
||
360 | sortByAddress(); |
||
361 | auto LastI = std::unique(Symbols.begin(), Symbols.end()); |
||
362 | Symbols.erase(LastI, Symbols.end()); |
||
363 | } |
||
364 | |||
365 | #ifndef NDEBUG |
||
366 | /// Returns true if this set contains any duplicates. This should only be used |
||
367 | /// in assertions. |
||
368 | bool containsDuplicates() { |
||
369 | if (Symbols.size() < 2) |
||
370 | return false; |
||
371 | sortByAddress(); |
||
372 | for (UnderlyingVector::size_type I = 1; I != Symbols.size(); ++I) |
||
373 | if (Symbols[I].first == Symbols[I - 1].first) |
||
374 | return true; |
||
375 | return false; |
||
376 | } |
||
377 | #endif |
||
378 | |||
379 | private: |
||
380 | UnderlyingVector Symbols; |
||
381 | }; |
||
382 | |||
383 | struct SymbolAliasMapEntry { |
||
384 | SymbolAliasMapEntry() = default; |
||
385 | SymbolAliasMapEntry(SymbolStringPtr Aliasee, JITSymbolFlags AliasFlags) |
||
386 | : Aliasee(std::move(Aliasee)), AliasFlags(AliasFlags) {} |
||
387 | |||
388 | SymbolStringPtr Aliasee; |
||
389 | JITSymbolFlags AliasFlags; |
||
390 | }; |
||
391 | |||
392 | /// A map of Symbols to (Symbol, Flags) pairs. |
||
393 | using SymbolAliasMap = DenseMap<SymbolStringPtr, SymbolAliasMapEntry>; |
||
394 | |||
395 | /// Callback to notify client that symbols have been resolved. |
||
396 | using SymbolsResolvedCallback = unique_function<void(Expected<SymbolMap>)>; |
||
397 | |||
398 | /// Callback to register the dependencies for a given query. |
||
399 | using RegisterDependenciesFunction = |
||
400 | std::function<void(const SymbolDependenceMap &)>; |
||
401 | |||
402 | /// This can be used as the value for a RegisterDependenciesFunction if there |
||
403 | /// are no dependants to register with. |
||
404 | extern RegisterDependenciesFunction NoDependenciesToRegister; |
||
405 | |||
406 | class ResourceTrackerDefunct : public ErrorInfo<ResourceTrackerDefunct> { |
||
407 | public: |
||
408 | static char ID; |
||
409 | |||
410 | ResourceTrackerDefunct(ResourceTrackerSP RT); |
||
411 | std::error_code convertToErrorCode() const override; |
||
412 | void log(raw_ostream &OS) const override; |
||
413 | |||
414 | private: |
||
415 | ResourceTrackerSP RT; |
||
416 | }; |
||
417 | |||
418 | /// Used to notify a JITDylib that the given set of symbols failed to |
||
419 | /// materialize. |
||
420 | class FailedToMaterialize : public ErrorInfo<FailedToMaterialize> { |
||
421 | public: |
||
422 | static char ID; |
||
423 | |||
424 | FailedToMaterialize(std::shared_ptr<SymbolStringPool> SSP, |
||
425 | std::shared_ptr<SymbolDependenceMap> Symbols); |
||
426 | ~FailedToMaterialize(); |
||
427 | std::error_code convertToErrorCode() const override; |
||
428 | void log(raw_ostream &OS) const override; |
||
429 | const SymbolDependenceMap &getSymbols() const { return *Symbols; } |
||
430 | |||
431 | private: |
||
432 | std::shared_ptr<SymbolStringPool> SSP; |
||
433 | std::shared_ptr<SymbolDependenceMap> Symbols; |
||
434 | }; |
||
435 | |||
436 | /// Used to notify clients when symbols can not be found during a lookup. |
||
437 | class SymbolsNotFound : public ErrorInfo<SymbolsNotFound> { |
||
438 | public: |
||
439 | static char ID; |
||
440 | |||
441 | SymbolsNotFound(std::shared_ptr<SymbolStringPool> SSP, SymbolNameSet Symbols); |
||
442 | SymbolsNotFound(std::shared_ptr<SymbolStringPool> SSP, |
||
443 | SymbolNameVector Symbols); |
||
444 | std::error_code convertToErrorCode() const override; |
||
445 | void log(raw_ostream &OS) const override; |
||
446 | std::shared_ptr<SymbolStringPool> getSymbolStringPool() { return SSP; } |
||
447 | const SymbolNameVector &getSymbols() const { return Symbols; } |
||
448 | |||
449 | private: |
||
450 | std::shared_ptr<SymbolStringPool> SSP; |
||
451 | SymbolNameVector Symbols; |
||
452 | }; |
||
453 | |||
454 | /// Used to notify clients that a set of symbols could not be removed. |
||
455 | class SymbolsCouldNotBeRemoved : public ErrorInfo<SymbolsCouldNotBeRemoved> { |
||
456 | public: |
||
457 | static char ID; |
||
458 | |||
459 | SymbolsCouldNotBeRemoved(std::shared_ptr<SymbolStringPool> SSP, |
||
460 | SymbolNameSet Symbols); |
||
461 | std::error_code convertToErrorCode() const override; |
||
462 | void log(raw_ostream &OS) const override; |
||
463 | std::shared_ptr<SymbolStringPool> getSymbolStringPool() { return SSP; } |
||
464 | const SymbolNameSet &getSymbols() const { return Symbols; } |
||
465 | |||
466 | private: |
||
467 | std::shared_ptr<SymbolStringPool> SSP; |
||
468 | SymbolNameSet Symbols; |
||
469 | }; |
||
470 | |||
471 | /// Errors of this type should be returned if a module fails to include |
||
472 | /// definitions that are claimed by the module's associated |
||
473 | /// MaterializationResponsibility. If this error is returned it is indicative of |
||
474 | /// a broken transformation / compiler / object cache. |
||
475 | class MissingSymbolDefinitions : public ErrorInfo<MissingSymbolDefinitions> { |
||
476 | public: |
||
477 | static char ID; |
||
478 | |||
479 | MissingSymbolDefinitions(std::shared_ptr<SymbolStringPool> SSP, |
||
480 | std::string ModuleName, SymbolNameVector Symbols) |
||
481 | : SSP(std::move(SSP)), ModuleName(std::move(ModuleName)), |
||
482 | Symbols(std::move(Symbols)) {} |
||
483 | std::error_code convertToErrorCode() const override; |
||
484 | void log(raw_ostream &OS) const override; |
||
485 | std::shared_ptr<SymbolStringPool> getSymbolStringPool() { return SSP; } |
||
486 | const std::string &getModuleName() const { return ModuleName; } |
||
487 | const SymbolNameVector &getSymbols() const { return Symbols; } |
||
488 | private: |
||
489 | std::shared_ptr<SymbolStringPool> SSP; |
||
490 | std::string ModuleName; |
||
491 | SymbolNameVector Symbols; |
||
492 | }; |
||
493 | |||
494 | /// Errors of this type should be returned if a module contains definitions for |
||
495 | /// symbols that are not claimed by the module's associated |
||
496 | /// MaterializationResponsibility. If this error is returned it is indicative of |
||
497 | /// a broken transformation / compiler / object cache. |
||
498 | class UnexpectedSymbolDefinitions : public ErrorInfo<UnexpectedSymbolDefinitions> { |
||
499 | public: |
||
500 | static char ID; |
||
501 | |||
502 | UnexpectedSymbolDefinitions(std::shared_ptr<SymbolStringPool> SSP, |
||
503 | std::string ModuleName, SymbolNameVector Symbols) |
||
504 | : SSP(std::move(SSP)), ModuleName(std::move(ModuleName)), |
||
505 | Symbols(std::move(Symbols)) {} |
||
506 | std::error_code convertToErrorCode() const override; |
||
507 | void log(raw_ostream &OS) const override; |
||
508 | std::shared_ptr<SymbolStringPool> getSymbolStringPool() { return SSP; } |
||
509 | const std::string &getModuleName() const { return ModuleName; } |
||
510 | const SymbolNameVector &getSymbols() const { return Symbols; } |
||
511 | private: |
||
512 | std::shared_ptr<SymbolStringPool> SSP; |
||
513 | std::string ModuleName; |
||
514 | SymbolNameVector Symbols; |
||
515 | }; |
||
516 | |||
517 | /// Tracks responsibility for materialization, and mediates interactions between |
||
518 | /// MaterializationUnits and JDs. |
||
519 | /// |
||
520 | /// An instance of this class is passed to MaterializationUnits when their |
||
521 | /// materialize method is called. It allows MaterializationUnits to resolve and |
||
522 | /// emit symbols, or abandon materialization by notifying any unmaterialized |
||
523 | /// symbols of an error. |
||
524 | class MaterializationResponsibility { |
||
525 | friend class ExecutionSession; |
||
526 | friend class JITDylib; |
||
527 | |||
528 | public: |
||
529 | MaterializationResponsibility(MaterializationResponsibility &&) = delete; |
||
530 | MaterializationResponsibility & |
||
531 | operator=(MaterializationResponsibility &&) = delete; |
||
532 | |||
533 | /// Destruct a MaterializationResponsibility instance. In debug mode |
||
534 | /// this asserts that all symbols being tracked have been either |
||
535 | /// emitted or notified of an error. |
||
536 | ~MaterializationResponsibility(); |
||
537 | |||
538 | /// Runs the given callback under the session lock, passing in the associated |
||
539 | /// ResourceKey. This is the safe way to associate resources with trackers. |
||
540 | template <typename Func> Error withResourceKeyDo(Func &&F) const { |
||
541 | return RT->withResourceKeyDo(std::forward<Func>(F)); |
||
542 | } |
||
543 | |||
544 | /// Returns the target JITDylib that these symbols are being materialized |
||
545 | /// into. |
||
546 | JITDylib &getTargetJITDylib() const { return JD; } |
||
547 | |||
548 | /// Returns the ExecutionSession for this instance. |
||
549 | ExecutionSession &getExecutionSession() const; |
||
550 | |||
551 | /// Returns the symbol flags map for this responsibility instance. |
||
552 | /// Note: The returned flags may have transient flags (Lazy, Materializing) |
||
553 | /// set. These should be stripped with JITSymbolFlags::stripTransientFlags |
||
554 | /// before using. |
||
555 | const SymbolFlagsMap &getSymbols() const { return SymbolFlags; } |
||
556 | |||
557 | /// Returns the initialization pseudo-symbol, if any. This symbol will also |
||
558 | /// be present in the SymbolFlagsMap for this MaterializationResponsibility |
||
559 | /// object. |
||
560 | const SymbolStringPtr &getInitializerSymbol() const { return InitSymbol; } |
||
561 | |||
562 | /// Returns the names of any symbols covered by this |
||
563 | /// MaterializationResponsibility object that have queries pending. This |
||
564 | /// information can be used to return responsibility for unrequested symbols |
||
565 | /// back to the JITDylib via the delegate method. |
||
566 | SymbolNameSet getRequestedSymbols() const; |
||
567 | |||
568 | /// Notifies the target JITDylib that the given symbols have been resolved. |
||
569 | /// This will update the given symbols' addresses in the JITDylib, and notify |
||
570 | /// any pending queries on the given symbols of their resolution. The given |
||
571 | /// symbols must be ones covered by this MaterializationResponsibility |
||
572 | /// instance. Individual calls to this method may resolve a subset of the |
||
573 | /// symbols, but all symbols must have been resolved prior to calling emit. |
||
574 | /// |
||
575 | /// This method will return an error if any symbols being resolved have been |
||
576 | /// moved to the error state due to the failure of a dependency. If this |
||
577 | /// method returns an error then clients should log it and call |
||
578 | /// failMaterialize. If no dependencies have been registered for the |
||
579 | /// symbols covered by this MaterializationResponsibiility then this method |
||
580 | /// is guaranteed to return Error::success() and can be wrapped with cantFail. |
||
581 | Error notifyResolved(const SymbolMap &Symbols); |
||
582 | |||
583 | /// Notifies the target JITDylib (and any pending queries on that JITDylib) |
||
584 | /// that all symbols covered by this MaterializationResponsibility instance |
||
585 | /// have been emitted. |
||
586 | /// |
||
587 | /// This method will return an error if any symbols being resolved have been |
||
588 | /// moved to the error state due to the failure of a dependency. If this |
||
589 | /// method returns an error then clients should log it and call |
||
590 | /// failMaterialize. If no dependencies have been registered for the |
||
591 | /// symbols covered by this MaterializationResponsibiility then this method |
||
592 | /// is guaranteed to return Error::success() and can be wrapped with cantFail. |
||
593 | Error notifyEmitted(); |
||
594 | |||
595 | /// Attempt to claim responsibility for new definitions. This method can be |
||
596 | /// used to claim responsibility for symbols that are added to a |
||
597 | /// materialization unit during the compilation process (e.g. literal pool |
||
598 | /// symbols). Symbol linkage rules are the same as for symbols that are |
||
599 | /// defined up front: duplicate strong definitions will result in errors. |
||
600 | /// Duplicate weak definitions will be discarded (in which case they will |
||
601 | /// not be added to this responsibility instance). |
||
602 | /// |
||
603 | /// This method can be used by materialization units that want to add |
||
604 | /// additional symbols at materialization time (e.g. stubs, compile |
||
605 | /// callbacks, metadata). |
||
606 | Error defineMaterializing(SymbolFlagsMap SymbolFlags); |
||
607 | |||
608 | /// Define the given symbols as non-existent, removing it from the symbol |
||
609 | /// table and notifying any pending queries. Queries that lookup up the |
||
610 | /// symbol using the SymbolLookupFlags::WeaklyReferencedSymbol flag will |
||
611 | /// behave as if the symbol had not been matched in the first place. Queries |
||
612 | /// that required this symbol will fail with a missing symbol definition |
||
613 | /// error. |
||
614 | /// |
||
615 | /// This method is intended to support cleanup of special symbols like |
||
616 | /// initializer symbols: Queries using |
||
617 | /// SymbolLookupFlags::WeaklyReferencedSymbol can be used to trigger their |
||
618 | /// emission, and this method can be used to remove them from the JITDylib |
||
619 | /// once materialization is complete. |
||
620 | void defineNonExistent(ArrayRef<SymbolStringPtr> Symbols); |
||
621 | |||
622 | /// Notify all not-yet-emitted covered by this MaterializationResponsibility |
||
623 | /// instance that an error has occurred. |
||
624 | /// This will remove all symbols covered by this MaterializationResponsibilty |
||
625 | /// from the target JITDylib, and send an error to any queries waiting on |
||
626 | /// these symbols. |
||
627 | void failMaterialization(); |
||
628 | |||
629 | /// Transfers responsibility to the given MaterializationUnit for all |
||
630 | /// symbols defined by that MaterializationUnit. This allows |
||
631 | /// materializers to break up work based on run-time information (e.g. |
||
632 | /// by introspecting which symbols have actually been looked up and |
||
633 | /// materializing only those). |
||
634 | Error replace(std::unique_ptr<MaterializationUnit> MU); |
||
635 | |||
636 | /// Delegates responsibility for the given symbols to the returned |
||
637 | /// materialization responsibility. Useful for breaking up work between |
||
638 | /// threads, or different kinds of materialization processes. |
||
639 | Expected<std::unique_ptr<MaterializationResponsibility>> |
||
640 | delegate(const SymbolNameSet &Symbols); |
||
641 | |||
642 | void addDependencies(const SymbolStringPtr &Name, |
||
643 | const SymbolDependenceMap &Dependencies); |
||
644 | |||
645 | /// Add dependencies that apply to all symbols covered by this instance. |
||
646 | void addDependenciesForAll(const SymbolDependenceMap &Dependencies); |
||
647 | |||
648 | private: |
||
649 | /// Create a MaterializationResponsibility for the given JITDylib and |
||
650 | /// initial symbols. |
||
651 | MaterializationResponsibility(ResourceTrackerSP RT, |
||
652 | SymbolFlagsMap SymbolFlags, |
||
653 | SymbolStringPtr InitSymbol) |
||
654 | : JD(RT->getJITDylib()), RT(std::move(RT)), |
||
655 | SymbolFlags(std::move(SymbolFlags)), InitSymbol(std::move(InitSymbol)) { |
||
656 | assert(!this->SymbolFlags.empty() && "Materializing nothing?"); |
||
657 | } |
||
658 | |||
659 | JITDylib &JD; |
||
660 | ResourceTrackerSP RT; |
||
661 | SymbolFlagsMap SymbolFlags; |
||
662 | SymbolStringPtr InitSymbol; |
||
663 | }; |
||
664 | |||
665 | /// A MaterializationUnit represents a set of symbol definitions that can |
||
666 | /// be materialized as a group, or individually discarded (when |
||
667 | /// overriding definitions are encountered). |
||
668 | /// |
||
669 | /// MaterializationUnits are used when providing lazy definitions of symbols to |
||
670 | /// JITDylibs. The JITDylib will call materialize when the address of a symbol |
||
671 | /// is requested via the lookup method. The JITDylib will call discard if a |
||
672 | /// stronger definition is added or already present. |
||
673 | class MaterializationUnit { |
||
674 | friend class ExecutionSession; |
||
675 | friend class JITDylib; |
||
676 | |||
677 | public: |
||
678 | static char ID; |
||
679 | |||
680 | struct Interface { |
||
681 | Interface() = default; |
||
682 | Interface(SymbolFlagsMap InitalSymbolFlags, SymbolStringPtr InitSymbol) |
||
683 | : SymbolFlags(std::move(InitalSymbolFlags)), |
||
684 | InitSymbol(std::move(InitSymbol)) { |
||
685 | assert((!this->InitSymbol || this->SymbolFlags.count(this->InitSymbol)) && |
||
686 | "If set, InitSymbol should appear in InitialSymbolFlags map"); |
||
687 | } |
||
688 | |||
689 | SymbolFlagsMap SymbolFlags; |
||
690 | SymbolStringPtr InitSymbol; |
||
691 | }; |
||
692 | |||
693 | MaterializationUnit(Interface I) |
||
694 | : SymbolFlags(std::move(I.SymbolFlags)), |
||
695 | InitSymbol(std::move(I.InitSymbol)) {} |
||
696 | virtual ~MaterializationUnit() = default; |
||
697 | |||
698 | /// Return the name of this materialization unit. Useful for debugging |
||
699 | /// output. |
||
700 | virtual StringRef getName() const = 0; |
||
701 | |||
702 | /// Return the set of symbols that this source provides. |
||
703 | const SymbolFlagsMap &getSymbols() const { return SymbolFlags; } |
||
704 | |||
705 | /// Returns the initialization symbol for this MaterializationUnit (if any). |
||
706 | const SymbolStringPtr &getInitializerSymbol() const { return InitSymbol; } |
||
707 | |||
708 | /// Implementations of this method should materialize all symbols |
||
709 | /// in the materialzation unit, except for those that have been |
||
710 | /// previously discarded. |
||
711 | virtual void |
||
712 | materialize(std::unique_ptr<MaterializationResponsibility> R) = 0; |
||
713 | |||
714 | /// Called by JITDylibs to notify MaterializationUnits that the given symbol |
||
715 | /// has been overridden. |
||
716 | void doDiscard(const JITDylib &JD, const SymbolStringPtr &Name) { |
||
717 | SymbolFlags.erase(Name); |
||
718 | if (InitSymbol == Name) { |
||
719 | DEBUG_WITH_TYPE("orc", { |
||
720 | dbgs() << "In " << getName() << ": discarding init symbol \"" |
||
721 | << *Name << "\"\n"; |
||
722 | }); |
||
723 | InitSymbol = nullptr; |
||
724 | } |
||
725 | discard(JD, std::move(Name)); |
||
726 | } |
||
727 | |||
728 | protected: |
||
729 | SymbolFlagsMap SymbolFlags; |
||
730 | SymbolStringPtr InitSymbol; |
||
731 | |||
732 | private: |
||
733 | virtual void anchor(); |
||
734 | |||
735 | /// Implementations of this method should discard the given symbol |
||
736 | /// from the source (e.g. if the source is an LLVM IR Module and the |
||
737 | /// symbol is a function, delete the function body or mark it available |
||
738 | /// externally). |
||
739 | virtual void discard(const JITDylib &JD, const SymbolStringPtr &Name) = 0; |
||
740 | }; |
||
741 | |||
742 | /// A MaterializationUnit implementation for pre-existing absolute symbols. |
||
743 | /// |
||
744 | /// All symbols will be resolved and marked ready as soon as the unit is |
||
745 | /// materialized. |
||
746 | class AbsoluteSymbolsMaterializationUnit : public MaterializationUnit { |
||
747 | public: |
||
748 | AbsoluteSymbolsMaterializationUnit(SymbolMap Symbols); |
||
749 | |||
750 | StringRef getName() const override; |
||
751 | |||
752 | private: |
||
753 | void materialize(std::unique_ptr<MaterializationResponsibility> R) override; |
||
754 | void discard(const JITDylib &JD, const SymbolStringPtr &Name) override; |
||
755 | static MaterializationUnit::Interface extractFlags(const SymbolMap &Symbols); |
||
756 | |||
757 | SymbolMap Symbols; |
||
758 | }; |
||
759 | |||
760 | /// Create an AbsoluteSymbolsMaterializationUnit with the given symbols. |
||
761 | /// Useful for inserting absolute symbols into a JITDylib. E.g.: |
||
762 | /// \code{.cpp} |
||
763 | /// JITDylib &JD = ...; |
||
764 | /// SymbolStringPtr Foo = ...; |
||
765 | /// JITEvaluatedSymbol FooSym = ...; |
||
766 | /// if (auto Err = JD.define(absoluteSymbols({{Foo, FooSym}}))) |
||
767 | /// return Err; |
||
768 | /// \endcode |
||
769 | /// |
||
770 | inline std::unique_ptr<AbsoluteSymbolsMaterializationUnit> |
||
771 | absoluteSymbols(SymbolMap Symbols) { |
||
772 | return std::make_unique<AbsoluteSymbolsMaterializationUnit>( |
||
773 | std::move(Symbols)); |
||
774 | } |
||
775 | |||
776 | /// A materialization unit for symbol aliases. Allows existing symbols to be |
||
777 | /// aliased with alternate flags. |
||
778 | class ReExportsMaterializationUnit : public MaterializationUnit { |
||
779 | public: |
||
780 | /// SourceJD is allowed to be nullptr, in which case the source JITDylib is |
||
781 | /// taken to be whatever JITDylib these definitions are materialized in (and |
||
782 | /// MatchNonExported has no effect). This is useful for defining aliases |
||
783 | /// within a JITDylib. |
||
784 | /// |
||
785 | /// Note: Care must be taken that no sets of aliases form a cycle, as such |
||
786 | /// a cycle will result in a deadlock when any symbol in the cycle is |
||
787 | /// resolved. |
||
788 | ReExportsMaterializationUnit(JITDylib *SourceJD, |
||
789 | JITDylibLookupFlags SourceJDLookupFlags, |
||
790 | SymbolAliasMap Aliases); |
||
791 | |||
792 | StringRef getName() const override; |
||
793 | |||
794 | private: |
||
795 | void materialize(std::unique_ptr<MaterializationResponsibility> R) override; |
||
796 | void discard(const JITDylib &JD, const SymbolStringPtr &Name) override; |
||
797 | static MaterializationUnit::Interface |
||
798 | extractFlags(const SymbolAliasMap &Aliases); |
||
799 | |||
800 | JITDylib *SourceJD = nullptr; |
||
801 | JITDylibLookupFlags SourceJDLookupFlags; |
||
802 | SymbolAliasMap Aliases; |
||
803 | }; |
||
804 | |||
805 | /// Create a ReExportsMaterializationUnit with the given aliases. |
||
806 | /// Useful for defining symbol aliases.: E.g., given a JITDylib JD containing |
||
807 | /// symbols "foo" and "bar", we can define aliases "baz" (for "foo") and "qux" |
||
808 | /// (for "bar") with: \code{.cpp} |
||
809 | /// SymbolStringPtr Baz = ...; |
||
810 | /// SymbolStringPtr Qux = ...; |
||
811 | /// if (auto Err = JD.define(symbolAliases({ |
||
812 | /// {Baz, { Foo, JITSymbolFlags::Exported }}, |
||
813 | /// {Qux, { Bar, JITSymbolFlags::Weak }}})) |
||
814 | /// return Err; |
||
815 | /// \endcode |
||
816 | inline std::unique_ptr<ReExportsMaterializationUnit> |
||
817 | symbolAliases(SymbolAliasMap Aliases) { |
||
818 | return std::make_unique<ReExportsMaterializationUnit>( |
||
819 | nullptr, JITDylibLookupFlags::MatchAllSymbols, std::move(Aliases)); |
||
820 | } |
||
821 | |||
822 | /// Create a materialization unit for re-exporting symbols from another JITDylib |
||
823 | /// with alternative names/flags. |
||
824 | /// SourceJD will be searched using the given JITDylibLookupFlags. |
||
825 | inline std::unique_ptr<ReExportsMaterializationUnit> |
||
826 | reexports(JITDylib &SourceJD, SymbolAliasMap Aliases, |
||
827 | JITDylibLookupFlags SourceJDLookupFlags = |
||
828 | JITDylibLookupFlags::MatchExportedSymbolsOnly) { |
||
829 | return std::make_unique<ReExportsMaterializationUnit>( |
||
830 | &SourceJD, SourceJDLookupFlags, std::move(Aliases)); |
||
831 | } |
||
832 | |||
833 | /// Build a SymbolAliasMap for the common case where you want to re-export |
||
834 | /// symbols from another JITDylib with the same linkage/flags. |
||
835 | Expected<SymbolAliasMap> |
||
836 | buildSimpleReexportsAliasMap(JITDylib &SourceJD, const SymbolNameSet &Symbols); |
||
837 | |||
838 | /// Represents the state that a symbol has reached during materialization. |
||
839 | enum class SymbolState : uint8_t { |
||
840 | Invalid, /// No symbol should be in this state. |
||
841 | NeverSearched, /// Added to the symbol table, never queried. |
||
842 | Materializing, /// Queried, materialization begun. |
||
843 | Resolved, /// Assigned address, still materializing. |
||
844 | Emitted, /// Emitted to memory, but waiting on transitive dependencies. |
||
845 | Ready = 0x3f /// Ready and safe for clients to access. |
||
846 | }; |
||
847 | |||
848 | /// A symbol query that returns results via a callback when results are |
||
849 | /// ready. |
||
850 | /// |
||
851 | /// makes a callback when all symbols are available. |
||
852 | class AsynchronousSymbolQuery { |
||
853 | friend class ExecutionSession; |
||
854 | friend class InProgressFullLookupState; |
||
855 | friend class JITDylib; |
||
856 | friend class JITSymbolResolverAdapter; |
||
857 | friend class MaterializationResponsibility; |
||
858 | |||
859 | public: |
||
860 | /// Create a query for the given symbols. The NotifyComplete |
||
861 | /// callback will be called once all queried symbols reach the given |
||
862 | /// minimum state. |
||
863 | AsynchronousSymbolQuery(const SymbolLookupSet &Symbols, |
||
864 | SymbolState RequiredState, |
||
865 | SymbolsResolvedCallback NotifyComplete); |
||
866 | |||
867 | /// Notify the query that a requested symbol has reached the required state. |
||
868 | void notifySymbolMetRequiredState(const SymbolStringPtr &Name, |
||
869 | JITEvaluatedSymbol Sym); |
||
870 | |||
871 | /// Returns true if all symbols covered by this query have been |
||
872 | /// resolved. |
||
873 | bool isComplete() const { return OutstandingSymbolsCount == 0; } |
||
874 | |||
875 | |||
876 | private: |
||
877 | void handleComplete(ExecutionSession &ES); |
||
878 | |||
879 | SymbolState getRequiredState() { return RequiredState; } |
||
880 | |||
881 | void addQueryDependence(JITDylib &JD, SymbolStringPtr Name); |
||
882 | |||
883 | void removeQueryDependence(JITDylib &JD, const SymbolStringPtr &Name); |
||
884 | |||
885 | void dropSymbol(const SymbolStringPtr &Name); |
||
886 | |||
887 | void handleFailed(Error Err); |
||
888 | |||
889 | void detach(); |
||
890 | |||
891 | SymbolsResolvedCallback NotifyComplete; |
||
892 | SymbolDependenceMap QueryRegistrations; |
||
893 | SymbolMap ResolvedSymbols; |
||
894 | size_t OutstandingSymbolsCount; |
||
895 | SymbolState RequiredState; |
||
896 | }; |
||
897 | |||
898 | /// Wraps state for a lookup-in-progress. |
||
899 | /// DefinitionGenerators can optionally take ownership of a LookupState object |
||
900 | /// to suspend a lookup-in-progress while they search for definitions. |
||
901 | class LookupState { |
||
902 | friend class OrcV2CAPIHelper; |
||
903 | friend class ExecutionSession; |
||
904 | |||
905 | public: |
||
906 | LookupState(); |
||
907 | LookupState(LookupState &&); |
||
908 | LookupState &operator=(LookupState &&); |
||
909 | ~LookupState(); |
||
910 | |||
911 | /// Continue the lookup. This can be called by DefinitionGenerators |
||
912 | /// to re-start a captured query-application operation. |
||
913 | void continueLookup(Error Err); |
||
914 | |||
915 | private: |
||
916 | LookupState(std::unique_ptr<InProgressLookupState> IPLS); |
||
917 | |||
918 | // For C API. |
||
919 | void reset(InProgressLookupState *IPLS); |
||
920 | |||
921 | std::unique_ptr<InProgressLookupState> IPLS; |
||
922 | }; |
||
923 | |||
924 | /// Definition generators can be attached to JITDylibs to generate new |
||
925 | /// definitions for otherwise unresolved symbols during lookup. |
||
926 | class DefinitionGenerator { |
||
927 | public: |
||
928 | virtual ~DefinitionGenerator(); |
||
929 | |||
930 | /// DefinitionGenerators should override this method to insert new |
||
931 | /// definitions into the parent JITDylib. K specifies the kind of this |
||
932 | /// lookup. JD specifies the target JITDylib being searched, and |
||
933 | /// JDLookupFlags specifies whether the search should match against |
||
934 | /// hidden symbols. Finally, Symbols describes the set of unresolved |
||
935 | /// symbols and their associated lookup flags. |
||
936 | virtual Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD, |
||
937 | JITDylibLookupFlags JDLookupFlags, |
||
938 | const SymbolLookupSet &LookupSet) = 0; |
||
939 | }; |
||
940 | |||
941 | /// Represents a JIT'd dynamic library. |
||
942 | /// |
||
943 | /// This class aims to mimic the behavior of a regular dylib or shared object, |
||
944 | /// but without requiring the contained program representations to be compiled |
||
945 | /// up-front. The JITDylib's content is defined by adding MaterializationUnits, |
||
946 | /// and contained MaterializationUnits will typically rely on the JITDylib's |
||
947 | /// links-against order to resolve external references (similar to a regular |
||
948 | /// dylib). |
||
949 | /// |
||
950 | /// The JITDylib object is a thin wrapper that references state held by the |
||
951 | /// ExecutionSession. JITDylibs can be removed, clearing this underlying state |
||
952 | /// and leaving the JITDylib object in a defunct state. In this state the |
||
953 | /// JITDylib's name is guaranteed to remain accessible. If the ExecutionSession |
||
954 | /// is still alive then other operations are callable but will return an Error |
||
955 | /// or null result (depending on the API). It is illegal to call any operation |
||
956 | /// other than getName on a JITDylib after the ExecutionSession has been torn |
||
957 | /// down. |
||
958 | /// |
||
959 | /// JITDylibs cannot be moved or copied. Their address is stable, and useful as |
||
960 | /// a key in some JIT data structures. |
||
961 | class JITDylib : public ThreadSafeRefCountedBase<JITDylib>, |
||
962 | public jitlink::JITLinkDylib { |
||
963 | friend class AsynchronousSymbolQuery; |
||
964 | friend class ExecutionSession; |
||
965 | friend class Platform; |
||
966 | friend class MaterializationResponsibility; |
||
967 | public: |
||
968 | |||
969 | JITDylib(const JITDylib &) = delete; |
||
970 | JITDylib &operator=(const JITDylib &) = delete; |
||
971 | JITDylib(JITDylib &&) = delete; |
||
972 | JITDylib &operator=(JITDylib &&) = delete; |
||
973 | ~JITDylib(); |
||
974 | |||
975 | /// Get a reference to the ExecutionSession for this JITDylib. |
||
976 | /// |
||
977 | /// It is legal to call this method on a defunct JITDylib, however the result |
||
978 | /// will only usable if the ExecutionSession is still alive. If this JITDylib |
||
979 | /// is held by an error that may have torn down the JIT then the result |
||
980 | /// should not be used. |
||
981 | ExecutionSession &getExecutionSession() const { return ES; } |
||
982 | |||
983 | /// Dump current JITDylib state to OS. |
||
984 | /// |
||
985 | /// It is legal to call this method on a defunct JITDylib. |
||
986 | void dump(raw_ostream &OS); |
||
987 | |||
988 | /// Calls remove on all trackers currently associated with this JITDylib. |
||
989 | /// Does not run static deinits. |
||
990 | /// |
||
991 | /// Note that removal happens outside the session lock, so new code may be |
||
992 | /// added concurrently while the clear is underway, and the newly added |
||
993 | /// code will *not* be cleared. Adding new code concurrently with a clear |
||
994 | /// is usually a bug and should be avoided. |
||
995 | /// |
||
996 | /// It is illegal to call this method on a defunct JITDylib and the client |
||
997 | /// is responsible for ensuring that they do not do so. |
||
998 | Error clear(); |
||
999 | |||
1000 | /// Get the default resource tracker for this JITDylib. |
||
1001 | /// |
||
1002 | /// It is illegal to call this method on a defunct JITDylib and the client |
||
1003 | /// is responsible for ensuring that they do not do so. |
||
1004 | ResourceTrackerSP getDefaultResourceTracker(); |
||
1005 | |||
1006 | /// Create a resource tracker for this JITDylib. |
||
1007 | /// |
||
1008 | /// It is illegal to call this method on a defunct JITDylib and the client |
||
1009 | /// is responsible for ensuring that they do not do so. |
||
1010 | ResourceTrackerSP createResourceTracker(); |
||
1011 | |||
1012 | /// Adds a definition generator to this JITDylib and returns a referenece to |
||
1013 | /// it. |
||
1014 | /// |
||
1015 | /// When JITDylibs are searched during lookup, if no existing definition of |
||
1016 | /// a symbol is found, then any generators that have been added are run (in |
||
1017 | /// the order that they were added) to potentially generate a definition. |
||
1018 | /// |
||
1019 | /// It is illegal to call this method on a defunct JITDylib and the client |
||
1020 | /// is responsible for ensuring that they do not do so. |
||
1021 | template <typename GeneratorT> |
||
1022 | GeneratorT &addGenerator(std::unique_ptr<GeneratorT> DefGenerator); |
||
1023 | |||
1024 | /// Remove a definition generator from this JITDylib. |
||
1025 | /// |
||
1026 | /// The given generator must exist in this JITDylib's generators list (i.e. |
||
1027 | /// have been added and not yet removed). |
||
1028 | /// |
||
1029 | /// It is illegal to call this method on a defunct JITDylib and the client |
||
1030 | /// is responsible for ensuring that they do not do so. |
||
1031 | void removeGenerator(DefinitionGenerator &G); |
||
1032 | |||
1033 | /// Set the link order to be used when fixing up definitions in JITDylib. |
||
1034 | /// This will replace the previous link order, and apply to any symbol |
||
1035 | /// resolutions made for definitions in this JITDylib after the call to |
||
1036 | /// setLinkOrder (even if the definition itself was added before the |
||
1037 | /// call). |
||
1038 | /// |
||
1039 | /// If LinkAgainstThisJITDylibFirst is true (the default) then this JITDylib |
||
1040 | /// will add itself to the beginning of the LinkOrder (Clients should not |
||
1041 | /// put this JITDylib in the list in this case, to avoid redundant lookups). |
||
1042 | /// |
||
1043 | /// If LinkAgainstThisJITDylibFirst is false then the link order will be used |
||
1044 | /// as-is. The primary motivation for this feature is to support deliberate |
||
1045 | /// shadowing of symbols in this JITDylib by a facade JITDylib. For example, |
||
1046 | /// the facade may resolve function names to stubs, and the stubs may compile |
||
1047 | /// lazily by looking up symbols in this dylib. Adding the facade dylib |
||
1048 | /// as the first in the link order (instead of this dylib) ensures that |
||
1049 | /// definitions within this dylib resolve to the lazy-compiling stubs, |
||
1050 | /// rather than immediately materializing the definitions in this dylib. |
||
1051 | /// |
||
1052 | /// It is illegal to call this method on a defunct JITDylib and the client |
||
1053 | /// is responsible for ensuring that they do not do so. |
||
1054 | void setLinkOrder(JITDylibSearchOrder NewSearchOrder, |
||
1055 | bool LinkAgainstThisJITDylibFirst = true); |
||
1056 | |||
1057 | /// Add the given JITDylib to the link order for definitions in this |
||
1058 | /// JITDylib. |
||
1059 | /// |
||
1060 | /// It is illegal to call this method on a defunct JITDylib and the client |
||
1061 | /// is responsible for ensuring that they do not do so. |
||
1062 | void addToLinkOrder(JITDylib &JD, |
||
1063 | JITDylibLookupFlags JDLookupFlags = |
||
1064 | JITDylibLookupFlags::MatchExportedSymbolsOnly); |
||
1065 | |||
1066 | /// Replace OldJD with NewJD in the link order if OldJD is present. |
||
1067 | /// Otherwise this operation is a no-op. |
||
1068 | /// |
||
1069 | /// It is illegal to call this method on a defunct JITDylib and the client |
||
1070 | /// is responsible for ensuring that they do not do so. |
||
1071 | void replaceInLinkOrder(JITDylib &OldJD, JITDylib &NewJD, |
||
1072 | JITDylibLookupFlags JDLookupFlags = |
||
1073 | JITDylibLookupFlags::MatchExportedSymbolsOnly); |
||
1074 | |||
1075 | /// Remove the given JITDylib from the link order for this JITDylib if it is |
||
1076 | /// present. Otherwise this operation is a no-op. |
||
1077 | /// |
||
1078 | /// It is illegal to call this method on a defunct JITDylib and the client |
||
1079 | /// is responsible for ensuring that they do not do so. |
||
1080 | void removeFromLinkOrder(JITDylib &JD); |
||
1081 | |||
1082 | /// Do something with the link order (run under the session lock). |
||
1083 | /// |
||
1084 | /// It is illegal to call this method on a defunct JITDylib and the client |
||
1085 | /// is responsible for ensuring that they do not do so. |
||
1086 | template <typename Func> |
||
1087 | auto withLinkOrderDo(Func &&F) |
||
1088 | -> decltype(F(std::declval<const JITDylibSearchOrder &>())); |
||
1089 | |||
1090 | /// Define all symbols provided by the materialization unit to be part of this |
||
1091 | /// JITDylib. |
||
1092 | /// |
||
1093 | /// If RT is not specified then the default resource tracker will be used. |
||
1094 | /// |
||
1095 | /// This overload always takes ownership of the MaterializationUnit. If any |
||
1096 | /// errors occur, the MaterializationUnit consumed. |
||
1097 | /// |
||
1098 | /// It is illegal to call this method on a defunct JITDylib and the client |
||
1099 | /// is responsible for ensuring that they do not do so. |
||
1100 | template <typename MaterializationUnitType> |
||
1101 | Error define(std::unique_ptr<MaterializationUnitType> &&MU, |
||
1102 | ResourceTrackerSP RT = nullptr); |
||
1103 | |||
1104 | /// Define all symbols provided by the materialization unit to be part of this |
||
1105 | /// JITDylib. |
||
1106 | /// |
||
1107 | /// This overload only takes ownership of the MaterializationUnit no error is |
||
1108 | /// generated. If an error occurs, ownership remains with the caller. This |
||
1109 | /// may allow the caller to modify the MaterializationUnit to correct the |
||
1110 | /// issue, then re-call define. |
||
1111 | /// |
||
1112 | /// It is illegal to call this method on a defunct JITDylib and the client |
||
1113 | /// is responsible for ensuring that they do not do so. |
||
1114 | template <typename MaterializationUnitType> |
||
1115 | Error define(std::unique_ptr<MaterializationUnitType> &MU, |
||
1116 | ResourceTrackerSP RT = nullptr); |
||
1117 | |||
1118 | /// Tries to remove the given symbols. |
||
1119 | /// |
||
1120 | /// If any symbols are not defined in this JITDylib this method will return |
||
1121 | /// a SymbolsNotFound error covering the missing symbols. |
||
1122 | /// |
||
1123 | /// If all symbols are found but some symbols are in the process of being |
||
1124 | /// materialized this method will return a SymbolsCouldNotBeRemoved error. |
||
1125 | /// |
||
1126 | /// On success, all symbols are removed. On failure, the JITDylib state is |
||
1127 | /// left unmodified (no symbols are removed). |
||
1128 | /// |
||
1129 | /// It is illegal to call this method on a defunct JITDylib and the client |
||
1130 | /// is responsible for ensuring that they do not do so. |
||
1131 | Error remove(const SymbolNameSet &Names); |
||
1132 | |||
1133 | /// Returns the given JITDylibs and all of their transitive dependencies in |
||
1134 | /// DFS order (based on linkage relationships). Each JITDylib will appear |
||
1135 | /// only once. |
||
1136 | /// |
||
1137 | /// If any JITDylib in the order is defunct then this method will return an |
||
1138 | /// error, otherwise returns the order. |
||
1139 | static Expected<std::vector<JITDylibSP>> |
||
1140 | getDFSLinkOrder(ArrayRef<JITDylibSP> JDs); |
||
1141 | |||
1142 | /// Returns the given JITDylibs and all of their transitive dependencies in |
||
1143 | /// reverse DFS order (based on linkage relationships). Each JITDylib will |
||
1144 | /// appear only once. |
||
1145 | /// |
||
1146 | /// If any JITDylib in the order is defunct then this method will return an |
||
1147 | /// error, otherwise returns the order. |
||
1148 | static Expected<std::vector<JITDylibSP>> |
||
1149 | getReverseDFSLinkOrder(ArrayRef<JITDylibSP> JDs); |
||
1150 | |||
1151 | /// Return this JITDylib and its transitive dependencies in DFS order |
||
1152 | /// based on linkage relationships. |
||
1153 | /// |
||
1154 | /// If any JITDylib in the order is defunct then this method will return an |
||
1155 | /// error, otherwise returns the order. |
||
1156 | Expected<std::vector<JITDylibSP>> getDFSLinkOrder(); |
||
1157 | |||
1158 | /// Rteurn this JITDylib and its transitive dependencies in reverse DFS order |
||
1159 | /// based on linkage relationships. |
||
1160 | /// |
||
1161 | /// If any JITDylib in the order is defunct then this method will return an |
||
1162 | /// error, otherwise returns the order. |
||
1163 | Expected<std::vector<JITDylibSP>> getReverseDFSLinkOrder(); |
||
1164 | |||
1165 | private: |
||
1166 | using AsynchronousSymbolQuerySet = |
||
1167 | std::set<std::shared_ptr<AsynchronousSymbolQuery>>; |
||
1168 | |||
1169 | using AsynchronousSymbolQueryList = |
||
1170 | std::vector<std::shared_ptr<AsynchronousSymbolQuery>>; |
||
1171 | |||
1172 | struct UnmaterializedInfo { |
||
1173 | UnmaterializedInfo(std::unique_ptr<MaterializationUnit> MU, |
||
1174 | ResourceTracker *RT) |
||
1175 | : MU(std::move(MU)), RT(RT) {} |
||
1176 | |||
1177 | std::unique_ptr<MaterializationUnit> MU; |
||
1178 | ResourceTracker *RT; |
||
1179 | }; |
||
1180 | |||
1181 | using UnmaterializedInfosMap = |
||
1182 | DenseMap<SymbolStringPtr, std::shared_ptr<UnmaterializedInfo>>; |
||
1183 | |||
1184 | using UnmaterializedInfosList = |
||
1185 | std::vector<std::shared_ptr<UnmaterializedInfo>>; |
||
1186 | |||
1187 | struct MaterializingInfo { |
||
1188 | SymbolDependenceMap Dependants; |
||
1189 | SymbolDependenceMap UnemittedDependencies; |
||
1190 | |||
1191 | void addQuery(std::shared_ptr<AsynchronousSymbolQuery> Q); |
||
1192 | void removeQuery(const AsynchronousSymbolQuery &Q); |
||
1193 | AsynchronousSymbolQueryList takeQueriesMeeting(SymbolState RequiredState); |
||
1194 | AsynchronousSymbolQueryList takeAllPendingQueries() { |
||
1195 | return std::move(PendingQueries); |
||
1196 | } |
||
1197 | bool hasQueriesPending() const { return !PendingQueries.empty(); } |
||
1198 | const AsynchronousSymbolQueryList &pendingQueries() const { |
||
1199 | return PendingQueries; |
||
1200 | } |
||
1201 | private: |
||
1202 | AsynchronousSymbolQueryList PendingQueries; |
||
1203 | }; |
||
1204 | |||
1205 | using MaterializingInfosMap = DenseMap<SymbolStringPtr, MaterializingInfo>; |
||
1206 | |||
1207 | class SymbolTableEntry { |
||
1208 | public: |
||
1209 | SymbolTableEntry() = default; |
||
1210 | SymbolTableEntry(JITSymbolFlags Flags) |
||
1211 | : Flags(Flags), State(static_cast<uint8_t>(SymbolState::NeverSearched)), |
||
1212 | MaterializerAttached(false), PendingRemoval(false) {} |
||
1213 | |||
1214 | JITTargetAddress getAddress() const { return Addr; } |
||
1215 | JITSymbolFlags getFlags() const { return Flags; } |
||
1216 | SymbolState getState() const { return static_cast<SymbolState>(State); } |
||
1217 | |||
1218 | bool hasMaterializerAttached() const { return MaterializerAttached; } |
||
1219 | bool isPendingRemoval() const { return PendingRemoval; } |
||
1220 | |||
1221 | void setAddress(JITTargetAddress Addr) { this->Addr = Addr; } |
||
1222 | void setFlags(JITSymbolFlags Flags) { this->Flags = Flags; } |
||
1223 | void setState(SymbolState State) { |
||
1224 | assert(static_cast<uint8_t>(State) < (1 << 6) && |
||
1225 | "State does not fit in bitfield"); |
||
1226 | this->State = static_cast<uint8_t>(State); |
||
1227 | } |
||
1228 | |||
1229 | void setMaterializerAttached(bool MaterializerAttached) { |
||
1230 | this->MaterializerAttached = MaterializerAttached; |
||
1231 | } |
||
1232 | |||
1233 | void setPendingRemoval(bool PendingRemoval) { |
||
1234 | this->PendingRemoval = PendingRemoval; |
||
1235 | } |
||
1236 | |||
1237 | JITEvaluatedSymbol getSymbol() const { |
||
1238 | return JITEvaluatedSymbol(Addr, Flags); |
||
1239 | } |
||
1240 | |||
1241 | private: |
||
1242 | JITTargetAddress Addr = 0; |
||
1243 | JITSymbolFlags Flags; |
||
1244 | uint8_t State : 6; |
||
1245 | uint8_t MaterializerAttached : 1; |
||
1246 | uint8_t PendingRemoval : 1; |
||
1247 | }; |
||
1248 | |||
1249 | using SymbolTable = DenseMap<SymbolStringPtr, SymbolTableEntry>; |
||
1250 | |||
1251 | JITDylib(ExecutionSession &ES, std::string Name); |
||
1252 | |||
1253 | std::pair<AsynchronousSymbolQuerySet, std::shared_ptr<SymbolDependenceMap>> |
||
1254 | removeTracker(ResourceTracker &RT); |
||
1255 | |||
1256 | void transferTracker(ResourceTracker &DstRT, ResourceTracker &SrcRT); |
||
1257 | |||
1258 | Error defineImpl(MaterializationUnit &MU); |
||
1259 | |||
1260 | void installMaterializationUnit(std::unique_ptr<MaterializationUnit> MU, |
||
1261 | ResourceTracker &RT); |
||
1262 | |||
1263 | void detachQueryHelper(AsynchronousSymbolQuery &Q, |
||
1264 | const SymbolNameSet &QuerySymbols); |
||
1265 | |||
1266 | void transferEmittedNodeDependencies(MaterializingInfo &DependantMI, |
||
1267 | const SymbolStringPtr &DependantName, |
||
1268 | MaterializingInfo &EmittedMI); |
||
1269 | |||
1270 | Expected<SymbolFlagsMap> defineMaterializing(SymbolFlagsMap SymbolFlags); |
||
1271 | |||
1272 | Error replace(MaterializationResponsibility &FromMR, |
||
1273 | std::unique_ptr<MaterializationUnit> MU); |
||
1274 | |||
1275 | Expected<std::unique_ptr<MaterializationResponsibility>> |
||
1276 | delegate(MaterializationResponsibility &FromMR, SymbolFlagsMap SymbolFlags, |
||
1277 | SymbolStringPtr InitSymbol); |
||
1278 | |||
1279 | SymbolNameSet getRequestedSymbols(const SymbolFlagsMap &SymbolFlags) const; |
||
1280 | |||
1281 | void addDependencies(const SymbolStringPtr &Name, |
||
1282 | const SymbolDependenceMap &Dependants); |
||
1283 | |||
1284 | Error resolve(MaterializationResponsibility &MR, const SymbolMap &Resolved); |
||
1285 | |||
1286 | Error emit(MaterializationResponsibility &MR, const SymbolFlagsMap &Emitted); |
||
1287 | |||
1288 | void unlinkMaterializationResponsibility(MaterializationResponsibility &MR); |
||
1289 | |||
1290 | using FailedSymbolsWorklist = |
||
1291 | std::vector<std::pair<JITDylib *, SymbolStringPtr>>; |
||
1292 | |||
1293 | static std::pair<AsynchronousSymbolQuerySet, |
||
1294 | std::shared_ptr<SymbolDependenceMap>> |
||
1295 | failSymbols(FailedSymbolsWorklist); |
||
1296 | |||
1297 | ExecutionSession &ES; |
||
1298 | enum { Open, Closing, Closed } State = Open; |
||
1299 | std::mutex GeneratorsMutex; |
||
1300 | SymbolTable Symbols; |
||
1301 | UnmaterializedInfosMap UnmaterializedInfos; |
||
1302 | MaterializingInfosMap MaterializingInfos; |
||
1303 | std::vector<std::shared_ptr<DefinitionGenerator>> DefGenerators; |
||
1304 | JITDylibSearchOrder LinkOrder; |
||
1305 | ResourceTrackerSP DefaultTracker; |
||
1306 | |||
1307 | // Map trackers to sets of symbols tracked. |
||
1308 | DenseMap<ResourceTracker *, SymbolNameVector> TrackerSymbols; |
||
1309 | DenseMap<ResourceTracker *, DenseSet<MaterializationResponsibility *>> |
||
1310 | TrackerMRs; |
||
1311 | }; |
||
1312 | |||
1313 | /// Platforms set up standard symbols and mediate interactions between dynamic |
||
1314 | /// initializers (e.g. C++ static constructors) and ExecutionSession state. |
||
1315 | /// Note that Platforms do not automatically run initializers: clients are still |
||
1316 | /// responsible for doing this. |
||
1317 | class Platform { |
||
1318 | public: |
||
1319 | virtual ~Platform(); |
||
1320 | |||
1321 | /// This method will be called outside the session lock each time a JITDylib |
||
1322 | /// is created (unless it is created with EmptyJITDylib set) to allow the |
||
1323 | /// Platform to install any JITDylib specific standard symbols (e.g |
||
1324 | /// __dso_handle). |
||
1325 | virtual Error setupJITDylib(JITDylib &JD) = 0; |
||
1326 | |||
1327 | /// This method will be called outside the session lock each time a JITDylib |
||
1328 | /// is removed to allow the Platform to remove any JITDylib-specific data. |
||
1329 | virtual Error teardownJITDylib(JITDylib &JD) = 0; |
||
1330 | |||
1331 | /// This method will be called under the ExecutionSession lock each time a |
||
1332 | /// MaterializationUnit is added to a JITDylib. |
||
1333 | virtual Error notifyAdding(ResourceTracker &RT, |
||
1334 | const MaterializationUnit &MU) = 0; |
||
1335 | |||
1336 | /// This method will be called under the ExecutionSession lock when a |
||
1337 | /// ResourceTracker is removed. |
||
1338 | virtual Error notifyRemoving(ResourceTracker &RT) = 0; |
||
1339 | |||
1340 | /// A utility function for looking up initializer symbols. Performs a blocking |
||
1341 | /// lookup for the given symbols in each of the given JITDylibs. |
||
1342 | /// |
||
1343 | /// Note: This function is deprecated and will be removed in the near future. |
||
1344 | static Expected<DenseMap<JITDylib *, SymbolMap>> |
||
1345 | lookupInitSymbols(ExecutionSession &ES, |
||
1346 | const DenseMap<JITDylib *, SymbolLookupSet> &InitSyms); |
||
1347 | |||
1348 | /// Performs an async lookup for the given symbols in each of the given |
||
1349 | /// JITDylibs, calling the given handler once all lookups have completed. |
||
1350 | static void |
||
1351 | lookupInitSymbolsAsync(unique_function<void(Error)> OnComplete, |
||
1352 | ExecutionSession &ES, |
||
1353 | const DenseMap<JITDylib *, SymbolLookupSet> &InitSyms); |
||
1354 | }; |
||
1355 | |||
1356 | /// A materialization task. |
||
1357 | class MaterializationTask : public RTTIExtends<MaterializationTask, Task> { |
||
1358 | public: |
||
1359 | static char ID; |
||
1360 | |||
1361 | MaterializationTask(std::unique_ptr<MaterializationUnit> MU, |
||
1362 | std::unique_ptr<MaterializationResponsibility> MR) |
||
1363 | : MU(std::move(MU)), MR(std::move(MR)) {} |
||
1364 | void printDescription(raw_ostream &OS) override; |
||
1365 | void run() override; |
||
1366 | |||
1367 | private: |
||
1368 | std::unique_ptr<MaterializationUnit> MU; |
||
1369 | std::unique_ptr<MaterializationResponsibility> MR; |
||
1370 | }; |
||
1371 | |||
1372 | /// An ExecutionSession represents a running JIT program. |
||
1373 | class ExecutionSession { |
||
1374 | friend class InProgressLookupFlagsState; |
||
1375 | friend class InProgressFullLookupState; |
||
1376 | friend class JITDylib; |
||
1377 | friend class LookupState; |
||
1378 | friend class MaterializationResponsibility; |
||
1379 | friend class ResourceTracker; |
||
1380 | |||
1381 | public: |
||
1382 | /// For reporting errors. |
||
1383 | using ErrorReporter = std::function<void(Error)>; |
||
1384 | |||
1385 | /// Send a result to the remote. |
||
1386 | using SendResultFunction = unique_function<void(shared::WrapperFunctionResult)>; |
||
1387 | |||
1388 | /// For dispatching ORC tasks (typically materialization tasks). |
||
1389 | using DispatchTaskFunction = unique_function<void(std::unique_ptr<Task> T)>; |
||
1390 | |||
1391 | /// An asynchronous wrapper-function callable from the executor via |
||
1392 | /// jit-dispatch. |
||
1393 | using JITDispatchHandlerFunction = unique_function<void( |
||
1394 | SendResultFunction SendResult, |
||
1395 | const char *ArgData, size_t ArgSize)>; |
||
1396 | |||
1397 | /// A map associating tag names with asynchronous wrapper function |
||
1398 | /// implementations in the JIT. |
||
1399 | using JITDispatchHandlerAssociationMap = |
||
1400 | DenseMap<SymbolStringPtr, JITDispatchHandlerFunction>; |
||
1401 | |||
1402 | /// Construct an ExecutionSession with the given ExecutorProcessControl |
||
1403 | /// object. |
||
1404 | ExecutionSession(std::unique_ptr<ExecutorProcessControl> EPC); |
||
1405 | |||
1406 | /// Destroy an ExecutionSession. Verifies that endSession was called prior to |
||
1407 | /// destruction. |
||
1408 | ~ExecutionSession(); |
||
1409 | |||
1410 | /// End the session. Closes all JITDylibs and disconnects from the |
||
1411 | /// executor. Clients must call this method before destroying the session. |
||
1412 | Error endSession(); |
||
1413 | |||
1414 | /// Get the ExecutorProcessControl object associated with this |
||
1415 | /// ExecutionSession. |
||
1416 | ExecutorProcessControl &getExecutorProcessControl() { return *EPC; } |
||
1417 | |||
1418 | /// Get the SymbolStringPool for this instance. |
||
1419 | std::shared_ptr<SymbolStringPool> getSymbolStringPool() { |
||
1420 | return EPC->getSymbolStringPool(); |
||
1421 | } |
||
1422 | |||
1423 | /// Add a symbol name to the SymbolStringPool and return a pointer to it. |
||
1424 | SymbolStringPtr intern(StringRef SymName) { return EPC->intern(SymName); } |
||
1425 | |||
1426 | /// Set the Platform for this ExecutionSession. |
||
1427 | void setPlatform(std::unique_ptr<Platform> P) { this->P = std::move(P); } |
||
1428 | |||
1429 | /// Get the Platform for this session. |
||
1430 | /// Will return null if no Platform has been set for this ExecutionSession. |
||
1431 | Platform *getPlatform() { return P.get(); } |
||
1432 | |||
1433 | /// Run the given lambda with the session mutex locked. |
||
1434 | template <typename Func> decltype(auto) runSessionLocked(Func &&F) { |
||
1435 | std::lock_guard<std::recursive_mutex> Lock(SessionMutex); |
||
1436 | return F(); |
||
1437 | } |
||
1438 | |||
1439 | /// Register the given ResourceManager with this ExecutionSession. |
||
1440 | /// Managers will be notified of events in reverse order of registration. |
||
1441 | void registerResourceManager(ResourceManager &RM); |
||
1442 | |||
1443 | /// Deregister the given ResourceManager with this ExecutionSession. |
||
1444 | /// Manager must have been previously registered. |
||
1445 | void deregisterResourceManager(ResourceManager &RM); |
||
1446 | |||
1447 | /// Return a pointer to the "name" JITDylib. |
||
1448 | /// Ownership of JITDylib remains within Execution Session |
||
1449 | JITDylib *getJITDylibByName(StringRef Name); |
||
1450 | |||
1451 | /// Add a new bare JITDylib to this ExecutionSession. |
||
1452 | /// |
||
1453 | /// The JITDylib Name is required to be unique. Clients should verify that |
||
1454 | /// names are not being re-used (E.g. by calling getJITDylibByName) if names |
||
1455 | /// are based on user input. |
||
1456 | /// |
||
1457 | /// This call does not install any library code or symbols into the newly |
||
1458 | /// created JITDylib. The client is responsible for all configuration. |
||
1459 | JITDylib &createBareJITDylib(std::string Name); |
||
1460 | |||
1461 | /// Add a new JITDylib to this ExecutionSession. |
||
1462 | /// |
||
1463 | /// The JITDylib Name is required to be unique. Clients should verify that |
||
1464 | /// names are not being re-used (e.g. by calling getJITDylibByName) if names |
||
1465 | /// are based on user input. |
||
1466 | /// |
||
1467 | /// If a Platform is attached then Platform::setupJITDylib will be called to |
||
1468 | /// install standard platform symbols (e.g. standard library interposes). |
||
1469 | /// If no Platform is attached this call is equivalent to createBareJITDylib. |
||
1470 | Expected<JITDylib &> createJITDylib(std::string Name); |
||
1471 | |||
1472 | /// Closes the given JITDylib. |
||
1473 | /// |
||
1474 | /// This method clears all resources held for the JITDylib, puts it in the |
||
1475 | /// closed state, and clears all references held by the ExecutionSession and |
||
1476 | /// other JITDylibs. No further code can be added to the JITDylib, and the |
||
1477 | /// object will be freed once any remaining JITDylibSPs to it are destroyed. |
||
1478 | /// |
||
1479 | /// This method does *not* run static destructors. |
||
1480 | /// |
||
1481 | /// This method can only be called once for each JITDylib. |
||
1482 | Error removeJITDylib(JITDylib &JD); |
||
1483 | |||
1484 | /// Set the error reporter function. |
||
1485 | ExecutionSession &setErrorReporter(ErrorReporter ReportError) { |
||
1486 | this->ReportError = std::move(ReportError); |
||
1487 | return *this; |
||
1488 | } |
||
1489 | |||
1490 | /// Report a error for this execution session. |
||
1491 | /// |
||
1492 | /// Unhandled errors can be sent here to log them. |
||
1493 | void reportError(Error Err) { ReportError(std::move(Err)); } |
||
1494 | |||
1495 | /// Set the task dispatch function. |
||
1496 | ExecutionSession &setDispatchTask(DispatchTaskFunction DispatchTask) { |
||
1497 | this->DispatchTask = std::move(DispatchTask); |
||
1498 | return *this; |
||
1499 | } |
||
1500 | |||
1501 | /// Search the given JITDylibs to find the flags associated with each of the |
||
1502 | /// given symbols. |
||
1503 | void lookupFlags(LookupKind K, JITDylibSearchOrder SearchOrder, |
||
1504 | SymbolLookupSet Symbols, |
||
1505 | unique_function<void(Expected<SymbolFlagsMap>)> OnComplete); |
||
1506 | |||
1507 | /// Blocking version of lookupFlags. |
||
1508 | Expected<SymbolFlagsMap> lookupFlags(LookupKind K, |
||
1509 | JITDylibSearchOrder SearchOrder, |
||
1510 | SymbolLookupSet Symbols); |
||
1511 | |||
1512 | /// Search the given JITDylibs for the given symbols. |
||
1513 | /// |
||
1514 | /// SearchOrder lists the JITDylibs to search. For each dylib, the associated |
||
1515 | /// boolean indicates whether the search should match against non-exported |
||
1516 | /// (hidden visibility) symbols in that dylib (true means match against |
||
1517 | /// non-exported symbols, false means do not match). |
||
1518 | /// |
||
1519 | /// The NotifyComplete callback will be called once all requested symbols |
||
1520 | /// reach the required state. |
||
1521 | /// |
||
1522 | /// If all symbols are found, the RegisterDependencies function will be called |
||
1523 | /// while the session lock is held. This gives clients a chance to register |
||
1524 | /// dependencies for on the queried symbols for any symbols they are |
||
1525 | /// materializing (if a MaterializationResponsibility instance is present, |
||
1526 | /// this can be implemented by calling |
||
1527 | /// MaterializationResponsibility::addDependencies). If there are no |
||
1528 | /// dependenant symbols for this query (e.g. it is being made by a top level |
||
1529 | /// client to get an address to call) then the value NoDependenciesToRegister |
||
1530 | /// can be used. |
||
1531 | void lookup(LookupKind K, const JITDylibSearchOrder &SearchOrder, |
||
1532 | SymbolLookupSet Symbols, SymbolState RequiredState, |
||
1533 | SymbolsResolvedCallback NotifyComplete, |
||
1534 | RegisterDependenciesFunction RegisterDependencies); |
||
1535 | |||
1536 | /// Blocking version of lookup above. Returns the resolved symbol map. |
||
1537 | /// If WaitUntilReady is true (the default), will not return until all |
||
1538 | /// requested symbols are ready (or an error occurs). If WaitUntilReady is |
||
1539 | /// false, will return as soon as all requested symbols are resolved, |
||
1540 | /// or an error occurs. If WaitUntilReady is false and an error occurs |
||
1541 | /// after resolution, the function will return a success value, but the |
||
1542 | /// error will be reported via reportErrors. |
||
1543 | Expected<SymbolMap> lookup(const JITDylibSearchOrder &SearchOrder, |
||
1544 | SymbolLookupSet Symbols, |
||
1545 | LookupKind K = LookupKind::Static, |
||
1546 | SymbolState RequiredState = SymbolState::Ready, |
||
1547 | RegisterDependenciesFunction RegisterDependencies = |
||
1548 | NoDependenciesToRegister); |
||
1549 | |||
1550 | /// Convenience version of blocking lookup. |
||
1551 | /// Searches each of the JITDylibs in the search order in turn for the given |
||
1552 | /// symbol. |
||
1553 | Expected<JITEvaluatedSymbol> |
||
1554 | lookup(const JITDylibSearchOrder &SearchOrder, SymbolStringPtr Symbol, |
||
1555 | SymbolState RequiredState = SymbolState::Ready); |
||
1556 | |||
1557 | /// Convenience version of blocking lookup. |
||
1558 | /// Searches each of the JITDylibs in the search order in turn for the given |
||
1559 | /// symbol. The search will not find non-exported symbols. |
||
1560 | Expected<JITEvaluatedSymbol> |
||
1561 | lookup(ArrayRef<JITDylib *> SearchOrder, SymbolStringPtr Symbol, |
||
1562 | SymbolState RequiredState = SymbolState::Ready); |
||
1563 | |||
1564 | /// Convenience version of blocking lookup. |
||
1565 | /// Searches each of the JITDylibs in the search order in turn for the given |
||
1566 | /// symbol. The search will not find non-exported symbols. |
||
1567 | Expected<JITEvaluatedSymbol> |
||
1568 | lookup(ArrayRef<JITDylib *> SearchOrder, StringRef Symbol, |
||
1569 | SymbolState RequiredState = SymbolState::Ready); |
||
1570 | |||
1571 | /// Materialize the given unit. |
||
1572 | void dispatchTask(std::unique_ptr<Task> T) { |
||
1573 | assert(T && "T must be non-null"); |
||
1574 | DEBUG_WITH_TYPE("orc", dumpDispatchInfo(*T)); |
||
1575 | DispatchTask(std::move(T)); |
||
1576 | } |
||
1577 | |||
1578 | /// Run a wrapper function in the executor. |
||
1579 | /// |
||
1580 | /// The wrapper function should be callable as: |
||
1581 | /// |
||
1582 | /// \code{.cpp} |
||
1583 | /// CWrapperFunctionResult fn(uint8_t *Data, uint64_t Size); |
||
1584 | /// \endcode{.cpp} |
||
1585 | /// |
||
1586 | /// The given OnComplete function will be called to return the result. |
||
1587 | template <typename... ArgTs> |
||
1588 | void callWrapperAsync(ArgTs &&... Args) { |
||
1589 | EPC->callWrapperAsync(std::forward<ArgTs>(Args)...); |
||
1590 | } |
||
1591 | |||
1592 | /// Run a wrapper function in the executor. The wrapper function should be |
||
1593 | /// callable as: |
||
1594 | /// |
||
1595 | /// \code{.cpp} |
||
1596 | /// CWrapperFunctionResult fn(uint8_t *Data, uint64_t Size); |
||
1597 | /// \endcode{.cpp} |
||
1598 | shared::WrapperFunctionResult callWrapper(ExecutorAddr WrapperFnAddr, |
||
1599 | ArrayRef<char> ArgBuffer) { |
||
1600 | return EPC->callWrapper(WrapperFnAddr, ArgBuffer); |
||
1601 | } |
||
1602 | |||
1603 | /// Run a wrapper function using SPS to serialize the arguments and |
||
1604 | /// deserialize the results. |
||
1605 | template <typename SPSSignature, typename SendResultT, typename... ArgTs> |
||
1606 | void callSPSWrapperAsync(ExecutorAddr WrapperFnAddr, SendResultT &&SendResult, |
||
1607 | const ArgTs &...Args) { |
||
1608 | EPC->callSPSWrapperAsync<SPSSignature, SendResultT, ArgTs...>( |
||
1609 | WrapperFnAddr, std::forward<SendResultT>(SendResult), Args...); |
||
1610 | } |
||
1611 | |||
1612 | /// Run a wrapper function using SPS to serialize the arguments and |
||
1613 | /// deserialize the results. |
||
1614 | /// |
||
1615 | /// If SPSSignature is a non-void function signature then the second argument |
||
1616 | /// (the first in the Args list) should be a reference to a return value. |
||
1617 | template <typename SPSSignature, typename... WrapperCallArgTs> |
||
1618 | Error callSPSWrapper(ExecutorAddr WrapperFnAddr, |
||
1619 | WrapperCallArgTs &&...WrapperCallArgs) { |
||
1620 | return EPC->callSPSWrapper<SPSSignature, WrapperCallArgTs...>( |
||
1621 | WrapperFnAddr, std::forward<WrapperCallArgTs>(WrapperCallArgs)...); |
||
1622 | } |
||
1623 | |||
1624 | /// Wrap a handler that takes concrete argument types (and a sender for a |
||
1625 | /// concrete return type) to produce an AsyncHandlerWrapperFunction. Uses SPS |
||
1626 | /// to unpack the arguments and pack the result. |
||
1627 | /// |
||
1628 | /// This function is intended to support easy construction of |
||
1629 | /// AsyncHandlerWrapperFunctions that can be associated with a tag |
||
1630 | /// (using registerJITDispatchHandler) and called from the executor. |
||
1631 | template <typename SPSSignature, typename HandlerT> |
||
1632 | static JITDispatchHandlerFunction wrapAsyncWithSPS(HandlerT &&H) { |
||
1633 | return [H = std::forward<HandlerT>(H)]( |
||
1634 | SendResultFunction SendResult, |
||
1635 | const char *ArgData, size_t ArgSize) mutable { |
||
1636 | shared::WrapperFunction<SPSSignature>::handleAsync(ArgData, ArgSize, H, |
||
1637 | std::move(SendResult)); |
||
1638 | }; |
||
1639 | } |
||
1640 | |||
1641 | /// Wrap a class method that takes concrete argument types (and a sender for |
||
1642 | /// a concrete return type) to produce an AsyncHandlerWrapperFunction. Uses |
||
1643 | /// SPS to unpack teh arguments and pack the result. |
||
1644 | /// |
||
1645 | /// This function is intended to support easy construction of |
||
1646 | /// AsyncHandlerWrapperFunctions that can be associated with a tag |
||
1647 | /// (using registerJITDispatchHandler) and called from the executor. |
||
1648 | template <typename SPSSignature, typename ClassT, typename... MethodArgTs> |
||
1649 | static JITDispatchHandlerFunction |
||
1650 | wrapAsyncWithSPS(ClassT *Instance, void (ClassT::*Method)(MethodArgTs...)) { |
||
1651 | return wrapAsyncWithSPS<SPSSignature>( |
||
1652 | [Instance, Method](MethodArgTs &&...MethodArgs) { |
||
1653 | (Instance->*Method)(std::forward<MethodArgTs>(MethodArgs)...); |
||
1654 | }); |
||
1655 | } |
||
1656 | |||
1657 | /// For each tag symbol name, associate the corresponding |
||
1658 | /// AsyncHandlerWrapperFunction with the address of that symbol. The |
||
1659 | /// handler becomes callable from the executor using the ORC runtime |
||
1660 | /// __orc_rt_jit_dispatch function and the given tag. |
||
1661 | /// |
||
1662 | /// Tag symbols will be looked up in JD using LookupKind::Static, |
||
1663 | /// JITDylibLookupFlags::MatchAllSymbols (hidden tags will be found), and |
||
1664 | /// LookupFlags::WeaklyReferencedSymbol. Missing tag definitions will not |
||
1665 | /// cause an error, the handler will simply be dropped. |
||
1666 | Error registerJITDispatchHandlers(JITDylib &JD, |
||
1667 | JITDispatchHandlerAssociationMap WFs); |
||
1668 | |||
1669 | /// Run a registered jit-side wrapper function. |
||
1670 | /// This should be called by the ExecutorProcessControl instance in response |
||
1671 | /// to incoming jit-dispatch requests from the executor. |
||
1672 | void |
||
1673 | runJITDispatchHandler(SendResultFunction SendResult, |
||
1674 | JITTargetAddress HandlerFnTagAddr, |
||
1675 | ArrayRef<char> ArgBuffer); |
||
1676 | |||
1677 | /// Dump the state of all the JITDylibs in this session. |
||
1678 | void dump(raw_ostream &OS); |
||
1679 | |||
1680 | private: |
||
1681 | static void logErrorsToStdErr(Error Err) { |
||
1682 | logAllUnhandledErrors(std::move(Err), errs(), "JIT session error: "); |
||
1683 | } |
||
1684 | |||
1685 | static void runOnCurrentThread(std::unique_ptr<Task> T) { T->run(); } |
||
1686 | |||
1687 | void dispatchOutstandingMUs(); |
||
1688 | |||
1689 | static std::unique_ptr<MaterializationResponsibility> |
||
1690 | createMaterializationResponsibility(ResourceTracker &RT, |
||
1691 | SymbolFlagsMap Symbols, |
||
1692 | SymbolStringPtr InitSymbol) { |
||
1693 | auto &JD = RT.getJITDylib(); |
||
1694 | std::unique_ptr<MaterializationResponsibility> MR( |
||
1695 | new MaterializationResponsibility(&RT, std::move(Symbols), |
||
1696 | std::move(InitSymbol))); |
||
1697 | JD.TrackerMRs[&RT].insert(MR.get()); |
||
1698 | return MR; |
||
1699 | } |
||
1700 | |||
1701 | Error removeResourceTracker(ResourceTracker &RT); |
||
1702 | void transferResourceTracker(ResourceTracker &DstRT, ResourceTracker &SrcRT); |
||
1703 | void destroyResourceTracker(ResourceTracker &RT); |
||
1704 | |||
1705 | // State machine functions for query application.. |
||
1706 | |||
1707 | /// IL_updateCandidatesFor is called to remove already-defined symbols that |
||
1708 | /// match a given query from the set of candidate symbols to generate |
||
1709 | /// definitions for (no need to generate a definition if one already exists). |
||
1710 | Error IL_updateCandidatesFor(JITDylib &JD, JITDylibLookupFlags JDLookupFlags, |
||
1711 | SymbolLookupSet &Candidates, |
||
1712 | SymbolLookupSet *NonCandidates); |
||
1713 | |||
1714 | /// OL_applyQueryPhase1 is an optionally re-startable loop for triggering |
||
1715 | /// definition generation. It is called when a lookup is performed, and again |
||
1716 | /// each time that LookupState::continueLookup is called. |
||
1717 | void OL_applyQueryPhase1(std::unique_ptr<InProgressLookupState> IPLS, |
||
1718 | Error Err); |
||
1719 | |||
1720 | /// OL_completeLookup is run once phase 1 successfully completes for a lookup |
||
1721 | /// call. It attempts to attach the symbol to all symbol table entries and |
||
1722 | /// collect all MaterializationUnits to dispatch. If this method fails then |
||
1723 | /// all MaterializationUnits will be left un-materialized. |
||
1724 | void OL_completeLookup(std::unique_ptr<InProgressLookupState> IPLS, |
||
1725 | std::shared_ptr<AsynchronousSymbolQuery> Q, |
||
1726 | RegisterDependenciesFunction RegisterDependencies); |
||
1727 | |||
1728 | /// OL_completeLookupFlags is run once phase 1 successfully completes for a |
||
1729 | /// lookupFlags call. |
||
1730 | void OL_completeLookupFlags( |
||
1731 | std::unique_ptr<InProgressLookupState> IPLS, |
||
1732 | unique_function<void(Expected<SymbolFlagsMap>)> OnComplete); |
||
1733 | |||
1734 | // State machine functions for MaterializationResponsibility. |
||
1735 | void OL_destroyMaterializationResponsibility( |
||
1736 | MaterializationResponsibility &MR); |
||
1737 | SymbolNameSet OL_getRequestedSymbols(const MaterializationResponsibility &MR); |
||
1738 | Error OL_notifyResolved(MaterializationResponsibility &MR, |
||
1739 | const SymbolMap &Symbols); |
||
1740 | Error OL_notifyEmitted(MaterializationResponsibility &MR); |
||
1741 | Error OL_defineMaterializing(MaterializationResponsibility &MR, |
||
1742 | SymbolFlagsMap SymbolFlags); |
||
1743 | void OL_notifyFailed(MaterializationResponsibility &MR); |
||
1744 | Error OL_replace(MaterializationResponsibility &MR, |
||
1745 | std::unique_ptr<MaterializationUnit> MU); |
||
1746 | Expected<std::unique_ptr<MaterializationResponsibility>> |
||
1747 | OL_delegate(MaterializationResponsibility &MR, const SymbolNameSet &Symbols); |
||
1748 | void OL_addDependencies(MaterializationResponsibility &MR, |
||
1749 | const SymbolStringPtr &Name, |
||
1750 | const SymbolDependenceMap &Dependencies); |
||
1751 | void OL_addDependenciesForAll(MaterializationResponsibility &MR, |
||
1752 | const SymbolDependenceMap &Dependencies); |
||
1753 | |||
1754 | #ifndef NDEBUG |
||
1755 | void dumpDispatchInfo(Task &T); |
||
1756 | #endif // NDEBUG |
||
1757 | |||
1758 | mutable std::recursive_mutex SessionMutex; |
||
1759 | bool SessionOpen = true; |
||
1760 | std::unique_ptr<ExecutorProcessControl> EPC; |
||
1761 | std::unique_ptr<Platform> P; |
||
1762 | ErrorReporter ReportError = logErrorsToStdErr; |
||
1763 | DispatchTaskFunction DispatchTask = runOnCurrentThread; |
||
1764 | |||
1765 | std::vector<ResourceManager *> ResourceManagers; |
||
1766 | |||
1767 | std::vector<JITDylibSP> JDs; |
||
1768 | |||
1769 | // FIXME: Remove this (and runOutstandingMUs) once the linking layer works |
||
1770 | // with callbacks from asynchronous queries. |
||
1771 | mutable std::recursive_mutex OutstandingMUsMutex; |
||
1772 | std::vector<std::pair<std::unique_ptr<MaterializationUnit>, |
||
1773 | std::unique_ptr<MaterializationResponsibility>>> |
||
1774 | OutstandingMUs; |
||
1775 | |||
1776 | mutable std::mutex JITDispatchHandlersMutex; |
||
1777 | DenseMap<JITTargetAddress, std::shared_ptr<JITDispatchHandlerFunction>> |
||
1778 | JITDispatchHandlers; |
||
1779 | }; |
||
1780 | |||
1781 | template <typename Func> Error ResourceTracker::withResourceKeyDo(Func &&F) { |
||
1782 | return getJITDylib().getExecutionSession().runSessionLocked([&]() -> Error { |
||
1783 | if (isDefunct()) |
||
1784 | return make_error<ResourceTrackerDefunct>(this); |
||
1785 | F(getKeyUnsafe()); |
||
1786 | return Error::success(); |
||
1787 | }); |
||
1788 | } |
||
1789 | |||
1790 | inline ExecutionSession & |
||
1791 | MaterializationResponsibility::getExecutionSession() const { |
||
1792 | return JD.getExecutionSession(); |
||
1793 | } |
||
1794 | |||
1795 | template <typename GeneratorT> |
||
1796 | GeneratorT &JITDylib::addGenerator(std::unique_ptr<GeneratorT> DefGenerator) { |
||
1797 | auto &G = *DefGenerator; |
||
1798 | ES.runSessionLocked([&] { |
||
1799 | assert(State == Open && "Cannot add generator to closed JITDylib"); |
||
1800 | DefGenerators.push_back(std::move(DefGenerator)); |
||
1801 | }); |
||
1802 | return G; |
||
1803 | } |
||
1804 | |||
1805 | template <typename Func> |
||
1806 | auto JITDylib::withLinkOrderDo(Func &&F) |
||
1807 | -> decltype(F(std::declval<const JITDylibSearchOrder &>())) { |
||
1808 | assert(State == Open && "Cannot use link order of closed JITDylib"); |
||
1809 | return ES.runSessionLocked([&]() { return F(LinkOrder); }); |
||
1810 | } |
||
1811 | |||
1812 | template <typename MaterializationUnitType> |
||
1813 | Error JITDylib::define(std::unique_ptr<MaterializationUnitType> &&MU, |
||
1814 | ResourceTrackerSP RT) { |
||
1815 | assert(MU && "Can not define with a null MU"); |
||
1816 | |||
1817 | if (MU->getSymbols().empty()) { |
||
1818 | // Empty MUs are allowable but pathological, so issue a warning. |
||
1819 | DEBUG_WITH_TYPE("orc", { |
||
1820 | dbgs() << "Warning: Discarding empty MU " << MU->getName() << " for " |
||
1821 | << getName() << "\n"; |
||
1822 | }); |
||
1823 | return Error::success(); |
||
1824 | } else |
||
1825 | DEBUG_WITH_TYPE("orc", { |
||
1826 | dbgs() << "Defining MU " << MU->getName() << " for " << getName() |
||
1827 | << " (tracker: "; |
||
1828 | if (RT == getDefaultResourceTracker()) |
||
1829 | dbgs() << "default)"; |
||
1830 | else if (RT) |
||
1831 | dbgs() << RT.get() << ")\n"; |
||
1832 | else |
||
1833 | dbgs() << "0x0, default will be used)\n"; |
||
1834 | }); |
||
1835 | |||
1836 | return ES.runSessionLocked([&, this]() -> Error { |
||
1837 | assert(State == Open && "JD is defunct"); |
||
1838 | |||
1839 | if (auto Err = defineImpl(*MU)) |
||
1840 | return Err; |
||
1841 | |||
1842 | if (!RT) |
||
1843 | RT = getDefaultResourceTracker(); |
||
1844 | |||
1845 | if (auto *P = ES.getPlatform()) { |
||
1846 | if (auto Err = P->notifyAdding(*RT, *MU)) |
||
1847 | return Err; |
||
1848 | } |
||
1849 | |||
1850 | installMaterializationUnit(std::move(MU), *RT); |
||
1851 | return Error::success(); |
||
1852 | }); |
||
1853 | } |
||
1854 | |||
1855 | template <typename MaterializationUnitType> |
||
1856 | Error JITDylib::define(std::unique_ptr<MaterializationUnitType> &MU, |
||
1857 | ResourceTrackerSP RT) { |
||
1858 | assert(MU && "Can not define with a null MU"); |
||
1859 | |||
1860 | if (MU->getSymbols().empty()) { |
||
1861 | // Empty MUs are allowable but pathological, so issue a warning. |
||
1862 | DEBUG_WITH_TYPE("orc", { |
||
1863 | dbgs() << "Warning: Discarding empty MU " << MU->getName() << getName() |
||
1864 | << "\n"; |
||
1865 | }); |
||
1866 | return Error::success(); |
||
1867 | } else |
||
1868 | DEBUG_WITH_TYPE("orc", { |
||
1869 | dbgs() << "Defining MU " << MU->getName() << " for " << getName() |
||
1870 | << " (tracker: "; |
||
1871 | if (RT == getDefaultResourceTracker()) |
||
1872 | dbgs() << "default)"; |
||
1873 | else if (RT) |
||
1874 | dbgs() << RT.get() << ")\n"; |
||
1875 | else |
||
1876 | dbgs() << "0x0, default will be used)\n"; |
||
1877 | }); |
||
1878 | |||
1879 | return ES.runSessionLocked([&, this]() -> Error { |
||
1880 | assert(State == Open && "JD is defunct"); |
||
1881 | |||
1882 | if (auto Err = defineImpl(*MU)) |
||
1883 | return Err; |
||
1884 | |||
1885 | if (!RT) |
||
1886 | RT = getDefaultResourceTracker(); |
||
1887 | |||
1888 | if (auto *P = ES.getPlatform()) { |
||
1889 | if (auto Err = P->notifyAdding(*RT, *MU)) |
||
1890 | return Err; |
||
1891 | } |
||
1892 | |||
1893 | installMaterializationUnit(std::move(MU), *RT); |
||
1894 | return Error::success(); |
||
1895 | }); |
||
1896 | } |
||
1897 | |||
1898 | /// ReexportsGenerator can be used with JITDylib::addGenerator to automatically |
||
1899 | /// re-export a subset of the source JITDylib's symbols in the target. |
||
1900 | class ReexportsGenerator : public DefinitionGenerator { |
||
1901 | public: |
||
1902 | using SymbolPredicate = std::function<bool(SymbolStringPtr)>; |
||
1903 | |||
1904 | /// Create a reexports generator. If an Allow predicate is passed, only |
||
1905 | /// symbols for which the predicate returns true will be reexported. If no |
||
1906 | /// Allow predicate is passed, all symbols will be exported. |
||
1907 | ReexportsGenerator(JITDylib &SourceJD, |
||
1908 | JITDylibLookupFlags SourceJDLookupFlags, |
||
1909 | SymbolPredicate Allow = SymbolPredicate()); |
||
1910 | |||
1911 | Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD, |
||
1912 | JITDylibLookupFlags JDLookupFlags, |
||
1913 | const SymbolLookupSet &LookupSet) override; |
||
1914 | |||
1915 | private: |
||
1916 | JITDylib &SourceJD; |
||
1917 | JITDylibLookupFlags SourceJDLookupFlags; |
||
1918 | SymbolPredicate Allow; |
||
1919 | }; |
||
1920 | |||
1921 | // --------------- IMPLEMENTATION -------------- |
||
1922 | // Implementations for inline functions/methods. |
||
1923 | // --------------------------------------------- |
||
1924 | |||
1925 | inline MaterializationResponsibility::~MaterializationResponsibility() { |
||
1926 | getExecutionSession().OL_destroyMaterializationResponsibility(*this); |
||
1927 | } |
||
1928 | |||
1929 | inline SymbolNameSet MaterializationResponsibility::getRequestedSymbols() const { |
||
1930 | return getExecutionSession().OL_getRequestedSymbols(*this); |
||
1931 | } |
||
1932 | |||
1933 | inline Error MaterializationResponsibility::notifyResolved( |
||
1934 | const SymbolMap &Symbols) { |
||
1935 | return getExecutionSession().OL_notifyResolved(*this, Symbols); |
||
1936 | } |
||
1937 | |||
1938 | inline Error MaterializationResponsibility::notifyEmitted() { |
||
1939 | return getExecutionSession().OL_notifyEmitted(*this); |
||
1940 | } |
||
1941 | |||
1942 | inline Error MaterializationResponsibility::defineMaterializing( |
||
1943 | SymbolFlagsMap SymbolFlags) { |
||
1944 | return getExecutionSession().OL_defineMaterializing(*this, |
||
1945 | std::move(SymbolFlags)); |
||
1946 | } |
||
1947 | |||
1948 | inline void MaterializationResponsibility::failMaterialization() { |
||
1949 | getExecutionSession().OL_notifyFailed(*this); |
||
1950 | } |
||
1951 | |||
1952 | inline Error MaterializationResponsibility::replace( |
||
1953 | std::unique_ptr<MaterializationUnit> MU) { |
||
1954 | return getExecutionSession().OL_replace(*this, std::move(MU)); |
||
1955 | } |
||
1956 | |||
1957 | inline Expected<std::unique_ptr<MaterializationResponsibility>> |
||
1958 | MaterializationResponsibility::delegate(const SymbolNameSet &Symbols) { |
||
1959 | return getExecutionSession().OL_delegate(*this, Symbols); |
||
1960 | } |
||
1961 | |||
1962 | inline void MaterializationResponsibility::addDependencies( |
||
1963 | const SymbolStringPtr &Name, const SymbolDependenceMap &Dependencies) { |
||
1964 | getExecutionSession().OL_addDependencies(*this, Name, Dependencies); |
||
1965 | } |
||
1966 | |||
1967 | inline void MaterializationResponsibility::addDependenciesForAll( |
||
1968 | const SymbolDependenceMap &Dependencies) { |
||
1969 | getExecutionSession().OL_addDependenciesForAll(*this, Dependencies); |
||
1970 | } |
||
1971 | |||
1972 | } // End namespace orc |
||
1973 | } // End namespace llvm |
||
1974 | |||
1975 | #endif // LLVM_EXECUTIONENGINE_ORC_CORE_H |