//===- CompileOnDemandLayer.h - Compile each function on demand -*- 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
//
//===----------------------------------------------------------------------===//
//
// JIT layer for breaking up modules and inserting callbacks to allow
// individual functions to be compiled on demand.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_EXECUTIONENGINE_ORC_COMPILEONDEMANDLAYER_H
#define LLVM_EXECUTIONENGINE_ORC_COMPILEONDEMANDLAYER_H

#include "llvm/ADT/APInt.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ExecutionEngine/JITSymbol.h"
#include "llvm/ExecutionEngine/Orc/IndirectionUtils.h"
#include "llvm/ExecutionEngine/Orc/LambdaResolver.h"
#include "llvm/ExecutionEngine/Orc/Layer.h"
#include "llvm/ExecutionEngine/Orc/LazyReexports.h"
#include "llvm/ExecutionEngine/Orc/Legacy.h"
#include "llvm/ExecutionEngine/Orc/OrcError.h"
#include "llvm/ExecutionEngine/Orc/Speculation.h"
#include "llvm/ExecutionEngine/RuntimeDyld.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalAlias.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Mangler.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Utils/ValueMapper.h"
#include <algorithm>
#include <cassert>
#include <functional>
#include <iterator>
#include <list>
#include <memory>
#include <set>
#include <string>
#include <utility>
#include <vector>

namespace llvm {

class Value;

namespace orc {

class ExtractingIRMaterializationUnit;

class CompileOnDemandLayer : public IRLayer {
  friend class PartitioningIRMaterializationUnit;

public:
  /// Builder for IndirectStubsManagers.
  using IndirectStubsManagerBuilder =
      std::function<std::unique_ptr<IndirectStubsManager>()>;

  using GlobalValueSet = std::set<const GlobalValue *>;

  /// Partitioning function.
  using PartitionFunction =
      std::function<Optional<GlobalValueSet>(GlobalValueSet Requested)>;

  /// Off-the-shelf partitioning which compiles all requested symbols (usually
  /// a single function at a time).
  static Optional<GlobalValueSet> compileRequested(GlobalValueSet Requested);

  /// Off-the-shelf partitioning which compiles whole modules whenever any
  /// symbol in them is requested.
  static Optional<GlobalValueSet> compileWholeModule(GlobalValueSet Requested);

  /// Construct a CompileOnDemandLayer.
  CompileOnDemandLayer(ExecutionSession &ES, IRLayer &BaseLayer,
                        LazyCallThroughManager &LCTMgr,
                        IndirectStubsManagerBuilder BuildIndirectStubsManager);

  /// Sets the partition function.
  void setPartitionFunction(PartitionFunction Partition);

  /// Sets the ImplSymbolMap
  void setImplMap(ImplSymbolMap *Imp);

  /// Emits the given module. This should not be called by clients: it will be
  /// called by the JIT when a definition added via the add method is requested.
  void emit(MaterializationResponsibility R, ThreadSafeModule TSM) override;

private:
  struct PerDylibResources {
  public:
    PerDylibResources(JITDylib &ImplD,
                      std::unique_ptr<IndirectStubsManager> ISMgr)
        : ImplD(ImplD), ISMgr(std::move(ISMgr)) {}
    JITDylib &getImplDylib() { return ImplD; }
    IndirectStubsManager &getISManager() { return *ISMgr; }

  private:
    JITDylib &ImplD;
    std::unique_ptr<IndirectStubsManager> ISMgr;
  };

  using PerDylibResourcesMap = std::map<const JITDylib *, PerDylibResources>;

  PerDylibResources &getPerDylibResources(JITDylib &TargetD);

  void cleanUpModule(Module &M);

  void expandPartition(GlobalValueSet &Partition);

  void emitPartition(MaterializationResponsibility R, ThreadSafeModule TSM,
                     IRMaterializationUnit::SymbolNameToDefinitionMap Defs);

  mutable std::mutex CODLayerMutex;

