1 //===-- LinkGraphLinkingLayer.h - Link LinkGraphs with JITLink --*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // LinkGraphLinkingLayer and associated utilities. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef LLVM_EXECUTIONENGINE_ORC_LINKGRAPHLINKINGLAYER_H 14 #define LLVM_EXECUTIONENGINE_ORC_LINKGRAPHLINKINGLAYER_H 15 16 #include "llvm/ADT/STLExtras.h" 17 #include "llvm/ADT/StringRef.h" 18 #include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h" 19 #include "llvm/ExecutionEngine/Orc/Core.h" 20 #include "llvm/ExecutionEngine/Orc/Layer.h" 21 #include "llvm/ExecutionEngine/Orc/LinkGraphLayer.h" 22 #include "llvm/Support/Compiler.h" 23 #include "llvm/Support/Error.h" 24 #include <algorithm> 25 #include <cassert> 26 #include <functional> 27 #include <memory> 28 #include <mutex> 29 #include <utility> 30 #include <vector> 31 32 namespace llvm { 33 34 namespace jitlink { 35 class EHFrameRegistrar; 36 } // namespace jitlink 37 38 namespace orc { 39 40 /// LinkGraphLinkingLayer links LinkGraphs into the Executor using JITLink. 41 /// 42 /// Clients can use this class to add LinkGraphs to an ExecutionSession, and it 43 /// serves as a base for the ObjectLinkingLayer that can link object files. 44 class LLVM_ABI LinkGraphLinkingLayer : public LinkGraphLayer, 45 private ResourceManager { 46 class JITLinkCtx; 47 48 public: 49 /// Plugin instances can be added to the ObjectLinkingLayer to receive 50 /// callbacks when code is loaded or emitted, and when JITLink is being 51 /// configured. 52 class LLVM_ABI Plugin { 53 public: 54 virtual ~Plugin(); modifyPassConfig(MaterializationResponsibility & MR,jitlink::LinkGraph & G,jitlink::PassConfiguration & Config)55 virtual void modifyPassConfig(MaterializationResponsibility &MR, 56 jitlink::LinkGraph &G, 57 jitlink::PassConfiguration &Config) {} 58 59 // Deprecated. Don't use this in new code. There will be a proper mechanism 60 // for capturing object buffers. notifyMaterializing(MaterializationResponsibility & MR,jitlink::LinkGraph & G,jitlink::JITLinkContext & Ctx,MemoryBufferRef InputObject)61 virtual void notifyMaterializing(MaterializationResponsibility &MR, 62 jitlink::LinkGraph &G, 63 jitlink::JITLinkContext &Ctx, 64 MemoryBufferRef InputObject) {} 65 notifyEmitted(MaterializationResponsibility & MR)66 virtual Error notifyEmitted(MaterializationResponsibility &MR) { 67 return Error::success(); 68 } 69 virtual Error notifyFailed(MaterializationResponsibility &MR) = 0; 70 virtual Error notifyRemovingResources(JITDylib &JD, ResourceKey K) = 0; 71 virtual void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey, 72 ResourceKey SrcKey) = 0; 73 }; 74 75 /// Construct a LinkGraphLinkingLayer using the ExecutorProcessControl 76 /// instance's memory manager. 77 LinkGraphLinkingLayer(ExecutionSession &ES); 78 79 /// Construct a LinkGraphLinkingLayer using a custom memory manager. 80 LinkGraphLinkingLayer(ExecutionSession &ES, 81 jitlink::JITLinkMemoryManager &MemMgr); 82 83 /// Construct an LinkGraphLinkingLayer. Takes ownership of the given 84 /// JITLinkMemoryManager. This method is a temporary hack to simplify 85 /// co-existence with RTDyldObjectLinkingLayer (which also owns its 86 /// allocators). 87 LinkGraphLinkingLayer(ExecutionSession &ES, 88 std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr); 89 90 /// Destroy the LinkGraphLinkingLayer. 91 ~LinkGraphLinkingLayer(); 92 93 /// Add a plugin. addPlugin(std::shared_ptr<Plugin> P)94 LinkGraphLinkingLayer &addPlugin(std::shared_ptr<Plugin> P) { 95 std::lock_guard<std::mutex> Lock(LayerMutex); 96 Plugins.push_back(std::move(P)); 97 return *this; 98 } 99 100 /// Remove a plugin. This remove applies only to subsequent links (links 101 /// already underway will continue to use the plugin), and does not of itself 102 /// destroy the plugin -- destruction will happen once all shared pointers 103 /// (including those held by in-progress links) are destroyed. removePlugin(Plugin & P)104 void removePlugin(Plugin &P) { 105 std::lock_guard<std::mutex> Lock(LayerMutex); 106 auto I = llvm::find_if(Plugins, [&](const std::shared_ptr<Plugin> &Elem) { 107 return Elem.get() == &P; 108 }); 109 assert(I != Plugins.end() && "Plugin not present"); 110 Plugins.erase(I); 111 } 112 113 /// Emit a LinkGraph. 114 void emit(std::unique_ptr<MaterializationResponsibility> R, 115 std::unique_ptr<jitlink::LinkGraph> G) override; 116 117 /// Instructs this LinkgraphLinkingLayer instance to override the symbol flags 118 /// found in the LinkGraph with the flags supplied by the 119 /// MaterializationResponsibility instance. This is a workaround to support 120 /// symbol visibility in COFF, which does not use the libObject's 121 /// SF_Exported flag. Use only when generating / adding COFF object files. 122 /// 123 /// FIXME: We should be able to remove this if/when COFF properly tracks 124 /// exported symbols. 125 LinkGraphLinkingLayer & setOverrideObjectFlagsWithResponsibilityFlags(bool OverrideObjectFlags)126 setOverrideObjectFlagsWithResponsibilityFlags(bool OverrideObjectFlags) { 127 this->OverrideObjectFlags = OverrideObjectFlags; 128 return *this; 129 } 130 131 /// If set, this LinkGraphLinkingLayer instance will claim responsibility 132 /// for any symbols provided by a given object file that were not already in 133 /// the MaterializationResponsibility instance. Setting this flag allows 134 /// higher-level program representations (e.g. LLVM IR) to be added based on 135 /// only a subset of the symbols they provide, without having to write 136 /// intervening layers to scan and add the additional symbols. This trades 137 /// diagnostic quality for convenience however: If all symbols are enumerated 138 /// up-front then clashes can be detected and reported early (and usually 139 /// deterministically). If this option is set, clashes for the additional 140 /// symbols may not be detected until late, and detection may depend on 141 /// the flow of control through JIT'd code. Use with care. 142 LinkGraphLinkingLayer & setAutoClaimResponsibilityForObjectSymbols(bool AutoClaimObjectSymbols)143 setAutoClaimResponsibilityForObjectSymbols(bool AutoClaimObjectSymbols) { 144 this->AutoClaimObjectSymbols = AutoClaimObjectSymbols; 145 return *this; 146 } 147 148 protected: 149 /// Emit a LinkGraph with the given backing buffer. 150 /// 151 /// This overload is intended for use by ObjectLinkingLayer. 152 void emit(std::unique_ptr<MaterializationResponsibility> R, 153 std::unique_ptr<jitlink::LinkGraph> G, 154 std::unique_ptr<MemoryBuffer> ObjBuf); 155 156 std::function<void(std::unique_ptr<MemoryBuffer>)> ReturnObjectBuffer; 157 158 private: 159 using FinalizedAlloc = jitlink::JITLinkMemoryManager::FinalizedAlloc; 160 161 Error recordFinalizedAlloc(MaterializationResponsibility &MR, 162 FinalizedAlloc FA); 163 164 Error handleRemoveResources(JITDylib &JD, ResourceKey K) override; 165 void handleTransferResources(JITDylib &JD, ResourceKey DstKey, 166 ResourceKey SrcKey) override; 167 168 mutable std::mutex LayerMutex; 169 jitlink::JITLinkMemoryManager &MemMgr; 170 std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgrOwnership; 171 bool OverrideObjectFlags = false; 172 bool AutoClaimObjectSymbols = false; 173 DenseMap<ResourceKey, std::vector<FinalizedAlloc>> Allocs; 174 std::vector<std::shared_ptr<Plugin>> Plugins; 175 }; 176 177 } // end namespace orc 178 } // end namespace llvm 179 180 #endif // LLVM_EXECUTIONENGINE_ORC_LINKGRAPHLINKINGLAYER_H 181