//===-- 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 #include #include #include #include #include #include namespace llvm { namespace jitlink { class EHFrameRegistrar; class LinkGraph; class Symbol; } // namespace jitlink 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 RTTIExtends, private ResourceManager { friend class ObjectLinkingLayerJITLinkContext; public: static char ID; /// 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: using JITLinkSymbolSet = DenseSet; using SyntheticSymbolDependenciesMap = DenseMap; virtual ~Plugin(); virtual void modifyPassConfig(MaterializationResponsibility &MR, jitlink::LinkGraph &G, jitlink::PassConfiguration &Config) {} // Deprecated. Don't use this in new code. There will be a proper mechanism // for capturing object buffers. virtual void notifyMaterializing(MaterializationResponsibility &MR, jitlink::LinkGraph &G, jitlink::JITLinkContext &Ctx, MemoryBufferRef InputObject) {} virtual void notifyLoaded(MaterializationResponsibility &MR) {} virtual Error notifyEmitted(MaterializationResponsibility &MR) { return Error::success(); } virtual Error notifyFailed(MaterializationResponsibility &MR) = 0; virtual Error notifyRemovingResources(JITDylib &JD, ResourceKey K) = 0; virtual void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey, ResourceKey SrcKey) = 0; /// Return any dependencies that synthetic symbols (e.g. init symbols) /// have on symbols in the LinkGraph. /// This is used by the ObjectLinkingLayer to update the dependencies for /// the synthetic symbols. virtual SyntheticSymbolDependenciesMap getSyntheticSymbolDependencies(MaterializationResponsibility &MR) { return SyntheticSymbolDependenciesMap(); } }; using ReturnObjectBufferFunction = std::function)>; /// Construct an ObjectLinkingLayer using the ExecutorProcessControl /// instance's memory manager. ObjectLinkingLayer(ExecutionSession &ES); /// Construct an ObjectLinkingLayer using a custom memory manager. ObjectLinkingLayer(ExecutionSession &ES, jitlink::JITLinkMemoryManager &MemMgr); /// Construct an ObjectLinkingLayer. Takes ownership of the given /// JITLinkMemoryManager. This method is a temporary hack to simplify /// co-existence with RTDyldObjectLinkingLayer (which also owns its /// allocators). ObjectLinkingLayer(ExecutionSession &ES, std::unique_ptr MemMgr); /// Destruct an ObjectLinkingLayer. ~ObjectLinkingLayer(); /// Set an object buffer return function. By default object buffers are /// deleted once the JIT has linked them. If a return function is set then /// it will be called to transfer ownership of the buffer instead. void setReturnObjectBuffer(ReturnObjectBufferFunction ReturnObjectBuffer) { this->ReturnObjectBuffer = std::move(ReturnObjectBuffer); } /// Add a pass-config modifier. ObjectLinkingLayer &addPlugin(std::unique_ptr P) { std::lock_guard Lock(LayerMutex); Plugins.push_back(std::move(P)); return *this; } /// Add a LinkGraph to the JITDylib targeted by the given tracker. Error add(ResourceTrackerSP, std::unique_ptr G); /// Add a LinkGraph to the given JITDylib. Error add(JITDylib &JD, std::unique_ptr G) { return add(JD.getDefaultResourceTracker(), std::move(G)); } // Un-hide ObjectLayer add methods. using ObjectLayer::add; /// Emit an object file. void emit(std::unique_ptr R, std::unique_ptr O) override; /// Emit a LinkGraph. void emit(std::unique_ptr R, std::unique_ptr G); /// 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 FinalizedAlloc = jitlink::JITLinkMemoryManager::FinalizedAlloc; void modifyPassConfig(MaterializationResponsibility &MR, jitlink::LinkGraph &G, jitlink::PassConfiguration &PassConfig); void notifyLoaded(MaterializationResponsibility &MR); Error notifyEmitted(MaterializationResponsibility &MR, FinalizedAlloc FA); Error handleRemoveResources(JITDylib &JD, ResourceKey K) override; void handleTransferResources(JITDylib &JD, ResourceKey DstKey, ResourceKey SrcKey) override; mutable std::mutex LayerMutex; jitlink::JITLinkMemoryManager &MemMgr; std::unique_ptr MemMgrOwnership; bool OverrideObjectFlags = false; bool AutoClaimObjectSymbols = false; ReturnObjectBufferFunction ReturnObjectBuffer; DenseMap> Allocs; std::vector> Plugins; }; class EHFrameRegistrationPlugin : public ObjectLinkingLayer::Plugin { public: EHFrameRegistrationPlugin( ExecutionSession &ES, std::unique_ptr Registrar); void modifyPassConfig(MaterializationResponsibility &MR, jitlink::LinkGraph &G, jitlink::PassConfiguration &PassConfig) override; Error notifyEmitted(MaterializationResponsibility &MR) override; Error notifyFailed(MaterializationResponsibility &MR) override; Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override; void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey, ResourceKey SrcKey) override; private: std::mutex EHFramePluginMutex; ExecutionSession &ES; std::unique_ptr Registrar; DenseMap InProcessLinks; DenseMap> EHFrameRanges; }; } // end namespace orc } // end namespace llvm #endif // LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H