//===------ Core.h -- Core ORC APIs (Layer, JITDylib, etc.) -----*- C++ -*-===//
 
//
 
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 
// See https://llvm.org/LICENSE.txt for license information.
 
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 
//
 
//===----------------------------------------------------------------------===//
 
//
 
// Contains core ORC APIs.
 
//
 
//===----------------------------------------------------------------------===//
 
 
 
#ifndef LLVM_EXECUTIONENGINE_ORC_CORE_H
 
#define LLVM_EXECUTIONENGINE_ORC_CORE_H
 
 
 
#include "llvm/ADT/BitmaskEnum.h"
 
#include "llvm/ADT/DenseSet.h"
 
#include "llvm/ADT/FunctionExtras.h"
 
#include "llvm/ADT/IntrusiveRefCntPtr.h"
 
#include "llvm/ExecutionEngine/JITLink/JITLinkDylib.h"
 
#include "llvm/ExecutionEngine/JITSymbol.h"
 
#include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
 
#include "llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h"
 
#include "llvm/ExecutionEngine/Orc/TaskDispatch.h"
 
#include "llvm/Support/Debug.h"
 
#include "llvm/Support/ExtensibleRTTI.h"
 
 
 
#include <atomic>
 
#include <future>
 
#include <memory>
 
#include <vector>
 
 
 
namespace llvm {
 
namespace orc {
 
 
 
// Forward declare some classes.
 
class AsynchronousSymbolQuery;
 
class ExecutionSession;
 
class MaterializationUnit;
 
class MaterializationResponsibility;
 
class JITDylib;
 
class ResourceTracker;
 
class InProgressLookupState;
 
 
 
enum class SymbolState : uint8_t;
 
 
 
using ResourceTrackerSP = IntrusiveRefCntPtr<ResourceTracker>;
 
using JITDylibSP = IntrusiveRefCntPtr<JITDylib>;
 
 
 
using ResourceKey = uintptr_t;
 
 
 
/// API to remove / transfer ownership of JIT resources.
 
class ResourceTracker : public ThreadSafeRefCountedBase<ResourceTracker> {
 
private:
 
  friend class ExecutionSession;
 
  friend class JITDylib;
 
  friend class MaterializationResponsibility;
 
 
 
public:
 
  ResourceTracker(const ResourceTracker &) = delete;
 
  ResourceTracker &operator=(const ResourceTracker &) = delete;
 
  ResourceTracker(ResourceTracker &&) = delete;
 
  ResourceTracker &operator=(ResourceTracker &&) = delete;
 
 
 
  ~ResourceTracker();
 
 
 
  /// Return the JITDylib targeted by this tracker.
 
  JITDylib &getJITDylib() const {
 
    return *reinterpret_cast<JITDylib *>(JDAndFlag.load() &
 
                                         ~static_cast<uintptr_t>(1));
 
  }
 
 
 
  /// Runs the given callback under the session lock, passing in the associated
 
  /// ResourceKey. This is the safe way to associate resources with trackers.
 
  template <typename Func> Error withResourceKeyDo(Func &&F);
 
 
 
  /// Remove all resources associated with this key.
 
  Error remove();
 
 
 
  /// Transfer all resources associated with this key to the given
 
  /// tracker, which must target the same JITDylib as this one.
 
  void transferTo(ResourceTracker &DstRT);
 
 
 
  /// Return true if this tracker has become defunct.
 
  bool isDefunct() const { return JDAndFlag.load() & 0x1; }
 
 
 
  /// Returns the key associated with this tracker.
 
  /// This method should not be used except for debug logging: there is no
 
  /// guarantee that the returned value will remain valid.
 
  ResourceKey getKeyUnsafe() const { return reinterpret_cast<uintptr_t>(this); }
 
 
 
private:
 
  ResourceTracker(JITDylibSP JD);
 
 
 
  void makeDefunct();
 
 
 
  std::atomic_uintptr_t JDAndFlag;
 
};
 
 
 
/// Listens for ResourceTracker operations.
 
class ResourceManager {
 
public:
 
  virtual ~ResourceManager();
 
  virtual Error handleRemoveResources(JITDylib &JD, ResourceKey K) = 0;
 
  virtual void handleTransferResources(JITDylib &JD, ResourceKey DstK,
 
                                       ResourceKey SrcK) = 0;
 
};
 
 
 
/// A set of symbol names (represented by SymbolStringPtrs for
 
//         efficiency).
 
using SymbolNameSet = DenseSet<SymbolStringPtr>;
 
 
 
/// A vector of symbol names.
 
using SymbolNameVector = std::vector<SymbolStringPtr>;
 
 
 
/// A map from symbol names (as SymbolStringPtrs) to JITSymbols
 
/// (address/flags pairs).
 
using SymbolMap = DenseMap<SymbolStringPtr, JITEvaluatedSymbol>;
 
 
 
/// A map from symbol names (as SymbolStringPtrs) to JITSymbolFlags.
 
using SymbolFlagsMap = DenseMap<SymbolStringPtr, JITSymbolFlags>;
 
 
 
/// A map from JITDylibs to sets of symbols.
 
using SymbolDependenceMap = DenseMap<JITDylib *, SymbolNameSet>;
 
 
 
/// Lookup flags that apply to each dylib in the search order for a lookup.
 
///
 
/// If MatchHiddenSymbolsOnly is used (the default) for a given dylib, then
 
/// only symbols in that Dylib's interface will be searched. If
 
/// MatchHiddenSymbols is used then symbols with hidden visibility will match
 
/// as well.
 
enum class JITDylibLookupFlags { MatchExportedSymbolsOnly, MatchAllSymbols };
 
 
 
/// Lookup flags that apply to each symbol in a lookup.
 
///
 
/// If RequiredSymbol is used (the default) for a given symbol then that symbol
 
/// must be found during the lookup or the lookup will fail returning a
 
/// SymbolNotFound error. If WeaklyReferencedSymbol is used and the given
 
/// symbol is not found then the query will continue, and no result for the
 
/// missing symbol will be present in the result (assuming the rest of the
 
/// lookup succeeds).
 
enum class SymbolLookupFlags { RequiredSymbol, WeaklyReferencedSymbol };
 
 
 
/// Describes the kind of lookup being performed. The lookup kind is passed to
 
/// symbol generators (if they're invoked) to help them determine what
 
/// definitions to generate.
 
///
 
/// Static -- Lookup is being performed as-if at static link time (e.g.
 
///           generators representing static archives should pull in new
 
///           definitions).
 
///
 
/// DLSym -- Lookup is being performed as-if at runtime (e.g. generators
 
///          representing static archives should not pull in new definitions).
 
enum class LookupKind { Static, DLSym };
 
 
 
/// A list of (JITDylib*, JITDylibLookupFlags) pairs to be used as a search
 
/// order during symbol lookup.
 
using JITDylibSearchOrder =
 
    std::vector<std::pair<JITDylib *, JITDylibLookupFlags>>;
 
 
 
/// Convenience function for creating a search order from an ArrayRef of
 
/// JITDylib*, all with the same flags.
 
inline JITDylibSearchOrder makeJITDylibSearchOrder(
 
    ArrayRef<JITDylib *> JDs,
 
    JITDylibLookupFlags Flags = JITDylibLookupFlags::MatchExportedSymbolsOnly) {
 
  JITDylibSearchOrder O;
 
  O.reserve(JDs.size());
 
  for (auto *JD : JDs)
 
    O.push_back(std::make_pair(JD, Flags));
 
  return O;
 
}
 
 
 
/// A set of symbols to look up, each associated with a SymbolLookupFlags
 
/// value.
 
///
 
/// This class is backed by a vector and optimized for fast insertion,
 
/// deletion and iteration. It does not guarantee a stable order between
 
/// operations, and will not automatically detect duplicate elements (they
 
/// can be manually checked by calling the validate method).
 
class SymbolLookupSet {
 
public:
 
  using value_type = std::pair<SymbolStringPtr, SymbolLookupFlags>;
 
  using UnderlyingVector = std::vector<value_type>;
 
  using iterator = UnderlyingVector::iterator;
 
  using const_iterator = UnderlyingVector::const_iterator;
 
 
 
  SymbolLookupSet() = default;
 
 
 
  explicit SymbolLookupSet(
 
      SymbolStringPtr Name,
 
      SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) {
 
    add(std::move(Name), Flags);
 
  }
 
 
 
  /// Construct a SymbolLookupSet from an initializer list of SymbolStringPtrs.
 
  explicit SymbolLookupSet(
 
      std::initializer_list<SymbolStringPtr> Names,
 
      SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) {
 
    Symbols.reserve(Names.size());
 
    for (const auto &Name : Names)
 
      add(std::move(Name), Flags);
 
  }
 
 
 
  /// Construct a SymbolLookupSet from a SymbolNameSet with the given
 
  /// Flags used for each value.
 
  explicit SymbolLookupSet(
 
      const SymbolNameSet &Names,
 
      SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) {
 
    Symbols.reserve(Names.size());
 
    for (const auto &Name : Names)
 
      add(Name, Flags);
 
  }
 
 
 
  /// Construct a SymbolLookupSet from a vector of symbols with the given Flags
 
  /// used for each value.
 
  /// If the ArrayRef contains duplicates it is up to the client to remove these
 
  /// before using this instance for lookup.
 
  explicit SymbolLookupSet(
 
      ArrayRef<SymbolStringPtr> Names,
 
      SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) {
 
    Symbols.reserve(Names.size());
 
    for (const auto &Name : Names)
 
      add(Name, Flags);
 
  }
 
 
 
  /// Construct a SymbolLookupSet from DenseMap keys.
 
  template <typename KeyT>
 
  static SymbolLookupSet
 
  fromMapKeys(const DenseMap<SymbolStringPtr, KeyT> &M,
 
              SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) {
 
    SymbolLookupSet Result;
 
    Result.Symbols.reserve(M.size());
 
    for (const auto &KV : M)
 
      Result.add(KV.first, Flags);
 
    return Result;
 
  }
 
 
 
  /// Add an element to the set. The client is responsible for checking that
 
  /// duplicates are not added.
 
  SymbolLookupSet &
 
  add(SymbolStringPtr Name,
 
      SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) {
 
    Symbols.push_back(std::make_pair(std::move(Name), Flags));
 
    return *this;
 
  }
 
 
 
  /// Quickly append one lookup set to another.
 
  SymbolLookupSet &append(SymbolLookupSet Other) {
 
    Symbols.reserve(Symbols.size() + Other.size());
 
    for (auto &KV : Other)
 
      Symbols.push_back(std::move(KV));
 
    return *this;
 
  }
 
 
 
  bool empty() const { return Symbols.empty(); }
 
  UnderlyingVector::size_type size() const { return Symbols.size(); }
 
  iterator begin() { return Symbols.begin(); }
 
  iterator end() { return Symbols.end(); }
 
  const_iterator begin() const { return Symbols.begin(); }
 
  const_iterator end() const { return Symbols.end(); }
 
 
 
  /// Removes the Ith element of the vector, replacing it with the last element.
 
  void remove(UnderlyingVector::size_type I) {
 
    std::swap(Symbols[I], Symbols.back());
 
    Symbols.pop_back();
 
  }
 
 
 
  /// Removes the element pointed to by the given iterator. This iterator and
 