  IRLayer &BaseLayer;
  LazyCallThroughManager &LCTMgr;
  IndirectStubsManagerBuilder BuildIndirectStubsManager;
  PerDylibResourcesMap DylibResources;
  PartitionFunction Partition = compileRequested;
  SymbolLinkagePromoter PromoteSymbols;
  ImplSymbolMap *AliaseeImpls = nullptr;
};

/// Compile-on-demand layer.
///
///   When a module is added to this layer a stub is created for each of its
/// function definitions. The stubs and other global values are immediately
/// added to the layer below. When a stub is called it triggers the extraction
/// of the function body from the original module. The extracted body is then
/// compiled and executed.
template <typename BaseLayerT,
          typename CompileCallbackMgrT = JITCompileCallbackManager,
          typename IndirectStubsMgrT = IndirectStubsManager>
class LegacyCompileOnDemandLayer {
private:
  template <typename MaterializerFtor>
  class LambdaMaterializer final : public ValueMaterializer {
  public:
    LambdaMaterializer(MaterializerFtor M) : M(std::move(M)) {}

    Value *materialize(Value *V) final { return M(V); }

  private:
    MaterializerFtor M;
  };

  template <typename MaterializerFtor>
  LambdaMaterializer<MaterializerFtor>
  createLambdaMaterializer(MaterializerFtor M) {
    return LambdaMaterializer<MaterializerFtor>(std::move(M));
  }

  // Provide type-erasure for the Modules and MemoryManagers.
  template <typename ResourceT>
  class ResourceOwner {
  public:
    ResourceOwner() = default;
    ResourceOwner(const ResourceOwner &) = delete;
    ResourceOwner &operator=(const ResourceOwner &) = delete;
    virtual ~ResourceOwner() = default;

    virtual ResourceT& getResource() const = 0;
  };

  template <typename ResourceT, typename ResourcePtrT>
  class ResourceOwnerImpl : public ResourceOwner<ResourceT> {
  public:
    ResourceOwnerImpl(ResourcePtrT ResourcePtr)
      : ResourcePtr(std::move(ResourcePtr)) {}

    ResourceT& getResource() const override { return *ResourcePtr; }

  private:
    ResourcePtrT ResourcePtr;
  };

  template <typename ResourceT, typename ResourcePtrT>
  std::unique_ptr<ResourceOwner<ResourceT>>
  wrapOwnership(ResourcePtrT ResourcePtr) {
    using RO = ResourceOwnerImpl<ResourceT, ResourcePtrT>;
    return std::make_unique<RO>(std::move(ResourcePtr));
  }

  struct LogicalDylib {
    struct SourceModuleEntry {
      std::unique_ptr<Module> SourceMod;
      std::set<Function*> StubsToClone;
    };

    using SourceModulesList = std::vector<SourceModuleEntry>;
    using SourceModuleHandle = typename SourceModulesList::size_type;

    LogicalDylib() = default;

    LogicalDylib(VModuleKey K, std::shared_ptr<SymbolResolver> BackingResolver,
                 std::unique_ptr<IndirectStubsMgrT> StubsMgr)
        : K(std::move(K)), BackingResolver(std::move(BackingResolver)),
          StubsMgr(std::move(StubsMgr)) {}

    SourceModuleHandle addSourceModule(std::unique_ptr<Module> M) {
      SourceModuleHandle H = SourceModules.size();
      SourceModules.push_back(SourceModuleEntry());
      SourceModules.back().SourceMod = std::move(M);
      return H;
    }

    Module& getSourceModule(SourceModuleHandle H) {
      return *SourceModules[H].SourceMod;
    }

    std::set<Function*>& getStubsToClone(SourceModuleHandle H) {
      return SourceModules[H].StubsToClone;
    }

    JITSymbol findSymbol(BaseLayerT &BaseLayer, const std::string &Name,
                         bool ExportedSymbolsOnly) {
      if (auto Sym = StubsMgr->findStub(Name, ExportedSymbolsOnly))
        return Sym;
      for (auto BLK : BaseLayerVModuleKeys)
        if (auto Sym = BaseLayer.findSymbolIn(BLK, Name, ExportedSymbolsOnly))
          return Sym;
        else if (auto Err = Sym.takeError())
          return std::move(Err);
      return nullptr;
    }

    Error removeModulesFromBaseLayer(BaseLayerT &BaseLayer) {
      for (auto &BLK : BaseLayerVModuleKeys)
        if (auto Err = BaseLayer.removeModule(BLK))
          return Err;
      return Error::success();
    }

