1 //===- IndirectionUtils.h - Utilities for adding indirections ---*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // Contains utilities for adding indirections and breaking up modules.
12 //===----------------------------------------------------------------------===//
14 #ifndef LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H
15 #define LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H
17 #include "llvm/ADT/StringMap.h"
18 #include "llvm/ADT/StringRef.h"
19 #include "llvm/ADT/Twine.h"
20 #include "llvm/ExecutionEngine/JITSymbol.h"
21 #include "llvm/ExecutionEngine/Orc/Core.h"
22 #include "llvm/Support/Error.h"
23 #include "llvm/Support/Memory.h"
24 #include "llvm/Support/Process.h"
25 #include "llvm/Transforms/Utils/ValueMapper.h"
32 #include <system_error>
50 /// Target-independent base class for compile callback management.
51 class JITCompileCallbackManager {
53 using CompileFunction = std::function<JITTargetAddress()>;
55 /// Construct a JITCompileCallbackManager.
56 /// @param ErrorHandlerAddress The address of an error handler in the target
57 /// process to be used if a compile callback fails.
58 JITCompileCallbackManager(ExecutionSession &ES,
59 JITTargetAddress ErrorHandlerAddress)
60 : ES(ES), CallbacksVSO(ES.createVSO("<Callbacks>")),
61 ErrorHandlerAddress(ErrorHandlerAddress) {}
63 virtual ~JITCompileCallbackManager() = default;
65 /// Reserve a compile callback.
66 Expected<JITTargetAddress> getCompileCallback(CompileFunction Compile);
68 /// Execute the callback for the given trampoline id. Called by the JIT
69 /// to compile functions on demand.
70 JITTargetAddress executeCompileCallback(JITTargetAddress TrampolineAddr);
73 std::vector<JITTargetAddress> AvailableTrampolines;
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;
87 // Create new trampolines - to be implemented in subclasses.
88 virtual Error grow() = 0;
90 virtual void anchor();
92 std::mutex CCMgrMutex;
95 JITTargetAddress ErrorHandlerAddress;
96 std::map<JITTargetAddress, SymbolStringPtr> AddrToSymbol;
97 size_t NextCallbackId = 0;
100 /// Manage compile callbacks for in-process JITs.
101 template <typename TargetT>
102 class LocalJITCompileCallbackManager : public JITCompileCallbackManager {
104 /// Construct a InProcessJITCompileCallbackManager.
105 /// @param ErrorHandlerAddress The address of an error handler in the target
106 /// process to be used if a compile callback fails.
107 LocalJITCompileCallbackManager(ExecutionSession &ES,
108 JITTargetAddress ErrorHandlerAddress)
109 : JITCompileCallbackManager(ES, ErrorHandlerAddress) {
110 /// Set up the resolver block.
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");
117 TargetT::writeResolverCode(static_cast<uint8_t *>(ResolverBlock.base()),
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");
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)));
135 Error grow() override {
136 assert(this->AvailableTrampolines.empty() && "Growing prematurely?");
139 auto TrampolineBlock =
140 sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
141 sys::Process::getPageSize(), nullptr,
142 sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
144 return errorCodeToError(EC);
146 unsigned NumTrampolines =
147 (sys::Process::getPageSize() - TargetT::PointerSize) /
148 TargetT::TrampolineSize;
150 uint8_t *TrampolineMem = static_cast<uint8_t *>(TrampolineBlock.base());
151 TargetT::writeTrampolines(TrampolineMem, ResolverBlock.base(),
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))));
159 if (auto EC = sys::Memory::protectMappedMemory(
160 TrampolineBlock.getMemoryBlock(),
161 sys::Memory::MF_READ | sys::Memory::MF_EXEC))
162 return errorCodeToError(EC);
164 TrampolineBlocks.push_back(std::move(TrampolineBlock));
165 return Error::success();
168 sys::OwningMemoryBlock ResolverBlock;
169 std::vector<sys::OwningMemoryBlock> TrampolineBlocks;
172 /// Base class for managing collections of named indirect stubs.
173 class IndirectStubsManager {
175 /// Map type for initializing the manager. See init.
176 using StubInitsMap = StringMap<std::pair<JITTargetAddress, JITSymbolFlags>>;
178 virtual ~IndirectStubsManager() = default;
180 /// Create a single stub with the given name, target address and flags.
181 virtual Error createStub(StringRef StubName, JITTargetAddress StubAddr,
182 JITSymbolFlags StubFlags) = 0;
184 /// Create StubInits.size() stubs with the given names, target
185 /// addresses, and flags.
186 virtual Error createStubs(const StubInitsMap &StubInits) = 0;
188 /// Find the stub with the given name. If ExportedStubsOnly is true,
189 /// this will only return a result if the stub's flags indicate that it
191 virtual JITEvaluatedSymbol findStub(StringRef Name, bool ExportedStubsOnly) = 0;
193 /// Find the implementation-pointer for the stub.
194 virtual JITEvaluatedSymbol findPointer(StringRef Name) = 0;
196 /// Change the value of the implementation pointer for the stub.
197 virtual Error updatePointer(StringRef Name, JITTargetAddress NewAddr) = 0;
200 virtual void anchor();
203 /// IndirectStubsManager implementation for the host architecture, e.g.
204 /// OrcX86_64. (See OrcArchitectureSupport.h).
205 template <typename TargetT>
206 class LocalIndirectStubsManager : public IndirectStubsManager {
208 Error createStub(StringRef StubName, JITTargetAddress StubAddr,
209 JITSymbolFlags StubFlags) override {
210 if (auto Err = reserveStubs(1))
213 createStubInternal(StubName, StubAddr, StubFlags);
215 return Error::success();
218 Error createStubs(const StubInitsMap &StubInits) override {
219 if (auto Err = reserveStubs(StubInits.size()))
222 for (auto &Entry : StubInits)
223 createStubInternal(Entry.first(), Entry.second.first,
224 Entry.second.second);
226 return Error::success();
229 JITEvaluatedSymbol findStub(StringRef Name, bool ExportedStubsOnly) override {
230 auto I = StubIndexes.find(Name);
231 if (I == StubIndexes.end())
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));
238 auto StubSymbol = JITEvaluatedSymbol(StubTargetAddr, I->second.second);
239 if (ExportedStubsOnly && !StubSymbol.getFlags().isExported())
244 JITEvaluatedSymbol findPointer(StringRef Name) override {
245 auto I = StubIndexes.find(Name);
246 if (I == StubIndexes.end())
248 auto Key = I->second.first;
249 void *PtrAddr = IndirectStubsInfos[Key.first].getPtr(Key.second);
250 assert(PtrAddr && "Missing pointer address");
252 static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(PtrAddr));
253 return JITEvaluatedSymbol(PtrTargetAddr, I->second.second);
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();
266 Error reserveStubs(unsigned NumStubs) {
267 if (NumStubs <= FreeStubs.size())
268 return Error::success();
270 unsigned NewStubsRequired = NumStubs - FreeStubs.size();
271 unsigned NewBlockId = IndirectStubsInfos.size();
272 typename TargetT::IndirectStubsInfo ISI;
274 TargetT::emitIndirectStubsBlock(ISI, NewStubsRequired, nullptr))
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();
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);
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;
297 /// Create a local compile callback manager.
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.
302 std::unique_ptr<JITCompileCallbackManager>
303 createLocalCompileCallbackManager(const Triple &T, ExecutionSession &ES,
304 JITTargetAddress ErrorHandlerAddress);
306 /// Create a local indriect stubs manager builder.
308 /// The given target triple will determine the ABI.
309 std::function<std::unique_ptr<IndirectStubsManager>()>
310 createLocalIndirectStubsManagerBuilder(const Triple &T);
312 /// Build a function pointer of FunctionType with the given constant
315 /// Usage example: Turn a trampoline address into a function pointer constant
316 /// for use in a stub.
317 Constant *createIRTypedAddress(FunctionType &FT, JITTargetAddress Addr);
319 /// Create a function pointer with the given type, name, and initializer
320 /// in the given Module.
321 GlobalVariable *createImplPointer(PointerType &PT, Module &M, const Twine &Name,
322 Constant *Initializer);
324 /// Turn a function declaration into a stub function that makes an
325 /// indirect call using the given function pointer.
326 void makeStub(Function &F, Value &ImplPointer);
328 /// Raise linkage types and rename as necessary to ensure that all
329 /// symbols are accessible for other modules.
331 /// This should be called before partitioning a module to ensure that the
332 /// partitions retain access to each other's symbols.
333 void makeAllSymbolsExternallyAccessible(Module &M);
335 /// Clone a function declaration into a new module.
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).
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.
347 Function *cloneFunctionDecl(Module &Dst, const Function &F,
348 ValueToValueMapTy *VMap = nullptr);
350 /// Move the body of function 'F' to a cloned function declaration in a
351 /// different module (See related cloneFunctionDecl).
353 /// If the target function declaration is not supplied via the NewF parameter
354 /// then it will be looked up via the VMap.
356 /// This will delete the body of function 'F' from its original parent module,
357 /// but leave its declaration.
358 void moveFunctionBody(Function &OrigF, ValueToValueMapTy &VMap,
359 ValueMaterializer *Materializer = nullptr,
360 Function *NewF = nullptr);
362 /// Clone a global variable declaration into a new module.
363 GlobalVariable *cloneGlobalVariableDecl(Module &Dst, const GlobalVariable &GV,
364 ValueToValueMapTy *VMap = nullptr);
366 /// Move global variable GV from its parent module to cloned global
367 /// declaration in a different module.
369 /// If the target global declaration is not supplied via the NewGV parameter
370 /// then it will be looked up via the VMap.
372 /// This will delete the initializer of GV from its original parent module,
373 /// but leave its declaration.
374 void moveGlobalVariableInitializer(GlobalVariable &OrigGV,
375 ValueToValueMapTy &VMap,
376 ValueMaterializer *Materializer = nullptr,
377 GlobalVariable *NewGV = nullptr);
379 /// Clone a global alias declaration into a new module.
380 GlobalAlias *cloneGlobalAliasDecl(Module &Dst, const GlobalAlias &OrigA,
381 ValueToValueMapTy &VMap);
383 /// Clone module flags metadata into the destination module.
384 void cloneModuleFlagsMetadata(Module &Dst, const Module &Src,
385 ValueToValueMapTy &VMap);
387 } // end namespace orc
389 } // end namespace llvm
391 #endif // LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H