• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/FunctionExtras.h"
18 #include "llvm/ExecutionEngine/JITSymbol.h"
19 #include "llvm/ExecutionEngine/Orc/SymbolStringPool.h"
20 #include "llvm/ExecutionEngine/OrcV1Deprecation.h"
21 #include "llvm/IR/Module.h"
22 #include "llvm/Support/Debug.h"
23 
24 #include <memory>
25 #include <vector>
26 
27 #define DEBUG_TYPE "orc"
28 
29 namespace llvm {
30 namespace orc {
31 
32 // Forward declare some classes.
33 class AsynchronousSymbolQuery;
34 class ExecutionSession;
35 class MaterializationUnit;
36 class MaterializationResponsibility;
37 class JITDylib;
38 enum class SymbolState : uint8_t;
39 
40 /// VModuleKey provides a unique identifier (allocated and managed by
41 /// ExecutionSessions) for a module added to the JIT.
42 using VModuleKey = uint64_t;
43 
44 /// A set of symbol names (represented by SymbolStringPtrs for
45 //         efficiency).
46 using SymbolNameSet = DenseSet<SymbolStringPtr>;
47 
48 /// A vector of symbol names.
49 using SymbolNameVector = std::vector<SymbolStringPtr>;
50 
51 /// A map from symbol names (as SymbolStringPtrs) to JITSymbols
52 /// (address/flags pairs).
53 using SymbolMap = DenseMap<SymbolStringPtr, JITEvaluatedSymbol>;
54 
55 /// A map from symbol names (as SymbolStringPtrs) to JITSymbolFlags.
56 using SymbolFlagsMap = DenseMap<SymbolStringPtr, JITSymbolFlags>;
57 
58 /// A map from JITDylibs to sets of symbols.
59 using SymbolDependenceMap = DenseMap<JITDylib *, SymbolNameSet>;
60 
61 /// Lookup flags that apply to each dylib in the search order for a lookup.
62 ///
63 /// If MatchHiddenSymbolsOnly is used (the default) for a given dylib, then
64 /// only symbols in that Dylib's interface will be searched. If
65 /// MatchHiddenSymbols is used then symbols with hidden visibility will match
66 /// as well.
67 enum class JITDylibLookupFlags { MatchExportedSymbolsOnly, MatchAllSymbols };
68 
69 /// Lookup flags that apply to each symbol in a lookup.
70 ///
71 /// If RequiredSymbol is used (the default) for a given symbol then that symbol
72 /// must be found during the lookup or the lookup will fail returning a
73 /// SymbolNotFound error. If WeaklyReferencedSymbol is used and the given
74 /// symbol is not found then the query will continue, and no result for the
75 /// missing symbol will be present in the result (assuming the rest of the
76 /// lookup succeeds).
77 enum class SymbolLookupFlags { RequiredSymbol, WeaklyReferencedSymbol };
78 
79 /// Describes the kind of lookup being performed. The lookup kind is passed to
80 /// symbol generators (if they're invoked) to help them determine what
81 /// definitions to generate.
82 ///
83 /// Static -- Lookup is being performed as-if at static link time (e.g.
84 ///           generators representing static archives should pull in new
85 ///           definitions).
86 ///
87 /// DLSym -- Lookup is being performed as-if at runtime (e.g. generators
88 ///          representing static archives should not pull in new definitions).
89 enum class LookupKind { Static, DLSym };
90 
91 /// A list of (JITDylib*, JITDylibLookupFlags) pairs to be used as a search
92 /// order during symbol lookup.
93 using JITDylibSearchOrder =
94     std::vector<std::pair<JITDylib *, JITDylibLookupFlags>>;
95 
96 /// Convenience function for creating a search order from an ArrayRef of
97 /// JITDylib*, all with the same flags.
98 inline JITDylibSearchOrder makeJITDylibSearchOrder(
99     ArrayRef<JITDylib *> JDs,
100     JITDylibLookupFlags Flags = JITDylibLookupFlags::MatchExportedSymbolsOnly) {
101   JITDylibSearchOrder O;
102   O.reserve(JDs.size());
103   for (auto *JD : JDs)
104     O.push_back(std::make_pair(JD, Flags));
105   return O;
106 }
107 
108 /// A set of symbols to look up, each associated with a SymbolLookupFlags
109 /// value.
110 ///
111 /// This class is backed by a vector and optimized for fast insertion,
112 /// deletion and iteration. It does not guarantee a stable order between
113 /// operations, and will not automatically detect duplicate elements (they
114 /// can be manually checked by calling the validate method).
115 class SymbolLookupSet {
116 public:
117   using value_type = std::pair<SymbolStringPtr, SymbolLookupFlags>;
118   using UnderlyingVector = std::vector<value_type>;
119   using iterator = UnderlyingVector::iterator;
120   using const_iterator = UnderlyingVector::const_iterator;
121 
122   SymbolLookupSet() = default;
123 
124   explicit SymbolLookupSet(
125       SymbolStringPtr Name,
126       SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) {
127     add(std::move(Name), Flags);
128   }
129 
130   /// Construct a SymbolLookupSet from an initializer list of SymbolStringPtrs.
131   explicit SymbolLookupSet(
132       std::initializer_list<SymbolStringPtr> Names,
133       SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) {
134     Symbols.reserve(Names.size());
135     for (auto &Name : Names)
136       add(std::move(Name), Flags);
137   }
138 
139   /// Construct a SymbolLookupSet from a SymbolNameSet with the given
140   /// Flags used for each value.
141   explicit SymbolLookupSet(
142       const SymbolNameSet &Names,
143       SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) {
144     Symbols.reserve(Names.size());
145     for (const auto &Name : Names)
146       add(Name, Flags);
147   }
148 
149   /// Construct a SymbolLookupSet from a vector of symbols with the given Flags
150   /// used for each value.
151   /// If the ArrayRef contains duplicates it is up to the client to remove these
152   /// before using this instance for lookup.
153   explicit SymbolLookupSet(
154       ArrayRef<SymbolStringPtr> Names,
155       SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) {
156     Symbols.reserve(Names.size());
157     for (const auto &Name : Names)
158       add(Name, Flags);
159   }
160 
161   /// Add an element to the set. The client is responsible for checking that
162   /// duplicates are not added.
163   void add(SymbolStringPtr Name,
164            SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) {
165     Symbols.push_back(std::make_pair(std::move(Name), Flags));
166   }
167 
empty()168   bool empty() const { return Symbols.empty(); }
size()169   UnderlyingVector::size_type size() const { return Symbols.size(); }
begin()170   iterator begin() { return Symbols.begin(); }
end()171   iterator end() { return Symbols.end(); }
begin()172   const_iterator begin() const { return Symbols.begin(); }
end()173   const_iterator end() const { return Symbols.end(); }
174 
175   /// Removes the Ith element of the vector, replacing it with the last element.
remove(UnderlyingVector::size_type I)176   void remove(UnderlyingVector::size_type I) {
177     std::swap(Symbols[I], Symbols.back());
178     Symbols.pop_back();
179   }
180 
181   /// Removes the element pointed to by the given iterator. This iterator and
182   /// all subsequent ones (including end()) are invalidated.
remove(iterator I)183   void remove(iterator I) { remove(I - begin()); }
184 
185   /// Removes all elements matching the given predicate, which must be callable
186   /// as bool(const SymbolStringPtr &, SymbolLookupFlags Flags).
remove_if(PredFn && Pred)187   template <typename PredFn> void remove_if(PredFn &&Pred) {
188     UnderlyingVector::size_type I = 0;
189     while (I != Symbols.size()) {
190       const auto &Name = Symbols[I].first;
191       auto Flags = Symbols[I].second;
192       if (Pred(Name, Flags))
193         remove(I);
194       else
195         ++I;
196     }
197   }
198 
199   /// Loop over the elements of this SymbolLookupSet, applying the Body function
200   /// to each one. Body must be callable as
201   /// bool(const SymbolStringPtr &, SymbolLookupFlags).
202   /// If Body returns true then the element just passed in is removed from the
203   /// set. If Body returns false then the element is retained.
204   template <typename BodyFn>
205   auto forEachWithRemoval(BodyFn &&Body) -> typename std::enable_if<
206       std::is_same<decltype(Body(std::declval<const SymbolStringPtr &>(),
207                                  std::declval<SymbolLookupFlags>())),
208                    bool>::value>::type {
209     UnderlyingVector::size_type I = 0;
210     while (I != Symbols.size()) {
211       const auto &Name = Symbols[I].first;
212       auto Flags = Symbols[I].second;
213       if (Body(Name, Flags))
214         remove(I);
215       else
216         ++I;
217     }
218   }
219 
220   /// Loop over the elements of this SymbolLookupSet, applying the Body function
221   /// to each one. Body must be callable as
222   /// Expected<bool>(const SymbolStringPtr &, SymbolLookupFlags).
223   /// If Body returns a failure value, the loop exits immediately. If Body
224   /// returns true then the element just passed in is removed from the set. If
225   /// Body returns false then the element is retained.
226   template <typename BodyFn>
227   auto forEachWithRemoval(BodyFn &&Body) -> typename std::enable_if<
228       std::is_same<decltype(Body(std::declval<const SymbolStringPtr &>(),
229                                  std::declval<SymbolLookupFlags>())),
230                    Expected<bool>>::value,
231       Error>::type {
232     UnderlyingVector::size_type I = 0;
233     while (I != Symbols.size()) {
234       const auto &Name = Symbols[I].first;
235       auto Flags = Symbols[I].second;
236       auto Remove = Body(Name, Flags);
237       if (!Remove)
238         return Remove.takeError();
239       if (*Remove)
240         remove(I);
241       else
242         ++I;
243     }
244     return Error::success();
245   }
246 
247   /// Construct a SymbolNameVector from this instance by dropping the Flags
248   /// values.
getSymbolNames()249   SymbolNameVector getSymbolNames() const {
250     SymbolNameVector Names;
251     Names.reserve(Symbols.size());
252     for (auto &KV : Symbols)
253       Names.push_back(KV.first);
254     return Names;
255   }
256 
257   /// Sort the lookup set by pointer value. This sort is fast but sensitive to
258   /// allocation order and so should not be used where a consistent order is
259   /// required.
sortByAddress()260   void sortByAddress() {
261     llvm::sort(Symbols, [](const value_type &LHS, const value_type &RHS) {
262       return LHS.first < RHS.first;
263     });
264   }
265 
266   /// Sort the lookup set lexicographically. This sort is slow but the order
267   /// is unaffected by allocation order.
sortByName()268   void sortByName() {
269     llvm::sort(Symbols, [](const value_type &LHS, const value_type &RHS) {
270       return *LHS.first < *RHS.first;
271     });
272   }
273 
274   /// Remove any duplicate elements. If a SymbolLookupSet is not duplicate-free
275   /// by construction, this method can be used to turn it into a proper set.
removeDuplicates()276   void removeDuplicates() {
277     sortByAddress();
278     auto LastI = std::unique(Symbols.begin(), Symbols.end());
279     Symbols.erase(LastI, Symbols.end());
280   }
281 
282 #ifndef NDEBUG
283   /// Returns true if this set contains any duplicates. This should only be used
284   /// in assertions.
containsDuplicates()285   bool containsDuplicates() {
286     if (Symbols.size() < 2)
287       return false;
288     sortByAddress();
289     for (UnderlyingVector::size_type I = 1; I != Symbols.size(); ++I)
290       if (Symbols[I].first == Symbols[I - 1].first)
291         return true;
292     return true;
293   }
294 #endif
295 
296 private:
297   UnderlyingVector Symbols;
298 };
299 
300 struct SymbolAliasMapEntry {
301   SymbolAliasMapEntry() = default;
SymbolAliasMapEntrySymbolAliasMapEntry302   SymbolAliasMapEntry(SymbolStringPtr Aliasee, JITSymbolFlags AliasFlags)
303       : Aliasee(std::move(Aliasee)), AliasFlags(AliasFlags) {}
304 
305   SymbolStringPtr Aliasee;
306   JITSymbolFlags AliasFlags;
307 };
308 
309 /// A map of Symbols to (Symbol, Flags) pairs.
310 using SymbolAliasMap = DenseMap<SymbolStringPtr, SymbolAliasMapEntry>;
311 
312 /// Render a SymbolStringPtr.
313 raw_ostream &operator<<(raw_ostream &OS, const SymbolStringPtr &Sym);
314 
315 /// Render a SymbolNameSet.
316 raw_ostream &operator<<(raw_ostream &OS, const SymbolNameSet &Symbols);
317 
318 /// Render a SymbolNameVector.
319 raw_ostream &operator<<(raw_ostream &OS, const SymbolNameVector &Symbols);
320 
321 /// Render a SymbolFlagsMap entry.
322 raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap::value_type &KV);
323 
324 /// Render a SymbolMap entry.
325 raw_ostream &operator<<(raw_ostream &OS, const SymbolMap::value_type &KV);
326 
327 /// Render a SymbolFlagsMap.
328 raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap &SymbolFlags);
329 
330 /// Render a SymbolMap.
331 raw_ostream &operator<<(raw_ostream &OS, const SymbolMap &Symbols);
332 
333 /// Render a SymbolDependenceMap entry.
334 raw_ostream &operator<<(raw_ostream &OS,
335                         const SymbolDependenceMap::value_type &KV);
336 
337 /// Render a SymbolDependendeMap.
338 raw_ostream &operator<<(raw_ostream &OS, const SymbolDependenceMap &Deps);
339 
340 /// Render a MaterializationUnit.
341 raw_ostream &operator<<(raw_ostream &OS, const MaterializationUnit &MU);
342 
343 //// Render a JITDylibLookupFlags instance.
344 raw_ostream &operator<<(raw_ostream &OS,
345                         const JITDylibLookupFlags &JDLookupFlags);
346 
347 /// Rendar a SymbolLookupFlags instance.
348 raw_ostream &operator<<(raw_ostream &OS, const SymbolLookupFlags &LookupFlags);
349 
350 /// Render a JITDylibLookupFlags instance.
351 raw_ostream &operator<<(raw_ostream &OS, const LookupKind &K);
352 
353 /// Render a SymbolLookupSet entry.
354 raw_ostream &operator<<(raw_ostream &OS, const SymbolLookupSet::value_type &KV);
355 
356 /// Render a SymbolLookupSet.
357 raw_ostream &operator<<(raw_ostream &OS, const SymbolLookupSet &LookupSet);
358 
359 /// Render a JITDylibSearchOrder.
360 raw_ostream &operator<<(raw_ostream &OS,
361                         const JITDylibSearchOrder &SearchOrder);
362 
363 /// Render a SymbolAliasMap.
364 raw_ostream &operator<<(raw_ostream &OS, const SymbolAliasMap &Aliases);
365 
366 /// Render a SymbolState.
367 raw_ostream &operator<<(raw_ostream &OS, const SymbolState &S);
368 
369 /// Render a LookupKind.
370 raw_ostream &operator<<(raw_ostream &OS, const LookupKind &K);
371 
372 /// Callback to notify client that symbols have been resolved.
373 using SymbolsResolvedCallback = unique_function<void(Expected<SymbolMap>)>;
374 
375 /// Callback to register the dependencies for a given query.
376 using RegisterDependenciesFunction =
377     std::function<void(const SymbolDependenceMap &)>;
378 
379 /// This can be used as the value for a RegisterDependenciesFunction if there
380 /// are no dependants to register with.
381 extern RegisterDependenciesFunction NoDependenciesToRegister;
382 
383 /// Used to notify a JITDylib that the given set of symbols failed to
384 /// materialize.
385 class FailedToMaterialize : public ErrorInfo<FailedToMaterialize> {
386 public:
387   static char ID;
388 
389   FailedToMaterialize(std::shared_ptr<SymbolDependenceMap> Symbols);
390   std::error_code convertToErrorCode() const override;
391   void log(raw_ostream &OS) const override;
getSymbols()392   const SymbolDependenceMap &getSymbols() const { return *Symbols; }
393 
394 private:
395   std::shared_ptr<SymbolDependenceMap> Symbols;
396 };
397 
398 /// Used to notify clients when symbols can not be found during a lookup.
399 class SymbolsNotFound : public ErrorInfo<SymbolsNotFound> {
400 public:
401   static char ID;
402 
403   SymbolsNotFound(SymbolNameSet Symbols);
404   SymbolsNotFound(SymbolNameVector Symbols);
405   std::error_code convertToErrorCode() const override;
406   void log(raw_ostream &OS) const override;
getSymbols()407   const SymbolNameVector &getSymbols() const { return Symbols; }
408 
409 private:
410   SymbolNameVector Symbols;
411 };
412 
413 /// Used to notify clients that a set of symbols could not be removed.
414 class SymbolsCouldNotBeRemoved : public ErrorInfo<SymbolsCouldNotBeRemoved> {
415 public:
416   static char ID;
417 
418   SymbolsCouldNotBeRemoved(SymbolNameSet Symbols);
419   std::error_code convertToErrorCode() const override;
420   void log(raw_ostream &OS) const override;
getSymbols()421   const SymbolNameSet &getSymbols() const { return Symbols; }
422 
423 private:
424   SymbolNameSet Symbols;
425 };
426 
427 /// Tracks responsibility for materialization, and mediates interactions between
428 /// MaterializationUnits and JDs.
429 ///
430 /// An instance of this class is passed to MaterializationUnits when their
431 /// materialize method is called. It allows MaterializationUnits to resolve and
432 /// emit symbols, or abandon materialization by notifying any unmaterialized
433 /// symbols of an error.
434 class MaterializationResponsibility {
435   friend class MaterializationUnit;
436 public:
437   MaterializationResponsibility(MaterializationResponsibility &&) = default;
438   MaterializationResponsibility &
439   operator=(MaterializationResponsibility &&) = delete;
440 
441   /// Destruct a MaterializationResponsibility instance. In debug mode
442   ///        this asserts that all symbols being tracked have been either
443   ///        emitted or notified of an error.
444   ~MaterializationResponsibility();
445 
446   /// Returns the target JITDylib that these symbols are being materialized
447   ///        into.
getTargetJITDylib()448   JITDylib &getTargetJITDylib() const { return JD; }
449 
450   /// Returns the VModuleKey for this instance.
getVModuleKey()451   VModuleKey getVModuleKey() const { return K; }
452 
453   /// Returns the symbol flags map for this responsibility instance.
454   /// Note: The returned flags may have transient flags (Lazy, Materializing)
455   /// set. These should be stripped with JITSymbolFlags::stripTransientFlags
456   /// before using.
getSymbols()457   const SymbolFlagsMap &getSymbols() const { return SymbolFlags; }
458 
459   /// Returns the names of any symbols covered by this
460   /// MaterializationResponsibility object that have queries pending. This
461   /// information can be used to return responsibility for unrequested symbols
462   /// back to the JITDylib via the delegate method.
463   SymbolNameSet getRequestedSymbols() const;
464 
465   /// Notifies the target JITDylib that the given symbols have been resolved.
466   /// This will update the given symbols' addresses in the JITDylib, and notify
467   /// any pending queries on the given symbols of their resolution. The given
468   /// symbols must be ones covered by this MaterializationResponsibility
469   /// instance. Individual calls to this method may resolve a subset of the
470   /// symbols, but all symbols must have been resolved prior to calling emit.
471   ///
472   /// This method will return an error if any symbols being resolved have been
473   /// moved to the error state due to the failure of a dependency. If this
474   /// method returns an error then clients should log it and call
475   /// failMaterialize. If no dependencies have been registered for the
476   /// symbols covered by this MaterializationResponsibiility then this method
477   /// is guaranteed to return Error::success() and can be wrapped with cantFail.
478   Error notifyResolved(const SymbolMap &Symbols);
479 
480   /// Notifies the target JITDylib (and any pending queries on that JITDylib)
481   /// that all symbols covered by this MaterializationResponsibility instance
482   /// have been emitted.
483   ///
484   /// This method will return an error if any symbols being resolved have been
485   /// moved to the error state due to the failure of a dependency. If this
486   /// method returns an error then clients should log it and call
487   /// failMaterialize. If no dependencies have been registered for the
488   /// symbols covered by this MaterializationResponsibiility then this method
489   /// is guaranteed to return Error::success() and can be wrapped with cantFail.
490   Error notifyEmitted();
491 
492   /// Attempt to claim responsibility for new definitions. This method can be
493   /// used to claim responsibility for symbols that are added to a
494   /// materialization unit during the compilation process (e.g. literal pool
495   /// symbols). Symbol linkage rules are the same as for symbols that are
496   /// defined up front: duplicate strong definitions will result in errors.
497   /// Duplicate weak definitions will be discarded (in which case they will
498   /// not be added to this responsibility instance).
499   ///
500   ///   This method can be used by materialization units that want to add
501   /// additional symbols at materialization time (e.g. stubs, compile
502   /// callbacks, metadata).
503   Error defineMaterializing(SymbolFlagsMap SymbolFlags);
504 
505   /// Notify all not-yet-emitted covered by this MaterializationResponsibility
506   /// instance that an error has occurred.
507   /// This will remove all symbols covered by this MaterializationResponsibilty
508   /// from the target JITDylib, and send an error to any queries waiting on
509   /// these symbols.
510   void failMaterialization();
511 
512   /// Transfers responsibility to the given MaterializationUnit for all
513   /// symbols defined by that MaterializationUnit. This allows
514   /// materializers to break up work based on run-time information (e.g.
515   /// by introspecting which symbols have actually been looked up and
516   /// materializing only those).
517   void replace(std::unique_ptr<MaterializationUnit> MU);
518 
519   /// Delegates responsibility for the given symbols to the returned
520   /// materialization responsibility. Useful for breaking up work between
521   /// threads, or different kinds of materialization processes.
522   MaterializationResponsibility delegate(const SymbolNameSet &Symbols,
523                                          VModuleKey NewKey = VModuleKey());
524 
525   void addDependencies(const SymbolStringPtr &Name,
526                        const SymbolDependenceMap &Dependencies);
527 
528   /// Add dependencies that apply to all symbols covered by this instance.
529   void addDependenciesForAll(const SymbolDependenceMap &Dependencies);
530 
531 private:
532   /// Create a MaterializationResponsibility for the given JITDylib and
533   ///        initial symbols.
534   MaterializationResponsibility(JITDylib &JD, SymbolFlagsMap SymbolFlags,
535                                 VModuleKey K);
536 
537   JITDylib &JD;
538   SymbolFlagsMap SymbolFlags;
539   VModuleKey K;
540 };
541 
542 /// A MaterializationUnit represents a set of symbol definitions that can
543 ///        be materialized as a group, or individually discarded (when
544 ///        overriding definitions are encountered).
545 ///
546 /// MaterializationUnits are used when providing lazy definitions of symbols to
547 /// JITDylibs. The JITDylib will call materialize when the address of a symbol
548 /// is requested via the lookup method. The JITDylib will call discard if a
549 /// stronger definition is added or already present.
550 class MaterializationUnit {
551 public:
MaterializationUnit(SymbolFlagsMap InitalSymbolFlags,VModuleKey K)552   MaterializationUnit(SymbolFlagsMap InitalSymbolFlags, VModuleKey K)
553       : SymbolFlags(std::move(InitalSymbolFlags)), K(std::move(K)) {}
554 
~MaterializationUnit()555   virtual ~MaterializationUnit() {}
556 
557   /// Return the name of this materialization unit. Useful for debugging
558   /// output.
559   virtual StringRef getName() const = 0;
560 
561   /// Return the set of symbols that this source provides.
getSymbols()562   const SymbolFlagsMap &getSymbols() const { return SymbolFlags; }
563 
564   /// Called by materialization dispatchers (see
565   /// ExecutionSession::DispatchMaterializationFunction) to trigger
566   /// materialization of this MaterializationUnit.
doMaterialize(JITDylib & JD)567   void doMaterialize(JITDylib &JD) {
568     materialize(MaterializationResponsibility(JD, std::move(SymbolFlags),
569                                               std::move(K)));
570   }
571 
572   /// Called by JITDylibs to notify MaterializationUnits that the given symbol
573   /// has been overridden.
doDiscard(const JITDylib & JD,const SymbolStringPtr & Name)574   void doDiscard(const JITDylib &JD, const SymbolStringPtr &Name) {
575     SymbolFlags.erase(Name);
576     discard(JD, std::move(Name));
577   }
578 
579 protected:
580   SymbolFlagsMap SymbolFlags;
581   VModuleKey K;
582 
583 private:
584   virtual void anchor();
585 
586   /// Implementations of this method should materialize all symbols
587   ///        in the materialzation unit, except for those that have been
588   ///        previously discarded.
589   virtual void materialize(MaterializationResponsibility R) = 0;
590 
591   /// Implementations of this method should discard the given symbol
592   ///        from the source (e.g. if the source is an LLVM IR Module and the
593   ///        symbol is a function, delete the function body or mark it available
594   ///        externally).
595   virtual void discard(const JITDylib &JD, const SymbolStringPtr &Name) = 0;
596 };
597 
598 using MaterializationUnitList =
599     std::vector<std::unique_ptr<MaterializationUnit>>;
600 
601 /// A MaterializationUnit implementation for pre-existing absolute symbols.
602 ///
603 /// All symbols will be resolved and marked ready as soon as the unit is
604 /// materialized.
605 class AbsoluteSymbolsMaterializationUnit : public MaterializationUnit {
606 public:
607   AbsoluteSymbolsMaterializationUnit(SymbolMap Symbols, VModuleKey K);
608 
609   StringRef getName() const override;
610 
611 private:
612   void materialize(MaterializationResponsibility R) override;
613   void discard(const JITDylib &JD, const SymbolStringPtr &Name) override;
614   static SymbolFlagsMap extractFlags(const SymbolMap &Symbols);
615 
616   SymbolMap Symbols;
617 };
618 
619 /// Create an AbsoluteSymbolsMaterializationUnit with the given symbols.
620 /// Useful for inserting absolute symbols into a JITDylib. E.g.:
621 /// \code{.cpp}
622 ///   JITDylib &JD = ...;
623 ///   SymbolStringPtr Foo = ...;
624 ///   JITEvaluatedSymbol FooSym = ...;
625 ///   if (auto Err = JD.define(absoluteSymbols({{Foo, FooSym}})))
626 ///     return Err;
627 /// \endcode
628 ///
629 inline std::unique_ptr<AbsoluteSymbolsMaterializationUnit>
630 absoluteSymbols(SymbolMap Symbols, VModuleKey K = VModuleKey()) {
631   return std::make_unique<AbsoluteSymbolsMaterializationUnit>(
632       std::move(Symbols), std::move(K));
633 }
634 
635 /// A materialization unit for symbol aliases. Allows existing symbols to be
636 /// aliased with alternate flags.
637 class ReExportsMaterializationUnit : public MaterializationUnit {
638 public:
639   /// SourceJD is allowed to be nullptr, in which case the source JITDylib is
640   /// taken to be whatever JITDylib these definitions are materialized in (and
641   /// MatchNonExported has no effect). This is useful for defining aliases
642   /// within a JITDylib.
643   ///
644   /// Note: Care must be taken that no sets of aliases form a cycle, as such
645   ///       a cycle will result in a deadlock when any symbol in the cycle is
646   ///       resolved.
647   ReExportsMaterializationUnit(JITDylib *SourceJD,
648                                JITDylibLookupFlags SourceJDLookupFlags,
649                                SymbolAliasMap Aliases, VModuleKey K);
650 
651   StringRef getName() const override;
652 
653 private:
654   void materialize(MaterializationResponsibility R) override;
655   void discard(const JITDylib &JD, const SymbolStringPtr &Name) override;
656   static SymbolFlagsMap extractFlags(const SymbolAliasMap &Aliases);
657 
658   JITDylib *SourceJD = nullptr;
659   JITDylibLookupFlags SourceJDLookupFlags;
660   SymbolAliasMap Aliases;
661 };
662 
663 /// Create a ReExportsMaterializationUnit with the given aliases.
664 /// Useful for defining symbol aliases.: E.g., given a JITDylib JD containing
665 /// symbols "foo" and "bar", we can define aliases "baz" (for "foo") and "qux"
666 /// (for "bar") with: \code{.cpp}
667 ///   SymbolStringPtr Baz = ...;
668 ///   SymbolStringPtr Qux = ...;
669 ///   if (auto Err = JD.define(symbolAliases({
670 ///       {Baz, { Foo, JITSymbolFlags::Exported }},
671 ///       {Qux, { Bar, JITSymbolFlags::Weak }}}))
672 ///     return Err;
673 /// \endcode
674 inline std::unique_ptr<ReExportsMaterializationUnit>
675 symbolAliases(SymbolAliasMap Aliases, VModuleKey K = VModuleKey()) {
676   return std::make_unique<ReExportsMaterializationUnit>(
677       nullptr, JITDylibLookupFlags::MatchAllSymbols, std::move(Aliases),
678       std::move(K));
679 }
680 
681 /// Create a materialization unit for re-exporting symbols from another JITDylib
682 /// with alternative names/flags.
683 /// SourceJD will be searched using the given JITDylibLookupFlags.
684 inline std::unique_ptr<ReExportsMaterializationUnit>
685 reexports(JITDylib &SourceJD, SymbolAliasMap Aliases,
686           JITDylibLookupFlags SourceJDLookupFlags =
687               JITDylibLookupFlags::MatchExportedSymbolsOnly,
688           VModuleKey K = VModuleKey()) {
689   return std::make_unique<ReExportsMaterializationUnit>(
690       &SourceJD, SourceJDLookupFlags, std::move(Aliases), std::move(K));
691 }
692 
693 /// Build a SymbolAliasMap for the common case where you want to re-export
694 /// symbols from another JITDylib with the same linkage/flags.
695 Expected<SymbolAliasMap>
696 buildSimpleReexportsAAliasMap(JITDylib &SourceJD, const SymbolNameSet &Symbols);
697 
698 /// Represents the state that a symbol has reached during materialization.
699 enum class SymbolState : uint8_t {
700   Invalid,       /// No symbol should be in this state.
701   NeverSearched, /// Added to the symbol table, never queried.
702   Materializing, /// Queried, materialization begun.
703   Resolved,      /// Assigned address, still materializing.
704   Emitted,       /// Emitted to memory, but waiting on transitive dependencies.
705   Ready = 0x3f   /// Ready and safe for clients to access.
706 };
707 
708 /// A symbol query that returns results via a callback when results are
709 ///        ready.
710 ///
711 /// makes a callback when all symbols are available.
712 class AsynchronousSymbolQuery {
713   friend class ExecutionSession;
714   friend class JITDylib;
715   friend class JITSymbolResolverAdapter;
716 
717 public:
718   /// Create a query for the given symbols. The NotifyComplete
719   /// callback will be called once all queried symbols reach the given
720   /// minimum state.
721   AsynchronousSymbolQuery(const SymbolLookupSet &Symbols,
722                           SymbolState RequiredState,
723                           SymbolsResolvedCallback NotifyComplete);
724 
725   /// Notify the query that a requested symbol has reached the required state.
726   void notifySymbolMetRequiredState(const SymbolStringPtr &Name,
727                                     JITEvaluatedSymbol Sym);
728 
729   /// Remove a symbol from the query. This is used to drop weakly referenced
730   /// symbols that are not found.
dropSymbol(const SymbolStringPtr & Name)731   void dropSymbol(const SymbolStringPtr &Name) {
732     assert(ResolvedSymbols.count(Name) &&
733            "Redundant removal of weakly-referenced symbol");
734     ResolvedSymbols.erase(Name);
735     --OutstandingSymbolsCount;
736   }
737 
738   /// Returns true if all symbols covered by this query have been
739   ///        resolved.
isComplete()740   bool isComplete() const { return OutstandingSymbolsCount == 0; }
741 
742   /// Call the NotifyComplete callback.
743   ///
744   /// This should only be called if all symbols covered by the query have
745   /// reached the specified state.
746   void handleComplete();
747 
748 private:
getRequiredState()749   SymbolState getRequiredState() { return RequiredState; }
750 
751   void addQueryDependence(JITDylib &JD, SymbolStringPtr Name);
752 
753   void removeQueryDependence(JITDylib &JD, const SymbolStringPtr &Name);
754 
755   bool canStillFail();
756 
757   void handleFailed(Error Err);
758 
759   void detach();
760 
761   SymbolsResolvedCallback NotifyComplete;
762   SymbolDependenceMap QueryRegistrations;
763   SymbolMap ResolvedSymbols;
764   size_t OutstandingSymbolsCount;
765   SymbolState RequiredState;
766 };
767 
768 /// A symbol table that supports asynchoronous symbol queries.
769 ///
770 /// Represents a virtual shared object. Instances can not be copied or moved, so
771 /// their addresses may be used as keys for resource management.
772 /// JITDylib state changes must be made via an ExecutionSession to guarantee
773 /// that they are synchronized with respect to other JITDylib operations.
774 class JITDylib {
775   friend class AsynchronousSymbolQuery;
776   friend class ExecutionSession;
777   friend class MaterializationResponsibility;
778 public:
779   /// Definition generators can be attached to JITDylibs to generate new
780   /// definitions for otherwise unresolved symbols during lookup.
781   class DefinitionGenerator {
782   public:
783     virtual ~DefinitionGenerator();
784 
785     /// DefinitionGenerators should override this method to insert new
786     /// definitions into the parent JITDylib. K specifies the kind of this
787     /// lookup. JD specifies the target JITDylib being searched, and
788     /// JDLookupFlags specifies whether the search should match against
789     /// hidden symbols. Finally, Symbols describes the set of unresolved
790     /// symbols and their associated lookup flags.
791     virtual Error tryToGenerate(LookupKind K, JITDylib &JD,
792                                 JITDylibLookupFlags JDLookupFlags,
793                                 const SymbolLookupSet &LookupSet) = 0;
794   };
795 
796   using AsynchronousSymbolQuerySet =
797     std::set<std::shared_ptr<AsynchronousSymbolQuery>>;
798 
799   JITDylib(const JITDylib &) = delete;
800   JITDylib &operator=(const JITDylib &) = delete;
801   JITDylib(JITDylib &&) = delete;
802   JITDylib &operator=(JITDylib &&) = delete;
803 
804   /// Get the name for this JITDylib.
getName()805   const std::string &getName() const { return JITDylibName; }
806 
807   /// Get a reference to the ExecutionSession for this JITDylib.
getExecutionSession()808   ExecutionSession &getExecutionSession() const { return ES; }
809 
810   /// Adds a definition generator to this JITDylib and returns a referenece to
811   /// it.
812   ///
813   /// When JITDylibs are searched during lookup, if no existing definition of
814   /// a symbol is found, then any generators that have been added are run (in
815   /// the order that they were added) to potentially generate a definition.
816   template <typename GeneratorT>
817   GeneratorT &addGenerator(std::unique_ptr<GeneratorT> DefGenerator);
818 
819   /// Remove a definition generator from this JITDylib.
820   ///
821   /// The given generator must exist in this JITDylib's generators list (i.e.
822   /// have been added and not yet removed).
823   void removeGenerator(DefinitionGenerator &G);
824 
825   /// Set the search order to be used when fixing up definitions in JITDylib.
826   /// This will replace the previous search order, and apply to any symbol
827   /// resolutions made for definitions in this JITDylib after the call to
828   /// setSearchOrder (even if the definition itself was added before the
829   /// call).
830   ///
831   /// If SearchThisJITDylibFirst is set, which by default it is, then this
832   /// JITDylib will add itself to the beginning of the SearchOrder (Clients
833   /// should *not* put this JITDylib in the list in this case, to avoid
834   /// redundant lookups).
835   ///
836   /// If SearchThisJITDylibFirst is false then the search order will be used as
837   /// given. The main motivation for this feature is to support deliberate
838   /// shadowing of symbols in this JITDylib by a facade JITDylib. For example,
839   /// the facade may resolve function names to stubs, and the stubs may compile
840   /// lazily by looking up symbols in this dylib. Adding the facade dylib
841   /// as the first in the search order (instead of this dylib) ensures that
842   /// definitions within this dylib resolve to the lazy-compiling stubs,
843   /// rather than immediately materializing the definitions in this dylib.
844   void setSearchOrder(JITDylibSearchOrder NewSearchOrder,
845                       bool SearchThisJITDylibFirst = true);
846 
847   /// Add the given JITDylib to the search order for definitions in this
848   /// JITDylib.
849   void addToSearchOrder(JITDylib &JD,
850                         JITDylibLookupFlags JDLookupFlags =
851                             JITDylibLookupFlags::MatchExportedSymbolsOnly);
852 
853   /// Replace OldJD with NewJD in the search order if OldJD is present.
854   /// Otherwise this operation is a no-op.
855   void replaceInSearchOrder(JITDylib &OldJD, JITDylib &NewJD,
856                             JITDylibLookupFlags JDLookupFlags =
857                                 JITDylibLookupFlags::MatchExportedSymbolsOnly);
858 
859   /// Remove the given JITDylib from the search order for this JITDylib if it is
860   /// present. Otherwise this operation is a no-op.
861   void removeFromSearchOrder(JITDylib &JD);
862 
863   /// Do something with the search order (run under the session lock).
864   template <typename Func>
865   auto withSearchOrderDo(Func &&F)
866       -> decltype(F(std::declval<const JITDylibSearchOrder &>()));
867 
868   /// Define all symbols provided by the materialization unit to be part of this
869   /// JITDylib.
870   ///
871   /// This overload always takes ownership of the MaterializationUnit. If any
872   /// errors occur, the MaterializationUnit consumed.
873   template <typename MaterializationUnitType>
874   Error define(std::unique_ptr<MaterializationUnitType> &&MU);
875 
876   /// Define all symbols provided by the materialization unit to be part of this
877   /// JITDylib.
878   ///
879   /// This overload only takes ownership of the MaterializationUnit no error is
880   /// generated. If an error occurs, ownership remains with the caller. This
881   /// may allow the caller to modify the MaterializationUnit to correct the
882   /// issue, then re-call define.
883   template <typename MaterializationUnitType>
884   Error define(std::unique_ptr<MaterializationUnitType> &MU);
885 
886   /// Tries to remove the given symbols.
887   ///
888   /// If any symbols are not defined in this JITDylib this method will return
889   /// a SymbolsNotFound error covering the missing symbols.
890   ///
891   /// If all symbols are found but some symbols are in the process of being
892   /// materialized this method will return a SymbolsCouldNotBeRemoved error.
893   ///
894   /// On success, all symbols are removed. On failure, the JITDylib state is
895   /// left unmodified (no symbols are removed).
896   Error remove(const SymbolNameSet &Names);
897 
898   /// Search the given JITDylib for the symbols in Symbols. If found, store
899   /// the flags for each symbol in Flags. If any required symbols are not found
900   /// then an error will be returned.
901   Expected<SymbolFlagsMap> lookupFlags(LookupKind K,
902                                        JITDylibLookupFlags JDLookupFlags,
903                                        SymbolLookupSet LookupSet);
904 
905   /// Dump current JITDylib state to OS.
906   void dump(raw_ostream &OS);
907 
908   /// FIXME: Remove this when we remove the old ORC layers.
909   /// Search the given JITDylibs in order for the symbols in Symbols. Results
910   ///        (once they become available) will be returned via the given Query.
911   ///
912   /// If any symbol is not found then the unresolved symbols will be returned,
913   /// and the query will not be applied. The Query is not failed and can be
914   /// re-used in a subsequent lookup once the symbols have been added, or
915   /// manually failed.
916   Expected<SymbolNameSet>
917   legacyLookup(std::shared_ptr<AsynchronousSymbolQuery> Q, SymbolNameSet Names);
918 
919 private:
920   using AsynchronousSymbolQueryList =
921       std::vector<std::shared_ptr<AsynchronousSymbolQuery>>;
922 
923   struct UnmaterializedInfo {
UnmaterializedInfoUnmaterializedInfo924     UnmaterializedInfo(std::unique_ptr<MaterializationUnit> MU)
925         : MU(std::move(MU)) {}
926 
927     std::unique_ptr<MaterializationUnit> MU;
928   };
929 
930   using UnmaterializedInfosMap =
931       DenseMap<SymbolStringPtr, std::shared_ptr<UnmaterializedInfo>>;
932 
933   struct MaterializingInfo {
934     SymbolDependenceMap Dependants;
935     SymbolDependenceMap UnemittedDependencies;
936 
937     void addQuery(std::shared_ptr<AsynchronousSymbolQuery> Q);
938     void removeQuery(const AsynchronousSymbolQuery &Q);
939     AsynchronousSymbolQueryList takeQueriesMeeting(SymbolState RequiredState);
takeAllPendingQueriesMaterializingInfo940     AsynchronousSymbolQueryList takeAllPendingQueries() {
941       return std::move(PendingQueries);
942     }
hasQueriesPendingMaterializingInfo943     bool hasQueriesPending() const { return !PendingQueries.empty(); }
pendingQueriesMaterializingInfo944     const AsynchronousSymbolQueryList &pendingQueries() const {
945       return PendingQueries;
946     }
947   private:
948     AsynchronousSymbolQueryList PendingQueries;
949   };
950 
951   using MaterializingInfosMap = DenseMap<SymbolStringPtr, MaterializingInfo>;
952 
953   class SymbolTableEntry {
954   public:
955     SymbolTableEntry() = default;
SymbolTableEntry(JITSymbolFlags Flags)956     SymbolTableEntry(JITSymbolFlags Flags)
957         : Flags(Flags), State(static_cast<uint8_t>(SymbolState::NeverSearched)),
958           MaterializerAttached(false), PendingRemoval(false) {}
959 
getAddress()960     JITTargetAddress getAddress() const { return Addr; }
getFlags()961     JITSymbolFlags getFlags() const { return Flags; }
getState()962     SymbolState getState() const { return static_cast<SymbolState>(State); }
963 
isInMaterializationPhase()964     bool isInMaterializationPhase() const {
965       return getState() == SymbolState::Materializing ||
966              getState() == SymbolState::Resolved;
967     }
968 
hasMaterializerAttached()969     bool hasMaterializerAttached() const { return MaterializerAttached; }
isPendingRemoval()970     bool isPendingRemoval() const { return PendingRemoval; }
971 
setAddress(JITTargetAddress Addr)972     void setAddress(JITTargetAddress Addr) { this->Addr = Addr; }
setFlags(JITSymbolFlags Flags)973     void setFlags(JITSymbolFlags Flags) { this->Flags = Flags; }
setState(SymbolState State)974     void setState(SymbolState State) {
975       assert(static_cast<uint8_t>(State) < (1 << 6) &&
976              "State does not fit in bitfield");
977       this->State = static_cast<uint8_t>(State);
978     }
979 
setMaterializerAttached(bool MaterializerAttached)980     void setMaterializerAttached(bool MaterializerAttached) {
981       this->MaterializerAttached = MaterializerAttached;
982     }
983 
setPendingRemoval(bool PendingRemoval)984     void setPendingRemoval(bool PendingRemoval) {
985       this->PendingRemoval = PendingRemoval;
986     }
987 
getSymbol()988     JITEvaluatedSymbol getSymbol() const {
989       return JITEvaluatedSymbol(Addr, Flags);
990     }
991 
992   private:
993     JITTargetAddress Addr = 0;
994     JITSymbolFlags Flags;
995     uint8_t State : 6;
996     uint8_t MaterializerAttached : 1;
997     uint8_t PendingRemoval : 1;
998   };
999 
1000   using SymbolTable = DenseMap<SymbolStringPtr, SymbolTableEntry>;
1001 
1002   JITDylib(ExecutionSession &ES, std::string Name);
1003 
1004   Error defineImpl(MaterializationUnit &MU);
1005 
1006   void lookupFlagsImpl(SymbolFlagsMap &Result, LookupKind K,
1007                        JITDylibLookupFlags JDLookupFlags,
1008                        SymbolLookupSet &Unresolved);
1009 
1010   Error lodgeQuery(MaterializationUnitList &MUs,
1011                    std::shared_ptr<AsynchronousSymbolQuery> &Q, LookupKind K,
1012                    JITDylibLookupFlags JDLookupFlags,
1013                    SymbolLookupSet &Unresolved);
1014 
1015   Error lodgeQueryImpl(MaterializationUnitList &MUs,
1016                        std::shared_ptr<AsynchronousSymbolQuery> &Q,
1017                        LookupKind K, JITDylibLookupFlags JDLookupFlags,
1018                        SymbolLookupSet &Unresolved);
1019 
1020   bool lookupImpl(std::shared_ptr<AsynchronousSymbolQuery> &Q,
1021                   std::vector<std::unique_ptr<MaterializationUnit>> &MUs,
1022                   SymbolLookupSet &Unresolved);
1023 
1024   void detachQueryHelper(AsynchronousSymbolQuery &Q,
1025                          const SymbolNameSet &QuerySymbols);
1026 
1027   void transferEmittedNodeDependencies(MaterializingInfo &DependantMI,
1028                                        const SymbolStringPtr &DependantName,
1029                                        MaterializingInfo &EmittedMI);
1030 
1031   Expected<SymbolFlagsMap> defineMaterializing(SymbolFlagsMap SymbolFlags);
1032 
1033   void replace(std::unique_ptr<MaterializationUnit> MU);
1034 
1035   SymbolNameSet getRequestedSymbols(const SymbolFlagsMap &SymbolFlags) const;
1036 
1037   void addDependencies(const SymbolStringPtr &Name,
1038                        const SymbolDependenceMap &Dependants);
1039 
1040   Error resolve(const SymbolMap &Resolved);
1041 
1042   Error emit(const SymbolFlagsMap &Emitted);
1043 
1044   using FailedSymbolsWorklist =
1045       std::vector<std::pair<JITDylib *, SymbolStringPtr>>;
1046   static void notifyFailed(FailedSymbolsWorklist FailedSymbols);
1047 
1048   ExecutionSession &ES;
1049   std::string JITDylibName;
1050   SymbolTable Symbols;
1051   UnmaterializedInfosMap UnmaterializedInfos;
1052   MaterializingInfosMap MaterializingInfos;
1053   std::vector<std::unique_ptr<DefinitionGenerator>> DefGenerators;
1054   JITDylibSearchOrder SearchOrder;
1055 };
1056 
1057 /// An ExecutionSession represents a running JIT program.
1058 class ExecutionSession {
1059   // FIXME: Remove this when we remove the old ORC layers.
1060   friend class JITDylib;
1061 
1062 public:
1063   /// For reporting errors.
1064   using ErrorReporter = std::function<void(Error)>;
1065 
1066   /// For dispatching MaterializationUnit::materialize calls.
1067   using DispatchMaterializationFunction = std::function<void(
1068       JITDylib &JD, std::unique_ptr<MaterializationUnit> MU)>;
1069 
1070   /// Construct an ExecutionSession.
1071   ///
1072   /// SymbolStringPools may be shared between ExecutionSessions.
1073   ExecutionSession(std::shared_ptr<SymbolStringPool> SSP = nullptr);
1074 
1075   /// Add a symbol name to the SymbolStringPool and return a pointer to it.
intern(StringRef SymName)1076   SymbolStringPtr intern(StringRef SymName) { return SSP->intern(SymName); }
1077 
1078   /// Returns a shared_ptr to the SymbolStringPool for this ExecutionSession.
getSymbolStringPool()1079   std::shared_ptr<SymbolStringPool> getSymbolStringPool() const { return SSP; }
1080 
1081   /// Run the given lambda with the session mutex locked.
1082   template <typename Func> auto runSessionLocked(Func &&F) -> decltype(F()) {
1083     std::lock_guard<std::recursive_mutex> Lock(SessionMutex);
1084     return F();
1085   }
1086 
1087   /// Return a pointer to the "name" JITDylib.
1088   /// Ownership of JITDylib remains within Execution Session
1089   JITDylib *getJITDylibByName(StringRef Name);
1090 
1091   /// Add a new JITDylib to this ExecutionSession.
1092   ///
1093   /// The JITDylib Name is required to be unique. Clients should verify that
1094   /// names are not being re-used (e.g. by calling getJITDylibByName) if names
1095   /// are based on user input.
1096   JITDylib &createJITDylib(std::string Name);
1097 
1098   /// Allocate a module key for a new module to add to the JIT.
allocateVModule()1099   VModuleKey allocateVModule() {
1100     return runSessionLocked([this]() { return ++LastKey; });
1101   }
1102 
1103   /// Return a module key to the ExecutionSession so that it can be
1104   ///        re-used. This should only be done once all resources associated
1105   ///        with the original key have been released.
releaseVModule(VModuleKey Key)1106   void releaseVModule(VModuleKey Key) { /* FIXME: Recycle keys */
1107   }
1108 
1109   /// Set the error reporter function.
setErrorReporter(ErrorReporter ReportError)1110   ExecutionSession &setErrorReporter(ErrorReporter ReportError) {
1111     this->ReportError = std::move(ReportError);
1112     return *this;
1113   }
1114 
1115   /// Report a error for this execution session.
1116   ///
1117   /// Unhandled errors can be sent here to log them.
reportError(Error Err)1118   void reportError(Error Err) { ReportError(std::move(Err)); }
1119 
1120   /// Set the materialization dispatch function.
setDispatchMaterialization(DispatchMaterializationFunction DispatchMaterialization)1121   ExecutionSession &setDispatchMaterialization(
1122       DispatchMaterializationFunction DispatchMaterialization) {
1123     this->DispatchMaterialization = std::move(DispatchMaterialization);
1124     return *this;
1125   }
1126 
1127   void legacyFailQuery(AsynchronousSymbolQuery &Q, Error Err);
1128 
1129   using LegacyAsyncLookupFunction = std::function<SymbolNameSet(
1130       std::shared_ptr<AsynchronousSymbolQuery> Q, SymbolNameSet Names)>;
1131 
1132   /// A legacy lookup function for JITSymbolResolverAdapter.
1133   /// Do not use -- this will be removed soon.
1134   Expected<SymbolMap>
1135   legacyLookup(LegacyAsyncLookupFunction AsyncLookup, SymbolNameSet Names,
1136                SymbolState RequiredState,
1137                RegisterDependenciesFunction RegisterDependencies);
1138 
1139   /// Search the given JITDylib list for the given symbols.
1140   ///
1141   /// SearchOrder lists the JITDylibs to search. For each dylib, the associated
1142   /// boolean indicates whether the search should match against non-exported
1143   /// (hidden visibility) symbols in that dylib (true means match against
1144   /// non-exported symbols, false means do not match).
1145   ///
1146   /// The NotifyComplete callback will be called once all requested symbols
1147   /// reach the required state.
1148   ///
1149   /// If all symbols are found, the RegisterDependencies function will be called
1150   /// while the session lock is held. This gives clients a chance to register
1151   /// dependencies for on the queried symbols for any symbols they are
1152   /// materializing (if a MaterializationResponsibility instance is present,
1153   /// this can be implemented by calling
1154   /// MaterializationResponsibility::addDependencies). If there are no
1155   /// dependenant symbols for this query (e.g. it is being made by a top level
1156   /// client to get an address to call) then the value NoDependenciesToRegister
1157   /// can be used.
1158   void lookup(LookupKind K, const JITDylibSearchOrder &SearchOrder,
1159               SymbolLookupSet Symbols, SymbolState RequiredState,
1160               SymbolsResolvedCallback NotifyComplete,
1161               RegisterDependenciesFunction RegisterDependencies);
1162 
1163   /// Blocking version of lookup above. Returns the resolved symbol map.
1164   /// If WaitUntilReady is true (the default), will not return until all
1165   /// requested symbols are ready (or an error occurs). If WaitUntilReady is
1166   /// false, will return as soon as all requested symbols are resolved,
1167   /// or an error occurs. If WaitUntilReady is false and an error occurs
1168   /// after resolution, the function will return a success value, but the
1169   /// error will be reported via reportErrors.
1170   Expected<SymbolMap> lookup(const JITDylibSearchOrder &SearchOrder,
1171                              const SymbolLookupSet &Symbols,
1172                              LookupKind K = LookupKind::Static,
1173                              SymbolState RequiredState = SymbolState::Ready,
1174                              RegisterDependenciesFunction RegisterDependencies =
1175                                  NoDependenciesToRegister);
1176 
1177   /// Convenience version of blocking lookup.
1178   /// Searches each of the JITDylibs in the search order in turn for the given
1179   /// symbol.
1180   Expected<JITEvaluatedSymbol> lookup(const JITDylibSearchOrder &SearchOrder,
1181                                       SymbolStringPtr Symbol);
1182 
1183   /// Convenience version of blocking lookup.
1184   /// Searches each of the JITDylibs in the search order in turn for the given
1185   /// symbol. The search will not find non-exported symbols.
1186   Expected<JITEvaluatedSymbol> lookup(ArrayRef<JITDylib *> SearchOrder,
1187                                       SymbolStringPtr Symbol);
1188 
1189   /// Convenience version of blocking lookup.
1190   /// Searches each of the JITDylibs in the search order in turn for the given
1191   /// symbol. The search will not find non-exported symbols.
1192   Expected<JITEvaluatedSymbol> lookup(ArrayRef<JITDylib *> SearchOrder,
1193                                       StringRef Symbol);
1194 
1195   /// Materialize the given unit.
dispatchMaterialization(JITDylib & JD,std::unique_ptr<MaterializationUnit> MU)1196   void dispatchMaterialization(JITDylib &JD,
1197                                std::unique_ptr<MaterializationUnit> MU) {
1198     LLVM_DEBUG({
1199       runSessionLocked([&]() {
1200         dbgs() << "Dispatching " << *MU << " for " << JD.getName() << "\n";
1201       });
1202     });
1203     DispatchMaterialization(JD, std::move(MU));
1204   }
1205 
1206   /// Dump the state of all the JITDylibs in this session.
1207   void dump(raw_ostream &OS);
1208 
1209 private:
logErrorsToStdErr(Error Err)1210   static void logErrorsToStdErr(Error Err) {
1211     logAllUnhandledErrors(std::move(Err), errs(), "JIT session error: ");
1212   }
1213 
1214   static void
materializeOnCurrentThread(JITDylib & JD,std::unique_ptr<MaterializationUnit> MU)1215   materializeOnCurrentThread(JITDylib &JD,
1216                              std::unique_ptr<MaterializationUnit> MU) {
1217     MU->doMaterialize(JD);
1218   }
1219 
1220   void runOutstandingMUs();
1221 
1222   mutable std::recursive_mutex SessionMutex;
1223   std::shared_ptr<SymbolStringPool> SSP;
1224   VModuleKey LastKey = 0;
1225   ErrorReporter ReportError = logErrorsToStdErr;
1226   DispatchMaterializationFunction DispatchMaterialization =
1227       materializeOnCurrentThread;
1228 
1229   std::vector<std::unique_ptr<JITDylib>> JDs;
1230 
1231   // FIXME: Remove this (and runOutstandingMUs) once the linking layer works
1232   //        with callbacks from asynchronous queries.
1233   mutable std::recursive_mutex OutstandingMUsMutex;
1234   std::vector<std::pair<JITDylib *, std::unique_ptr<MaterializationUnit>>>
1235       OutstandingMUs;
1236 };
1237 
1238 template <typename GeneratorT>
addGenerator(std::unique_ptr<GeneratorT> DefGenerator)1239 GeneratorT &JITDylib::addGenerator(std::unique_ptr<GeneratorT> DefGenerator) {
1240   auto &G = *DefGenerator;
1241   ES.runSessionLocked(
1242       [&]() { DefGenerators.push_back(std::move(DefGenerator)); });
1243   return G;
1244 }
1245 
1246 template <typename Func>
1247 auto JITDylib::withSearchOrderDo(Func &&F)
1248     -> decltype(F(std::declval<const JITDylibSearchOrder &>())) {
1249   return ES.runSessionLocked([&]() { return F(SearchOrder); });
1250 }
1251 
1252 template <typename MaterializationUnitType>
define(std::unique_ptr<MaterializationUnitType> && MU)1253 Error JITDylib::define(std::unique_ptr<MaterializationUnitType> &&MU) {
1254   assert(MU && "Can not define with a null MU");
1255   return ES.runSessionLocked([&, this]() -> Error {
1256     if (auto Err = defineImpl(*MU))
1257       return Err;
1258 
1259     /// defineImpl succeeded.
1260     auto UMI = std::make_shared<UnmaterializedInfo>(std::move(MU));
1261     for (auto &KV : UMI->MU->getSymbols())
1262       UnmaterializedInfos[KV.first] = UMI;
1263 
1264     return Error::success();
1265   });
1266 }
1267 
1268 template <typename MaterializationUnitType>
define(std::unique_ptr<MaterializationUnitType> & MU)1269 Error JITDylib::define(std::unique_ptr<MaterializationUnitType> &MU) {
1270   assert(MU && "Can not define with a null MU");
1271 
1272   return ES.runSessionLocked([&, this]() -> Error {
1273     if (auto Err = defineImpl(*MU))
1274       return Err;
1275 
1276     /// defineImpl succeeded.
1277     auto UMI = std::make_shared<UnmaterializedInfo>(std::move(MU));
1278     for (auto &KV : UMI->MU->getSymbols())
1279       UnmaterializedInfos[KV.first] = UMI;
1280 
1281     return Error::success();
1282   });
1283 }
1284 
1285 /// ReexportsGenerator can be used with JITDylib::addGenerator to automatically
1286 /// re-export a subset of the source JITDylib's symbols in the target.
1287 class ReexportsGenerator : public JITDylib::DefinitionGenerator {
1288 public:
1289   using SymbolPredicate = std::function<bool(SymbolStringPtr)>;
1290 
1291   /// Create a reexports generator. If an Allow predicate is passed, only
1292   /// symbols for which the predicate returns true will be reexported. If no
1293   /// Allow predicate is passed, all symbols will be exported.
1294   ReexportsGenerator(JITDylib &SourceJD,
1295                      JITDylibLookupFlags SourceJDLookupFlags,
1296                      SymbolPredicate Allow = SymbolPredicate());
1297 
1298   Error tryToGenerate(LookupKind K, JITDylib &JD,
1299                       JITDylibLookupFlags JDLookupFlags,
1300                       const SymbolLookupSet &LookupSet) override;
1301 
1302 private:
1303   JITDylib &SourceJD;
1304   JITDylibLookupFlags SourceJDLookupFlags;
1305   SymbolPredicate Allow;
1306 };
1307 
1308 /// Mangles symbol names then uniques them in the context of an
1309 /// ExecutionSession.
1310 class MangleAndInterner {
1311 public:
1312   MangleAndInterner(ExecutionSession &ES, const DataLayout &DL);
1313   SymbolStringPtr operator()(StringRef Name);
1314 
1315 private:
1316   ExecutionSession &ES;
1317   const DataLayout &DL;
1318 };
1319 
1320 } // End namespace orc
1321 } // End namespace llvm
1322 
1323 #undef DEBUG_TYPE // "orc"
1324 
1325 #endif // LLVM_EXECUTIONENGINE_ORC_CORE_H
1326