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