1 //===------ Core.h -- Core ORC APIs (Layer, JITDylib, etc.) -----*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Contains core ORC APIs.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #ifndef LLVM_EXECUTIONENGINE_ORC_CORE_H
14 #define LLVM_EXECUTIONENGINE_ORC_CORE_H
15
16 #include "llvm/ADT/BitmaskEnum.h"
17 #include "llvm/ADT/DenseSet.h"
18 #include "llvm/ADT/FunctionExtras.h"
19 #include "llvm/ADT/IntrusiveRefCntPtr.h"
20 #include "llvm/ExecutionEngine/JITLink/JITLinkDylib.h"
21 #include "llvm/ExecutionEngine/JITSymbol.h"
22 #include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
23 #include "llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h"
24 #include "llvm/ExecutionEngine/Orc/TaskDispatch.h"
25 #include "llvm/Support/Debug.h"
26 #include "llvm/Support/ExtensibleRTTI.h"
27
28 #include <atomic>
29 #include <future>
30 #include <memory>
31 #include <vector>
32
33 namespace llvm {
34 namespace orc {
35
36 // Forward declare some classes.
37 class AsynchronousSymbolQuery;
38 class ExecutionSession;
39 class MaterializationUnit;
40 class MaterializationResponsibility;
41 class JITDylib;
42 class ResourceTracker;
43 class InProgressLookupState;
44
45 enum class SymbolState : uint8_t;
46
47 using ResourceTrackerSP = IntrusiveRefCntPtr<ResourceTracker>;
48 using JITDylibSP = IntrusiveRefCntPtr<JITDylib>;
49
50 using ResourceKey = uintptr_t;
51
52 /// API to remove / transfer ownership of JIT resources.
53 class ResourceTracker : public ThreadSafeRefCountedBase<ResourceTracker> {
54 private:
55 friend class ExecutionSession;
56 friend class JITDylib;
57 friend class MaterializationResponsibility;
58
59 public:
60 ResourceTracker(const ResourceTracker &) = delete;
61 ResourceTracker &operator=(const ResourceTracker &) = delete;
62 ResourceTracker(ResourceTracker &&) = delete;
63 ResourceTracker &operator=(ResourceTracker &&) = delete;
64
65 ~ResourceTracker();
66
67 /// Return the JITDylib targeted by this tracker.
getJITDylib()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.
isDefunct()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.
getKeyUnsafe()86 ResourceKey getKeyUnsafe() const { return reinterpret_cast<uintptr_t>(this); }
87
88 private:
89 ResourceTracker(JITDylibSP JD);
90
91 void makeDefunct();
92
93 std::atomic_uintptr_t JDAndFlag;
94 };
95
96 /// Listens for ResourceTracker operations.
97 class ResourceManager {
98 public:
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).
106 using SymbolNameSet = DenseSet<SymbolStringPtr>;
107
108 /// A vector of symbol names.
109 using SymbolNameVector = std::vector<SymbolStringPtr>;
110
111 /// A map from symbol names (as SymbolStringPtrs) to JITSymbols
112 /// (address/flags pairs).
113 using SymbolMap = DenseMap<SymbolStringPtr, JITEvaluatedSymbol>;
114
115 /// A map from symbol names (as SymbolStringPtrs) to JITSymbolFlags.
116 using SymbolFlagsMap = DenseMap<SymbolStringPtr, JITSymbolFlags>;
117
118 /// A map from JITDylibs to sets of symbols.
119 using 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.
127 enum 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).
137 enum 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).
149 enum class LookupKind { Static, DLSym };
150
151 /// A list of (JITDylib*, JITDylibLookupFlags) pairs to be used as a search
152 /// order during symbol lookup.
153 using 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.
158 inline 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).
175 class SymbolLookupSet {
176 public:
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 (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.
append(SymbolLookupSet Other)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
empty()250 bool empty() const { return Symbols.empty(); }
size()251 UnderlyingVector::size_type size() const { return Symbols.size(); }
begin()252 iterator begin() { return Symbols.begin(); }
end()253 iterator end() { return Symbols.end(); }
begin()254 const_iterator begin() const { return Symbols.begin(); }
end()255 const_iterator end() const { return Symbols.end(); }
256
257 /// Removes the Ith element of the vector, replacing it with the last element.
remove(UnderlyingVector::size_type I)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.
remove(iterator I)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).
remove_if(PredFn && Pred)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.
getSymbolNames()331 SymbolNameVector getSymbolNames() const {
332 SymbolNameVector Names;
333 Names.reserve(Symbols.size());
334 for (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.
sortByAddress()342 void sortByAddress() {
343 llvm::sort(Symbols, [](const value_type &LHS, const value_type &RHS) {
344 return LHS.first < RHS.first;
345 });
346 }
347
348 /// Sort the lookup set lexicographically. This sort is slow but the order
349 /// is unaffected by allocation order.
sortByName()350 void sortByName() {
351 llvm::sort(Symbols, [](const value_type &LHS, const value_type &RHS) {
352 return *LHS.first < *RHS.first;
353 });
354 }
355
356 /// Remove any duplicate elements. If a SymbolLookupSet is not duplicate-free
357 /// by construction, this method can be used to turn it into a proper set.
removeDuplicates()358 void removeDuplicates() {
359 sortByAddress();
360 auto LastI = std::unique(Symbols.begin(), Symbols.end());
361 Symbols.erase(LastI, Symbols.end());
362 }
363
364 #ifndef NDEBUG
365 /// Returns true if this set contains any duplicates. This should only be used
366 /// in assertions.
containsDuplicates()367 bool containsDuplicates() {
368 if (Symbols.size() < 2)
369 return false;
370 sortByAddress();
371 for (UnderlyingVector::size_type I = 1; I != Symbols.size(); ++I)
372 if (Symbols[I].first == Symbols[I - 1].first)
373 return true;
374 return false;
375 }
376 #endif
377
378 private:
379 UnderlyingVector Symbols;
380 };
381
382 struct SymbolAliasMapEntry {
383 SymbolAliasMapEntry() = default;
SymbolAliasMapEntrySymbolAliasMapEntry384 SymbolAliasMapEntry(SymbolStringPtr Aliasee, JITSymbolFlags AliasFlags)
385 : Aliasee(std::move(Aliasee)), AliasFlags(AliasFlags) {}
386
387 SymbolStringPtr Aliasee;
388 JITSymbolFlags AliasFlags;
389 };
390
391 /// A map of Symbols to (Symbol, Flags) pairs.
392 using SymbolAliasMap = DenseMap<SymbolStringPtr, SymbolAliasMapEntry>;
393
394 /// Callback to notify client that symbols have been resolved.
395 using SymbolsResolvedCallback = unique_function<void(Expected<SymbolMap>)>;
396
397 /// Callback to register the dependencies for a given query.
398 using RegisterDependenciesFunction =
399 std::function<void(const SymbolDependenceMap &)>;
400
401 /// This can be used as the value for a RegisterDependenciesFunction if there
402 /// are no dependants to register with.
403 extern RegisterDependenciesFunction NoDependenciesToRegister;
404
405 class ResourceTrackerDefunct : public ErrorInfo<ResourceTrackerDefunct> {
406 public:
407 static char ID;
408
409 ResourceTrackerDefunct(ResourceTrackerSP RT);
410 std::error_code convertToErrorCode() const override;
411 void log(raw_ostream &OS) const override;
412
413 private:
414 ResourceTrackerSP RT;
415 };
416
417 /// Used to notify a JITDylib that the given set of symbols failed to
418 /// materialize.
419 class FailedToMaterialize : public ErrorInfo<FailedToMaterialize> {
420 public:
421 static char ID;
422
423 FailedToMaterialize(std::shared_ptr<SymbolDependenceMap> Symbols);
424 std::error_code convertToErrorCode() const override;
425 void log(raw_ostream &OS) const override;
getSymbols()426 const SymbolDependenceMap &getSymbols() const { return *Symbols; }
427
428 private:
429 std::shared_ptr<SymbolDependenceMap> Symbols;
430 };
431
432 /// Used to notify clients when symbols can not be found during a lookup.
433 class SymbolsNotFound : public ErrorInfo<SymbolsNotFound> {
434 public:
435 static char ID;
436
437 SymbolsNotFound(std::shared_ptr<SymbolStringPool> SSP, SymbolNameSet Symbols);
438 SymbolsNotFound(std::shared_ptr<SymbolStringPool> SSP,
439 SymbolNameVector Symbols);
440 std::error_code convertToErrorCode() const override;
441 void log(raw_ostream &OS) const override;
getSymbolStringPool()442 std::shared_ptr<SymbolStringPool> getSymbolStringPool() { return SSP; }
getSymbols()443 const SymbolNameVector &getSymbols() const { return Symbols; }
444
445 private:
446 std::shared_ptr<SymbolStringPool> SSP;
447 SymbolNameVector Symbols;
448 };
449
450 /// Used to notify clients that a set of symbols could not be removed.
451 class SymbolsCouldNotBeRemoved : public ErrorInfo<SymbolsCouldNotBeRemoved> {
452 public:
453 static char ID;
454
455 SymbolsCouldNotBeRemoved(std::shared_ptr<SymbolStringPool> SSP,
456 SymbolNameSet Symbols);
457 std::error_code convertToErrorCode() const override;
458 void log(raw_ostream &OS) const override;
getSymbolStringPool()459 std::shared_ptr<SymbolStringPool> getSymbolStringPool() { return SSP; }
getSymbols()460 const SymbolNameSet &getSymbols() const { return Symbols; }
461
462 private:
463 std::shared_ptr<SymbolStringPool> SSP;
464 SymbolNameSet Symbols;
465 };
466
467 /// Errors of this type should be returned if a module fails to include
468 /// definitions that are claimed by the module's associated
469 /// MaterializationResponsibility. If this error is returned it is indicative of
470 /// a broken transformation / compiler / object cache.
471 class MissingSymbolDefinitions : public ErrorInfo<MissingSymbolDefinitions> {
472 public:
473 static char ID;
474
MissingSymbolDefinitions(std::shared_ptr<SymbolStringPool> SSP,std::string ModuleName,SymbolNameVector Symbols)475 MissingSymbolDefinitions(std::shared_ptr<SymbolStringPool> SSP,
476 std::string ModuleName, SymbolNameVector Symbols)
477 : SSP(std::move(SSP)), ModuleName(std::move(ModuleName)),
478 Symbols(std::move(Symbols)) {}
479 std::error_code convertToErrorCode() const override;
480 void log(raw_ostream &OS) const override;
getSymbolStringPool()481 std::shared_ptr<SymbolStringPool> getSymbolStringPool() { return SSP; }
getModuleName()482 const std::string &getModuleName() const { return ModuleName; }
getSymbols()483 const SymbolNameVector &getSymbols() const { return Symbols; }
484 private:
485 std::shared_ptr<SymbolStringPool> SSP;
486 std::string ModuleName;
487 SymbolNameVector Symbols;
488 };
489
490 /// Errors of this type should be returned if a module contains definitions for
491 /// symbols that are not claimed by the module's associated
492 /// MaterializationResponsibility. If this error is returned it is indicative of
493 /// a broken transformation / compiler / object cache.
494 class UnexpectedSymbolDefinitions : public ErrorInfo<UnexpectedSymbolDefinitions> {
495 public:
496 static char ID;
497
UnexpectedSymbolDefinitions(std::shared_ptr<SymbolStringPool> SSP,std::string ModuleName,SymbolNameVector Symbols)498 UnexpectedSymbolDefinitions(std::shared_ptr<SymbolStringPool> SSP,
499 std::string ModuleName, SymbolNameVector Symbols)
500 : SSP(std::move(SSP)), ModuleName(std::move(ModuleName)),
501 Symbols(std::move(Symbols)) {}
502 std::error_code convertToErrorCode() const override;
503 void log(raw_ostream &OS) const override;
getSymbolStringPool()504 std::shared_ptr<SymbolStringPool> getSymbolStringPool() { return SSP; }
getModuleName()505 const std::string &getModuleName() const { return ModuleName; }
getSymbols()506 const SymbolNameVector &getSymbols() const { return Symbols; }
507 private:
508 std::shared_ptr<SymbolStringPool> SSP;
509 std::string ModuleName;
510 SymbolNameVector Symbols;
511 };
512
513 /// Tracks responsibility for materialization, and mediates interactions between
514 /// MaterializationUnits and JDs.
515 ///
516 /// An instance of this class is passed to MaterializationUnits when their
517 /// materialize method is called. It allows MaterializationUnits to resolve and
518 /// emit symbols, or abandon materialization by notifying any unmaterialized
519 /// symbols of an error.
520 class MaterializationResponsibility {
521 friend class ExecutionSession;
522
523 public:
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.
getTargetJITDylib()538 JITDylib &getTargetJITDylib() const { return *JD; }
539
540 /// Returns the ExecutionSession for this instance.
541 ExecutionSession &getExecutionSession();
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.
getSymbols()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.
getInitializerSymbol()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
640 private:
641 /// Create a MaterializationResponsibility for the given JITDylib and
642 /// initial symbols.
MaterializationResponsibility(JITDylibSP JD,SymbolFlagsMap SymbolFlags,SymbolStringPtr InitSymbol)643 MaterializationResponsibility(JITDylibSP JD, SymbolFlagsMap SymbolFlags,
644 SymbolStringPtr InitSymbol)
645 : JD(std::move(JD)), SymbolFlags(std::move(SymbolFlags)),
646 InitSymbol(std::move(InitSymbol)) {
647 assert(this->JD && "Cannot initialize with null JITDylib");
648 assert(!this->SymbolFlags.empty() && "Materializing nothing?");
649 }
650
651 JITDylibSP JD;
652 SymbolFlagsMap SymbolFlags;
653 SymbolStringPtr InitSymbol;
654 };
655
656 /// A MaterializationUnit represents a set of symbol definitions that can
657 /// be materialized as a group, or individually discarded (when
658 /// overriding definitions are encountered).
659 ///
660 /// MaterializationUnits are used when providing lazy definitions of symbols to
661 /// JITDylibs. The JITDylib will call materialize when the address of a symbol
662 /// is requested via the lookup method. The JITDylib will call discard if a
663 /// stronger definition is added or already present.
664 class MaterializationUnit {
665 friend class ExecutionSession;
666 friend class JITDylib;
667
668 public:
669 static char ID;
670
MaterializationUnit(SymbolFlagsMap InitalSymbolFlags,SymbolStringPtr InitSymbol)671 MaterializationUnit(SymbolFlagsMap InitalSymbolFlags,
672 SymbolStringPtr InitSymbol)
673 : SymbolFlags(std::move(InitalSymbolFlags)),
674 InitSymbol(std::move(InitSymbol)) {
675 assert((!this->InitSymbol || this->SymbolFlags.count(this->InitSymbol)) &&
676 "If set, InitSymbol should appear in InitialSymbolFlags map");
677 }
678
~MaterializationUnit()679 virtual ~MaterializationUnit() {}
680
681 /// Return the name of this materialization unit. Useful for debugging
682 /// output.
683 virtual StringRef getName() const = 0;
684
685 /// Return the set of symbols that this source provides.
getSymbols()686 const SymbolFlagsMap &getSymbols() const { return SymbolFlags; }
687
688 /// Returns the initialization symbol for this MaterializationUnit (if any).
getInitializerSymbol()689 const SymbolStringPtr &getInitializerSymbol() const { return InitSymbol; }
690
691 /// Implementations of this method should materialize all symbols
692 /// in the materialzation unit, except for those that have been
693 /// previously discarded.
694 virtual void
695 materialize(std::unique_ptr<MaterializationResponsibility> R) = 0;
696
697 /// Called by JITDylibs to notify MaterializationUnits that the given symbol
698 /// has been overridden.
doDiscard(const JITDylib & JD,const SymbolStringPtr & Name)699 void doDiscard(const JITDylib &JD, const SymbolStringPtr &Name) {
700 SymbolFlags.erase(Name);
701 discard(JD, std::move(Name));
702 }
703
704 protected:
705 SymbolFlagsMap SymbolFlags;
706 SymbolStringPtr InitSymbol;
707
708 private:
709 virtual void anchor();
710
711 /// Implementations of this method should discard the given symbol
712 /// from the source (e.g. if the source is an LLVM IR Module and the
713 /// symbol is a function, delete the function body or mark it available
714 /// externally).
715 virtual void discard(const JITDylib &JD, const SymbolStringPtr &Name) = 0;
716 };
717
718 /// A MaterializationUnit implementation for pre-existing absolute symbols.
719 ///
720 /// All symbols will be resolved and marked ready as soon as the unit is
721 /// materialized.
722 class AbsoluteSymbolsMaterializationUnit : public MaterializationUnit {
723 public:
724 AbsoluteSymbolsMaterializationUnit(SymbolMap Symbols);
725
726 StringRef getName() const override;
727
728 private:
729 void materialize(std::unique_ptr<MaterializationResponsibility> R) override;
730 void discard(const JITDylib &JD, const SymbolStringPtr &Name) override;
731 static SymbolFlagsMap extractFlags(const SymbolMap &Symbols);
732
733 SymbolMap Symbols;
734 };
735
736 /// Create an AbsoluteSymbolsMaterializationUnit with the given symbols.
737 /// Useful for inserting absolute symbols into a JITDylib. E.g.:
738 /// \code{.cpp}
739 /// JITDylib &JD = ...;
740 /// SymbolStringPtr Foo = ...;
741 /// JITEvaluatedSymbol FooSym = ...;
742 /// if (auto Err = JD.define(absoluteSymbols({{Foo, FooSym}})))
743 /// return Err;
744 /// \endcode
745 ///
746 inline std::unique_ptr<AbsoluteSymbolsMaterializationUnit>
absoluteSymbols(SymbolMap Symbols)747 absoluteSymbols(SymbolMap Symbols) {
748 return std::make_unique<AbsoluteSymbolsMaterializationUnit>(
749 std::move(Symbols));
750 }
751
752 /// A materialization unit for symbol aliases. Allows existing symbols to be
753 /// aliased with alternate flags.
754 class ReExportsMaterializationUnit : public MaterializationUnit {
755 public:
756 /// SourceJD is allowed to be nullptr, in which case the source JITDylib is
757 /// taken to be whatever JITDylib these definitions are materialized in (and
758 /// MatchNonExported has no effect). This is useful for defining aliases
759 /// within a JITDylib.
760 ///
761 /// Note: Care must be taken that no sets of aliases form a cycle, as such
762 /// a cycle will result in a deadlock when any symbol in the cycle is
763 /// resolved.
764 ReExportsMaterializationUnit(JITDylib *SourceJD,
765 JITDylibLookupFlags SourceJDLookupFlags,
766 SymbolAliasMap Aliases);
767
768 StringRef getName() const override;
769
770 private:
771 void materialize(std::unique_ptr<MaterializationResponsibility> R) override;
772 void discard(const JITDylib &JD, const SymbolStringPtr &Name) override;
773 static SymbolFlagsMap extractFlags(const SymbolAliasMap &Aliases);
774
775 JITDylib *SourceJD = nullptr;
776 JITDylibLookupFlags SourceJDLookupFlags;
777 SymbolAliasMap Aliases;
778 };
779
780 /// Create a ReExportsMaterializationUnit with the given aliases.
781 /// Useful for defining symbol aliases.: E.g., given a JITDylib JD containing
782 /// symbols "foo" and "bar", we can define aliases "baz" (for "foo") and "qux"
783 /// (for "bar") with: \code{.cpp}
784 /// SymbolStringPtr Baz = ...;
785 /// SymbolStringPtr Qux = ...;
786 /// if (auto Err = JD.define(symbolAliases({
787 /// {Baz, { Foo, JITSymbolFlags::Exported }},
788 /// {Qux, { Bar, JITSymbolFlags::Weak }}}))
789 /// return Err;
790 /// \endcode
791 inline std::unique_ptr<ReExportsMaterializationUnit>
symbolAliases(SymbolAliasMap Aliases)792 symbolAliases(SymbolAliasMap Aliases) {
793 return std::make_unique<ReExportsMaterializationUnit>(
794 nullptr, JITDylibLookupFlags::MatchAllSymbols, std::move(Aliases));
795 }
796
797 /// Create a materialization unit for re-exporting symbols from another JITDylib
798 /// with alternative names/flags.
799 /// SourceJD will be searched using the given JITDylibLookupFlags.
800 inline std::unique_ptr<ReExportsMaterializationUnit>
801 reexports(JITDylib &SourceJD, SymbolAliasMap Aliases,
802 JITDylibLookupFlags SourceJDLookupFlags =
803 JITDylibLookupFlags::MatchExportedSymbolsOnly) {
804 return std::make_unique<ReExportsMaterializationUnit>(
805 &SourceJD, SourceJDLookupFlags, std::move(Aliases));
806 }
807
808 /// Build a SymbolAliasMap for the common case where you want to re-export
809 /// symbols from another JITDylib with the same linkage/flags.
810 Expected<SymbolAliasMap>
811 buildSimpleReexportsAliasMap(JITDylib &SourceJD, const SymbolNameSet &Symbols);
812
813 /// Represents the state that a symbol has reached during materialization.
814 enum class SymbolState : uint8_t {
815 Invalid, /// No symbol should be in this state.
816 NeverSearched, /// Added to the symbol table, never queried.
817 Materializing, /// Queried, materialization begun.
818 Resolved, /// Assigned address, still materializing.
819 Emitted, /// Emitted to memory, but waiting on transitive dependencies.
820 Ready = 0x3f /// Ready and safe for clients to access.
821 };
822
823 /// A symbol query that returns results via a callback when results are
824 /// ready.
825 ///
826 /// makes a callback when all symbols are available.
827 class AsynchronousSymbolQuery {
828 friend class ExecutionSession;
829 friend class InProgressFullLookupState;
830 friend class JITDylib;
831 friend class JITSymbolResolverAdapter;
832 friend class MaterializationResponsibility;
833
834 public:
835 /// Create a query for the given symbols. The NotifyComplete
836 /// callback will be called once all queried symbols reach the given
837 /// minimum state.
838 AsynchronousSymbolQuery(const SymbolLookupSet &Symbols,
839 SymbolState RequiredState,
840 SymbolsResolvedCallback NotifyComplete);
841
842 /// Notify the query that a requested symbol has reached the required state.
843 void notifySymbolMetRequiredState(const SymbolStringPtr &Name,
844 JITEvaluatedSymbol Sym);
845
846 /// Returns true if all symbols covered by this query have been
847 /// resolved.
isComplete()848 bool isComplete() const { return OutstandingSymbolsCount == 0; }
849
850
851 private:
852 void handleComplete(ExecutionSession &ES);
853
getRequiredState()854 SymbolState getRequiredState() { return RequiredState; }
855
856 void addQueryDependence(JITDylib &JD, SymbolStringPtr Name);
857
858 void removeQueryDependence(JITDylib &JD, const SymbolStringPtr &Name);
859
860 void dropSymbol(const SymbolStringPtr &Name);
861
862 void handleFailed(Error Err);
863
864 void detach();
865
866 SymbolsResolvedCallback NotifyComplete;
867 SymbolDependenceMap QueryRegistrations;
868 SymbolMap ResolvedSymbols;
869 size_t OutstandingSymbolsCount;
870 SymbolState RequiredState;
871 };
872
873 /// Wraps state for a lookup-in-progress.
874 /// DefinitionGenerators can optionally take ownership of a LookupState object
875 /// to suspend a lookup-in-progress while they search for definitions.
876 class LookupState {
877 friend class OrcV2CAPIHelper;
878 friend class ExecutionSession;
879
880 public:
881 LookupState();
882 LookupState(LookupState &&);
883 LookupState &operator=(LookupState &&);
884 ~LookupState();
885
886 /// Continue the lookup. This can be called by DefinitionGenerators
887 /// to re-start a captured query-application operation.
888 void continueLookup(Error Err);
889
890 private:
891 LookupState(std::unique_ptr<InProgressLookupState> IPLS);
892
893 // For C API.
894 void reset(InProgressLookupState *IPLS);
895
896 std::unique_ptr<InProgressLookupState> IPLS;
897 };
898
899 /// Definition generators can be attached to JITDylibs to generate new
900 /// definitions for otherwise unresolved symbols during lookup.
901 class DefinitionGenerator {
902 public:
903 virtual ~DefinitionGenerator();
904
905 /// DefinitionGenerators should override this method to insert new
906 /// definitions into the parent JITDylib. K specifies the kind of this
907 /// lookup. JD specifies the target JITDylib being searched, and
908 /// JDLookupFlags specifies whether the search should match against
909 /// hidden symbols. Finally, Symbols describes the set of unresolved
910 /// symbols and their associated lookup flags.
911 virtual Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD,
912 JITDylibLookupFlags JDLookupFlags,
913 const SymbolLookupSet &LookupSet) = 0;
914 };
915
916 /// A symbol table that supports asynchoronous symbol queries.
917 ///
918 /// Represents a virtual shared object. Instances can not be copied or moved, so
919 /// their addresses may be used as keys for resource management.
920 /// JITDylib state changes must be made via an ExecutionSession to guarantee
921 /// that they are synchronized with respect to other JITDylib operations.
922 class JITDylib : public ThreadSafeRefCountedBase<JITDylib>,
923 public jitlink::JITLinkDylib {
924 friend class AsynchronousSymbolQuery;
925 friend class ExecutionSession;
926 friend class Platform;
927 friend class MaterializationResponsibility;
928 public:
929
930 using AsynchronousSymbolQuerySet =
931 std::set<std::shared_ptr<AsynchronousSymbolQuery>>;
932
933 JITDylib(const JITDylib &) = delete;
934 JITDylib &operator=(const JITDylib &) = delete;
935 JITDylib(JITDylib &&) = delete;
936 JITDylib &operator=(JITDylib &&) = delete;
937
938 /// Get the name for this JITDylib.
getName()939 const std::string &getName() const { return JITDylibName; }
940
941 /// Get a reference to the ExecutionSession for this JITDylib.
getExecutionSession()942 ExecutionSession &getExecutionSession() const { return ES; }
943
944 /// Calls remove on all trackers currently associated with this JITDylib.
945 /// Does not run static deinits.
946 ///
947 /// Note that removal happens outside the session lock, so new code may be
948 /// added concurrently while the clear is underway, and the newly added
949 /// code will *not* be cleared. Adding new code concurrently with a clear
950 /// is usually a bug and should be avoided.
951 Error clear();
952
953 /// Get the default resource tracker for this JITDylib.
954 ResourceTrackerSP getDefaultResourceTracker();
955
956 /// Create a resource tracker for this JITDylib.
957 ResourceTrackerSP createResourceTracker();
958
959 /// Adds a definition generator to this JITDylib and returns a referenece to
960 /// it.
961 ///
962 /// When JITDylibs are searched during lookup, if no existing definition of
963 /// a symbol is found, then any generators that have been added are run (in
964 /// the order that they were added) to potentially generate a definition.
965 template <typename GeneratorT>
966 GeneratorT &addGenerator(std::unique_ptr<GeneratorT> DefGenerator);
967
968 /// Remove a definition generator from this JITDylib.
969 ///
970 /// The given generator must exist in this JITDylib's generators list (i.e.
971 /// have been added and not yet removed).
972 void removeGenerator(DefinitionGenerator &G);
973
974 /// Set the link order to be used when fixing up definitions in JITDylib.
975 /// This will replace the previous link order, and apply to any symbol
976 /// resolutions made for definitions in this JITDylib after the call to
977 /// setLinkOrder (even if the definition itself was added before the
978 /// call).
979 ///
980 /// If LinkAgainstThisJITDylibFirst is true (the default) then this JITDylib
981 /// will add itself to the beginning of the LinkOrder (Clients should not
982 /// put this JITDylib in the list in this case, to avoid redundant lookups).
983 ///
984 /// If LinkAgainstThisJITDylibFirst is false then the link order will be used
985 /// as-is. The primary motivation for this feature is to support deliberate
986 /// shadowing of symbols in this JITDylib by a facade JITDylib. For example,
987 /// the facade may resolve function names to stubs, and the stubs may compile
988 /// lazily by looking up symbols in this dylib. Adding the facade dylib
989 /// as the first in the link order (instead of this dylib) ensures that
990 /// definitions within this dylib resolve to the lazy-compiling stubs,
991 /// rather than immediately materializing the definitions in this dylib.
992 void setLinkOrder(JITDylibSearchOrder NewSearchOrder,
993 bool LinkAgainstThisJITDylibFirst = true);
994
995 /// Add the given JITDylib to the link order for definitions in this
996 /// JITDylib.
997 void addToLinkOrder(JITDylib &JD,
998 JITDylibLookupFlags JDLookupFlags =
999 JITDylibLookupFlags::MatchExportedSymbolsOnly);
1000
1001 /// Replace OldJD with NewJD in the link order if OldJD is present.
1002 /// Otherwise this operation is a no-op.
1003 void replaceInLinkOrder(JITDylib &OldJD, JITDylib &NewJD,
1004 JITDylibLookupFlags JDLookupFlags =
1005 JITDylibLookupFlags::MatchExportedSymbolsOnly);
1006
1007 /// Remove the given JITDylib from the link order for this JITDylib if it is
1008 /// present. Otherwise this operation is a no-op.
1009 void removeFromLinkOrder(JITDylib &JD);
1010
1011 /// Do something with the link order (run under the session lock).
1012 template <typename Func>
1013 auto withLinkOrderDo(Func &&F)
1014 -> decltype(F(std::declval<const JITDylibSearchOrder &>()));
1015
1016 /// Define all symbols provided by the materialization unit to be part of this
1017 /// JITDylib.
1018 ///
1019 /// If RT is not specified then the default resource tracker will be used.
1020 ///
1021 /// This overload always takes ownership of the MaterializationUnit. If any
1022 /// errors occur, the MaterializationUnit consumed.
1023 template <typename MaterializationUnitType>
1024 Error define(std::unique_ptr<MaterializationUnitType> &&MU,
1025 ResourceTrackerSP RT = nullptr);
1026
1027 /// Define all symbols provided by the materialization unit to be part of this
1028 /// JITDylib.
1029 ///
1030 /// This overload only takes ownership of the MaterializationUnit no error is
1031 /// generated. If an error occurs, ownership remains with the caller. This
1032 /// may allow the caller to modify the MaterializationUnit to correct the
1033 /// issue, then re-call define.
1034 template <typename MaterializationUnitType>
1035 Error define(std::unique_ptr<MaterializationUnitType> &MU,
1036 ResourceTrackerSP RT = nullptr);
1037
1038 /// Tries to remove the given symbols.
1039 ///
1040 /// If any symbols are not defined in this JITDylib this method will return
1041 /// a SymbolsNotFound error covering the missing symbols.
1042 ///
1043 /// If all symbols are found but some symbols are in the process of being
1044 /// materialized this method will return a SymbolsCouldNotBeRemoved error.
1045 ///
1046 /// On success, all symbols are removed. On failure, the JITDylib state is
1047 /// left unmodified (no symbols are removed).
1048 Error remove(const SymbolNameSet &Names);
1049
1050 /// Dump current JITDylib state to OS.
1051 void dump(raw_ostream &OS);
1052
1053 /// Returns the given JITDylibs and all of their transitive dependencies in
1054 /// DFS order (based on linkage relationships). Each JITDylib will appear
1055 /// only once.
1056 static std::vector<JITDylibSP> getDFSLinkOrder(ArrayRef<JITDylibSP> JDs);
1057
1058 /// Returns the given JITDylibs and all of their transitive dependensies in
1059 /// reverse DFS order (based on linkage relationships). Each JITDylib will
1060 /// appear only once.
1061 static std::vector<JITDylibSP>
1062 getReverseDFSLinkOrder(ArrayRef<JITDylibSP> JDs);
1063
1064 /// Return this JITDylib and its transitive dependencies in DFS order
1065 /// based on linkage relationships.
1066 std::vector<JITDylibSP> getDFSLinkOrder();
1067
1068 /// Rteurn this JITDylib and its transitive dependencies in reverse DFS order
1069 /// based on linkage relationships.
1070 std::vector<JITDylibSP> getReverseDFSLinkOrder();
1071
1072 private:
1073 using AsynchronousSymbolQueryList =
1074 std::vector<std::shared_ptr<AsynchronousSymbolQuery>>;
1075
1076 struct UnmaterializedInfo {
UnmaterializedInfoUnmaterializedInfo1077 UnmaterializedInfo(std::unique_ptr<MaterializationUnit> MU,
1078 ResourceTracker *RT)
1079 : MU(std::move(MU)), RT(RT) {}
1080
1081 std::unique_ptr<MaterializationUnit> MU;
1082 ResourceTracker *RT;
1083 };
1084
1085 using UnmaterializedInfosMap =
1086 DenseMap<SymbolStringPtr, std::shared_ptr<UnmaterializedInfo>>;
1087
1088 using UnmaterializedInfosList =
1089 std::vector<std::shared_ptr<UnmaterializedInfo>>;
1090
1091 struct MaterializingInfo {
1092 SymbolDependenceMap Dependants;
1093 SymbolDependenceMap UnemittedDependencies;
1094
1095 void addQuery(std::shared_ptr<AsynchronousSymbolQuery> Q);
1096 void removeQuery(const AsynchronousSymbolQuery &Q);
1097 AsynchronousSymbolQueryList takeQueriesMeeting(SymbolState RequiredState);
takeAllPendingQueriesMaterializingInfo1098 AsynchronousSymbolQueryList takeAllPendingQueries() {
1099 return std::move(PendingQueries);
1100 }
hasQueriesPendingMaterializingInfo1101 bool hasQueriesPending() const { return !PendingQueries.empty(); }
pendingQueriesMaterializingInfo1102 const AsynchronousSymbolQueryList &pendingQueries() const {
1103 return PendingQueries;
1104 }
1105 private:
1106 AsynchronousSymbolQueryList PendingQueries;
1107 };
1108
1109 using MaterializingInfosMap = DenseMap<SymbolStringPtr, MaterializingInfo>;
1110
1111 class SymbolTableEntry {
1112 public:
1113 SymbolTableEntry() = default;
SymbolTableEntry(JITSymbolFlags Flags)1114 SymbolTableEntry(JITSymbolFlags Flags)
1115 : Flags(Flags), State(static_cast<uint8_t>(SymbolState::NeverSearched)),
1116 MaterializerAttached(false), PendingRemoval(false) {}
1117
getAddress()1118 JITTargetAddress getAddress() const { return Addr; }
getFlags()1119 JITSymbolFlags getFlags() const { return Flags; }
getState()1120 SymbolState getState() const { return static_cast<SymbolState>(State); }
1121
hasMaterializerAttached()1122 bool hasMaterializerAttached() const { return MaterializerAttached; }
isPendingRemoval()1123 bool isPendingRemoval() const { return PendingRemoval; }
1124
setAddress(JITTargetAddress Addr)1125 void setAddress(JITTargetAddress Addr) { this->Addr = Addr; }
setFlags(JITSymbolFlags Flags)1126 void setFlags(JITSymbolFlags Flags) { this->Flags = Flags; }
setState(SymbolState State)1127 void setState(SymbolState State) {
1128 assert(static_cast<uint8_t>(State) < (1 << 6) &&
1129 "State does not fit in bitfield");
1130 this->State = static_cast<uint8_t>(State);
1131 }
1132
setMaterializerAttached(bool MaterializerAttached)1133 void setMaterializerAttached(bool MaterializerAttached) {
1134 this->MaterializerAttached = MaterializerAttached;
1135 }
1136
setPendingRemoval(bool PendingRemoval)1137 void setPendingRemoval(bool PendingRemoval) {
1138 this->PendingRemoval = PendingRemoval;
1139 }
1140
getSymbol()1141 JITEvaluatedSymbol getSymbol() const {
1142 return JITEvaluatedSymbol(Addr, Flags);
1143 }
1144
1145 private:
1146 JITTargetAddress Addr = 0;
1147 JITSymbolFlags Flags;
1148 uint8_t State : 6;
1149 uint8_t MaterializerAttached : 1;
1150 uint8_t PendingRemoval : 1;
1151 };
1152
1153 using SymbolTable = DenseMap<SymbolStringPtr, SymbolTableEntry>;
1154
1155 JITDylib(ExecutionSession &ES, std::string Name);
1156
1157 ResourceTrackerSP getTracker(MaterializationResponsibility &MR);
1158 std::pair<AsynchronousSymbolQuerySet, std::shared_ptr<SymbolDependenceMap>>
1159 removeTracker(ResourceTracker &RT);
1160
1161 void transferTracker(ResourceTracker &DstRT, ResourceTracker &SrcRT);
1162
1163 Error defineImpl(MaterializationUnit &MU);
1164
1165 void installMaterializationUnit(std::unique_ptr<MaterializationUnit> MU,
1166 ResourceTracker &RT);
1167
1168 void detachQueryHelper(AsynchronousSymbolQuery &Q,
1169 const SymbolNameSet &QuerySymbols);
1170
1171 void transferEmittedNodeDependencies(MaterializingInfo &DependantMI,
1172 const SymbolStringPtr &DependantName,
1173 MaterializingInfo &EmittedMI);
1174
1175 Expected<SymbolFlagsMap> defineMaterializing(SymbolFlagsMap SymbolFlags);
1176
1177 Error replace(MaterializationResponsibility &FromMR,
1178 std::unique_ptr<MaterializationUnit> MU);
1179
1180 Expected<std::unique_ptr<MaterializationResponsibility>>
1181 delegate(MaterializationResponsibility &FromMR, SymbolFlagsMap SymbolFlags,
1182 SymbolStringPtr InitSymbol);
1183
1184 SymbolNameSet getRequestedSymbols(const SymbolFlagsMap &SymbolFlags) const;
1185
1186 void addDependencies(const SymbolStringPtr &Name,
1187 const SymbolDependenceMap &Dependants);
1188
1189 Error resolve(MaterializationResponsibility &MR, const SymbolMap &Resolved);
1190
1191 Error emit(MaterializationResponsibility &MR, const SymbolFlagsMap &Emitted);
1192
1193 void unlinkMaterializationResponsibility(MaterializationResponsibility &MR);
1194
1195 using FailedSymbolsWorklist =
1196 std::vector<std::pair<JITDylib *, SymbolStringPtr>>;
1197
1198 static std::pair<AsynchronousSymbolQuerySet,
1199 std::shared_ptr<SymbolDependenceMap>>
1200 failSymbols(FailedSymbolsWorklist);
1201
1202 ExecutionSession &ES;
1203 std::string JITDylibName;
1204 std::mutex GeneratorsMutex;
1205 bool Open = true;
1206 SymbolTable Symbols;
1207 UnmaterializedInfosMap UnmaterializedInfos;
1208 MaterializingInfosMap MaterializingInfos;
1209 std::vector<std::shared_ptr<DefinitionGenerator>> DefGenerators;
1210 JITDylibSearchOrder LinkOrder;
1211 ResourceTrackerSP DefaultTracker;
1212
1213 // Map trackers to sets of symbols tracked.
1214 DenseMap<ResourceTracker *, SymbolNameVector> TrackerSymbols;
1215 DenseMap<MaterializationResponsibility *, ResourceTracker *> MRTrackers;
1216 };
1217
1218 /// Platforms set up standard symbols and mediate interactions between dynamic
1219 /// initializers (e.g. C++ static constructors) and ExecutionSession state.
1220 /// Note that Platforms do not automatically run initializers: clients are still
1221 /// responsible for doing this.
1222 class Platform {
1223 public:
1224 virtual ~Platform();
1225
1226 /// This method will be called outside the session lock each time a JITDylib
1227 /// is created (unless it is created with EmptyJITDylib set) to allow the
1228 /// Platform to install any JITDylib specific standard symbols (e.g
1229 /// __dso_handle).
1230 virtual Error setupJITDylib(JITDylib &JD) = 0;
1231
1232 /// This method will be called under the ExecutionSession lock each time a
1233 /// MaterializationUnit is added to a JITDylib.
1234 virtual Error notifyAdding(ResourceTracker &RT,
1235 const MaterializationUnit &MU) = 0;
1236
1237 /// This method will be called under the ExecutionSession lock when a
1238 /// ResourceTracker is removed.
1239 virtual Error notifyRemoving(ResourceTracker &RT) = 0;
1240
1241 /// A utility function for looking up initializer symbols. Performs a blocking
1242 /// lookup for the given symbols in each of the given JITDylibs.
1243 ///
1244 /// Note: This function is deprecated and will be removed in the near future.
1245 static Expected<DenseMap<JITDylib *, SymbolMap>>
1246 lookupInitSymbols(ExecutionSession &ES,
1247 const DenseMap<JITDylib *, SymbolLookupSet> &InitSyms);
1248
1249 /// Performs an async lookup for the the given symbols in each of the given
1250 /// JITDylibs, calling the given handler with the compound result map once
1251 /// all lookups have completed.
1252 static void
1253 lookupInitSymbolsAsync(unique_function<void(Error)> OnComplete,
1254 ExecutionSession &ES,
1255 const DenseMap<JITDylib *, SymbolLookupSet> &InitSyms);
1256 };
1257
1258 /// A materialization task.
1259 class MaterializationTask : public RTTIExtends<MaterializationTask, Task> {
1260 public:
1261 static char ID;
1262
MaterializationTask(std::unique_ptr<MaterializationUnit> MU,std::unique_ptr<MaterializationResponsibility> MR)1263 MaterializationTask(std::unique_ptr<MaterializationUnit> MU,
1264 std::unique_ptr<MaterializationResponsibility> MR)
1265 : MU(std::move(MU)), MR(std::move(MR)) {}
1266 void printDescription(raw_ostream &OS) override;
1267 void run() override;
1268
1269 private:
1270 std::unique_ptr<MaterializationUnit> MU;
1271 std::unique_ptr<MaterializationResponsibility> MR;
1272 };
1273
1274 /// An ExecutionSession represents a running JIT program.
1275 class ExecutionSession {
1276 friend class InProgressLookupFlagsState;
1277 friend class InProgressFullLookupState;
1278 friend class JITDylib;
1279 friend class LookupState;
1280 friend class MaterializationResponsibility;
1281 friend class ResourceTracker;
1282
1283 public:
1284 /// For reporting errors.
1285 using ErrorReporter = std::function<void(Error)>;
1286
1287 /// Send a result to the remote.
1288 using SendResultFunction = unique_function<void(shared::WrapperFunctionResult)>;
1289
1290 /// For dispatching ORC tasks (typically materialization tasks).
1291 using DispatchTaskFunction = unique_function<void(std::unique_ptr<Task> T)>;
1292
1293 /// An asynchronous wrapper-function callable from the executor via
1294 /// jit-dispatch.
1295 using JITDispatchHandlerFunction = unique_function<void(
1296 SendResultFunction SendResult,
1297 const char *ArgData, size_t ArgSize)>;
1298
1299 /// A map associating tag names with asynchronous wrapper function
1300 /// implementations in the JIT.
1301 using JITDispatchHandlerAssociationMap =
1302 DenseMap<SymbolStringPtr, JITDispatchHandlerFunction>;
1303
1304 /// Construct an ExecutionSession with the given ExecutorProcessControl
1305 /// object.
1306 ExecutionSession(std::unique_ptr<ExecutorProcessControl> EPC);
1307
1308 /// End the session. Closes all JITDylibs and disconnects from the
1309 /// executor.
1310 Error endSession();
1311
1312 /// Get the ExecutorProcessControl object associated with this
1313 /// ExecutionSession.
getExecutorProcessControl()1314 ExecutorProcessControl &getExecutorProcessControl() { return *EPC; }
1315
1316 /// Get the SymbolStringPool for this instance.
getSymbolStringPool()1317 std::shared_ptr<SymbolStringPool> getSymbolStringPool() {
1318 return EPC->getSymbolStringPool();
1319 }
1320
1321 /// Add a symbol name to the SymbolStringPool and return a pointer to it.
intern(StringRef SymName)1322 SymbolStringPtr intern(StringRef SymName) { return EPC->intern(SymName); }
1323
1324 /// Set the Platform for this ExecutionSession.
setPlatform(std::unique_ptr<Platform> P)1325 void setPlatform(std::unique_ptr<Platform> P) { this->P = std::move(P); }
1326
1327 /// Get the Platform for this session.
1328 /// Will return null if no Platform has been set for this ExecutionSession.
getPlatform()1329 Platform *getPlatform() { return P.get(); }
1330
1331 /// Run the given lambda with the session mutex locked.
decltype(auto)1332 template <typename Func> decltype(auto) runSessionLocked(Func &&F) {
1333 std::lock_guard<std::recursive_mutex> Lock(SessionMutex);
1334 return F();
1335 }
1336
1337 /// Register the given ResourceManager with this ExecutionSession.
1338 /// Managers will be notified of events in reverse order of registration.
1339 void registerResourceManager(ResourceManager &RM);
1340
1341 /// Deregister the given ResourceManager with this ExecutionSession.
1342 /// Manager must have been previously registered.
1343 void deregisterResourceManager(ResourceManager &RM);
1344
1345 /// Return a pointer to the "name" JITDylib.
1346 /// Ownership of JITDylib remains within Execution Session
1347 JITDylib *getJITDylibByName(StringRef Name);
1348
1349 /// Add a new bare JITDylib to this ExecutionSession.
1350 ///
1351 /// The JITDylib Name is required to be unique. Clients should verify that
1352 /// names are not being re-used (E.g. by calling getJITDylibByName) if names
1353 /// are based on user input.
1354 ///
1355 /// This call does not install any library code or symbols into the newly
1356 /// created JITDylib. The client is responsible for all configuration.
1357 JITDylib &createBareJITDylib(std::string Name);
1358
1359 /// Add a new JITDylib to this ExecutionSession.
1360 ///
1361 /// The JITDylib Name is required to be unique. Clients should verify that
1362 /// names are not being re-used (e.g. by calling getJITDylibByName) if names
1363 /// are based on user input.
1364 ///
1365 /// If a Platform is attached then Platform::setupJITDylib will be called to
1366 /// install standard platform symbols (e.g. standard library interposes).
1367 /// If no Platform is attached this call is equivalent to createBareJITDylib.
1368 Expected<JITDylib &> createJITDylib(std::string Name);
1369
1370 /// Set the error reporter function.
setErrorReporter(ErrorReporter ReportError)1371 ExecutionSession &setErrorReporter(ErrorReporter ReportError) {
1372 this->ReportError = std::move(ReportError);
1373 return *this;
1374 }
1375
1376 /// Report a error for this execution session.
1377 ///
1378 /// Unhandled errors can be sent here to log them.
reportError(Error Err)1379 void reportError(Error Err) { ReportError(std::move(Err)); }
1380
1381 /// Set the task dispatch function.
setDispatchTask(DispatchTaskFunction DispatchTask)1382 ExecutionSession &setDispatchTask(DispatchTaskFunction DispatchTask) {
1383 this->DispatchTask = std::move(DispatchTask);
1384 return *this;
1385 }
1386
1387 /// Search the given JITDylibs to find the flags associated with each of the
1388 /// given symbols.
1389 void lookupFlags(LookupKind K, JITDylibSearchOrder SearchOrder,
1390 SymbolLookupSet Symbols,
1391 unique_function<void(Expected<SymbolFlagsMap>)> OnComplete);
1392
1393 /// Blocking version of lookupFlags.
1394 Expected<SymbolFlagsMap> lookupFlags(LookupKind K,
1395 JITDylibSearchOrder SearchOrder,
1396 SymbolLookupSet Symbols);
1397
1398 /// Search the given JITDylibs for the given symbols.
1399 ///
1400 /// SearchOrder lists the JITDylibs to search. For each dylib, the associated
1401 /// boolean indicates whether the search should match against non-exported
1402 /// (hidden visibility) symbols in that dylib (true means match against
1403 /// non-exported symbols, false means do not match).
1404 ///
1405 /// The NotifyComplete callback will be called once all requested symbols
1406 /// reach the required state.
1407 ///
1408 /// If all symbols are found, the RegisterDependencies function will be called
1409 /// while the session lock is held. This gives clients a chance to register
1410 /// dependencies for on the queried symbols for any symbols they are
1411 /// materializing (if a MaterializationResponsibility instance is present,
1412 /// this can be implemented by calling
1413 /// MaterializationResponsibility::addDependencies). If there are no
1414 /// dependenant symbols for this query (e.g. it is being made by a top level
1415 /// client to get an address to call) then the value NoDependenciesToRegister
1416 /// can be used.
1417 void lookup(LookupKind K, const JITDylibSearchOrder &SearchOrder,
1418 SymbolLookupSet Symbols, SymbolState RequiredState,
1419 SymbolsResolvedCallback NotifyComplete,
1420 RegisterDependenciesFunction RegisterDependencies);
1421
1422 /// Blocking version of lookup above. Returns the resolved symbol map.
1423 /// If WaitUntilReady is true (the default), will not return until all
1424 /// requested symbols are ready (or an error occurs). If WaitUntilReady is
1425 /// false, will return as soon as all requested symbols are resolved,
1426 /// or an error occurs. If WaitUntilReady is false and an error occurs
1427 /// after resolution, the function will return a success value, but the
1428 /// error will be reported via reportErrors.
1429 Expected<SymbolMap> lookup(const JITDylibSearchOrder &SearchOrder,
1430 const SymbolLookupSet &Symbols,
1431 LookupKind K = LookupKind::Static,
1432 SymbolState RequiredState = SymbolState::Ready,
1433 RegisterDependenciesFunction RegisterDependencies =
1434 NoDependenciesToRegister);
1435
1436 /// Convenience version of blocking lookup.
1437 /// Searches each of the JITDylibs in the search order in turn for the given
1438 /// symbol.
1439 Expected<JITEvaluatedSymbol>
1440 lookup(const JITDylibSearchOrder &SearchOrder, SymbolStringPtr Symbol,
1441 SymbolState RequiredState = SymbolState::Ready);
1442
1443 /// Convenience version of blocking lookup.
1444 /// Searches each of the JITDylibs in the search order in turn for the given
1445 /// symbol. The search will not find non-exported symbols.
1446 Expected<JITEvaluatedSymbol>
1447 lookup(ArrayRef<JITDylib *> SearchOrder, SymbolStringPtr Symbol,
1448 SymbolState RequiredState = SymbolState::Ready);
1449
1450 /// Convenience version of blocking lookup.
1451 /// Searches each of the JITDylibs in the search order in turn for the given
1452 /// symbol. The search will not find non-exported symbols.
1453 Expected<JITEvaluatedSymbol>
1454 lookup(ArrayRef<JITDylib *> SearchOrder, StringRef Symbol,
1455 SymbolState RequiredState = SymbolState::Ready);
1456
1457 /// Materialize the given unit.
dispatchTask(std::unique_ptr<Task> T)1458 void dispatchTask(std::unique_ptr<Task> T) {
1459 assert(T && "T must be non-null");
1460 DEBUG_WITH_TYPE("orc", dumpDispatchInfo(*T));
1461 DispatchTask(std::move(T));
1462 }
1463
1464 /// Run a wrapper function in the executor.
1465 ///
1466 /// The wrapper function should be callable as:
1467 ///
1468 /// \code{.cpp}
1469 /// CWrapperFunctionResult fn(uint8_t *Data, uint64_t Size);
1470 /// \endcode{.cpp}
1471 ///
1472 /// The given OnComplete function will be called to return the result.
1473 template <typename... ArgTs>
callWrapperAsync(ArgTs &&...Args)1474 void callWrapperAsync(ArgTs &&... Args) {
1475 EPC->callWrapperAsync(std::forward<ArgTs>(Args)...);
1476 }
1477
1478 /// Run a wrapper function in the executor. The wrapper function should be
1479 /// callable as:
1480 ///
1481 /// \code{.cpp}
1482 /// CWrapperFunctionResult fn(uint8_t *Data, uint64_t Size);
1483 /// \endcode{.cpp}
callWrapper(ExecutorAddr WrapperFnAddr,ArrayRef<char> ArgBuffer)1484 shared::WrapperFunctionResult callWrapper(ExecutorAddr WrapperFnAddr,
1485 ArrayRef<char> ArgBuffer) {
1486 return EPC->callWrapper(WrapperFnAddr, ArgBuffer);
1487 }
1488
1489 /// Run a wrapper function using SPS to serialize the arguments and
1490 /// deserialize the results.
1491 template <typename SPSSignature, typename SendResultT, typename... ArgTs>
callSPSWrapperAsync(ExecutorAddr WrapperFnAddr,SendResultT && SendResult,const ArgTs &...Args)1492 void callSPSWrapperAsync(ExecutorAddr WrapperFnAddr, SendResultT &&SendResult,
1493 const ArgTs &...Args) {
1494 EPC->callSPSWrapperAsync<SPSSignature, SendResultT, ArgTs...>(
1495 WrapperFnAddr, std::forward<SendResultT>(SendResult), Args...);
1496 }
1497
1498 /// Run a wrapper function using SPS to serialize the arguments and
1499 /// deserialize the results.
1500 ///
1501 /// If SPSSignature is a non-void function signature then the second argument
1502 /// (the first in the Args list) should be a reference to a return value.
1503 template <typename SPSSignature, typename... WrapperCallArgTs>
callSPSWrapper(ExecutorAddr WrapperFnAddr,WrapperCallArgTs &&...WrapperCallArgs)1504 Error callSPSWrapper(ExecutorAddr WrapperFnAddr,
1505 WrapperCallArgTs &&...WrapperCallArgs) {
1506 return EPC->callSPSWrapper<SPSSignature, WrapperCallArgTs...>(
1507 WrapperFnAddr, std::forward<WrapperCallArgTs>(WrapperCallArgs)...);
1508 }
1509
1510 /// Wrap a handler that takes concrete argument types (and a sender for a
1511 /// concrete return type) to produce an AsyncHandlerWrapperFunction. Uses SPS
1512 /// to unpack the arguments and pack the result.
1513 ///
1514 /// This function is intended to support easy construction of
1515 /// AsyncHandlerWrapperFunctions that can be associated with a tag
1516 /// (using registerJITDispatchHandler) and called from the executor.
1517 template <typename SPSSignature, typename HandlerT>
wrapAsyncWithSPS(HandlerT && H)1518 static JITDispatchHandlerFunction wrapAsyncWithSPS(HandlerT &&H) {
1519 return [H = std::forward<HandlerT>(H)](
1520 SendResultFunction SendResult,
1521 const char *ArgData, size_t ArgSize) mutable {
1522 shared::WrapperFunction<SPSSignature>::handleAsync(ArgData, ArgSize, H,
1523 std::move(SendResult));
1524 };
1525 }
1526
1527 /// Wrap a class method that takes concrete argument types (and a sender for
1528 /// a concrete return type) to produce an AsyncHandlerWrapperFunction. Uses
1529 /// SPS to unpack teh arguments and pack the result.
1530 ///
1531 /// This function is intended to support easy construction of
1532 /// AsyncHandlerWrapperFunctions that can be associated with a tag
1533 /// (using registerJITDispatchHandler) and called from the executor.
1534 template <typename SPSSignature, typename ClassT, typename... MethodArgTs>
1535 static JITDispatchHandlerFunction
wrapAsyncWithSPS(ClassT * Instance,void (ClassT::* Method)(MethodArgTs...))1536 wrapAsyncWithSPS(ClassT *Instance, void (ClassT::*Method)(MethodArgTs...)) {
1537 return wrapAsyncWithSPS<SPSSignature>(
1538 [Instance, Method](MethodArgTs &&...MethodArgs) {
1539 (Instance->*Method)(std::forward<MethodArgTs>(MethodArgs)...);
1540 });
1541 }
1542
1543 /// For each tag symbol name, associate the corresponding
1544 /// AsyncHandlerWrapperFunction with the address of that symbol. The
1545 /// handler becomes callable from the executor using the ORC runtime
1546 /// __orc_rt_jit_dispatch function and the given tag.
1547 ///
1548 /// Tag symbols will be looked up in JD using LookupKind::Static,
1549 /// JITDylibLookupFlags::MatchAllSymbols (hidden tags will be found), and
1550 /// LookupFlags::WeaklyReferencedSymbol. Missing tag definitions will not
1551 /// cause an error, the handler will simply be dropped.
1552 Error registerJITDispatchHandlers(JITDylib &JD,
1553 JITDispatchHandlerAssociationMap WFs);
1554
1555 /// Run a registered jit-side wrapper function.
1556 /// This should be called by the ExecutorProcessControl instance in response
1557 /// to incoming jit-dispatch requests from the executor.
1558 void
1559 runJITDispatchHandler(SendResultFunction SendResult,
1560 JITTargetAddress HandlerFnTagAddr,
1561 ArrayRef<char> ArgBuffer);
1562
1563 /// Dump the state of all the JITDylibs in this session.
1564 void dump(raw_ostream &OS);
1565
1566 private:
logErrorsToStdErr(Error Err)1567 static void logErrorsToStdErr(Error Err) {
1568 logAllUnhandledErrors(std::move(Err), errs(), "JIT session error: ");
1569 }
1570
runOnCurrentThread(std::unique_ptr<Task> T)1571 static void runOnCurrentThread(std::unique_ptr<Task> T) { T->run(); }
1572
1573 void dispatchOutstandingMUs();
1574
1575 static std::unique_ptr<MaterializationResponsibility>
createMaterializationResponsibility(ResourceTracker & RT,SymbolFlagsMap Symbols,SymbolStringPtr InitSymbol)1576 createMaterializationResponsibility(ResourceTracker &RT,
1577 SymbolFlagsMap Symbols,
1578 SymbolStringPtr InitSymbol) {
1579 auto &JD = RT.getJITDylib();
1580 std::unique_ptr<MaterializationResponsibility> MR(
1581 new MaterializationResponsibility(&JD, std::move(Symbols),
1582 std::move(InitSymbol)));
1583 JD.MRTrackers[MR.get()] = &RT;
1584 return MR;
1585 }
1586
1587 Error removeResourceTracker(ResourceTracker &RT);
1588 void transferResourceTracker(ResourceTracker &DstRT, ResourceTracker &SrcRT);
1589 void destroyResourceTracker(ResourceTracker &RT);
1590
1591 // State machine functions for query application..
1592
1593 /// IL_updateCandidatesFor is called to remove already-defined symbols that
1594 /// match a given query from the set of candidate symbols to generate
1595 /// definitions for (no need to generate a definition if one already exists).
1596 Error IL_updateCandidatesFor(JITDylib &JD, JITDylibLookupFlags JDLookupFlags,
1597 SymbolLookupSet &Candidates,
1598 SymbolLookupSet *NonCandidates);
1599
1600 /// OL_applyQueryPhase1 is an optionally re-startable loop for triggering
1601 /// definition generation. It is called when a lookup is performed, and again
1602 /// each time that LookupState::continueLookup is called.
1603 void OL_applyQueryPhase1(std::unique_ptr<InProgressLookupState> IPLS,
1604 Error Err);
1605
1606 /// OL_completeLookup is run once phase 1 successfully completes for a lookup
1607 /// call. It attempts to attach the symbol to all symbol table entries and
1608 /// collect all MaterializationUnits to dispatch. If this method fails then
1609 /// all MaterializationUnits will be left un-materialized.
1610 void OL_completeLookup(std::unique_ptr<InProgressLookupState> IPLS,
1611 std::shared_ptr<AsynchronousSymbolQuery> Q,
1612 RegisterDependenciesFunction RegisterDependencies);
1613
1614 /// OL_completeLookupFlags is run once phase 1 successfully completes for a
1615 /// lookupFlags call.
1616 void OL_completeLookupFlags(
1617 std::unique_ptr<InProgressLookupState> IPLS,
1618 unique_function<void(Expected<SymbolFlagsMap>)> OnComplete);
1619
1620 // State machine functions for MaterializationResponsibility.
1621 void OL_destroyMaterializationResponsibility(
1622 MaterializationResponsibility &MR);
1623 SymbolNameSet OL_getRequestedSymbols(const MaterializationResponsibility &MR);
1624 Error OL_notifyResolved(MaterializationResponsibility &MR,
1625 const SymbolMap &Symbols);
1626 Error OL_notifyEmitted(MaterializationResponsibility &MR);
1627 Error OL_defineMaterializing(MaterializationResponsibility &MR,
1628 SymbolFlagsMap SymbolFlags);
1629 void OL_notifyFailed(MaterializationResponsibility &MR);
1630 Error OL_replace(MaterializationResponsibility &MR,
1631 std::unique_ptr<MaterializationUnit> MU);
1632 Expected<std::unique_ptr<MaterializationResponsibility>>
1633 OL_delegate(MaterializationResponsibility &MR, const SymbolNameSet &Symbols);
1634 void OL_addDependencies(MaterializationResponsibility &MR,
1635 const SymbolStringPtr &Name,
1636 const SymbolDependenceMap &Dependencies);
1637 void OL_addDependenciesForAll(MaterializationResponsibility &MR,
1638 const SymbolDependenceMap &Dependencies);
1639
1640 #ifndef NDEBUG
1641 void dumpDispatchInfo(Task &T);
1642 #endif // NDEBUG
1643
1644 mutable std::recursive_mutex SessionMutex;
1645 bool SessionOpen = true;
1646 std::unique_ptr<ExecutorProcessControl> EPC;
1647 std::unique_ptr<Platform> P;
1648 ErrorReporter ReportError = logErrorsToStdErr;
1649 DispatchTaskFunction DispatchTask = runOnCurrentThread;
1650
1651 std::vector<ResourceManager *> ResourceManagers;
1652
1653 std::vector<JITDylibSP> JDs;
1654
1655 // FIXME: Remove this (and runOutstandingMUs) once the linking layer works
1656 // with callbacks from asynchronous queries.
1657 mutable std::recursive_mutex OutstandingMUsMutex;
1658 std::vector<std::pair<std::unique_ptr<MaterializationUnit>,
1659 std::unique_ptr<MaterializationResponsibility>>>
1660 OutstandingMUs;
1661
1662 mutable std::mutex JITDispatchHandlersMutex;
1663 DenseMap<JITTargetAddress, std::shared_ptr<JITDispatchHandlerFunction>>
1664 JITDispatchHandlers;
1665 };
1666
getExecutionSession()1667 inline ExecutionSession &MaterializationResponsibility::getExecutionSession() {
1668 return JD->getExecutionSession();
1669 }
1670
1671 template <typename Func>
withResourceKeyDo(Func && F)1672 Error MaterializationResponsibility::withResourceKeyDo(Func &&F) const {
1673 return JD->getExecutionSession().runSessionLocked([&]() -> Error {
1674 auto I = JD->MRTrackers.find(this);
1675 assert(I != JD->MRTrackers.end() && "No tracker for this MR");
1676 if (I->second->isDefunct())
1677 return make_error<ResourceTrackerDefunct>(I->second);
1678 F(I->second->getKeyUnsafe());
1679 return Error::success();
1680 });
1681 }
1682
1683 template <typename GeneratorT>
addGenerator(std::unique_ptr<GeneratorT> DefGenerator)1684 GeneratorT &JITDylib::addGenerator(std::unique_ptr<GeneratorT> DefGenerator) {
1685 auto &G = *DefGenerator;
1686 std::lock_guard<std::mutex> Lock(GeneratorsMutex);
1687 DefGenerators.push_back(std::move(DefGenerator));
1688 return G;
1689 }
1690
1691 template <typename Func>
1692 auto JITDylib::withLinkOrderDo(Func &&F)
1693 -> decltype(F(std::declval<const JITDylibSearchOrder &>())) {
1694 return ES.runSessionLocked([&]() { return F(LinkOrder); });
1695 }
1696
1697 template <typename MaterializationUnitType>
define(std::unique_ptr<MaterializationUnitType> && MU,ResourceTrackerSP RT)1698 Error JITDylib::define(std::unique_ptr<MaterializationUnitType> &&MU,
1699 ResourceTrackerSP RT) {
1700 assert(MU && "Can not define with a null MU");
1701
1702 if (MU->getSymbols().empty()) {
1703 // Empty MUs are allowable but pathological, so issue a warning.
1704 DEBUG_WITH_TYPE("orc", {
1705 dbgs() << "Warning: Discarding empty MU " << MU->getName() << " for "
1706 << getName() << "\n";
1707 });
1708 return Error::success();
1709 } else
1710 DEBUG_WITH_TYPE("orc", {
1711 dbgs() << "Defining MU " << MU->getName() << " for " << getName()
1712 << " (tracker: ";
1713 if (RT == getDefaultResourceTracker())
1714 dbgs() << "default)";
1715 else if (RT)
1716 dbgs() << RT.get() << ")\n";
1717 else
1718 dbgs() << "0x0, default will be used)\n";
1719 });
1720
1721 return ES.runSessionLocked([&, this]() -> Error {
1722 if (auto Err = defineImpl(*MU))
1723 return Err;
1724
1725 if (!RT)
1726 RT = getDefaultResourceTracker();
1727
1728 if (auto *P = ES.getPlatform()) {
1729 if (auto Err = P->notifyAdding(*RT, *MU))
1730 return Err;
1731 }
1732
1733 installMaterializationUnit(std::move(MU), *RT);
1734 return Error::success();
1735 });
1736 }
1737
1738 template <typename MaterializationUnitType>
define(std::unique_ptr<MaterializationUnitType> & MU,ResourceTrackerSP RT)1739 Error JITDylib::define(std::unique_ptr<MaterializationUnitType> &MU,
1740 ResourceTrackerSP RT) {
1741 assert(MU && "Can not define with a null MU");
1742
1743 if (MU->getSymbols().empty()) {
1744 // Empty MUs are allowable but pathological, so issue a warning.
1745 DEBUG_WITH_TYPE("orc", {
1746 dbgs() << "Warning: Discarding empty MU " << MU->getName() << getName()
1747 << "\n";
1748 });
1749 return Error::success();
1750 } else
1751 DEBUG_WITH_TYPE("orc", {
1752 dbgs() << "Defining MU " << MU->getName() << " for " << getName()
1753 << " (tracker: ";
1754 if (RT == getDefaultResourceTracker())
1755 dbgs() << "default)";
1756 else if (RT)
1757 dbgs() << RT.get() << ")\n";
1758 else
1759 dbgs() << "0x0, default will be used)\n";
1760 });
1761
1762 return ES.runSessionLocked([&, this]() -> Error {
1763 if (auto Err = defineImpl(*MU))
1764 return Err;
1765
1766 if (!RT)
1767 RT = getDefaultResourceTracker();
1768
1769 if (auto *P = ES.getPlatform()) {
1770 if (auto Err = P->notifyAdding(*RT, *MU))
1771 return Err;
1772 }
1773
1774 installMaterializationUnit(std::move(MU), *RT);
1775 return Error::success();
1776 });
1777 }
1778
1779 /// ReexportsGenerator can be used with JITDylib::addGenerator to automatically
1780 /// re-export a subset of the source JITDylib's symbols in the target.
1781 class ReexportsGenerator : public DefinitionGenerator {
1782 public:
1783 using SymbolPredicate = std::function<bool(SymbolStringPtr)>;
1784
1785 /// Create a reexports generator. If an Allow predicate is passed, only
1786 /// symbols for which the predicate returns true will be reexported. If no
1787 /// Allow predicate is passed, all symbols will be exported.
1788 ReexportsGenerator(JITDylib &SourceJD,
1789 JITDylibLookupFlags SourceJDLookupFlags,
1790 SymbolPredicate Allow = SymbolPredicate());
1791
1792 Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD,
1793 JITDylibLookupFlags JDLookupFlags,
1794 const SymbolLookupSet &LookupSet) override;
1795
1796 private:
1797 JITDylib &SourceJD;
1798 JITDylibLookupFlags SourceJDLookupFlags;
1799 SymbolPredicate Allow;
1800 };
1801
1802 // --------------- IMPLEMENTATION --------------
1803 // Implementations for inline functions/methods.
1804 // ---------------------------------------------
1805
~MaterializationResponsibility()1806 inline MaterializationResponsibility::~MaterializationResponsibility() {
1807 JD->getExecutionSession().OL_destroyMaterializationResponsibility(*this);
1808 }
1809
getRequestedSymbols()1810 inline SymbolNameSet MaterializationResponsibility::getRequestedSymbols() const {
1811 return JD->getExecutionSession().OL_getRequestedSymbols(*this);
1812 }
1813
notifyResolved(const SymbolMap & Symbols)1814 inline Error MaterializationResponsibility::notifyResolved(
1815 const SymbolMap &Symbols) {
1816 return JD->getExecutionSession().OL_notifyResolved(*this, Symbols);
1817 }
1818
notifyEmitted()1819 inline Error MaterializationResponsibility::notifyEmitted() {
1820 return JD->getExecutionSession().OL_notifyEmitted(*this);
1821 }
1822
defineMaterializing(SymbolFlagsMap SymbolFlags)1823 inline Error MaterializationResponsibility::defineMaterializing(
1824 SymbolFlagsMap SymbolFlags) {
1825 return JD->getExecutionSession().OL_defineMaterializing(
1826 *this, std::move(SymbolFlags));
1827 }
1828
failMaterialization()1829 inline void MaterializationResponsibility::failMaterialization() {
1830 JD->getExecutionSession().OL_notifyFailed(*this);
1831 }
1832
replace(std::unique_ptr<MaterializationUnit> MU)1833 inline Error MaterializationResponsibility::replace(
1834 std::unique_ptr<MaterializationUnit> MU) {
1835 return JD->getExecutionSession().OL_replace(*this, std::move(MU));
1836 }
1837
1838 inline Expected<std::unique_ptr<MaterializationResponsibility>>
delegate(const SymbolNameSet & Symbols)1839 MaterializationResponsibility::delegate(const SymbolNameSet &Symbols) {
1840 return JD->getExecutionSession().OL_delegate(*this, Symbols);
1841 }
1842
addDependencies(const SymbolStringPtr & Name,const SymbolDependenceMap & Dependencies)1843 inline void MaterializationResponsibility::addDependencies(
1844 const SymbolStringPtr &Name, const SymbolDependenceMap &Dependencies) {
1845 JD->getExecutionSession().OL_addDependencies(*this, Name, Dependencies);
1846 }
1847
addDependenciesForAll(const SymbolDependenceMap & Dependencies)1848 inline void MaterializationResponsibility::addDependenciesForAll(
1849 const SymbolDependenceMap &Dependencies) {
1850 JD->getExecutionSession().OL_addDependenciesForAll(*this, Dependencies);
1851 }
1852
1853 } // End namespace orc
1854 } // End namespace llvm
1855
1856 #endif // LLVM_EXECUTIONENGINE_ORC_CORE_H
1857