text: //===-- ObjectLinkingLayer.h - JITLink-based jit linking layer --*- 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 the definition for an JITLink-based, in-process object linking
  // layer.
  //
  //===----------------------------------------------------------------------===//
  
  #ifndef LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H
  #define LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H
  
  #include "llvm/ADT/STLExtras.h"
  #include "llvm/ADT/StringMap.h"
  #include "llvm/ADT/StringRef.h"
  #include "llvm/ExecutionEngine/JITLink/JITLink.h"
  #include "llvm/ExecutionEngine/JITSymbol.h"
  #include "llvm/ExecutionEngine/Orc/Core.h"
  #include "llvm/ExecutionEngine/Orc/Layer.h"
  #include "llvm/Support/Error.h"
  #include <algorithm>
  #include <cassert>
  #include <functional>
  #include <list>
  #include <memory>
  #include <string>
  #include <utility>
  #include <vector>
  
  namespace llvm {
  
  namespace jitlink {
  class EHFrameRegistrar;
  } // namespace jitlink
  
  namespace object {
  class ObjectFile;
  } // namespace object
  
  namespace orc {
  
  class ObjectLinkingLayerJITLinkContext;
  
  /// An ObjectLayer implementation built on JITLink.
  ///
  /// Clients can use this class to add relocatable object files to an
  /// ExecutionSession, and it typically serves as the base layer (underneath
  /// a compiling layer like IRCompileLayer) for the rest of the JIT.
  class ObjectLinkingLayer : public ObjectLayer {
    friend class ObjectLinkingLayerJITLinkContext;
  
  public:
    /// Plugin instances can be added to the ObjectLinkingLayer to receive
    /// callbacks when code is loaded or emitted, and when JITLink is being
    /// configured.
    class Plugin {
    public:
      virtual ~Plugin();
      virtual void modifyPassConfig(MaterializationResponsibility &MR,
                                    const Triple &TT,
                                    jitlink::PassConfiguration &Config) {}
      virtual void notifyLoaded(MaterializationResponsibility &MR) {}
      virtual Error notifyEmitted(MaterializationResponsibility &MR) {
        return Error::success();
      }
      virtual Error notifyRemovingModule(VModuleKey K) {
        return Error::success();
      }
      virtual Error notifyRemovingAllModules() { return Error::success(); }
    };
  
    /// Construct an ObjectLinkingLayer with the given NotifyLoaded,
    /// and NotifyEmitted functors.
    ObjectLinkingLayer(ExecutionSession &ES,
                       jitlink::JITLinkMemoryManager &MemMgr);
  
    /// Destruct an ObjectLinkingLayer.
    ~ObjectLinkingLayer();
  
    /// Add a pass-config modifier.
    ObjectLinkingLayer &addPlugin(std::unique_ptr<Plugin> P) {
      std::lock_guard<std::mutex> Lock(LayerMutex);
      Plugins.push_back(std::move(P));
      return *this;
    }
  
    /// Emit the object.
    void emit(MaterializationResponsibility R,
              std::unique_ptr<MemoryBuffer> O) override;
  
    /// Instructs this ObjectLinkingLayer instance to override the symbol flags
    /// found in the AtomGraph with the flags supplied by the
    /// MaterializationResponsibility instance. This is a workaround to support
    /// symbol visibility in COFF, which does not use the libObject's
    /// SF_Exported flag. Use only when generating / adding COFF object files.
    ///
    /// FIXME: We should be able to remove this if/when COFF properly tracks
    /// exported symbols.
    ObjectLinkingLayer &
    setOverrideObjectFlagsWithResponsibilityFlags(bool OverrideObjectFlags) {
      this->OverrideObjectFlags = OverrideObjectFlags;
      return *this;
    }
  
    /// If set, this ObjectLinkingLayer instance will claim responsibility
    /// for any symbols provided by a given object file that were not already in
    /// the MaterializationResponsibility instance. Setting this flag allows
    /// higher-level program representations (e.g. LLVM IR) to be added based on
    /// only a subset of the symbols they provide, without having to write
    /// intervening layers to scan and add the additional symbols. This trades
    /// diagnostic quality for convenience however: If all symbols are enumerated
    /// up-front then clashes can be detected and reported early (and usually
    /// deterministically). If this option is set, clashes for the additional
    /// symbols may not be detected until late, and detection may depend on
    /// the flow of control through JIT'd code. Use with care.
    ObjectLinkingLayer &
    setAutoClaimResponsibilityForObjectSymbols(bool AutoClaimObjectSymbols) {
      this->AutoClaimObjectSymbols = AutoClaimObjectSymbols;
      return *this;
    }
  
  private:
    using AllocPtr = std::unique_ptr<jitlink::JITLinkMemoryManager::Allocation>;
  
    void modifyPassConfig(MaterializationResponsibility &MR, const Triple &TT,
                          jitlink::PassConfiguration &PassConfig);
    void notifyLoaded(MaterializationResponsibility &MR);
    Error notifyEmitted(MaterializationResponsibility &MR, AllocPtr Alloc);
  
    Error removeModule(VModuleKey K);
    Error removeAllModules();
  
    mutable std::mutex LayerMutex;
    jitlink::JITLinkMemoryManager &MemMgr;
    bool OverrideObjectFlags = false;
    bool AutoClaimObjectSymbols = false;
    DenseMap<VModuleKey, AllocPtr> TrackedAllocs;
    std::vector<AllocPtr> UntrackedAllocs;
    std::vector<std::unique_ptr<Plugin>> Plugins;
  };
  
  class EHFrameRegistrationPlugin : public ObjectLinkingLayer::Plugin {
  public:
    EHFrameRegistrationPlugin(jitlink::EHFrameRegistrar &Registrar);
    Error notifyEmitted(MaterializationResponsibility &MR) override;
    void modifyPassConfig(MaterializationResponsibility &MR, const Triple &TT,
                          jitlink::PassConfiguration &PassConfig) override;
    Error notifyRemovingModule(VModuleKey K) override;
    Error notifyRemovingAllModules() override;
  
  private:
  
    struct EHFrameRange {
      JITTargetAddress Addr = 0;
      size_t Size;
    };
  
    jitlink::EHFrameRegistrar &Registrar;
    DenseMap<MaterializationResponsibility *, EHFrameRange> InProcessLinks;
    DenseMap<VModuleKey, EHFrameRange> TrackedEHFrameRanges;
    std::vector<EHFrameRange> UntrackedEHFrameRanges;
  };
  
  } // end namespace orc
  } // end namespace llvm
  
  #endif // LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H
  