  /// all subsequent ones (including end()) are invalidated.
 
  void remove(iterator I) { remove(I - begin()); }
 
 
 
  /// Removes all elements matching the given predicate, which must be callable
 
  /// as bool(const SymbolStringPtr &, SymbolLookupFlags Flags).
 
  template <typename PredFn> void remove_if(PredFn &&Pred) {
 
    UnderlyingVector::size_type I = 0;
 
    while (I != Symbols.size()) {
 
      const auto &Name = Symbols[I].first;
 
      auto Flags = Symbols[I].second;
 
      if (Pred(Name, Flags))
 
        remove(I);
 
      else
 
        ++I;
 
    }
 
  }
 
 
 
  /// Loop over the elements of this SymbolLookupSet, applying the Body function
 
  /// to each one. Body must be callable as
 
  /// bool(const SymbolStringPtr &, SymbolLookupFlags).
 
  /// If Body returns true then the element just passed in is removed from the
 
  /// set. If Body returns false then the element is retained.
 
  template <typename BodyFn>
 
  auto forEachWithRemoval(BodyFn &&Body) -> std::enable_if_t<
 
      std::is_same<decltype(Body(std::declval<const SymbolStringPtr &>(),
 
                                 std::declval<SymbolLookupFlags>())),
 
                   bool>::value> {
 
    UnderlyingVector::size_type I = 0;
 
    while (I != Symbols.size()) {
 
      const auto &Name = Symbols[I].first;
 
      auto Flags = Symbols[I].second;
 
      if (Body(Name, Flags))
 
        remove(I);
 
      else
 
        ++I;
 
    }
 
  }
 
 
 
  /// Loop over the elements of this SymbolLookupSet, applying the Body function
 
  /// to each one. Body must be callable as
 
  /// Expected<bool>(const SymbolStringPtr &, SymbolLookupFlags).
 
  /// If Body returns a failure value, the loop exits immediately. If Body
 
  /// returns true then the element just passed in is removed from the set. If
 
  /// Body returns false then the element is retained.
 
  template <typename BodyFn>
 
  auto forEachWithRemoval(BodyFn &&Body) -> std::enable_if_t<
 
      std::is_same<decltype(Body(std::declval<const SymbolStringPtr &>(),
 
                                 std::declval<SymbolLookupFlags>())),
 
                   Expected<bool>>::value,
 
      Error> {
 
    UnderlyingVector::size_type I = 0;
 
    while (I != Symbols.size()) {
 
      const auto &Name = Symbols[I].first;
 
      auto Flags = Symbols[I].second;
 
      auto Remove = Body(Name, Flags);
 
      if (!Remove)
 
        return Remove.takeError();
 
      if (*Remove)
 
        remove(I);
 
      else
 
        ++I;
 
    }
 
    return Error::success();
 
  }
 
 
 
  /// Construct a SymbolNameVector from this instance by dropping the Flags
 
  /// values.
 
  SymbolNameVector getSymbolNames() const {
 
    SymbolNameVector Names;
 
    Names.reserve(Symbols.size());
 
    for (const auto &KV : Symbols)
 
      Names.push_back(KV.first);
 
    return Names;
 
  }
 
 
 
  /// Sort the lookup set by pointer value. This sort is fast but sensitive to
 
  /// allocation order and so should not be used where a consistent order is
 
  /// required.
 
  void sortByAddress() { llvm::sort(Symbols, llvm::less_first()); }
 
 
 
  /// Sort the lookup set lexicographically. This sort is slow but the order
 
  /// is unaffected by allocation order.
 
  void sortByName() {
 
    llvm::sort(Symbols, [](const value_type &LHS, const value_type &RHS) {
 
      return *LHS.first < *RHS.first;
 
    });
 
  }
 
 
 
  /// Remove any duplicate elements. If a SymbolLookupSet is not duplicate-free
 
  /// by construction, this method can be used to turn it into a proper set.
 
  void removeDuplicates() {
 
    sortByAddress();
 
    auto LastI = std::unique(Symbols.begin(), Symbols.end());
 
    Symbols.erase(LastI, Symbols.end());
 
  }
 
 
 
#ifndef NDEBUG
 
  /// Returns true if this set contains any duplicates. This should only be used
 
  /// in assertions.
 
  bool containsDuplicates() {
 
    if (Symbols.size() < 2)
 
      return false;
 
    sortByAddress();
 
    for (UnderlyingVector::size_type I = 1; I != Symbols.size(); ++I)
 
      if (Symbols[I].first == Symbols[I - 1].first)
 
        return true;
 
    return false;
 
  }
 
#endif
 
 
 
private:
 
  UnderlyingVector Symbols;
 
};
 
 
 
struct SymbolAliasMapEntry {
 
  SymbolAliasMapEntry() = default;
 
  SymbolAliasMapEntry(SymbolStringPtr Aliasee, JITSymbolFlags AliasFlags)
 
      : Aliasee(std::move(Aliasee)), AliasFlags(AliasFlags) {}
 
 
 
  SymbolStringPtr Aliasee;
 
  JITSymbolFlags AliasFlags;
 
};
 
 
 
/// A map of Symbols to (Symbol, Flags) pairs.
 
using SymbolAliasMap = DenseMap<SymbolStringPtr, SymbolAliasMapEntry>;
 
 
 
/// Callback to notify client that symbols have been resolved.
 
using SymbolsResolvedCallback = unique_function<void(Expected<SymbolMap>)>;
 
 
 
/// Callback to register the dependencies for a given query.
 
using RegisterDependenciesFunction =
 
    std::function<void(const SymbolDependenceMap &)>;
 
 
 
/// This can be used as the value for a RegisterDependenciesFunction if there
 
/// are no dependants to register with.
 
extern RegisterDependenciesFunction NoDependenciesToRegister;
 
 
 
class ResourceTrackerDefunct : public ErrorInfo<ResourceTrackerDefunct> {
 
public:
 
  static char ID;
 
 
 
  ResourceTrackerDefunct(ResourceTrackerSP RT);
 
  std::error_code convertToErrorCode() const override;
 
  void log(raw_ostream &OS) const override;
 
 
 
private:
 
  ResourceTrackerSP RT;
 
};
 
 
 
/// Used to notify a JITDylib that the given set of symbols failed to
 
/// materialize.
 
class FailedToMaterialize : public ErrorInfo<FailedToMaterialize> {
 
public:
 
  static char ID;
 
 
 
  FailedToMaterialize(std::shared_ptr<SymbolStringPool> SSP,
 
                      std::shared_ptr<SymbolDependenceMap> Symbols);
 
  ~FailedToMaterialize();
 
  std::error_code convertToErrorCode() const override;
 
  void log(raw_ostream &OS) const override;
 
  const SymbolDependenceMap &getSymbols() const { return *Symbols; }
 
 
 
private:
 
  std::shared_ptr<SymbolStringPool> SSP;
 
  std::shared_ptr<SymbolDependenceMap> Symbols;
 
};
 
 
 
/// Used to notify clients when symbols can not be found during a lookup.
 
class SymbolsNotFound : public ErrorInfo<SymbolsNotFound> {
 
public:
 
  static char ID;
 
 
 
  SymbolsNotFound(std::shared_ptr<SymbolStringPool> SSP, SymbolNameSet Symbols);
 
  SymbolsNotFound(std::shared_ptr<SymbolStringPool> SSP,
 
                  SymbolNameVector Symbols);
 
  std::error_code convertToErrorCode() const override;
 
  void log(raw_ostream &OS) const override;
 
  std::shared_ptr<SymbolStringPool> getSymbolStringPool() { return SSP; }
 
  const SymbolNameVector &getSymbols() const { return Symbols; }
 
 
 
private:
 
  std::shared_ptr<SymbolStringPool> SSP;
 
  SymbolNameVector Symbols;
 
};
 
 
 
/// Used to notify clients that a set of symbols could not be removed.
 
class SymbolsCouldNotBeRemoved : public ErrorInfo<SymbolsCouldNotBeRemoved> {
 
public:
 
  static char ID;
 
 
 
  SymbolsCouldNotBeRemoved(std::shared_ptr<SymbolStringPool> SSP,
 
                           SymbolNameSet Symbols);
 
  std::error_code convertToErrorCode() const override;
 
  void log(raw_ostream &OS) const override;
 
  std::shared_ptr<SymbolStringPool> getSymbolStringPool() { return SSP; }
 
  const SymbolNameSet &getSymbols() const { return Symbols; }
 
 
 
private:
 
  std::shared_ptr<SymbolStringPool> SSP;
 
  SymbolNameSet Symbols;
 
};
 
 
 
/// Errors of this type should be returned if a module fails to include
 
/// definitions that are claimed by the module's associated
 
/// MaterializationResponsibility. If this error is returned it is indicative of
 
/// a broken transformation / compiler / object cache.
 
class MissingSymbolDefinitions : public ErrorInfo<MissingSymbolDefinitions> {
 
public:
 
  static char ID;
 
 
 
  MissingSymbolDefinitions(std::shared_ptr<SymbolStringPool> SSP,
 
                           std::string ModuleName, SymbolNameVector Symbols)
 
      : SSP(std::move(SSP)), ModuleName(std::move(ModuleName)),
 
        Symbols(std::move(Symbols)) {}
 
  std::error_code convertToErrorCode() const override;
 
  void log(raw_ostream &OS) const override;
 
  std::shared_ptr<SymbolStringPool> getSymbolStringPool() { return SSP; }
 
  const std::string &getModuleName() const { return ModuleName; }
 
  const SymbolNameVector &getSymbols() const { return Symbols; }
 
private:
 
  std::shared_ptr<SymbolStringPool> SSP;
 
  std::string ModuleName;
 
  SymbolNameVector Symbols;
 
};
 
 
 
/// Errors of this type should be returned if a module contains definitions for
 
/// symbols that are not claimed by the module's associated
 
/// MaterializationResponsibility. If this error is returned it is indicative of
 
/// a broken transformation / compiler / object cache.
 
class UnexpectedSymbolDefinitions : public ErrorInfo<UnexpectedSymbolDefinitions> {
 
public:
 
  static char ID;
 
 
 
  UnexpectedSymbolDefinitions(std::shared_ptr<SymbolStringPool> SSP,
 
                              std::string ModuleName, SymbolNameVector Symbols)
 
      : SSP(std::move(SSP)), ModuleName(std::move(ModuleName)),
 
        Symbols(std::move(Symbols)) {}
 
  std::error_code convertToErrorCode() const override;
 
  void log(raw_ostream &OS) const override;
 
  std::shared_ptr<SymbolStringPool> getSymbolStringPool() { return SSP; }
 
  const std::string &getModuleName() const { return ModuleName; }
 
  const SymbolNameVector &getSymbols() const { return Symbols; }
 
private:
 
  std::shared_ptr<SymbolStringPool> SSP;
 
  std::string ModuleName;
 
  SymbolNameVector Symbols;
 
};
 
 
 
/// Tracks responsibility for materialization, and mediates interactions between
 
/// MaterializationUnits and JDs.
 
///
 
/// An instance of this class is passed to MaterializationUnits when their
 
/// materialize method is called. It allows MaterializationUnits to resolve and
 
/// emit symbols, or abandon materialization by notifying any unmaterialized
 
/// symbols of an error.
 
class MaterializationResponsibility {
 
