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