    VModuleKey K;
    std::shared_ptr<SymbolResolver> BackingResolver;
    std::unique_ptr<IndirectStubsMgrT> StubsMgr;
    SymbolLinkagePromoter PromoteSymbols;
    SourceModulesList SourceModules;
    std::vector<VModuleKey> BaseLayerVModuleKeys;
  };

public:

  /// Module partitioning functor.
  using PartitioningFtor = std::function<std::set<Function*>(Function&)>;

  /// Builder for IndirectStubsManagers.
  using IndirectStubsManagerBuilderT =
      std::function<std::unique_ptr<IndirectStubsMgrT>()>;

  using SymbolResolverGetter =
      std::function<std::shared_ptr<SymbolResolver>(VModuleKey K)>;

  using SymbolResolverSetter =
      std::function<void(VModuleKey K, std::shared_ptr<SymbolResolver> R)>;

  /// Construct a compile-on-demand layer instance.
  LLVM_ATTRIBUTE_DEPRECATED(
      LegacyCompileOnDemandLayer(
          ExecutionSession &ES, BaseLayerT &BaseLayer,
          SymbolResolverGetter GetSymbolResolver,
          SymbolResolverSetter SetSymbolResolver, PartitioningFtor Partition,
          CompileCallbackMgrT &CallbackMgr,
          IndirectStubsManagerBuilderT CreateIndirectStubsManager,
          bool CloneStubsIntoPartitions = true),
      "ORCv1 layers (layers with the 'Legacy' prefix) are deprecated. Please "
      "use "
      "the ORCv2 LegacyCompileOnDemandLayer instead");

  /// Legacy layer constructor with deprecation acknowledgement.
  LegacyCompileOnDemandLayer(
      ORCv1DeprecationAcknowledgement, ExecutionSession &ES,
      BaseLayerT &BaseLayer, SymbolResolverGetter GetSymbolResolver,
      SymbolResolverSetter SetSymbolResolver, PartitioningFtor Partition,
      CompileCallbackMgrT &CallbackMgr,
      IndirectStubsManagerBuilderT CreateIndirectStubsManager,
      bool CloneStubsIntoPartitions = true)
      : ES(ES), BaseLayer(BaseLayer),
        GetSymbolResolver(std::move(GetSymbolResolver)),
        SetSymbolResolver(std::move(SetSymbolResolver)),
        Partition(std::move(Partition)), CompileCallbackMgr(CallbackMgr),
        CreateIndirectStubsManager(std::move(CreateIndirectStubsManager)),
        CloneStubsIntoPartitions(CloneStubsIntoPartitions) {}

  ~LegacyCompileOnDemandLayer() {
    // FIXME: Report error on log.
    while (!LogicalDylibs.empty())
      consumeError(removeModule(LogicalDylibs.begin()->first));
  }

  /// Add a module to the compile-on-demand layer.
  Error addModule(VModuleKey K, std::unique_ptr<Module> M) {

    assert(!LogicalDylibs.count(K) && "VModuleKey K already in use");
    auto I = LogicalDylibs.insert(
        LogicalDylibs.end(),
        std::make_pair(K, LogicalDylib(K, GetSymbolResolver(K),
                                       CreateIndirectStubsManager())));

    return addLogicalModule(I->second, std::move(M));
  }

  /// Add extra modules to an existing logical module.
  Error addExtraModule(VModuleKey K, std::unique_ptr<Module> M) {
    return addLogicalModule(LogicalDylibs[K], std::move(M));
  }

  /// Remove the module represented by the given key.
  ///
  ///   This will remove all modules in the layers below that were derived from
  /// the module represented by K.
  Error removeModule(VModuleKey K) {
    auto I = LogicalDylibs.find(K);
    assert(I != LogicalDylibs.end() && "VModuleKey K not valid here");
    auto Err = I->second.removeModulesFromBaseLayer(BaseLayer);
    LogicalDylibs.erase(I);
    return Err;
  }