  friend class ExecutionSession;
 
  friend class JITDylib;
 
 
 
public:
 
  MaterializationResponsibility(MaterializationResponsibility &&) = delete;
 
  MaterializationResponsibility &
 
  operator=(MaterializationResponsibility &&) = delete;
 
 
 
  /// Destruct a MaterializationResponsibility instance. In debug mode
 
  ///        this asserts that all symbols being tracked have been either
 
  ///        emitted or notified of an error.
 
  ~MaterializationResponsibility();
 
 
 
  /// Runs the given callback under the session lock, passing in the associated
 
  /// ResourceKey. This is the safe way to associate resources with trackers.
 
  template <typename Func> Error withResourceKeyDo(Func &&F) const {
 
    return RT->withResourceKeyDo(std::forward<Func>(F));
 
  }
 
 
 
  /// Returns the target JITDylib that these symbols are being materialized
 
  ///        into.
 
  JITDylib &getTargetJITDylib() const { return JD; }
 
 
 
  /// Returns the ExecutionSession for this instance.
 
  ExecutionSession &getExecutionSession() const;
 
 
 
  /// Returns the symbol flags map for this responsibility instance.
 
  /// Note: The returned flags may have transient flags (Lazy, Materializing)
 
  /// set. These should be stripped with JITSymbolFlags::stripTransientFlags
 
  /// before using.
 
  const SymbolFlagsMap &getSymbols() const { return SymbolFlags; }
 
 
 
  /// Returns the initialization pseudo-symbol, if any. This symbol will also
 
  /// be present in the SymbolFlagsMap for this MaterializationResponsibility
 
  /// object.
 
  const SymbolStringPtr &getInitializerSymbol() const { return InitSymbol; }
 
 
 
  /// Returns the names of any symbols covered by this
 
  /// MaterializationResponsibility object that have queries pending. This
 
  /// information can be used to return responsibility for unrequested symbols
 
  /// back to the JITDylib via the delegate method.
 
  SymbolNameSet getRequestedSymbols() const;
 
 
 
  /// Notifies the target JITDylib that the given symbols have been resolved.
 
  /// This will update the given symbols' addresses in the JITDylib, and notify
 
  /// any pending queries on the given symbols of their resolution. The given
 
  /// symbols must be ones covered by this MaterializationResponsibility
 
  /// instance. Individual calls to this method may resolve a subset of the
 
  /// symbols, but all symbols must have been resolved prior to calling emit.
 
  ///
 
  /// This method will return an error if any symbols being resolved have been
 
  /// moved to the error state due to the failure of a dependency. If this
 
  /// method returns an error then clients should log it and call
 
  /// failMaterialize. If no dependencies have been registered for the
 
  /// symbols covered by this MaterializationResponsibiility then this method
 
  /// is guaranteed to return Error::success() and can be wrapped with cantFail.
 
  Error notifyResolved(const SymbolMap &Symbols);
 
 
 
  /// Notifies the target JITDylib (and any pending queries on that JITDylib)
 
  /// that all symbols covered by this MaterializationResponsibility instance
 
  /// have been emitted.
 
  ///
 
  /// This method will return an error if any symbols being resolved have been
 
  /// moved to the error state due to the failure of a dependency. If this
 
  /// method returns an error then clients should log it and call
 
  /// failMaterialize. If no dependencies have been registered for the
 
  /// symbols covered by this MaterializationResponsibiility then this method
 
  /// is guaranteed to return Error::success() and can be wrapped with cantFail.
 
  Error notifyEmitted();
 
 
 
  /// Attempt to claim responsibility for new definitions. This method can be
 
  /// used to claim responsibility for symbols that are added to a
 
  /// materialization unit during the compilation process (e.g. literal pool
 
  /// symbols). Symbol linkage rules are the same as for symbols that are
 
  /// defined up front: duplicate strong definitions will result in errors.
 
  /// Duplicate weak definitions will be discarded (in which case they will
 
  /// not be added to this responsibility instance).
 
  ///
 
  ///   This method can be used by materialization units that want to add
 
  /// additional symbols at materialization time (e.g. stubs, compile
 
  /// callbacks, metadata).
 
  Error defineMaterializing(SymbolFlagsMap SymbolFlags);
 
 
 
  /// Define the given symbols as non-existent, removing it from the symbol
 
  /// table and notifying any pending queries. Queries that lookup up the
 
  /// symbol using the SymbolLookupFlags::WeaklyReferencedSymbol flag will
 
  /// behave as if the symbol had not been matched in the first place. Queries
 
  /// that required this symbol will fail with a missing symbol definition
 
  /// error.
 
  ///
 
  /// This method is intended to support cleanup of special symbols like
 
  /// initializer symbols: Queries using
 
  /// SymbolLookupFlags::WeaklyReferencedSymbol can be used to trigger their
 
  /// emission, and this method can be used to remove them from the JITDylib
 
  /// once materialization is complete.
 
  void defineNonExistent(ArrayRef<SymbolStringPtr> Symbols);
 
 
 
  /// Notify all not-yet-emitted covered by this MaterializationResponsibility
 
  /// instance that an error has occurred.
 
  /// This will remove all symbols covered by this MaterializationResponsibilty
 
  /// from the target JITDylib, and send an error to any queries waiting on
 
  /// these symbols.
 
  void failMaterialization();
 
 
 
  /// Transfers responsibility to the given MaterializationUnit for all
 
  /// symbols defined by that MaterializationUnit. This allows
 
  /// materializers to break up work based on run-time information (e.g.
 
  /// by introspecting which symbols have actually been looked up and
 
  /// materializing only those).
 
  Error replace(std::unique_ptr<MaterializationUnit> MU);
 
 
 
  /// Delegates responsibility for the given symbols to the returned
 
  /// materialization responsibility. Useful for breaking up work between
 
  /// threads, or different kinds of materialization processes.
 
  Expected<std::unique_ptr<MaterializationResponsibility>>
 
  delegate(const SymbolNameSet &Symbols);
 
 
 
  void addDependencies(const SymbolStringPtr &Name,
 
                       const SymbolDependenceMap &Dependencies);
 
 
 
  /// Add dependencies that apply to all symbols covered by this instance.
 
  void addDependenciesForAll(const SymbolDependenceMap &Dependencies);
 
 
 
private:
 
  /// Create a MaterializationResponsibility for the given JITDylib and
 
  ///        initial symbols.
 
  MaterializationResponsibility(ResourceTrackerSP RT,
 
                                SymbolFlagsMap SymbolFlags,
 
                                SymbolStringPtr InitSymbol)
 
      : JD(RT->getJITDylib()), RT(std::move(RT)),
 
        SymbolFlags(std::move(SymbolFlags)), InitSymbol(std::move(InitSymbol)) {
 
    assert(!this->SymbolFlags.empty() && "Materializing nothing?");
 
  }
 
 
 
  JITDylib &JD;
 
  ResourceTrackerSP RT;
 
  SymbolFlagsMap SymbolFlags;
 
  SymbolStringPtr InitSymbol;
 
};
 
 
 
/// A MaterializationUnit represents a set of symbol definitions that can
 
///        be materialized as a group, or individually discarded (when
 
///        overriding definitions are encountered).
 
///
 
/// MaterializationUnits are used when providing lazy definitions of symbols to
 
/// JITDylibs. The JITDylib will call materialize when the address of a symbol
 
/// is requested via the lookup method. The JITDylib will call discard if a
 
/// stronger definition is added or already present.
 
class MaterializationUnit {
 
  friend class ExecutionSession;
 
  friend class JITDylib;
 
 
 
public:
 
  static char ID;
 
 
 
  struct Interface {
 
    Interface() = default;
 
    Interface(SymbolFlagsMap InitalSymbolFlags, SymbolStringPtr InitSymbol)
 
        : SymbolFlags(std::move(InitalSymbolFlags)),
 
          InitSymbol(std::move(InitSymbol)) {
 
      assert((!this->InitSymbol || this->SymbolFlags.count(this->InitSymbol)) &&
 
             "If set, InitSymbol should appear in InitialSymbolFlags map");
 
    }
 
 
 
    SymbolFlagsMap SymbolFlags;
 
    SymbolStringPtr InitSymbol;
 
  };
 
 
 
  MaterializationUnit(Interface I)
 
      : SymbolFlags(std::move(I.SymbolFlags)),
 
        InitSymbol(std::move(I.InitSymbol)) {}
 
  virtual ~MaterializationUnit() = default;
 
 
 
  /// Return the name of this materialization unit. Useful for debugging
 
  /// output.
 
  virtual StringRef getName() const = 0;
 
 
 
  /// Return the set of symbols that this source provides.
 
  const SymbolFlagsMap &getSymbols() const { return SymbolFlags; }
 
 
 
  /// Returns the initialization symbol for this MaterializationUnit (if any).
 
  const SymbolStringPtr &getInitializerSymbol() const { return InitSymbol; }
 
 
 
  /// Implementations of this method should materialize all symbols
 
  ///        in the materialzation unit, except for those that have been
 
  ///        previously discarded.
 
  virtual void
 
  materialize(std::unique_ptr<MaterializationResponsibility> R) = 0;
 
 
 
  /// Called by JITDylibs to notify MaterializationUnits that the given symbol
 
  /// has been overridden.
 
  void doDiscard(const JITDylib &JD, const SymbolStringPtr &Name) {
 
    SymbolFlags.erase(Name);
 
    if (InitSymbol == Name) {
 
      DEBUG_WITH_TYPE("orc", {
 
        dbgs() << "In " << getName() << ": discarding init symbol \""
 
               << *Name << "\"\n";
 
      });
 
      InitSymbol = nullptr;
 
    }
 
    discard(JD, std::move(Name));
 
  }
 
 
 
protected:
 
  SymbolFlagsMap SymbolFlags;
 
  SymbolStringPtr InitSymbol;
 
 
 
private:
 
  virtual void anchor();
 
 
 
  /// Implementations of this method should discard the given symbol
 
  ///        from the source (e.g. if the source is an LLVM IR Module and the
 
  ///        symbol is a function, delete the function body or mark it available
 
  ///        externally).
 
  virtual void discard(const JITDylib &JD, const SymbolStringPtr &Name) = 0;
 
};
 
 
 
/// A MaterializationUnit implementation for pre-existing absolute symbols.
 
///
 
/// All symbols will be resolved and marked ready as soon as the unit is
 
/// materialized.
 
class AbsoluteSymbolsMaterializationUnit : public MaterializationUnit {
 
public:
 
  AbsoluteSymbolsMaterializationUnit(SymbolMap Symbols);
 
 
 
  StringRef getName() const override;
 
 
 
private:
 
  void materialize(std::unique_ptr<MaterializationResponsibility> R) override;
 
  void discard(const JITDylib &JD, const SymbolStringPtr &Name) override;
 
  static MaterializationUnit::Interface extractFlags(const SymbolMap &Symbols);
 
 
 
