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