xref: /freebsd/contrib/llvm-project/llvm/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1 //===-- ObjectLinkingLayer.h - JITLink-based jit linking layer --*- 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 // Contains the definition for an JITLink-based, in-process object linking
10 // layer.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H
15 #define LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H
16 
17 #include "llvm/ADT/STLExtras.h"
18 #include "llvm/ADT/StringRef.h"
19 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
20 #include "llvm/ExecutionEngine/JITSymbol.h"
21 #include "llvm/ExecutionEngine/Orc/Core.h"
22 #include "llvm/ExecutionEngine/Orc/Layer.h"
23 #include "llvm/Support/Error.h"
24 #include <algorithm>
25 #include <cassert>
26 #include <functional>
27 #include <list>
28 #include <memory>
29 #include <utility>
30 #include <vector>
31 
32 namespace llvm {
33 
34 namespace jitlink {
35 class EHFrameRegistrar;
36 class LinkGraph;
37 class Symbol;
38 } // namespace jitlink
39 
40 namespace orc {
41 
42 class ObjectLinkingLayerJITLinkContext;
43 
44 /// An ObjectLayer implementation built on JITLink.
45 ///
46 /// Clients can use this class to add relocatable object files to an
47 /// ExecutionSession, and it typically serves as the base layer (underneath
48 /// a compiling layer like IRCompileLayer) for the rest of the JIT.
49 class ObjectLinkingLayer : public RTTIExtends<ObjectLinkingLayer, ObjectLayer>,
50                            private ResourceManager {
51   friend class ObjectLinkingLayerJITLinkContext;
52 
53 public:
54   static char ID;
55 
56   /// Plugin instances can be added to the ObjectLinkingLayer to receive
57   /// callbacks when code is loaded or emitted, and when JITLink is being
58   /// configured.
59   class Plugin {
60   public:
61     using JITLinkSymbolSet = DenseSet<jitlink::Symbol *>;
62     using SyntheticSymbolDependenciesMap =
63         DenseMap<SymbolStringPtr, JITLinkSymbolSet>;
64 
65     virtual ~Plugin();
modifyPassConfig(MaterializationResponsibility & MR,jitlink::LinkGraph & G,jitlink::PassConfiguration & Config)66     virtual void modifyPassConfig(MaterializationResponsibility &MR,
67                                   jitlink::LinkGraph &G,
68                                   jitlink::PassConfiguration &Config) {}
69 
70     // Deprecated. Don't use this in new code. There will be a proper mechanism
71     // for capturing object buffers.
notifyMaterializing(MaterializationResponsibility & MR,jitlink::LinkGraph & G,jitlink::JITLinkContext & Ctx,MemoryBufferRef InputObject)72     virtual void notifyMaterializing(MaterializationResponsibility &MR,
73                                      jitlink::LinkGraph &G,
74                                      jitlink::JITLinkContext &Ctx,
75                                      MemoryBufferRef InputObject) {}
76 
notifyLoaded(MaterializationResponsibility & MR)77     virtual void notifyLoaded(MaterializationResponsibility &MR) {}
notifyEmitted(MaterializationResponsibility & MR)78     virtual Error notifyEmitted(MaterializationResponsibility &MR) {
79       return Error::success();
80     }
81     virtual Error notifyFailed(MaterializationResponsibility &MR) = 0;
82     virtual Error notifyRemovingResources(JITDylib &JD, ResourceKey K) = 0;
83     virtual void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey,
84                                              ResourceKey SrcKey) = 0;
85 
86     /// Return any dependencies that synthetic symbols (e.g. init symbols)
87     /// have on symbols in the LinkGraph.
88     /// This is used by the ObjectLinkingLayer to update the dependencies for
89     /// the synthetic symbols.
90     virtual SyntheticSymbolDependenciesMap
getSyntheticSymbolDependencies(MaterializationResponsibility & MR)91     getSyntheticSymbolDependencies(MaterializationResponsibility &MR) {
92       return SyntheticSymbolDependenciesMap();
93     }
94   };
95 
96   using ReturnObjectBufferFunction =
97       std::function<void(std::unique_ptr<MemoryBuffer>)>;
98 
99   /// Construct an ObjectLinkingLayer using the ExecutorProcessControl
100   /// instance's memory manager.
101   ObjectLinkingLayer(ExecutionSession &ES);
102 
103   /// Construct an ObjectLinkingLayer using a custom memory manager.
104   ObjectLinkingLayer(ExecutionSession &ES,
105                      jitlink::JITLinkMemoryManager &MemMgr);
106 
107   /// Construct an ObjectLinkingLayer. Takes ownership of the given
108   /// JITLinkMemoryManager. This method is a temporary hack to simplify
109   /// co-existence with RTDyldObjectLinkingLayer (which also owns its
110   /// allocators).
111   ObjectLinkingLayer(ExecutionSession &ES,
112                      std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr);
113 
114   /// Destruct an ObjectLinkingLayer.
115   ~ObjectLinkingLayer();
116 
117   /// Set an object buffer return function. By default object buffers are
118   /// deleted once the JIT has linked them. If a return function is set then
119   /// it will be called to transfer ownership of the buffer instead.
setReturnObjectBuffer(ReturnObjectBufferFunction ReturnObjectBuffer)120   void setReturnObjectBuffer(ReturnObjectBufferFunction ReturnObjectBuffer) {
121     this->ReturnObjectBuffer = std::move(ReturnObjectBuffer);
122   }
123 
124   /// Add a plugin.
addPlugin(std::shared_ptr<Plugin> P)125   ObjectLinkingLayer &addPlugin(std::shared_ptr<Plugin> P) {
126     std::lock_guard<std::mutex> Lock(LayerMutex);
127     Plugins.push_back(std::move(P));
128     return *this;
129   }
130 
131   /// Remove a plugin. This remove applies only to subsequent links (links
132   /// already underway will continue to use the plugin), and does not of itself
133   /// destroy the plugin -- destruction will happen once all shared pointers
134   /// (including those held by in-progress links) are destroyed.
removePlugin(Plugin & P)135   void removePlugin(Plugin &P) {
136     std::lock_guard<std::mutex> Lock(LayerMutex);
137     auto I = llvm::find_if(Plugins, [&](const std::shared_ptr<Plugin> &Elem) {
138       return Elem.get() == &P;
139     });
140     assert(I != Plugins.end() && "Plugin not present");
141     Plugins.erase(I);
142   }
143 
144   /// Add a LinkGraph to the JITDylib targeted by the given tracker.
145   Error add(ResourceTrackerSP, std::unique_ptr<jitlink::LinkGraph> G);
146 
147   /// Add a LinkGraph to the given JITDylib.
add(JITDylib & JD,std::unique_ptr<jitlink::LinkGraph> G)148   Error add(JITDylib &JD, std::unique_ptr<jitlink::LinkGraph> G) {
149     return add(JD.getDefaultResourceTracker(), std::move(G));
150   }
151 
152   // Un-hide ObjectLayer add methods.
153   using ObjectLayer::add;
154 
155   /// Emit an object file.
156   void emit(std::unique_ptr<MaterializationResponsibility> R,
157             std::unique_ptr<MemoryBuffer> O) override;
158 
159   /// Emit a LinkGraph.
160   void emit(std::unique_ptr<MaterializationResponsibility> R,
161             std::unique_ptr<jitlink::LinkGraph> G);
162 
163   /// Instructs this ObjectLinkingLayer instance to override the symbol flags
164   /// found in the AtomGraph with the flags supplied by the
165   /// MaterializationResponsibility instance. This is a workaround to support
166   /// symbol visibility in COFF, which does not use the libObject's
167   /// SF_Exported flag. Use only when generating / adding COFF object files.
168   ///
169   /// FIXME: We should be able to remove this if/when COFF properly tracks
170   /// exported symbols.
171   ObjectLinkingLayer &
setOverrideObjectFlagsWithResponsibilityFlags(bool OverrideObjectFlags)172   setOverrideObjectFlagsWithResponsibilityFlags(bool OverrideObjectFlags) {
173     this->OverrideObjectFlags = OverrideObjectFlags;
174     return *this;
175   }
176 
177   /// If set, this ObjectLinkingLayer instance will claim responsibility
178   /// for any symbols provided by a given object file that were not already in
179   /// the MaterializationResponsibility instance. Setting this flag allows
180   /// higher-level program representations (e.g. LLVM IR) to be added based on
181   /// only a subset of the symbols they provide, without having to write
182   /// intervening layers to scan and add the additional symbols. This trades
183   /// diagnostic quality for convenience however: If all symbols are enumerated
184   /// up-front then clashes can be detected and reported early (and usually
185   /// deterministically). If this option is set, clashes for the additional
186   /// symbols may not be detected until late, and detection may depend on
187   /// the flow of control through JIT'd code. Use with care.
188   ObjectLinkingLayer &
setAutoClaimResponsibilityForObjectSymbols(bool AutoClaimObjectSymbols)189   setAutoClaimResponsibilityForObjectSymbols(bool AutoClaimObjectSymbols) {
190     this->AutoClaimObjectSymbols = AutoClaimObjectSymbols;
191     return *this;
192   }
193 
194 private:
195   using FinalizedAlloc = jitlink::JITLinkMemoryManager::FinalizedAlloc;
196 
197   Error recordFinalizedAlloc(MaterializationResponsibility &MR,
198                              FinalizedAlloc FA);
199 
200   Error handleRemoveResources(JITDylib &JD, ResourceKey K) override;
201   void handleTransferResources(JITDylib &JD, ResourceKey DstKey,
202                                ResourceKey SrcKey) override;
203 
204   mutable std::mutex LayerMutex;
205   jitlink::JITLinkMemoryManager &MemMgr;
206   std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgrOwnership;
207   bool OverrideObjectFlags = false;
208   bool AutoClaimObjectSymbols = false;
209   ReturnObjectBufferFunction ReturnObjectBuffer;
210   DenseMap<ResourceKey, std::vector<FinalizedAlloc>> Allocs;
211   std::vector<std::shared_ptr<Plugin>> Plugins;
212 };
213 
214 class EHFrameRegistrationPlugin : public ObjectLinkingLayer::Plugin {
215 public:
216   EHFrameRegistrationPlugin(
217       ExecutionSession &ES,
218       std::unique_ptr<jitlink::EHFrameRegistrar> Registrar);
219   void modifyPassConfig(MaterializationResponsibility &MR,
220                         jitlink::LinkGraph &G,
221                         jitlink::PassConfiguration &PassConfig) override;
222   Error notifyEmitted(MaterializationResponsibility &MR) override;
223   Error notifyFailed(MaterializationResponsibility &MR) override;
224   Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override;
225   void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey,
226                                    ResourceKey SrcKey) override;
227 
228 private:
229   std::mutex EHFramePluginMutex;
230   ExecutionSession &ES;
231   std::unique_ptr<jitlink::EHFrameRegistrar> Registrar;
232   DenseMap<MaterializationResponsibility *, ExecutorAddrRange> InProcessLinks;
233   DenseMap<ResourceKey, std::vector<ExecutorAddrRange>> EHFrameRanges;
234 };
235 
236 } // end namespace orc
237 } // end namespace llvm
238 
239 #endif // LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H
240