  SymbolMap Symbols;
 
};
 
 
 
/// Create an AbsoluteSymbolsMaterializationUnit with the given symbols.
 
/// Useful for inserting absolute symbols into a JITDylib. E.g.:
 
/// \code{.cpp}
 
///   JITDylib &JD = ...;
 
///   SymbolStringPtr Foo = ...;
 
///   JITEvaluatedSymbol FooSym = ...;
 
///   if (auto Err = JD.define(absoluteSymbols({{Foo, FooSym}})))
 
///     return Err;
 
/// \endcode
 
///
 
inline std::unique_ptr<AbsoluteSymbolsMaterializationUnit>
 
absoluteSymbols(SymbolMap Symbols) {
 
  return std::make_unique<AbsoluteSymbolsMaterializationUnit>(
 
      std::move(Symbols));
 
}
 
 
 
/// A materialization unit for symbol aliases. Allows existing symbols to be
 
/// aliased with alternate flags.
 
class ReExportsMaterializationUnit : public MaterializationUnit {
 
public:
 
  /// SourceJD is allowed to be nullptr, in which case the source JITDylib is
 
  /// taken to be whatever JITDylib these definitions are materialized in (and
 
  /// MatchNonExported has no effect). This is useful for defining aliases
 
  /// within a JITDylib.
 
  ///
 
  /// Note: Care must be taken that no sets of aliases form a cycle, as such
 
  ///       a cycle will result in a deadlock when any symbol in the cycle is
 
  ///       resolved.
 
  ReExportsMaterializationUnit(JITDylib *SourceJD,
 
                               JITDylibLookupFlags SourceJDLookupFlags,
 
                               SymbolAliasMap Aliases);
 
 
 
  StringRef getName() const override;
 
 
 
private:
 
  void materialize(std::unique_ptr<MaterializationResponsibility> R) override;
 
  void discard(const JITDylib &JD, const SymbolStringPtr &Name) override;
 
  static MaterializationUnit::Interface
 
  extractFlags(const SymbolAliasMap &Aliases);
 
 
 
  JITDylib *SourceJD = nullptr;
 
  JITDylibLookupFlags SourceJDLookupFlags;
 
  SymbolAliasMap Aliases;
 
};
 
 
 
/// Create a ReExportsMaterializationUnit with the given aliases.
 
/// Useful for defining symbol aliases.: E.g., given a JITDylib JD containing
 
/// symbols "foo" and "bar", we can define aliases "baz" (for "foo") and "qux"
 
/// (for "bar") with: \code{.cpp}
 
///   SymbolStringPtr Baz = ...;
 
///   SymbolStringPtr Qux = ...;
 
///   if (auto Err = JD.define(symbolAliases({
 
///       {Baz, { Foo, JITSymbolFlags::Exported }},
 
///       {Qux, { Bar, JITSymbolFlags::Weak }}}))
 
///     return Err;
 
/// \endcode
 
inline std::unique_ptr<ReExportsMaterializationUnit>
 
symbolAliases(SymbolAliasMap Aliases) {
 
  return std::make_unique<ReExportsMaterializationUnit>(
 
      nullptr, JITDylibLookupFlags::MatchAllSymbols, std::move(Aliases));
 
}
 
 
 
/// Create a materialization unit for re-exporting symbols from another JITDylib
 
/// with alternative names/flags.
 
/// SourceJD will be searched using the given JITDylibLookupFlags.
 
inline std::unique_ptr<ReExportsMaterializationUnit>
 
reexports(JITDylib &SourceJD, SymbolAliasMap Aliases,
 
          JITDylibLookupFlags SourceJDLookupFlags =
 
              JITDylibLookupFlags::MatchExportedSymbolsOnly) {
 
  return std::make_unique<ReExportsMaterializationUnit>(
 
      &SourceJD, SourceJDLookupFlags, std::move(Aliases));
 
}
 
 
 
/// Build a SymbolAliasMap for the common case where you want to re-export
 
/// symbols from another JITDylib with the same linkage/flags.
 
Expected<SymbolAliasMap>
 
buildSimpleReexportsAliasMap(JITDylib &SourceJD, const SymbolNameSet &Symbols);
 
 
 
/// Represents the state that a symbol has reached during materialization.
 
enum class SymbolState : uint8_t {
 
  Invalid,       /// No symbol should be in this state.
 
  NeverSearched, /// Added to the symbol table, never queried.
 
  Materializing, /// Queried, materialization begun.
 
  Resolved,      /// Assigned address, still materializing.
 
  Emitted,       /// Emitted to memory, but waiting on transitive dependencies.
 
  Ready = 0x3f   /// Ready and safe for clients to access.
 
};
 
 
 
/// A symbol query that returns results via a callback when results are
 
///        ready.
 
///
 
/// makes a callback when all symbols are available.
 
class AsynchronousSymbolQuery {
 
  friend class ExecutionSession;
 
  friend class InProgressFullLookupState;
 
  friend class JITDylib;
 
  friend class JITSymbolResolverAdapter;
 
  friend class MaterializationResponsibility;
 
 
 
public:
 
  /// Create a query for the given symbols. The NotifyComplete
 
  /// callback will be called once all queried symbols reach the given
 
  /// minimum state.
 
  AsynchronousSymbolQuery(const SymbolLookupSet &Symbols,
 
                          SymbolState RequiredState,
 
                          SymbolsResolvedCallback NotifyComplete);
 
 
 
  /// Notify the query that a requested symbol has reached the required state.
 
  void notifySymbolMetRequiredState(const SymbolStringPtr &Name,
 
                                    JITEvaluatedSymbol Sym);
 
 
 
  /// Returns true if all symbols covered by this query have been
 
  ///        resolved.
 
  bool isComplete() const { return OutstandingSymbolsCount == 0; }
 
 
 
 
 
private:
 
  void handleComplete(ExecutionSession &ES);
 
 
 
  SymbolState getRequiredState() { return RequiredState; }
 
 
 
  void addQueryDependence(JITDylib &JD, SymbolStringPtr Name);
 
 
 
  void removeQueryDependence(JITDylib &JD, const SymbolStringPtr &Name);
 
 
 
  void dropSymbol(const SymbolStringPtr &Name);
 
 
 
  void handleFailed(Error Err);
 
 
 
  void detach();
 
 
 
  SymbolsResolvedCallback NotifyComplete;
 
  SymbolDependenceMap QueryRegistrations;
 
  SymbolMap ResolvedSymbols;
 
  size_t OutstandingSymbolsCount;
 
  SymbolState RequiredState;
 
};
 
 
 
/// Wraps state for a lookup-in-progress.
 
/// DefinitionGenerators can optionally take ownership of a LookupState object
 
/// to suspend a lookup-in-progress while they search for definitions.
 
class LookupState {
 
  friend class OrcV2CAPIHelper;
 
  friend class ExecutionSession;
 
 
 
public:
 
  LookupState();
 
  LookupState(LookupState &&);
 
  LookupState &operator=(LookupState &&);
 
  ~LookupState();
 
 
 
  /// Continue the lookup. This can be called by DefinitionGenerators
 
  /// to re-start a captured query-application operation.
 
  void continueLookup(Error Err);
 
 
 
private:
 
  LookupState(std::unique_ptr<InProgressLookupState> IPLS);
 
 
 
  // For C API.
 
  void reset(InProgressLookupState *IPLS);
 
 
 
  std::unique_ptr<InProgressLookupState> IPLS;
 
};
 
 
 
/// Definition generators can be attached to JITDylibs to generate new
 
/// definitions for otherwise unresolved symbols during lookup.
 
class DefinitionGenerator {
 
public:
 
  virtual ~DefinitionGenerator();
 
 
 
  /// DefinitionGenerators should override this method to insert new
 
  /// definitions into the parent JITDylib. K specifies the kind of this
 
  /// lookup. JD specifies the target JITDylib being searched, and
 
  /// JDLookupFlags specifies whether the search should match against
 
  /// hidden symbols. Finally, Symbols describes the set of unresolved
 
  /// symbols and their associated lookup flags.
 
  virtual Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD,
 
                              JITDylibLookupFlags JDLookupFlags,
 
                              const SymbolLookupSet &LookupSet) = 0;
 
};
 
 
 
/// Represents a JIT'd dynamic library.
 
///
 
/// This class aims to mimic the behavior of a regular dylib or shared object,
 
/// but without requiring the contained program representations to be compiled
 
/// up-front. The JITDylib's content is defined by adding MaterializationUnits,
 
/// and contained MaterializationUnits will typically rely on the JITDylib's
 
/// links-against order to resolve external references (similar to a regular
 
/// dylib).
 
///
 
/// The JITDylib object is a thin wrapper that references state held by the
 
/// ExecutionSession. JITDylibs can be removed, clearing this underlying state
 
/// and leaving the JITDylib object in a defunct state. In this state the
 
/// JITDylib's name is guaranteed to remain accessible. If the ExecutionSession
 
/// is still alive then other operations are callable but will return an Error
 
/// or null result (depending on the API). It is illegal to call any operation
 
/// other than getName on a JITDylib after the ExecutionSession has been torn
 
/// down.
 
///
 
/// JITDylibs cannot be moved or copied. Their address is stable, and useful as
 
/// a key in some JIT data structures.
 
class JITDylib : public ThreadSafeRefCountedBase<JITDylib>,
 
