Core.h revision 360784
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
29namespace llvm {
30namespace orc {
31
32// Forward declare some classes.
33class AsynchronousSymbolQuery;
34class ExecutionSession;
35class MaterializationUnit;
36class MaterializationResponsibility;
37class JITDylib;
38enum class SymbolState : uint8_t;
39
40/// VModuleKey provides a unique identifier (allocated and managed by
41/// ExecutionSessions) for a module added to the JIT.
42using VModuleKey = uint64_t;
43
44/// A set of symbol names (represented by SymbolStringPtrs for
45//         efficiency).
46using SymbolNameSet = DenseSet<SymbolStringPtr>;
47
48/// A vector of symbol names.
49using SymbolNameVector = std::vector<SymbolStringPtr>;
50
51/// A map from symbol names (as SymbolStringPtrs) to JITSymbols
52/// (address/flags pairs).
53using SymbolMap = DenseMap<SymbolStringPtr, JITEvaluatedSymbol>;
54
55/// A map from symbol names (as SymbolStringPtrs) to JITSymbolFlags.
56using SymbolFlagsMap = DenseMap<SymbolStringPtr, JITSymbolFlags>;
57
58/// A map from JITDylibs to sets of symbols.
59using 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.
67enum 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).
77enum 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).
89enum class LookupKind { Static, DLSym };
90
91/// A list of (JITDylib*, JITDylibLookupFlags) pairs to be used as a search
92/// order during symbol lookup.
93using 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.
98inline 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).
115class SymbolLookupSet {
116public:
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
168  bool empty() const { return Symbols.empty(); }
169  UnderlyingVector::size_type size() const { return Symbols.size(); }
170  iterator begin() { return Symbols.begin(); }
171  iterator end() { return Symbols.end(); }
172  const_iterator begin() const { return Symbols.begin(); }
173  const_iterator end() const { return Symbols.end(); }
174
175  /// Removes the Ith element of the vector, replacing it with the last element.
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.
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).
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.
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.
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.
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.
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.
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
296private:
297  UnderlyingVector Symbols;
298};
299
300struct SymbolAliasMapEntry {
301  SymbolAliasMapEntry() = default;
302  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.
310using SymbolAliasMap = DenseMap<SymbolStringPtr, SymbolAliasMapEntry>;
311
312/// Render a SymbolStringPtr.
313raw_ostream &operator<<(raw_ostream &OS, const SymbolStringPtr &Sym);
314
315/// Render a SymbolNameSet.
316raw_ostream &operator<<(raw_ostream &OS, const SymbolNameSet &Symbols);
317
318/// Render a SymbolNameVector.
319raw_ostream &operator<<(raw_ostream &OS, const SymbolNameVector &Symbols);
320
321/// Render a SymbolFlagsMap entry.
322raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap::value_type &KV);
323
324/// Render a SymbolMap entry.
325raw_ostream &operator<<(raw_ostream &OS, const SymbolMap::value_type &KV);
326
327/// Render a SymbolFlagsMap.
328raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap &SymbolFlags);
329
330/// Render a SymbolMap.
331raw_ostream &operator<<(raw_ostream &OS, const SymbolMap &Symbols);
332
333/// Render a SymbolDependenceMap entry.
334raw_ostream &operator<<(raw_ostream &OS,
335                        const SymbolDependenceMap::value_type &KV);
336
337/// Render a SymbolDependendeMap.
338raw_ostream &operator<<(raw_ostream &OS, const SymbolDependenceMap &Deps);
339
340/// Render a MaterializationUnit.
341raw_ostream &operator<<(raw_ostream &OS, const MaterializationUnit &MU);
342
343//// Render a JITDylibLookupFlags instance.
344raw_ostream &operator<<(raw_ostream &OS,
345                        const JITDylibLookupFlags &JDLookupFlags);
346
347/// Rendar a SymbolLookupFlags instance.
348raw_ostream &operator<<(raw_ostream &OS, const SymbolLookupFlags &LookupFlags);
349
350/// Render a JITDylibLookupFlags instance.
351raw_ostream &operator<<(raw_ostream &OS, const LookupKind &K);
352
353/// Render a SymbolLookupSet entry.
354raw_ostream &operator<<(raw_ostream &OS, const SymbolLookupSet::value_type &KV);
355
356/// Render a SymbolLookupSet.
357raw_ostream &operator<<(raw_ostream &OS, const SymbolLookupSet &LookupSet);
358
359/// Render a JITDylibSearchOrder.
360raw_ostream &operator<<(raw_ostream &OS,
361                        const JITDylibSearchOrder &SearchOrder);
362
363/// Render a SymbolAliasMap.
364raw_ostream &operator<<(raw_ostream &OS, const SymbolAliasMap &Aliases);
365
366/// Render a SymbolState.
367raw_ostream &operator<<(raw_ostream &OS, const SymbolState &S);
368
369/// Render a LookupKind.
370raw_ostream &operator<<(raw_ostream &OS, const LookupKind &K);
371
372/// Callback to notify client that symbols have been resolved.
373using SymbolsResolvedCallback = unique_function<void(Expected<SymbolMap>)>;
374
375/// Callback to register the dependencies for a given query.
376using 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.
381extern RegisterDependenciesFunction NoDependenciesToRegister;
382
383/// Used to notify a JITDylib that the given set of symbols failed to
384/// materialize.
385class FailedToMaterialize : public ErrorInfo<FailedToMaterialize> {
386public:
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;
392  const SymbolDependenceMap &getSymbols() const { return *Symbols; }
393
394private:
395  std::shared_ptr<SymbolDependenceMap> Symbols;
396};
397
398/// Used to notify clients when symbols can not be found during a lookup.
399class SymbolsNotFound : public ErrorInfo<SymbolsNotFound> {
400public:
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;
407  const SymbolNameVector &getSymbols() const { return Symbols; }
408
409private:
410  SymbolNameVector Symbols;
411};
412
413/// Used to notify clients that a set of symbols could not be removed.
414class SymbolsCouldNotBeRemoved : public ErrorInfo<SymbolsCouldNotBeRemoved> {
415public:
416  static char ID;
417
418  SymbolsCouldNotBeRemoved(SymbolNameSet Symbols);
419  std::error_code convertToErrorCode() const override;
420  void log(raw_ostream &OS) const override;
421  const SymbolNameSet &getSymbols() const { return Symbols; }
422
423private:
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.
434class MaterializationResponsibility {
435  friend class MaterializationUnit;
436public:
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.
448  JITDylib &getTargetJITDylib() const { return JD; }
449
450  /// Returns the VModuleKey for this instance.
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.
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
531private:
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.
550class MaterializationUnit {
551public:
552  MaterializationUnit(SymbolFlagsMap InitalSymbolFlags, VModuleKey K)
553      : SymbolFlags(std::move(InitalSymbolFlags)), K(std::move(K)) {}
554
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.
562  const SymbolFlagsMap &getSymbols() const { return SymbolFlags; }
563
564  /// Called by materialization dispatchers (see
565  /// ExecutionSession::DispatchMaterializationFunction) to trigger
566  /// materialization of this MaterializationUnit.
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.
574  void doDiscard(const JITDylib &JD, const SymbolStringPtr &Name) {
575    SymbolFlags.erase(Name);
576    discard(JD, std::move(Name));
577  }
578
579protected:
580  SymbolFlagsMap SymbolFlags;
581  VModuleKey K;
582
583private:
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
598using 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.
605class AbsoluteSymbolsMaterializationUnit : public MaterializationUnit {
606public:
607  AbsoluteSymbolsMaterializationUnit(SymbolMap Symbols, VModuleKey K);
608
609  StringRef getName() const override;
610
611private:
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///
629inline std::unique_ptr<AbsoluteSymbolsMaterializationUnit>
630absoluteSymbols(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.
637class ReExportsMaterializationUnit : public MaterializationUnit {
638public:
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
653private:
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
674inline std::unique_ptr<ReExportsMaterializationUnit>
675symbolAliases(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.
684inline std::unique_ptr<ReExportsMaterializationUnit>
685reexports(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.
695Expected<SymbolAliasMap>
696buildSimpleReexportsAAliasMap(JITDylib &SourceJD, const SymbolNameSet &Symbols);
697
698/// Represents the state that a symbol has reached during materialization.
699enum 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.
712class AsynchronousSymbolQuery {
713  friend class ExecutionSession;
714  friend class JITDylib;
715  friend class JITSymbolResolverAdapter;
716
717public:
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.
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.
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
748private:
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.
774class JITDylib {
775  friend class AsynchronousSymbolQuery;
776  friend class ExecutionSession;
777  friend class MaterializationResponsibility;
778public:
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.
805  const std::string &getName() const { return JITDylibName; }
806
807  /// Get a reference to the ExecutionSession for this JITDylib.
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
919private:
920  using AsynchronousSymbolQueryList =
921      std::vector<std::shared_ptr<AsynchronousSymbolQuery>>;
922
923  struct UnmaterializedInfo {
924    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);
940    AsynchronousSymbolQueryList takeAllPendingQueries() {
941      return std::move(PendingQueries);
942    }
943    bool hasQueriesPending() const { return !PendingQueries.empty(); }
944    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;
956    SymbolTableEntry(JITSymbolFlags Flags)
957        : Flags(Flags), State(static_cast<uint8_t>(SymbolState::NeverSearched)),
958          MaterializerAttached(false), PendingRemoval(false) {}
959
960    JITTargetAddress getAddress() const { return Addr; }
961    JITSymbolFlags getFlags() const { return Flags; }
962    SymbolState getState() const { return static_cast<SymbolState>(State); }
963
964    bool isInMaterializationPhase() const {
965      return getState() == SymbolState::Materializing ||
966             getState() == SymbolState::Resolved;
967    }
968
969    bool hasMaterializerAttached() const { return MaterializerAttached; }
970    bool isPendingRemoval() const { return PendingRemoval; }
971
972    void setAddress(JITTargetAddress Addr) { this->Addr = Addr; }
973    void setFlags(JITSymbolFlags Flags) { this->Flags = Flags; }
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
980    void setMaterializerAttached(bool MaterializerAttached) {
981      this->MaterializerAttached = MaterializerAttached;
982    }
983
984    void setPendingRemoval(bool PendingRemoval) {
985      this->PendingRemoval = PendingRemoval;
986    }
987
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.
1058class ExecutionSession {
1059  // FIXME: Remove this when we remove the old ORC layers.
1060  friend class JITDylib;
1061
1062public:
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.
1076  SymbolStringPtr intern(StringRef SymName) { return SSP->intern(SymName); }
1077
1078  /// Returns a shared_ptr to the SymbolStringPool for this ExecutionSession.
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.
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.
1106  void releaseVModule(VModuleKey Key) { /* FIXME: Recycle keys */
1107  }
1108
1109  /// Set the error reporter function.
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.
1118  void reportError(Error Err) { ReportError(std::move(Err)); }
1119
1120  /// Set the materialization dispatch function.
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.
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
1209private:
1210  static void logErrorsToStdErr(Error Err) {
1211    logAllUnhandledErrors(std::move(Err), errs(), "JIT session error: ");
1212  }
1213
1214  static void
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
1238template <typename GeneratorT>
1239GeneratorT &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
1246template <typename Func>
1247auto JITDylib::withSearchOrderDo(Func &&F)
1248    -> decltype(F(std::declval<const JITDylibSearchOrder &>())) {
1249  return ES.runSessionLocked([&]() { return F(SearchOrder); });
1250}
1251
1252template <typename MaterializationUnitType>
1253Error 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
1268template <typename MaterializationUnitType>
1269Error 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.
1287class ReexportsGenerator : public JITDylib::DefinitionGenerator {
1288public:
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
1302private:
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.
1310class MangleAndInterner {
1311public:
1312  MangleAndInterner(ExecutionSession &ES, const DataLayout &DL);
1313  SymbolStringPtr operator()(StringRef Name);
1314
1315private:
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