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