  /// Search for the given named symbol.
  /// @param Name The name of the symbol to search for.
  /// @param ExportedSymbolsOnly If true, search only for exported symbols.
  /// @return A handle for the given named symbol, if it exists.
  JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
    for (auto &KV : LogicalDylibs) {
      if (auto Sym = KV.second.StubsMgr->findStub(Name, ExportedSymbolsOnly))
        return Sym;
      if (auto Sym =
              findSymbolIn(KV.first, std::string(Name), ExportedSymbolsOnly))
        return Sym;
      else if (auto Err = Sym.takeError())
        return std::move(Err);
    }
    return BaseLayer.findSymbol(std::string(Name), ExportedSymbolsOnly);
  }

  /// Get the address of a symbol provided by this layer, or some layer
  ///        below this one.
  JITSymbol findSymbolIn(VModuleKey K, const std::string &Name,
                         bool ExportedSymbolsOnly) {
    assert(LogicalDylibs.count(K) && "VModuleKey K is not valid here");
    return LogicalDylibs[K].findSymbol(BaseLayer, Name, ExportedSymbolsOnly);
  }

  /// Update the stub for the given function to point at FnBodyAddr.
  /// This can be used to support re-optimization.
  /// @return true if the function exists and the stub is updated, false
  ///         otherwise.
  //
  // FIXME: We should track and free associated resources (unused compile
  //        callbacks, uncompiled IR, and no-longer-needed/reachable function
  //        implementations).
  Error updatePointer(std::string FuncName, JITTargetAddress FnBodyAddr) {
    //Find out which logical dylib contains our symbol
    auto LDI = LogicalDylibs.begin();
    for (auto LDE = LogicalDylibs.end(); LDI != LDE; ++LDI) {
      if (auto LMResources =
            LDI->getLogicalModuleResourcesForSymbol(FuncName, false)) {
        Module &SrcM = LMResources->SourceModule->getResource();
        std::string CalledFnName = mangle(FuncName, SrcM.getDataLayout());
        if (auto Err = LMResources->StubsMgr->updatePointer(CalledFnName,
                                                            FnBodyAddr))
          return Err;
        return Error::success();
      }
    }
    return make_error<JITSymbolNotFound>(FuncName);
  }

private:
  Error addLogicalModule(LogicalDylib &LD, std::unique_ptr<Module> SrcMPtr) {

    // Rename anonymous globals and promote linkage to ensure that everything
    // will resolve properly after we partition SrcM.
    LD.PromoteSymbols(*SrcMPtr);

    // Create a logical module handle for SrcM within the logical dylib.
    Module &SrcM = *SrcMPtr;
    auto LMId = LD.addSourceModule(std::move(SrcMPtr));

    // Create stub functions.
    const DataLayout &DL = SrcM.getDataLayout();

    typename IndirectStubsMgrT::StubInitsMap StubInits;
    for (auto &F : SrcM) {
      // Skip declarations.
      if (F.isDeclaration())
        continue;

      // Skip weak functions for which we already have definitions.
      auto MangledName = mangle(F.getName(), DL);
      if (F.hasWeakLinkage() || F.hasLinkOnceLinkage()) {
        if (auto Sym = LD.findSymbol(BaseLayer, MangledName, false))
          continue;
        else if (auto Err = Sym.takeError())
          return Err;
      }

      // Record all functions defined by this module.
      if (CloneStubsIntoPartitions)
        LD.getStubsToClone(LMId).insert(&F);

      // Create a callback, associate it with the stub for the function,
      // and set the compile action to compile the partition containing the
      // function.
      auto CompileAction = [this, &LD, LMId, &F]() -> JITTargetAddress {
        if (auto FnImplAddrOrErr = this->extractAndCompile(LD, LMId, F))
          return *FnImplAddrOrErr;
        else {
          // FIXME: Report error, return to 'abort' or something similar.
          consumeError(FnImplAddrOrErr.takeError());
          return 0;
        }
      };
      if (auto CCAddr =
              CompileCallbackMgr.getCompileCallback(std::move(CompileAction)))
        StubInits[MangledName] =
            std::make_pair(*CCAddr, JITSymbolFlags::fromGlobalValue(F));
      else
        return CCAddr.takeError();
    }

    if (auto Err = LD.StubsMgr->createStubs(StubInits))
      return Err;

    // If this module doesn't contain any globals, aliases, or module flags then
    // we can bail out early and avoid the overhead of creating and managing an
    // empty globals module.
    if (SrcM.global_empty() && SrcM.alias_empty() &&
        !SrcM.getModuleFlagsMetadata())
      return Error::success();

    // Create the GlobalValues module.
    auto GVsM = std::make_unique<Module>((SrcM.getName() + ".globals").str(),
                                          SrcM.getContext());
    GVsM->setDataLayout(DL);

    ValueToValueMapTy VMap;

    // Clone global variable decls.
    for (auto &GV : SrcM.globals())
      if (!GV.isDeclaration() && !VMap.count(&GV))
        cloneGlobalVariableDecl(*GVsM, GV, &VMap);

    // And the aliases.
    for (auto &A : SrcM.aliases())
      if (!VMap.count(&A))
        cloneGlobalAliasDecl(*GVsM, A, VMap);

    // Clone the module flags.
    cloneModuleFlagsMetadata(*GVsM, SrcM, VMap);

    // Now we need to clone the GV and alias initializers.

    // Initializers may refer to functions declared (but not defined) in this
    // module. Build a materializer to clone decls on demand.
    auto Materializer = createLambdaMaterializer(
      [&LD, &GVsM](Value *V) -> Value* {
        if (auto *F = dyn_cast<Function>(V)) {
          // Decls in the original module just get cloned.
          if (F->isDeclaration())
            return cloneFunctionDecl(*GVsM, *F);

          // Definitions in the original module (which we have emitted stubs
          // for at this point) get turned into a constant alias to the stub
          // instead.
          const DataLayout &DL = GVsM->getDataLayout();
          std::string FName = mangle(F->getName(), DL);
          unsigned PtrBitWidth = DL.getPointerTypeSizeInBits(F->getType());
          JITTargetAddress StubAddr =
            LD.StubsMgr->findStub(FName, false).getAddress();

          ConstantInt *StubAddrCI =
            ConstantInt::get(GVsM->getContext(), APInt(PtrBitWidth, StubAddr));
          Constant *Init = ConstantExpr::getCast(Instruction::IntToPtr,
                                                 StubAddrCI, F->getType());
          return GlobalAlias::create(F->getFunctionType(),
                                     F->getType()->getAddressSpace(),
                                     F->getLinkage(), F->getName(),
                                     Init, GVsM.get());
        }
        // else....
        return nullptr;
      });

    // Clone the global variable initializers.
    for (auto &GV : SrcM.globals())
      if (!GV.isDeclaration())
        moveGlobalVariableInitializer(GV, VMap, &Materializer);

    // Clone the global alias initializers.
    for (auto &A : SrcM.aliases()) {
      auto *NewA = cast<GlobalAlias>(VMap[&A]);
      assert(NewA && "Alias not cloned?");
      Value *Init = MapValue(A.getAliasee(), VMap, RF_None, nullptr,
                             &Materializer);
      NewA->setAliasee(cast<Constant>(Init));
    }

    // Build a resolver for the globals module and add it to the base layer.
    auto LegacyLookup = [this, &LD](StringRef Name) -> JITSymbol {
      if (auto Sym = LD.StubsMgr->findStub(Name, false))
        return Sym;

      if (auto Sym = LD.findSymbol(BaseLayer, std::string(Name), false))
        return Sym;
      else if (auto Err = Sym.takeError())
        return std::move(Err);

      return nullptr;
    };

    auto GVsResolver = createSymbolResolver(
        [&LD, LegacyLookup](const SymbolNameSet &Symbols) {
          auto RS = getResponsibilitySetWithLegacyFn(Symbols, LegacyLookup);

          if (!RS) {
            logAllUnhandledErrors(
                RS.takeError(), errs(),
                "CODLayer/GVsResolver responsibility set lookup failed: ");
            return SymbolNameSet();
          }

          if (RS->size() == Symbols.size())
            return *RS;

          SymbolNameSet NotFoundViaLegacyLookup;
          for (auto &S : Symbols)
            if (!RS->count(S))
              NotFoundViaLegacyLookup.insert(S);
          auto RS2 =
              LD.BackingResolver->getResponsibilitySet(NotFoundViaLegacyLookup);

          for (auto &S : RS2)
            (*RS).insert(S);

          return *RS;
        },
        [this, &LD,
         LegacyLookup](std::shared_ptr<AsynchronousSymbolQuery> Query,
                       SymbolNameSet Symbols) {
          auto NotFoundViaLegacyLookup =
              lookupWithLegacyFn(ES, *Query, Symbols, LegacyLookup);
          return LD.BackingResolver->lookup(Query, NotFoundViaLegacyLookup);
        });

    SetSymbolResolver(LD.K, std::move(GVsResolver));

    if (auto Err = BaseLayer.addModule(LD.K, std::move(GVsM)))
      return Err;

    LD.BaseLayerVModuleKeys.push_back(LD.K);

    return Error::success();
  }

