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