                 public jitlink::JITLinkDylib {
 
  friend class AsynchronousSymbolQuery;
 
  friend class ExecutionSession;
 
  friend class Platform;
 
  friend class MaterializationResponsibility;
 
public:
 
 
 
  JITDylib(const JITDylib &) = delete;
 
  JITDylib &operator=(const JITDylib &) = delete;
 
  JITDylib(JITDylib &&) = delete;
 
  JITDylib &operator=(JITDylib &&) = delete;
 
  ~JITDylib();
 
 
 
  /// Get a reference to the ExecutionSession for this JITDylib.
 
  ///
 
  /// It is legal to call this method on a defunct JITDylib, however the result
 
  /// will only usable if the ExecutionSession is still alive. If this JITDylib
 
  /// is held by an error that may have torn down the JIT then the result
 
  /// should not be used.
 
  ExecutionSession &getExecutionSession() const { return ES; }
 
 
 
  /// Dump current JITDylib state to OS.
 
  ///
 
  /// It is legal to call this method on a defunct JITDylib.
 
  void dump(raw_ostream &OS);
 
 
 
  /// Calls remove on all trackers currently associated with this JITDylib.
 
  /// Does not run static deinits.
 
  ///
 
  /// Note that removal happens outside the session lock, so new code may be
 
  /// added concurrently while the clear is underway, and the newly added
 
  /// code will *not* be cleared. Adding new code concurrently with a clear
 
  /// is usually a bug and should be avoided.
 
  ///
 
  /// It is illegal to call this method on a defunct JITDylib and the client
 
  /// is responsible for ensuring that they do not do so.
 
  Error clear();
 
 
 
  /// Get the default resource tracker for this JITDylib.
 
  ///
 
  /// It is illegal to call this method on a defunct JITDylib and the client
 
  /// is responsible for ensuring that they do not do so.
 
  ResourceTrackerSP getDefaultResourceTracker();
 
 
 
  /// Create a resource tracker for this JITDylib.
 
  ///
 
  /// It is illegal to call this method on a defunct JITDylib and the client
 
  /// is responsible for ensuring that they do not do so.
 
  ResourceTrackerSP createResourceTracker();
 
 
 
  /// Adds a definition generator to this JITDylib and returns a referenece to
 
  /// it.
 
  ///
 
  /// When JITDylibs are searched during lookup, if no existing definition of
 
  /// a symbol is found, then any generators that have been added are run (in
 
  /// the order that they were added) to potentially generate a definition.
 
  ///
 
  /// It is illegal to call this method on a defunct JITDylib and the client
 
  /// is responsible for ensuring that they do not do so.
 
  template <typename GeneratorT>
 
  GeneratorT &addGenerator(std::unique_ptr<GeneratorT> DefGenerator);
 
 
 
  /// Remove a definition generator from this JITDylib.
 
  ///
 
  /// The given generator must exist in this JITDylib's generators list (i.e.
 
  /// have been added and not yet removed).
 
  ///
 
  /// It is illegal to call this method on a defunct JITDylib and the client
 
  /// is responsible for ensuring that they do not do so.
 
  void removeGenerator(DefinitionGenerator &G);
 
 
 
  /// Set the link order to be used when fixing up definitions in JITDylib.
 
  /// This will replace the previous link order, and apply to any symbol
 
  /// resolutions made for definitions in this JITDylib after the call to
 
  /// setLinkOrder (even if the definition itself was added before the
 
  /// call).
 
  ///
 
  /// If LinkAgainstThisJITDylibFirst is true (the default) then this JITDylib
 
  /// will add itself to the beginning of the LinkOrder (Clients should not
 
  /// put this JITDylib in the list in this case, to avoid redundant lookups).
 
  ///
 
  /// If LinkAgainstThisJITDylibFirst is false then the link order will be used
 
  /// as-is. The primary motivation for this feature is to support deliberate
 
  /// shadowing of symbols in this JITDylib by a facade JITDylib. For example,
 
  /// the facade may resolve function names to stubs, and the stubs may compile
 
  /// lazily by looking up symbols in this dylib. Adding the facade dylib
 
  /// as the first in the link order (instead of this dylib) ensures that
 
  /// definitions within this dylib resolve to the lazy-compiling stubs,
 
  /// rather than immediately materializing the definitions in this dylib.
 
  ///
 
  /// It is illegal to call this method on a defunct JITDylib and the client
 
  /// is responsible for ensuring that they do not do so.
 
  void setLinkOrder(JITDylibSearchOrder NewSearchOrder,
 
                    bool LinkAgainstThisJITDylibFirst = true);
 
 
 
  /// Add the given JITDylib to the link order for definitions in this
 
  /// JITDylib.
 
  ///
 
  /// It is illegal to call this method on a defunct JITDylib and the client
 
  /// is responsible for ensuring that they do not do so.
 
  void addToLinkOrder(JITDylib &JD,
 
                      JITDylibLookupFlags JDLookupFlags =
 
                          JITDylibLookupFlags::MatchExportedSymbolsOnly);
 
 
 
  /// Replace OldJD with NewJD in the link order if OldJD is present.
 
  /// Otherwise this operation is a no-op.
 
  ///
 
  /// It is illegal to call this method on a defunct JITDylib and the client
 
  /// is responsible for ensuring that they do not do so.
 
  void replaceInLinkOrder(JITDylib &OldJD, JITDylib &NewJD,
 
                          JITDylibLookupFlags JDLookupFlags =
 
                              JITDylibLookupFlags::MatchExportedSymbolsOnly);
 
 
 
  /// Remove the given JITDylib from the link order for this JITDylib if it is
 
  /// present. Otherwise this operation is a no-op.
 
  ///
 
  /// It is illegal to call this method on a defunct JITDylib and the client
 
  /// is responsible for ensuring that they do not do so.
 
  void removeFromLinkOrder(JITDylib &JD);
 
 
 
  /// Do something with the link order (run under the session lock).
 
  ///
 
  /// It is illegal to call this method on a defunct JITDylib and the client
 
  /// is responsible for ensuring that they do not do so.
 
  template <typename Func>
 
  auto withLinkOrderDo(Func &&F)
 
      -> decltype(F(std::declval<const JITDylibSearchOrder &>()));
 
 
 
  /// Define all symbols provided by the materialization unit to be part of this
 
  /// JITDylib.
 
  ///
 
  /// If RT is not specified then the default resource tracker will be used.
 
  ///
 
  /// This overload always takes ownership of the MaterializationUnit. If any
 
  /// errors occur, the MaterializationUnit consumed.
 
  ///
 
  /// It is illegal to call this method on a defunct JITDylib and the client
 
  /// is responsible for ensuring that they do not do so.
 
  template <typename MaterializationUnitType>
 
  Error define(std::unique_ptr<MaterializationUnitType> &&MU,
 
               ResourceTrackerSP RT = nullptr);
 
 
 
  /// Define all symbols provided by the materialization unit to be part of this
 
  /// JITDylib.
 
  ///
 
  /// This overload only takes ownership of the MaterializationUnit no error is
 
  /// generated. If an error occurs, ownership remains with the caller. This
 
  /// may allow the caller to modify the MaterializationUnit to correct the
 
  /// issue, then re-call define.
 
  ///
 
  /// It is illegal to call this method on a defunct JITDylib and the client
 
  /// is responsible for ensuring that they do not do so.
 
  template <typename MaterializationUnitType>
 
  Error define(std::unique_ptr<MaterializationUnitType> &MU,
 
               ResourceTrackerSP RT = nullptr);
 
 
 
  /// Tries to remove the given symbols.
 
  ///
 
  /// If any symbols are not defined in this JITDylib this method will return
 
  /// a SymbolsNotFound error covering the missing symbols.
 
  ///
 
  /// If all symbols are found but some symbols are in the process of being
 
  /// materialized this method will return a SymbolsCouldNotBeRemoved error.
 
  ///
 
  /// On success, all symbols are removed. On failure, the JITDylib state is
 
  /// left unmodified (no symbols are removed).
 
  ///
 
  /// It is illegal to call this method on a defunct JITDylib and the client
 
  /// is responsible for ensuring that they do not do so.
 
  Error remove(const SymbolNameSet &Names);
 
 
 
  /// Returns the given JITDylibs and all of their transitive dependencies in
 
  /// DFS order (based on linkage relationships). Each JITDylib will appear
 
  /// only once.
 
  ///
 
  /// If any JITDylib in the order is defunct then this method will return an
 
  /// error, otherwise returns the order.
 
  static Expected<std::vector<JITDylibSP>>
 
  getDFSLinkOrder(ArrayRef<JITDylibSP> JDs);
 
 
 
  /// Returns the given JITDylibs and all of their transitive dependencies in
 
  /// reverse DFS order (based on linkage relationships). Each JITDylib will
 
  /// appear only once.
 
  ///
 
  /// If any JITDylib in the order is defunct then this method will return an
 
  /// error, otherwise returns the order.
 
  static Expected<std::vector<JITDylibSP>>
 
  getReverseDFSLinkOrder(ArrayRef<JITDylibSP> JDs);
 
 
 
  /// Return this JITDylib and its transitive dependencies in DFS order
 
  /// based on linkage relationships.
 
  ///
 
  /// If any JITDylib in the order is defunct then this method will return an
 
  /// error, otherwise returns the order.
 
  Expected<std::vector<JITDylibSP>> getDFSLinkOrder();
 
 
 
  /// Rteurn this JITDylib and its transitive dependencies in reverse DFS order
 
  /// based on linkage relationships.
 
  ///
 
  /// If any JITDylib in the order is defunct then this method will return an
 
  /// error, otherwise returns the order.
 
  Expected<std::vector<JITDylibSP>> getReverseDFSLinkOrder();
 
 
 
private:
 
  using AsynchronousSymbolQuerySet =
 
    std::set<std::shared_ptr<AsynchronousSymbolQuery>>;
 
 
 
  using AsynchronousSymbolQueryList =
 
      std::vector<std::shared_ptr<AsynchronousSymbolQuery>>;
 
 
 
  struct UnmaterializedInfo {
 
    UnmaterializedInfo(std::unique_ptr<MaterializationUnit> MU,
 
                       ResourceTracker *RT)
 
        : MU(std::move(MU)), RT(RT) {}
 
 
 
    std::unique_ptr<MaterializationUnit> MU;
 
    ResourceTracker *RT;
 
  };
 
 
 
  using UnmaterializedInfosMap =
 
      DenseMap<SymbolStringPtr, std::shared_ptr<UnmaterializedInfo>>;
 
 
 
  using UnmaterializedInfosList =
 
      std::vector<std::shared_ptr<UnmaterializedInfo>>;
 
 
 
  struct MaterializingInfo {
 
    SymbolDependenceMap Dependants;
 
    SymbolDependenceMap UnemittedDependencies;
 
 
 
    void addQuery(std::shared_ptr<AsynchronousSymbolQuery> Q);
 
    void removeQuery(const AsynchronousSymbolQuery &Q);
 
    AsynchronousSymbolQueryList takeQueriesMeeting(SymbolState RequiredState);
 
    AsynchronousSymbolQueryList takeAllPendingQueries() {
 
      return std::move(PendingQueries);
 
    }
 
    bool hasQueriesPending() const { return !PendingQueries.empty(); }
 
    const AsynchronousSymbolQueryList &pendingQueries() const {
 
      return PendingQueries;
 
    }
 
  private:
 
    AsynchronousSymbolQueryList PendingQueries;
 
  };
 
 
 
  using MaterializingInfosMap = DenseMap<SymbolStringPtr, MaterializingInfo>;
 
 
 
  class SymbolTableEntry {
 
  public:
 
    SymbolTableEntry() = default;
 
    SymbolTableEntry(JITSymbolFlags Flags)
 
        : Flags(Flags), State(static_cast<uint8_t>(SymbolState::NeverSearched)),
 
          MaterializerAttached(false), PendingRemoval(false) {}
 
 
 
    JITTargetAddress getAddress() const { return Addr; }
 
    JITSymbolFlags getFlags() const { return Flags; }
 
    SymbolState getState() const { return static_cast<SymbolState>(State); }
 
 
 
    bool hasMaterializerAttached() const { return MaterializerAttached; }
 
    bool isPendingRemoval() const { return PendingRemoval; }
 
 
 
    void setAddress(JITTargetAddress Addr) { this->Addr = Addr; }
 
    void setFlags(JITSymbolFlags Flags) { this->Flags = Flags; }
 
    void setState(SymbolState State) {
 
      assert(static_cast<uint8_t>(State) < (1 << 6) &&
 
             "State does not fit in bitfield");
 
      this->State = static_cast<uint8_t>(State);
 
    }
 
 
 
    void setMaterializerAttached(bool MaterializerAttached) {
 
      this->MaterializerAttached = MaterializerAttached;
 
    }
 
 
 
    void setPendingRemoval(bool PendingRemoval) {
 
      this->PendingRemoval = PendingRemoval;
 
    }
 
 
 
    JITEvaluatedSymbol getSymbol() const {
 
      return JITEvaluatedSymbol(Addr, Flags);
 
    }
 
 
 
  private:
 
    JITTargetAddress Addr = 0;
 
    JITSymbolFlags Flags;
 
    uint8_t State : 6;
 
    uint8_t MaterializerAttached : 1;
 
    uint8_t PendingRemoval : 1;
 
  };
 
 
 
  using SymbolTable = DenseMap<SymbolStringPtr, SymbolTableEntry>;
 
 
 
  JITDylib(ExecutionSession &ES, std::string Name);
 
 
 
  std::pair<AsynchronousSymbolQuerySet, std::shared_ptr<SymbolDependenceMap>>
 
  removeTracker(ResourceTracker &RT);
 
 
 
  void transferTracker(ResourceTracker &DstRT, ResourceTracker &SrcRT);
 
 
 
  Error defineImpl(MaterializationUnit &MU);
 
 
 
  void installMaterializationUnit(std::unique_ptr<MaterializationUnit> MU,
 
                                  ResourceTracker &RT);
 
 
 
  void detachQueryHelper(AsynchronousSymbolQuery &Q,
 
                         const SymbolNameSet &QuerySymbols);
 
 
 
  void transferEmittedNodeDependencies(MaterializingInfo &DependantMI,
 
                                       const SymbolStringPtr &DependantName,
 
                                       MaterializingInfo &EmittedMI);
 
 
 
  Expected<SymbolFlagsMap> defineMaterializing(SymbolFlagsMap SymbolFlags);
 
 
 
  Error replace(MaterializationResponsibility &FromMR,
 
                std::unique_ptr<MaterializationUnit> MU);
 
 
 
  Expected<std::unique_ptr<MaterializationResponsibility>>
 
  delegate(MaterializationResponsibility &FromMR, SymbolFlagsMap SymbolFlags,
 
           SymbolStringPtr InitSymbol);
 
 
 
  SymbolNameSet getRequestedSymbols(const SymbolFlagsMap &SymbolFlags) const;
 
 
 
  void addDependencies(const SymbolStringPtr &Name,
 
                       const SymbolDependenceMap &Dependants);
 
 
 
  Error resolve(MaterializationResponsibility &MR, const SymbolMap &Resolved);
 
 
 
  Error emit(MaterializationResponsibility &MR, const SymbolFlagsMap &Emitted);
 
 
 
  void unlinkMaterializationResponsibility(MaterializationResponsibility &MR);
 
 
 
  using FailedSymbolsWorklist =
 
      std::vector<std::pair<JITDylib *, SymbolStringPtr>>;
 
 
 
  static std::pair<AsynchronousSymbolQuerySet,
 
                   std::shared_ptr<SymbolDependenceMap>>
 
      failSymbols(FailedSymbolsWorklist);
 
 
 
  ExecutionSession &ES;
 
  enum { Open, Closing, Closed } State = Open;
 
  std::mutex GeneratorsMutex;
 
  SymbolTable Symbols;
 
  UnmaterializedInfosMap UnmaterializedInfos;
 
  MaterializingInfosMap MaterializingInfos;
 
  std::vector<std::shared_ptr<DefinitionGenerator>> DefGenerators;
 
  JITDylibSearchOrder LinkOrder;
 
  ResourceTrackerSP DefaultTracker;
 
 
 
  // Map trackers to sets of symbols tracked.
 
  DenseMap<ResourceTracker *, SymbolNameVector> TrackerSymbols;
 
  DenseMap<ResourceTracker *, DenseSet<MaterializationResponsibility *>>
 
      TrackerMRs;
 
};
 
 
 
/// Platforms set up standard symbols and mediate interactions between dynamic
 
/// initializers (e.g. C++ static constructors) and ExecutionSession state.
 
/// Note that Platforms do not automatically run initializers: clients are still
 
/// responsible for doing this.
 
class Platform {
 
public:
 