  static std::string mangle(StringRef Name, const DataLayout &DL) {
    std::string MangledName;
    {
      raw_string_ostream MangledNameStream(MangledName);
      Mangler::getNameWithPrefix(MangledNameStream, Name, DL);
    }
    return MangledName;
  }

  Expected<JITTargetAddress>
  extractAndCompile(LogicalDylib &LD,
                    typename LogicalDylib::SourceModuleHandle LMId,
                    Function &F) {
    Module &SrcM = LD.getSourceModule(LMId);

    // If F is a declaration we must already have compiled it.
    if (F.isDeclaration())
      return 0;

    // Grab the name of the function being called here.
    std::string CalledFnName = mangle(F.getName(), SrcM.getDataLayout());

    JITTargetAddress CalledAddr = 0;
    auto Part = Partition(F);
    if (auto PartKeyOrErr = emitPartition(LD, LMId, Part)) {
      auto &PartKey = *PartKeyOrErr;
      for (auto *SubF : Part) {
        std::string FnName = mangle(SubF->getName(), SrcM.getDataLayout());
        if (auto FnBodySym = BaseLayer.findSymbolIn(PartKey, FnName, false)) {
          if (auto FnBodyAddrOrErr = FnBodySym.getAddress()) {
            JITTargetAddress FnBodyAddr = *FnBodyAddrOrErr;

            // If this is the function we're calling record the address so we can
            // return it from this function.
            if (SubF == &F)
              CalledAddr = FnBodyAddr;

            // Update the function body pointer for the stub.
            if (auto EC = LD.StubsMgr->updatePointer(FnName, FnBodyAddr))
              return 0;

          } else
            return FnBodyAddrOrErr.takeError();
        } else if (auto Err = FnBodySym.takeError())
          return std::move(Err);
        else
          llvm_unreachable("Function not emitted for partition");
      }

      LD.BaseLayerVModuleKeys.push_back(PartKey);
    } else
      return PartKeyOrErr.takeError();

    return CalledAddr;
  }

