blob: 8b0b3fdb7df4b4343b0c8bc36406464d1638b119 [file] [log] [blame]
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01001//===- IndirectionUtils.h - Utilities for adding indirections ---*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// Contains utilities for adding indirections and breaking up modules.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H
15#define LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H
16
17#include "llvm/ADT/StringMap.h"
18#include "llvm/ADT/StringRef.h"
19#include "llvm/ADT/Twine.h"
20#include "llvm/ExecutionEngine/JITSymbol.h"
Andrew Scullcdfcccc2018-10-05 20:58:37 +010021#include "llvm/ExecutionEngine/Orc/Core.h"
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010022#include "llvm/Support/Error.h"
23#include "llvm/Support/Memory.h"
24#include "llvm/Support/Process.h"
25#include "llvm/Transforms/Utils/ValueMapper.h"
26#include <algorithm>
27#include <cassert>
28#include <cstdint>
29#include <functional>
30#include <map>
31#include <memory>
32#include <system_error>
33#include <utility>
34#include <vector>
35
36namespace llvm {
37
38class Constant;
39class Function;
40class FunctionType;
41class GlobalAlias;
42class GlobalVariable;
43class Module;
44class PointerType;
45class Triple;
46class Value;
47
48namespace orc {
49
Andrew Scullcdfcccc2018-10-05 20:58:37 +010050/// Target-independent base class for compile callback management.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010051class JITCompileCallbackManager {
52public:
Andrew Scullcdfcccc2018-10-05 20:58:37 +010053 using CompileFunction = std::function<JITTargetAddress()>;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010054
Andrew Scullcdfcccc2018-10-05 20:58:37 +010055 /// Construct a JITCompileCallbackManager.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010056 /// @param ErrorHandlerAddress The address of an error handler in the target
57 /// process to be used if a compile callback fails.
Andrew Scullcdfcccc2018-10-05 20:58:37 +010058 JITCompileCallbackManager(ExecutionSession &ES,
59 JITTargetAddress ErrorHandlerAddress)
60 : ES(ES), CallbacksVSO(ES.createVSO("<Callbacks>")),
61 ErrorHandlerAddress(ErrorHandlerAddress) {}
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010062
63 virtual ~JITCompileCallbackManager() = default;
64
Andrew Scullcdfcccc2018-10-05 20:58:37 +010065 /// Reserve a compile callback.
66 Expected<JITTargetAddress> getCompileCallback(CompileFunction Compile);
67
68 /// Execute the callback for the given trampoline id. Called by the JIT
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010069 /// to compile functions on demand.
Andrew Scullcdfcccc2018-10-05 20:58:37 +010070 JITTargetAddress executeCompileCallback(JITTargetAddress TrampolineAddr);
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010071
72protected:
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010073 std::vector<JITTargetAddress> AvailableTrampolines;
74
75private:
76 Expected<JITTargetAddress> getAvailableTrampolineAddr() {
77 if (this->AvailableTrampolines.empty())
78 if (auto Err = grow())
79 return std::move(Err);
80 assert(!this->AvailableTrampolines.empty() &&
81 "Failed to grow available trampolines.");
82 JITTargetAddress TrampolineAddr = this->AvailableTrampolines.back();
83 this->AvailableTrampolines.pop_back();
84 return TrampolineAddr;
85 }
86
87 // Create new trampolines - to be implemented in subclasses.
88 virtual Error grow() = 0;
89
90 virtual void anchor();
Andrew Scullcdfcccc2018-10-05 20:58:37 +010091
92 std::mutex CCMgrMutex;
93 ExecutionSession &ES;
94 VSO &CallbacksVSO;
95 JITTargetAddress ErrorHandlerAddress;
96 std::map<JITTargetAddress, SymbolStringPtr> AddrToSymbol;
97 size_t NextCallbackId = 0;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010098};
99
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100100/// Manage compile callbacks for in-process JITs.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100101template <typename TargetT>
102class LocalJITCompileCallbackManager : public JITCompileCallbackManager {
103public:
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100104 /// Construct a InProcessJITCompileCallbackManager.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100105 /// @param ErrorHandlerAddress The address of an error handler in the target
106 /// process to be used if a compile callback fails.
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100107 LocalJITCompileCallbackManager(ExecutionSession &ES,
108 JITTargetAddress ErrorHandlerAddress)
109 : JITCompileCallbackManager(ES, ErrorHandlerAddress) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100110 /// Set up the resolver block.
111 std::error_code EC;
112 ResolverBlock = sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
113 TargetT::ResolverCodeSize, nullptr,
114 sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
115 assert(!EC && "Failed to allocate resolver block");
116
117 TargetT::writeResolverCode(static_cast<uint8_t *>(ResolverBlock.base()),
118 &reenter, this);
119
120 EC = sys::Memory::protectMappedMemory(ResolverBlock.getMemoryBlock(),
121 sys::Memory::MF_READ |
122 sys::Memory::MF_EXEC);
123 assert(!EC && "Failed to mprotect resolver block");
124 }
125
126private:
127 static JITTargetAddress reenter(void *CCMgr, void *TrampolineId) {
128 JITCompileCallbackManager *Mgr =
129 static_cast<JITCompileCallbackManager *>(CCMgr);
130 return Mgr->executeCompileCallback(
131 static_cast<JITTargetAddress>(
132 reinterpret_cast<uintptr_t>(TrampolineId)));
133 }
134
135 Error grow() override {
136 assert(this->AvailableTrampolines.empty() && "Growing prematurely?");
137
138 std::error_code EC;
139 auto TrampolineBlock =
140 sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
141 sys::Process::getPageSize(), nullptr,
142 sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
143 if (EC)
144 return errorCodeToError(EC);
145
146 unsigned NumTrampolines =
147 (sys::Process::getPageSize() - TargetT::PointerSize) /
148 TargetT::TrampolineSize;
149
150 uint8_t *TrampolineMem = static_cast<uint8_t *>(TrampolineBlock.base());
151 TargetT::writeTrampolines(TrampolineMem, ResolverBlock.base(),
152 NumTrampolines);
153
154 for (unsigned I = 0; I < NumTrampolines; ++I)
155 this->AvailableTrampolines.push_back(
156 static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(
157 TrampolineMem + (I * TargetT::TrampolineSize))));
158
159 if (auto EC = sys::Memory::protectMappedMemory(
160 TrampolineBlock.getMemoryBlock(),
161 sys::Memory::MF_READ | sys::Memory::MF_EXEC))
162 return errorCodeToError(EC);
163
164 TrampolineBlocks.push_back(std::move(TrampolineBlock));
165 return Error::success();
166 }
167
168 sys::OwningMemoryBlock ResolverBlock;
169 std::vector<sys::OwningMemoryBlock> TrampolineBlocks;
170};
171
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100172/// Base class for managing collections of named indirect stubs.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100173class IndirectStubsManager {
174public:
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100175 /// Map type for initializing the manager. See init.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100176 using StubInitsMap = StringMap<std::pair<JITTargetAddress, JITSymbolFlags>>;
177
178 virtual ~IndirectStubsManager() = default;
179
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100180 /// Create a single stub with the given name, target address and flags.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100181 virtual Error createStub(StringRef StubName, JITTargetAddress StubAddr,
182 JITSymbolFlags StubFlags) = 0;
183
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100184 /// Create StubInits.size() stubs with the given names, target
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100185 /// addresses, and flags.
186 virtual Error createStubs(const StubInitsMap &StubInits) = 0;
187
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100188 /// Find the stub with the given name. If ExportedStubsOnly is true,
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100189 /// this will only return a result if the stub's flags indicate that it
190 /// is exported.
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100191 virtual JITEvaluatedSymbol findStub(StringRef Name, bool ExportedStubsOnly) = 0;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100192
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100193 /// Find the implementation-pointer for the stub.
194 virtual JITEvaluatedSymbol findPointer(StringRef Name) = 0;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100195
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100196 /// Change the value of the implementation pointer for the stub.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100197 virtual Error updatePointer(StringRef Name, JITTargetAddress NewAddr) = 0;
198
199private:
200 virtual void anchor();
201};
202
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100203/// IndirectStubsManager implementation for the host architecture, e.g.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100204/// OrcX86_64. (See OrcArchitectureSupport.h).
205template <typename TargetT>
206class LocalIndirectStubsManager : public IndirectStubsManager {
207public:
208 Error createStub(StringRef StubName, JITTargetAddress StubAddr,
209 JITSymbolFlags StubFlags) override {
210 if (auto Err = reserveStubs(1))
211 return Err;
212
213 createStubInternal(StubName, StubAddr, StubFlags);
214
215 return Error::success();
216 }
217
218 Error createStubs(const StubInitsMap &StubInits) override {
219 if (auto Err = reserveStubs(StubInits.size()))
220 return Err;
221
222 for (auto &Entry : StubInits)
223 createStubInternal(Entry.first(), Entry.second.first,
224 Entry.second.second);
225
226 return Error::success();
227 }
228
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100229 JITEvaluatedSymbol findStub(StringRef Name, bool ExportedStubsOnly) override {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100230 auto I = StubIndexes.find(Name);
231 if (I == StubIndexes.end())
232 return nullptr;
233 auto Key = I->second.first;
234 void *StubAddr = IndirectStubsInfos[Key.first].getStub(Key.second);
235 assert(StubAddr && "Missing stub address");
236 auto StubTargetAddr =
237 static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(StubAddr));
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100238 auto StubSymbol = JITEvaluatedSymbol(StubTargetAddr, I->second.second);
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100239 if (ExportedStubsOnly && !StubSymbol.getFlags().isExported())
240 return nullptr;
241 return StubSymbol;
242 }
243
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100244 JITEvaluatedSymbol findPointer(StringRef Name) override {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100245 auto I = StubIndexes.find(Name);
246 if (I == StubIndexes.end())
247 return nullptr;
248 auto Key = I->second.first;
249 void *PtrAddr = IndirectStubsInfos[Key.first].getPtr(Key.second);
250 assert(PtrAddr && "Missing pointer address");
251 auto PtrTargetAddr =
252 static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(PtrAddr));
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100253 return JITEvaluatedSymbol(PtrTargetAddr, I->second.second);
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100254 }
255
256 Error updatePointer(StringRef Name, JITTargetAddress NewAddr) override {
257 auto I = StubIndexes.find(Name);
258 assert(I != StubIndexes.end() && "No stub pointer for symbol");
259 auto Key = I->second.first;
260 *IndirectStubsInfos[Key.first].getPtr(Key.second) =
261 reinterpret_cast<void *>(static_cast<uintptr_t>(NewAddr));
262 return Error::success();
263 }
264
265private:
266 Error reserveStubs(unsigned NumStubs) {
267 if (NumStubs <= FreeStubs.size())
268 return Error::success();
269
270 unsigned NewStubsRequired = NumStubs - FreeStubs.size();
271 unsigned NewBlockId = IndirectStubsInfos.size();
272 typename TargetT::IndirectStubsInfo ISI;
273 if (auto Err =
274 TargetT::emitIndirectStubsBlock(ISI, NewStubsRequired, nullptr))
275 return Err;
276 for (unsigned I = 0; I < ISI.getNumStubs(); ++I)
277 FreeStubs.push_back(std::make_pair(NewBlockId, I));
278 IndirectStubsInfos.push_back(std::move(ISI));
279 return Error::success();
280 }
281
282 void createStubInternal(StringRef StubName, JITTargetAddress InitAddr,
283 JITSymbolFlags StubFlags) {
284 auto Key = FreeStubs.back();
285 FreeStubs.pop_back();
286 *IndirectStubsInfos[Key.first].getPtr(Key.second) =
287 reinterpret_cast<void *>(static_cast<uintptr_t>(InitAddr));
288 StubIndexes[StubName] = std::make_pair(Key, StubFlags);
289 }
290
291 std::vector<typename TargetT::IndirectStubsInfo> IndirectStubsInfos;
292 using StubKey = std::pair<uint16_t, uint16_t>;
293 std::vector<StubKey> FreeStubs;
294 StringMap<std::pair<StubKey, JITSymbolFlags>> StubIndexes;
295};
296
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100297/// Create a local compile callback manager.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100298///
299/// The given target triple will determine the ABI, and the given
300/// ErrorHandlerAddress will be used by the resulting compile callback
301/// manager if a compile callback fails.
302std::unique_ptr<JITCompileCallbackManager>
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100303createLocalCompileCallbackManager(const Triple &T, ExecutionSession &ES,
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100304 JITTargetAddress ErrorHandlerAddress);
305
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100306/// Create a local indriect stubs manager builder.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100307///
308/// The given target triple will determine the ABI.
309std::function<std::unique_ptr<IndirectStubsManager>()>
310createLocalIndirectStubsManagerBuilder(const Triple &T);
311
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100312/// Build a function pointer of FunctionType with the given constant
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100313/// address.
314///
315/// Usage example: Turn a trampoline address into a function pointer constant
316/// for use in a stub.
317Constant *createIRTypedAddress(FunctionType &FT, JITTargetAddress Addr);
318
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100319/// Create a function pointer with the given type, name, and initializer
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100320/// in the given Module.
321GlobalVariable *createImplPointer(PointerType &PT, Module &M, const Twine &Name,
322 Constant *Initializer);
323
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100324/// Turn a function declaration into a stub function that makes an
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100325/// indirect call using the given function pointer.
326void makeStub(Function &F, Value &ImplPointer);
327
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100328/// Raise linkage types and rename as necessary to ensure that all
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100329/// symbols are accessible for other modules.
330///
331/// This should be called before partitioning a module to ensure that the
332/// partitions retain access to each other's symbols.
333void makeAllSymbolsExternallyAccessible(Module &M);
334
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100335/// Clone a function declaration into a new module.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100336///
337/// This function can be used as the first step towards creating a callback
338/// stub (see makeStub), or moving a function body (see moveFunctionBody).
339///
340/// If the VMap argument is non-null, a mapping will be added between F and
341/// the new declaration, and between each of F's arguments and the new
342/// declaration's arguments. This map can then be passed in to moveFunction to
343/// move the function body if required. Note: When moving functions between
344/// modules with these utilities, all decls should be cloned (and added to a
345/// single VMap) before any bodies are moved. This will ensure that references
346/// between functions all refer to the versions in the new module.
347Function *cloneFunctionDecl(Module &Dst, const Function &F,
348 ValueToValueMapTy *VMap = nullptr);
349
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100350/// Move the body of function 'F' to a cloned function declaration in a
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100351/// different module (See related cloneFunctionDecl).
352///
353/// If the target function declaration is not supplied via the NewF parameter
354/// then it will be looked up via the VMap.
355///
356/// This will delete the body of function 'F' from its original parent module,
357/// but leave its declaration.
358void moveFunctionBody(Function &OrigF, ValueToValueMapTy &VMap,
359 ValueMaterializer *Materializer = nullptr,
360 Function *NewF = nullptr);
361
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100362/// Clone a global variable declaration into a new module.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100363GlobalVariable *cloneGlobalVariableDecl(Module &Dst, const GlobalVariable &GV,
364 ValueToValueMapTy *VMap = nullptr);
365
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100366/// Move global variable GV from its parent module to cloned global
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100367/// declaration in a different module.
368///
369/// If the target global declaration is not supplied via the NewGV parameter
370/// then it will be looked up via the VMap.
371///
372/// This will delete the initializer of GV from its original parent module,
373/// but leave its declaration.
374void moveGlobalVariableInitializer(GlobalVariable &OrigGV,
375 ValueToValueMapTy &VMap,
376 ValueMaterializer *Materializer = nullptr,
377 GlobalVariable *NewGV = nullptr);
378
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100379/// Clone a global alias declaration into a new module.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100380GlobalAlias *cloneGlobalAliasDecl(Module &Dst, const GlobalAlias &OrigA,
381 ValueToValueMapTy &VMap);
382
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100383/// Clone module flags metadata into the destination module.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100384void cloneModuleFlagsMetadata(Module &Dst, const Module &Src,
385 ValueToValueMapTy &VMap);
386
387} // end namespace orc
388
389} // end namespace llvm
390
391#endif // LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H