  virtual ~Platform();
 
 
 
  /// This method will be called outside the session lock each time a JITDylib
 
  /// is created (unless it is created with EmptyJITDylib set) to allow the
 
  /// Platform to install any JITDylib specific standard symbols (e.g
 
  /// __dso_handle).
 
  virtual Error setupJITDylib(JITDylib &JD) = 0;
 
 
 
  /// This method will be called outside the session lock each time a JITDylib
 
  /// is removed to allow the Platform to remove any JITDylib-specific data.
 
  virtual Error teardownJITDylib(JITDylib &JD) = 0;
 
 
 
  /// This method will be called under the ExecutionSession lock each time a
 
  /// MaterializationUnit is added to a JITDylib.
 
  virtual Error notifyAdding(ResourceTracker &RT,
 
                             const MaterializationUnit &MU) = 0;
 
 
 
  /// This method will be called under the ExecutionSession lock when a
 
  /// ResourceTracker is removed.
 
  virtual Error notifyRemoving(ResourceTracker &RT) = 0;
 
 
 
  /// A utility function for looking up initializer symbols. Performs a blocking
 
  /// lookup for the given symbols in each of the given JITDylibs.
 
  ///
 
  /// Note: This function is deprecated and will be removed in the near future.
 
  static Expected<DenseMap<JITDylib *, SymbolMap>>
 
  lookupInitSymbols(ExecutionSession &ES,
 
                    const DenseMap<JITDylib *, SymbolLookupSet> &InitSyms);
 
 
 
  /// Performs an async lookup for the given symbols in each of the given
 
  /// JITDylibs, calling the given handler once all lookups have completed.
 
  static void
 
  lookupInitSymbolsAsync(unique_function<void(Error)> OnComplete,
 
                         ExecutionSession &ES,
 
                         const DenseMap<JITDylib *, SymbolLookupSet> &InitSyms);
 
};
 
 
 
/// A materialization task.
 
class MaterializationTask : public RTTIExtends<MaterializationTask, Task> {
 
public:
 
  static char ID;
 
 
 
  MaterializationTask(std::unique_ptr<MaterializationUnit> MU,
 
                      std::unique_ptr<MaterializationResponsibility> MR)
 
      : MU(std::move(MU)), MR(std::move(MR)) {}
 
  void printDescription(raw_ostream &OS) override;
 
  void run() override;
 
 
 
private:
 
  std::unique_ptr<MaterializationUnit> MU;
 
  std::unique_ptr<MaterializationResponsibility> MR;
 
};
 
 
 
/// An ExecutionSession represents a running JIT program.
 
class ExecutionSession {
 
  friend class InProgressLookupFlagsState;
 
  friend class InProgressFullLookupState;
 
  friend class JITDylib;
 
  friend class LookupState;
 
  friend class MaterializationResponsibility;
 
  friend class ResourceTracker;
 
 
 
public:
 
  /// For reporting errors.
 
  using ErrorReporter = std::function<void(Error)>;
 
 
 
  /// Send a result to the remote.
 
  using SendResultFunction = unique_function<void(shared::WrapperFunctionResult)>;
 
 
 
  /// For dispatching ORC tasks (typically materialization tasks).
 
  using DispatchTaskFunction = unique_function<void(std::unique_ptr<Task> T)>;
 
 
 
  /// An asynchronous wrapper-function callable from the executor via
 
  /// jit-dispatch.
 
  using JITDispatchHandlerFunction = unique_function<void(
 
      SendResultFunction SendResult,
 
      const char *ArgData, size_t ArgSize)>;
 
 
 
  /// A map associating tag names with asynchronous wrapper function
 
  /// implementations in the JIT.
 
  using JITDispatchHandlerAssociationMap =
 
      DenseMap<SymbolStringPtr, JITDispatchHandlerFunction>;
 
 
 
  /// Construct an ExecutionSession with the given ExecutorProcessControl
 
  /// object.
 
  ExecutionSession(std::unique_ptr<ExecutorProcessControl> EPC);
 
 
 
  /// Destroy an ExecutionSession. Verifies that endSession was called prior to
 
  /// destruction.
 
  ~ExecutionSession();
 
 
 
  /// End the session. Closes all JITDylibs and disconnects from the
 
  /// executor. Clients must call this method before destroying the session.
 
  Error endSession();
 
 
 
  /// Get the ExecutorProcessControl object associated with this
 
  /// ExecutionSession.
 
  ExecutorProcessControl &getExecutorProcessControl() { return *EPC; }
 
 
 
  /// Get the SymbolStringPool for this instance.
 
  std::shared_ptr<SymbolStringPool> getSymbolStringPool() {
 
    return EPC->getSymbolStringPool();
 
  }
 
 
 
  /// Add a symbol name to the SymbolStringPool and return a pointer to it.
 
  SymbolStringPtr intern(StringRef SymName) { return EPC->intern(SymName); }
 
 
 
  /// Set the Platform for this ExecutionSession.
 
  void setPlatform(std::unique_ptr<Platform> P) { this->P = std::move(P); }
 
 
 
  /// Get the Platform for this session.
 
  /// Will return null if no Platform has been set for this ExecutionSession.
 
  Platform *getPlatform() { return P.get(); }
 
 
 
  /// Run the given lambda with the session mutex locked.
 
  template <typename Func> decltype(auto) runSessionLocked(Func &&F) {
 
    std::lock_guard<std::recursive_mutex> Lock(SessionMutex);
 
    return F();
 
  }
 
 
 
  /// Register the given ResourceManager with this ExecutionSession.
 
  /// Managers will be notified of events in reverse order of registration.
 
  void registerResourceManager(ResourceManager &RM);
 
 
 
  /// Deregister the given ResourceManager with this ExecutionSession.
 
  /// Manager must have been previously registered.
 
  void deregisterResourceManager(ResourceManager &RM);
 
 
 
  /// Return a pointer to the "name" JITDylib.
 
  /// Ownership of JITDylib remains within Execution Session
 
  JITDylib *getJITDylibByName(StringRef Name);
 
 
 
  /// Add a new bare JITDylib to this ExecutionSession.
 
  ///
 
  /// The JITDylib Name is required to be unique. Clients should verify that
 
  /// names are not being re-used (E.g. by calling getJITDylibByName) if names
 
  /// are based on user input.
 
  ///
 
  /// This call does not install any library code or symbols into the newly
 
  /// created JITDylib. The client is responsible for all configuration.
 
  JITDylib &createBareJITDylib(std::string Name);
 
 
 
  /// Add a new JITDylib to this ExecutionSession.
 
  ///
 
  /// The JITDylib Name is required to be unique. Clients should verify that
 
  /// names are not being re-used (e.g. by calling getJITDylibByName) if names
 
  /// are based on user input.
 
  ///
 
  /// If a Platform is attached then Platform::setupJITDylib will be called to
 
  /// install standard platform symbols (e.g. standard library interposes).
 
  /// If no Platform is attached this call is equivalent to createBareJITDylib.
 
  Expected<JITDylib &> createJITDylib(std::string Name);
 
 
 
  /// Closes the given JITDylib.
 
  ///
 
  /// This method clears all resources held for the JITDylib, puts it in the
 
  /// closed state, and clears all references held by the ExecutionSession and
 
  /// other JITDylibs. No further code can be added to the JITDylib, and the
 
  /// object will be freed once any remaining JITDylibSPs to it are destroyed.
 
  ///
 
  /// This method does *not* run static destructors.
 
  ///
 
  /// This method can only be called once for each JITDylib.
 
  Error removeJITDylib(JITDylib &JD);
 
 
 
  /// Set the error reporter function.
 
  ExecutionSession &setErrorReporter(ErrorReporter ReportError) {
 
    this->ReportError = std::move(ReportError);
 
    return *this;
 
  }
 
 
 
  /// Report a error for this execution session.
 
  ///
 
  /// Unhandled errors can be sent here to log them.
 
  void reportError(Error Err) { ReportError(std::move(Err)); }
 
 
 
  /// Set the task dispatch function.
 
  ExecutionSession &setDispatchTask(DispatchTaskFunction DispatchTask) {
 
    this->DispatchTask = std::move(DispatchTask);
 
    return *this;
 
  }
 
 
 