  template <typename PartitionT>
  Expected<VModuleKey>
  emitPartition(LogicalDylib &LD,
                typename LogicalDylib::SourceModuleHandle LMId,
                const PartitionT &Part) {
    Module &SrcM = LD.getSourceModule(LMId);

    // Create the module.
    std::string NewName(SrcM.getName());
    for (auto *F : Part) {
      NewName += ".";
      NewName += F->getName();
    }

    auto M = std::make_unique<Module>(NewName, SrcM.getContext());
    M->setDataLayout(SrcM.getDataLayout());
    ValueToValueMapTy VMap;

    auto Materializer = createLambdaMaterializer([&LD, &LMId,
                                                  &M](Value *V) -> Value * {
      if (auto *GV = dyn_cast<GlobalVariable>(V))
        return cloneGlobalVariableDecl(*M, *GV);

      if (auto *F = dyn_cast<Function>(V)) {
        // Check whether we want to clone an available_externally definition.
        if (!LD.getStubsToClone(LMId).count(F))
          return cloneFunctionDecl(*M, *F);

        // Ok - we want an inlinable stub. For that to work we need a decl
        // for the stub pointer.
        auto *StubPtr = createImplPointer(*F->getType(), *M,
                                          F->getName() + "$stub_ptr", nullptr);
        auto *ClonedF = cloneFunctionDecl(*M, *F);
        makeStub(*ClonedF, *StubPtr);
        ClonedF->setLinkage(GlobalValue::AvailableExternallyLinkage);
        ClonedF->addFnAttr(Attribute::AlwaysInline);
        return ClonedF;
      }

      if (auto *A = dyn_cast<GlobalAlias>(V)) {
        auto *Ty = A->getValueType();
        if (Ty->isFunctionTy())
          return Function::Create(cast<FunctionType>(Ty),
                                  GlobalValue::ExternalLinkage, A->getName(),
                                  M.get());

        return new GlobalVariable(*M, Ty, false, GlobalValue::ExternalLinkage,
                                  nullptr, A->getName(), nullptr,
                                  GlobalValue::NotThreadLocal,
                                  A->getType()->getAddressSpace());
      }

      return nullptr;
    });

    // Create decls in the new module.
    for (auto *F : Part)
      cloneFunctionDecl(*M, *F, &VMap);

    // Move the function bodies.
    for (auto *F : Part)
      moveFunctionBody(*F, VMap, &Materializer);

    auto K = ES.allocateVModule();

    auto LegacyLookup = [this, &LD](StringRef Name) -> JITSymbol {
      return LD.findSymbol(BaseLayer, std::string(Name), false);
    };

    // Create memory manager and symbol resolver.
    auto Resolver = createSymbolResolver(
        [&LD, LegacyLookup](const SymbolNameSet &Symbols) {
          auto RS = getResponsibilitySetWithLegacyFn(Symbols, LegacyLookup);
          if (!RS) {
            logAllUnhandledErrors(
                RS.takeError(), errs(),
                "CODLayer/SubResolver responsibility set lookup failed: ");
            return SymbolNameSet();
          }

          if (RS->size() == Symbols.size())
            return *RS;

          SymbolNameSet NotFoundViaLegacyLookup;
          for (auto &S : Symbols)
            if (!RS->count(S))
              NotFoundViaLegacyLookup.insert(S);

          auto RS2 =
              LD.BackingResolver->getResponsibilitySet(NotFoundViaLegacyLookup);

          for (auto &S : RS2)
            (*RS).insert(S);

          return *RS;
        },
        [this, &LD, LegacyLookup](std::shared_ptr<AsynchronousSymbolQuery> Q,
                                  SymbolNameSet Symbols) {
          auto NotFoundViaLegacyLookup =
              lookupWithLegacyFn(ES, *Q, Symbols, LegacyLookup);
          return LD.BackingResolver->lookup(Q,
                                            std::move(NotFoundViaLegacyLookup));
        });
    SetSymbolResolver(K, std::move(Resolver));

    if (auto Err = BaseLayer.addModule(std::move(K), std::move(M)))
      return std::move(Err);

    return K;
  }

