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

source code of llvm/include/llvm/ExecutionEngine/Orc/Core.h