  /// Search the given JITDylibs to find the flags associated with each of the
 
  /// given symbols.
 
  void lookupFlags(LookupKind K, JITDylibSearchOrder SearchOrder,
 
                   SymbolLookupSet Symbols,
 
                   unique_function<void(Expected<SymbolFlagsMap>)> OnComplete);
 
 
 
  /// Blocking version of lookupFlags.
 
  Expected<SymbolFlagsMap> lookupFlags(LookupKind K,
 
                                       JITDylibSearchOrder SearchOrder,
 
                                       SymbolLookupSet Symbols);
 
 
 
  /// Search the given JITDylibs for the given symbols.
 
  ///
 
  /// SearchOrder lists the JITDylibs to search. For each dylib, the associated
 
  /// boolean indicates whether the search should match against non-exported
 
  /// (hidden visibility) symbols in that dylib (true means match against
 
  /// non-exported symbols, false means do not match).
 
  ///
 
  /// The NotifyComplete callback will be called once all requested symbols
 
  /// reach the required state.
 
  ///
 
  /// If all symbols are found, the RegisterDependencies function will be called
 
  /// while the session lock is held. This gives clients a chance to register
 
  /// dependencies for on the queried symbols for any symbols they are
 
  /// materializing (if a MaterializationResponsibility instance is present,
 
  /// this can be implemented by calling
 
  /// MaterializationResponsibility::addDependencies). If there are no
 
  /// dependenant symbols for this query (e.g. it is being made by a top level
 
  /// client to get an address to call) then the value NoDependenciesToRegister
 
  /// can be used.
 
  void lookup(LookupKind K, const JITDylibSearchOrder &SearchOrder,
 
              SymbolLookupSet Symbols, SymbolState RequiredState,
 
              SymbolsResolvedCallback NotifyComplete,
 
              RegisterDependenciesFunction RegisterDependencies);
 
 
 
  /// Blocking version of lookup above. Returns the resolved symbol map.
 
  /// If WaitUntilReady is true (the default), will not return until all
 
  /// requested symbols are ready (or an error occurs). If WaitUntilReady is
 
  /// false, will return as soon as all requested symbols are resolved,
 
  /// or an error occurs. If WaitUntilReady is false and an error occurs
 
  /// after resolution, the function will return a success value, but the
 
  /// error will be reported via reportErrors.
 
  Expected<SymbolMap> lookup(const JITDylibSearchOrder &SearchOrder,
 
                             SymbolLookupSet Symbols,
 
                             LookupKind K = LookupKind::Static,
 
                             SymbolState RequiredState = SymbolState::Ready,
 
                             RegisterDependenciesFunction RegisterDependencies =
 
                                 NoDependenciesToRegister);
 
 
 
  /// Convenience version of blocking lookup.
 
  /// Searches each of the JITDylibs in the search order in turn for the given
 
  /// symbol.
 
  Expected<JITEvaluatedSymbol>
 
  lookup(const JITDylibSearchOrder &SearchOrder, SymbolStringPtr Symbol,
 
         SymbolState RequiredState = SymbolState::Ready);
 
 
 
  /// Convenience version of blocking lookup.
 
  /// Searches each of the JITDylibs in the search order in turn for the given
 
  /// symbol. The search will not find non-exported symbols.
 
  Expected<JITEvaluatedSymbol>
 
  lookup(ArrayRef<JITDylib *> SearchOrder, SymbolStringPtr Symbol,
 
         SymbolState RequiredState = SymbolState::Ready);
 
 
 
  /// Convenience version of blocking lookup.
 
  /// Searches each of the JITDylibs in the search order in turn for the given
 
  /// symbol. The search will not find non-exported symbols.
 
  Expected<JITEvaluatedSymbol>
 
  lookup(ArrayRef<JITDylib *> SearchOrder, StringRef Symbol,
 
         SymbolState RequiredState = SymbolState::Ready);
 
 
 
  /// Materialize the given unit.
 
  void dispatchTask(std::unique_ptr<Task> T) {
 
    assert(T && "T must be non-null");
 
    DEBUG_WITH_TYPE("orc", dumpDispatchInfo(*T));
 
    DispatchTask(std::move(T));
 
  }
 
 
 
  /// Run a wrapper function in the executor.
 
  ///
 
  /// The wrapper function should be callable as:
 
  ///
 
  /// \code{.cpp}
 
  ///   CWrapperFunctionResult fn(uint8_t *Data, uint64_t Size);
 
  /// \endcode{.cpp}
 
  ///
 
  /// The given OnComplete function will be called to return the result.
 
  template <typename... ArgTs>
 
  void callWrapperAsync(ArgTs &&... Args) {
 
    EPC->callWrapperAsync(std::forward<ArgTs>(Args)...);
 
  }
 
 
 
  /// Run a wrapper function in the executor. The wrapper function should be
 
  /// callable as:
 
  ///
 
  /// \code{.cpp}
 
  ///   CWrapperFunctionResult fn(uint8_t *Data, uint64_t Size);
 
  /// \endcode{.cpp}
 
  shared::WrapperFunctionResult callWrapper(ExecutorAddr WrapperFnAddr,
 
                                            ArrayRef<char> ArgBuffer) {
 
    return EPC->callWrapper(WrapperFnAddr, ArgBuffer);
 
  }
 
 
 
  /// Run a wrapper function using SPS to serialize the arguments and
 
  /// deserialize the results.
 
  template <typename SPSSignature, typename SendResultT, typename... ArgTs>
 
  void callSPSWrapperAsync(ExecutorAddr WrapperFnAddr, SendResultT &&SendResult,
 
                           const ArgTs &...Args) {
 
    EPC->callSPSWrapperAsync<SPSSignature, SendResultT, ArgTs...>(
 
        WrapperFnAddr, std::forward<SendResultT>(SendResult), Args...);
 
  }
 
 
 
  /// Run a wrapper function using SPS to serialize the arguments and
 
  /// deserialize the results.
 
  ///
 
  /// If SPSSignature is a non-void function signature then the second argument
 
  /// (the first in the Args list) should be a reference to a return value.
 
  template <typename SPSSignature, typename... WrapperCallArgTs>
 
  Error callSPSWrapper(ExecutorAddr WrapperFnAddr,
 
                       WrapperCallArgTs &&...WrapperCallArgs) {
 
    return EPC->callSPSWrapper<SPSSignature, WrapperCallArgTs...>(
 
        WrapperFnAddr, std::forward<WrapperCallArgTs>(WrapperCallArgs)...);
 
  }
 
 
 
  /// Wrap a handler that takes concrete argument types (and a sender for a
 
  /// concrete return type) to produce an AsyncHandlerWrapperFunction. Uses SPS
 
  /// to unpack the arguments and pack the result.
 
  ///
 
  /// This function is intended to support easy construction of
 
  /// AsyncHandlerWrapperFunctions that can be associated with a tag
 
  /// (using registerJITDispatchHandler) and called from the executor.
 
  template <typename SPSSignature, typename HandlerT>
 
  static JITDispatchHandlerFunction wrapAsyncWithSPS(HandlerT &&H) {
 
    return [H = std::forward<HandlerT>(H)](
 
               SendResultFunction SendResult,
 
               const char *ArgData, size_t ArgSize) mutable {
 
      shared::WrapperFunction<SPSSignature>::handleAsync(ArgData, ArgSize, H,
 
                                                         std::move(SendResult));
 
    };
 
  }
 
 
 
  /// Wrap a class method that takes concrete argument types (and a sender for
 
  /// a concrete return type) to produce an AsyncHandlerWrapperFunction. Uses
 
  /// SPS to unpack teh arguments and pack the result.
 
  ///
 
  /// This function is intended to support easy construction of
 
  /// AsyncHandlerWrapperFunctions that can be associated with a tag
 
  /// (using registerJITDispatchHandler) and called from the executor.
 
  template <typename SPSSignature, typename ClassT, typename... MethodArgTs>
 
  static JITDispatchHandlerFunction
 
  wrapAsyncWithSPS(ClassT *Instance, void (ClassT::*Method)(MethodArgTs...)) {
 
    return wrapAsyncWithSPS<SPSSignature>(
 
        [Instance, Method](MethodArgTs &&...MethodArgs) {
 
          (Instance->*Method)(std::forward<MethodArgTs>(MethodArgs)...);
 
        });
 
  }
 
 
 
  /// For each tag symbol name, associate the corresponding
 
  /// AsyncHandlerWrapperFunction with the address of that symbol. The
 
  /// handler becomes callable from the executor using the ORC runtime
 
  /// __orc_rt_jit_dispatch function and the given tag.
 
  ///
 
  /// Tag symbols will be looked up in JD using LookupKind::Static,
 
  /// JITDylibLookupFlags::MatchAllSymbols (hidden tags will be found), and
 
  /// LookupFlags::WeaklyReferencedSymbol. Missing tag definitions will not
 
  /// cause an error, the handler will simply be dropped.
 
  Error registerJITDispatchHandlers(JITDylib &JD,
 
                                    JITDispatchHandlerAssociationMap WFs);
 
 
 
  /// Run a registered jit-side wrapper function.
 
  /// This should be called by the ExecutorProcessControl instance in response
 
  /// to incoming jit-dispatch requests from the executor.
 
  void
 
  runJITDispatchHandler(SendResultFunction SendResult,
 
                        JITTargetAddress HandlerFnTagAddr,
 
                        ArrayRef<char> ArgBuffer);
 
 
 
  /// Dump the state of all the JITDylibs in this session.
 
  void dump(raw_ostream &OS);
 
 
 
private:
 
  static void logErrorsToStdErr(Error Err) {
 
    logAllUnhandledErrors(std::move(Err), errs(), "JIT session error: ");
 
  }
 
 
 
  static void runOnCurrentThread(std::unique_ptr<Task> T) { T->run(); }
 
 
 
  void dispatchOutstandingMUs();
 
 
 
  static std::unique_ptr<MaterializationResponsibility>
 
  createMaterializationResponsibility(ResourceTracker &RT,
 
                                      SymbolFlagsMap Symbols,
 
                                      SymbolStringPtr InitSymbol) {
 
    auto &JD = RT.getJITDylib();
 
    std::unique_ptr<MaterializationResponsibility> MR(
 
        new MaterializationResponsibility(&RT, std::move(Symbols),
 
                                          std::move(InitSymbol)));
 
    JD.TrackerMRs[&RT].insert(MR.get());
 
    return MR;
 
  }
 
 
 
  Error removeResourceTracker(ResourceTracker &RT);
 
  void transferResourceTracker(ResourceTracker &DstRT, ResourceTracker &SrcRT);
 
  void destroyResourceTracker(ResourceTracker &RT);
 
 
 
  // State machine functions for query application..
 
 
 
  /// IL_updateCandidatesFor is called to remove already-defined symbols that
 
  /// match a given query from the set of candidate symbols to generate
 
  /// definitions for (no need to generate a definition if one already exists).
 
  Error IL_updateCandidatesFor(JITDylib &JD, JITDylibLookupFlags JDLookupFlags,
 
                               SymbolLookupSet &Candidates,
 
                               SymbolLookupSet *NonCandidates);
 
 
 
  /// OL_applyQueryPhase1 is an optionally re-startable loop for triggering
 
  /// definition generation. It is called when a lookup is performed, and again
 