  ExecutionSession &ES;
  BaseLayerT &BaseLayer;
  SymbolResolverGetter GetSymbolResolver;
  SymbolResolverSetter SetSymbolResolver;
  PartitioningFtor Partition;
  CompileCallbackMgrT &CompileCallbackMgr;
  IndirectStubsManagerBuilderT CreateIndirectStubsManager;

  std::map<VModuleKey, LogicalDylib> LogicalDylibs;
  bool CloneStubsIntoPartitions;
};

template <typename BaseLayerT, typename CompileCallbackMgrT,
          typename IndirectStubsMgrT>
LegacyCompileOnDemandLayer<BaseLayerT, CompileCallbackMgrT, IndirectStubsMgrT>::
    LegacyCompileOnDemandLayer(
        ExecutionSession &ES, BaseLayerT &BaseLayer,
        SymbolResolverGetter GetSymbolResolver,
        SymbolResolverSetter SetSymbolResolver, PartitioningFtor Partition,
        CompileCallbackMgrT &CallbackMgr,
        IndirectStubsManagerBuilderT CreateIndirectStubsManager,
        bool CloneStubsIntoPartitions)
    : ES(ES), BaseLayer(BaseLayer),
      GetSymbolResolver(std::move(GetSymbolResolver)),
      SetSymbolResolver(std::move(SetSymbolResolver)),
      Partition(std::move(Partition)), CompileCallbackMgr(CallbackMgr),
      CreateIndirectStubsManager(std::move(CreateIndirectStubsManager)),
      CloneStubsIntoPartitions(CloneStubsIntoPartitions) {}

} // end namespace orc
} // end namespace llvm

#endif // LLVM_EXECUTIONENGINE_ORC_COMPILEONDEMANDLAYER_H
