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(); |
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. |
72 | virtual void notifyMaterializing(MaterializationResponsibility &MR, |
73 | jitlink::LinkGraph &G, |
74 | jitlink::JITLinkContext &Ctx, |
75 | MemoryBufferRef InputObject) {} |
76 | |
77 | virtual void notifyLoaded(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 |
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. |
120 | void setReturnObjectBuffer(ReturnObjectBufferFunction ReturnObjectBuffer) { |
121 | this->ReturnObjectBuffer = std::move(ReturnObjectBuffer); |
122 | } |
123 | |
124 | /// Add a plugin. |
125 | ObjectLinkingLayer &addPlugin(std::shared_ptr<Plugin> P) { |
126 | std::lock_guard<std::mutex> Lock(LayerMutex); |
127 | Plugins.push_back(x: 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. |
135 | void removePlugin(Plugin &P) { |
136 | std::lock_guard<std::mutex> Lock(LayerMutex); |
137 | auto I = llvm::find_if(Range&: Plugins, P: [&](const std::shared_ptr<Plugin> &Elem) { |
138 | return Elem.get() == &P; |
139 | }); |
140 | assert(I != Plugins.end() && "Plugin not present" ); |
141 | Plugins.erase(position: 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. |
148 | Error add(JITDylib &JD, std::unique_ptr<jitlink::LinkGraph> G) { |
149 | return add(JD.getDefaultResourceTracker(), G: 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 & |
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 & |
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 | |