  /// each time that LookupState::continueLookup is called.
 
  void OL_applyQueryPhase1(std::unique_ptr<InProgressLookupState> IPLS,
 
                           Error Err);
 
 
 
  /// OL_completeLookup is run once phase 1 successfully completes for a lookup
 
  /// call. It attempts to attach the symbol to all symbol table entries and
 
  /// collect all MaterializationUnits to dispatch. If this method fails then
 
  /// all MaterializationUnits will be left un-materialized.
 
  void OL_completeLookup(std::unique_ptr<InProgressLookupState> IPLS,
 
                         std::shared_ptr<AsynchronousSymbolQuery> Q,
 
                         RegisterDependenciesFunction RegisterDependencies);
 
 
 
  /// OL_completeLookupFlags is run once phase 1 successfully completes for a
 
  /// lookupFlags call.
 
  void OL_completeLookupFlags(
 
      std::unique_ptr<InProgressLookupState> IPLS,
 
      unique_function<void(Expected<SymbolFlagsMap>)> OnComplete);
 
 
 
  // State machine functions for MaterializationResponsibility.
 
  void OL_destroyMaterializationResponsibility(
 
      MaterializationResponsibility &MR);
 
  SymbolNameSet OL_getRequestedSymbols(const MaterializationResponsibility &MR);
 
  Error OL_notifyResolved(MaterializationResponsibility &MR,
 
                          const SymbolMap &Symbols);
 
  Error OL_notifyEmitted(MaterializationResponsibility &MR);
 
  Error OL_defineMaterializing(MaterializationResponsibility &MR,
 
                               SymbolFlagsMap SymbolFlags);
 
  void OL_notifyFailed(MaterializationResponsibility &MR);
 
  Error OL_replace(MaterializationResponsibility &MR,
 
                   std::unique_ptr<MaterializationUnit> MU);
 
  Expected<std::unique_ptr<MaterializationResponsibility>>
 
  OL_delegate(MaterializationResponsibility &MR, const SymbolNameSet &Symbols);
 
  void OL_addDependencies(MaterializationResponsibility &MR,
 
                          const SymbolStringPtr &Name,
 
                          const SymbolDependenceMap &Dependencies);
 
  void OL_addDependenciesForAll(MaterializationResponsibility &MR,
 
                                const SymbolDependenceMap &Dependencies);
 
 
 
#ifndef NDEBUG
 
  void dumpDispatchInfo(Task &T);
 
#endif // NDEBUG
 
 
 
  mutable std::recursive_mutex SessionMutex;
 
  bool SessionOpen = true;
 
  std::unique_ptr<ExecutorProcessControl> EPC;
 
  std::unique_ptr<Platform> P;
 
  ErrorReporter ReportError = logErrorsToStdErr;
 
  DispatchTaskFunction DispatchTask = runOnCurrentThread;
 
 
 
  std::vector<ResourceManager *> ResourceManagers;
 
 
 
  std::vector<JITDylibSP> JDs;
 
 
 
  // FIXME: Remove this (and runOutstandingMUs) once the linking layer works
 
  //        with callbacks from asynchronous queries.
 
  mutable std::recursive_mutex OutstandingMUsMutex;
 
  std::vector<std::pair<std::unique_ptr<MaterializationUnit>,
 
                        std::unique_ptr<MaterializationResponsibility>>>
 
      OutstandingMUs;
 
 
 
  mutable std::mutex JITDispatchHandlersMutex;
 
  DenseMap<JITTargetAddress, std::shared_ptr<JITDispatchHandlerFunction>>
 
      JITDispatchHandlers;
 
};
 
 
 
template <typename Func> Error ResourceTracker::withResourceKeyDo(Func &&F) {
 
  return getJITDylib().getExecutionSession().runSessionLocked([&]() -> Error {
 
    if (isDefunct())
 
      return make_error<ResourceTrackerDefunct>(this);
 
    F(getKeyUnsafe());
 
    return Error::success();
 
  });
 
}
 
 
 
inline ExecutionSession &
 
MaterializationResponsibility::getExecutionSession() const {
 
  return JD.getExecutionSession();
 
}
 
 
 
template <typename GeneratorT>
 
GeneratorT &JITDylib::addGenerator(std::unique_ptr<GeneratorT> DefGenerator) {
 
  auto &G = *DefGenerator;
 
  ES.runSessionLocked([&] {
 
    assert(State == Open && "Cannot add generator to closed JITDylib");
 
    DefGenerators.push_back(std::move(DefGenerator));
 
  });
 
  return G;
 
}
 
 
 
template <typename Func>
 
auto JITDylib::withLinkOrderDo(Func &&F)
 
    -> decltype(F(std::declval<const JITDylibSearchOrder &>())) {
 
  assert(State == Open && "Cannot use link order of closed JITDylib");
 
  return ES.runSessionLocked([&]() { return F(LinkOrder); });
 
}
 
 
 
template <typename MaterializationUnitType>
 
Error JITDylib::define(std::unique_ptr<MaterializationUnitType> &&MU,
 
                       ResourceTrackerSP RT) {
 
  assert(MU && "Can not define with a null MU");
 
 
 
  if (MU->getSymbols().empty()) {
 
    // Empty MUs are allowable but pathological, so issue a warning.
 
    DEBUG_WITH_TYPE("orc", {
 
      dbgs() << "Warning: Discarding empty MU " << MU->getName() << " for "
 
             << getName() << "\n";
 
    });
 
    return Error::success();
 
  } else
 
    DEBUG_WITH_TYPE("orc", {
 
      dbgs() << "Defining MU " << MU->getName() << " for " << getName()
 
             << " (tracker: ";
 
      if (RT == getDefaultResourceTracker())
 
        dbgs() << "default)";
 
      else if (RT)
 
        dbgs() << RT.get() << ")\n";
 
      else
 
        dbgs() << "0x0, default will be used)\n";
 
    });
 
 
 
  return ES.runSessionLocked([&, this]() -> Error {
 
    assert(State == Open && "JD is defunct");
 
 
 
    if (auto Err = defineImpl(*MU))
 
      return Err;
 
 
 
    if (!RT)
 
      RT = getDefaultResourceTracker();
 
 
 
    if (auto *P = ES.getPlatform()) {
 
      if (auto Err = P->notifyAdding(*RT, *MU))
 
        return Err;
 
    }
 
 
 
    installMaterializationUnit(std::move(MU), *RT);
 
    return Error::success();
 
  });
 
}
 
 
 
template <typename MaterializationUnitType>
 
Error JITDylib::define(std::unique_ptr<MaterializationUnitType> &MU,
 
                       ResourceTrackerSP RT) {
 
  assert(MU && "Can not define with a null MU");
 
 
 
  if (MU->getSymbols().empty()) {
 
    // Empty MUs are allowable but pathological, so issue a warning.
 
    DEBUG_WITH_TYPE("orc", {
 
      dbgs() << "Warning: Discarding empty MU " << MU->getName() << getName()
 
             << "\n";
 
    });
 
    return Error::success();
 
  } else
 
    DEBUG_WITH_TYPE("orc", {
 
      dbgs() << "Defining MU " << MU->getName() << " for " << getName()
 
             << " (tracker: ";
 
      if (RT == getDefaultResourceTracker())
 
        dbgs() << "default)";
 
      else if (RT)
 
        dbgs() << RT.get() << ")\n";
 
      else
 
        dbgs() << "0x0, default will be used)\n";
 
    });
 
 
 
  return ES.runSessionLocked([&, this]() -> Error {
 
    assert(State == Open && "JD is defunct");
 
 
 
    if (auto Err = defineImpl(*MU))
 
      return Err;
 
 
 
    if (!RT)
 
      RT = getDefaultResourceTracker();
 
 
 
    if (auto *P = ES.getPlatform()) {
 
      if (auto Err = P->notifyAdding(*RT, *MU))
 
        return Err;
 
    }
 
 
 
    installMaterializationUnit(std::move(MU), *RT);
 
    return Error::success();
 
  });
 
}
 
 
 
/// ReexportsGenerator can be used with JITDylib::addGenerator to automatically
 
/// re-export a subset of the source JITDylib's symbols in the target.
 
class ReexportsGenerator : public DefinitionGenerator {
 
public:
 
  using SymbolPredicate = std::function<bool(SymbolStringPtr)>;
 
 
 
  /// Create a reexports generator. If an Allow predicate is passed, only
 
  /// symbols for which the predicate returns true will be reexported. If no
 
  /// Allow predicate is passed, all symbols will be exported.
 
  ReexportsGenerator(JITDylib &SourceJD,
 
                     JITDylibLookupFlags SourceJDLookupFlags,
 
                     SymbolPredicate Allow = SymbolPredicate());
 
 
 
  Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD,
 
                      JITDylibLookupFlags JDLookupFlags,
 
                      const SymbolLookupSet &LookupSet) override;
 
 
 
private:
 
  JITDylib &SourceJD;
 
  JITDylibLookupFlags SourceJDLookupFlags;
 
  SymbolPredicate Allow;
 
};
 
 
 
// --------------- IMPLEMENTATION --------------
 
// Implementations for inline functions/methods.
 
// ---------------------------------------------
 
 
 
inline MaterializationResponsibility::~MaterializationResponsibility() {
 
  getExecutionSession().OL_destroyMaterializationResponsibility(*this);
 
}
 
 
 
inline SymbolNameSet MaterializationResponsibility::getRequestedSymbols() const {
 
  return getExecutionSession().OL_getRequestedSymbols(*this);
 
}
 
 
 
inline Error MaterializationResponsibility::notifyResolved(
 
    const SymbolMap &Symbols) {
 
  return getExecutionSession().OL_notifyResolved(*this, Symbols);
 
}
 
 
 
inline Error MaterializationResponsibility::notifyEmitted() {
 
  return getExecutionSession().OL_notifyEmitted(*this);
 
}
 
 
 
inline Error MaterializationResponsibility::defineMaterializing(
 
    SymbolFlagsMap SymbolFlags) {
 
  return getExecutionSession().OL_defineMaterializing(*this,
 
                                                      std::move(SymbolFlags));
 
}
 
 
 
inline void MaterializationResponsibility::failMaterialization() {
 
  getExecutionSession().OL_notifyFailed(*this);
 
}
 
 
 
inline Error MaterializationResponsibility::replace(
 
    std::unique_ptr<MaterializationUnit> MU) {
 
  return getExecutionSession().OL_replace(*this, std::move(MU));
 
}
 
 
 
inline Expected<std::unique_ptr<MaterializationResponsibility>>
 
MaterializationResponsibility::delegate(const SymbolNameSet &Symbols) {
 
  return getExecutionSession().OL_delegate(*this, Symbols);
 
}
 
 
 
inline void MaterializationResponsibility::addDependencies(
 
    const SymbolStringPtr &Name, const SymbolDependenceMap &Dependencies) {
 
  getExecutionSession().OL_addDependencies(*this, Name, Dependencies);
 
}
 
 
 
inline void MaterializationResponsibility::addDependenciesForAll(
 
    const SymbolDependenceMap &Dependencies) {
 
  getExecutionSession().OL_addDependenciesForAll(*this, Dependencies);
 
}
 
 
 
} // End namespace orc
 
} // End namespace llvm
 
 
 
#endif // LLVM_EXECUTIONENGINE_ORC_CORE_H