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

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