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/Support/Error.h"
22 #include "llvm/Support/Memory.h"
23 #include "llvm/Support/Process.h"
24 #include "llvm/Transforms/Utils/ValueMapper.h"
31 #include <system_error>
49 /// Target-independent base class for compile callback management.
50 class JITCompileCallbackManager {
52 using CompileFtor = std::function<JITTargetAddress()>;
54 /// Handle to a newly created compile callback. Can be used to get an
55 /// IR constant representing the address of the trampoline, and to set
56 /// the compile action for the callback.
57 class CompileCallbackInfo {
59 CompileCallbackInfo(JITTargetAddress Addr, CompileFtor &Compile)
60 : Addr(Addr), Compile(Compile) {}
62 JITTargetAddress getAddress() const { return Addr; }
63 void setCompileAction(CompileFtor Compile) {
64 this->Compile = std::move(Compile);
68 JITTargetAddress Addr;
72 /// Construct a JITCompileCallbackManager.
73 /// @param ErrorHandlerAddress The address of an error handler in the target
74 /// process to be used if a compile callback fails.
75 JITCompileCallbackManager(JITTargetAddress ErrorHandlerAddress)
76 : ErrorHandlerAddress(ErrorHandlerAddress) {}
78 virtual ~JITCompileCallbackManager() = default;
80 /// Execute the callback for the given trampoline id. Called by the JIT
81 /// to compile functions on demand.
82 JITTargetAddress executeCompileCallback(JITTargetAddress TrampolineAddr) {
83 auto I = ActiveTrampolines.find(TrampolineAddr);
84 // FIXME: Also raise an error in the Orc error-handler when we finally have
86 if (I == ActiveTrampolines.end())
87 return ErrorHandlerAddress;
89 // Found a callback handler. Yank this trampoline out of the active list and
90 // put it back in the available trampolines list, then try to run the
91 // handler's compile and update actions.
92 // Moving the trampoline ID back to the available list first means there's
94 // least one available trampoline if the compile action triggers a request
97 auto Compile = std::move(I->second);
98 ActiveTrampolines.erase(I);
99 AvailableTrampolines.push_back(TrampolineAddr);
101 if (auto Addr = Compile())
104 return ErrorHandlerAddress;
107 /// Reserve a compile callback.
108 Expected<CompileCallbackInfo> getCompileCallback() {
109 if (auto TrampolineAddrOrErr = getAvailableTrampolineAddr()) {
110 const auto &TrampolineAddr = *TrampolineAddrOrErr;
111 auto &Compile = this->ActiveTrampolines[TrampolineAddr];
112 return CompileCallbackInfo(TrampolineAddr, Compile);
114 return TrampolineAddrOrErr.takeError();
117 /// Get a CompileCallbackInfo for an existing callback.
118 CompileCallbackInfo getCompileCallbackInfo(JITTargetAddress TrampolineAddr) {
119 auto I = ActiveTrampolines.find(TrampolineAddr);
120 assert(I != ActiveTrampolines.end() && "Not an active trampoline.");
121 return CompileCallbackInfo(I->first, I->second);
124 /// Release a compile callback.
126 /// Note: Callbacks are auto-released after they execute. This method should
127 /// only be called to manually release a callback that is not going to
129 void releaseCompileCallback(JITTargetAddress TrampolineAddr) {
130 auto I = ActiveTrampolines.find(TrampolineAddr);
131 assert(I != ActiveTrampolines.end() && "Not an active trampoline.");
132 ActiveTrampolines.erase(I);
133 AvailableTrampolines.push_back(TrampolineAddr);
137 JITTargetAddress ErrorHandlerAddress;
139 using TrampolineMapT = std::map<JITTargetAddress, CompileFtor>;
140 TrampolineMapT ActiveTrampolines;
141 std::vector<JITTargetAddress> AvailableTrampolines;
144 Expected<JITTargetAddress> getAvailableTrampolineAddr() {
145 if (this->AvailableTrampolines.empty())
146 if (auto Err = grow())
147 return std::move(Err);
148 assert(!this->AvailableTrampolines.empty() &&
149 "Failed to grow available trampolines.");
150 JITTargetAddress TrampolineAddr = this->AvailableTrampolines.back();
151 this->AvailableTrampolines.pop_back();
152 return TrampolineAddr;
155 // Create new trampolines - to be implemented in subclasses.
156 virtual Error grow() = 0;
158 virtual void anchor();
161 /// Manage compile callbacks for in-process JITs.
162 template <typename TargetT>
163 class LocalJITCompileCallbackManager : public JITCompileCallbackManager {
165 /// Construct a InProcessJITCompileCallbackManager.
166 /// @param ErrorHandlerAddress The address of an error handler in the target
167 /// process to be used if a compile callback fails.
168 LocalJITCompileCallbackManager(JITTargetAddress ErrorHandlerAddress)
169 : JITCompileCallbackManager(ErrorHandlerAddress) {
170 /// Set up the resolver block.
172 ResolverBlock = sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
173 TargetT::ResolverCodeSize, nullptr,
174 sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
175 assert(!EC && "Failed to allocate resolver block");
177 TargetT::writeResolverCode(static_cast<uint8_t *>(ResolverBlock.base()),
180 EC = sys::Memory::protectMappedMemory(ResolverBlock.getMemoryBlock(),
181 sys::Memory::MF_READ |
182 sys::Memory::MF_EXEC);
183 assert(!EC && "Failed to mprotect resolver block");
187 static JITTargetAddress reenter(void *CCMgr, void *TrampolineId) {
188 JITCompileCallbackManager *Mgr =
189 static_cast<JITCompileCallbackManager *>(CCMgr);
190 return Mgr->executeCompileCallback(
191 static_cast<JITTargetAddress>(
192 reinterpret_cast<uintptr_t>(TrampolineId)));
195 Error grow() override {
196 assert(this->AvailableTrampolines.empty() && "Growing prematurely?");
199 auto TrampolineBlock =
200 sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
201 sys::Process::getPageSize(), nullptr,
202 sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
204 return errorCodeToError(EC);
206 unsigned NumTrampolines =
207 (sys::Process::getPageSize() - TargetT::PointerSize) /
208 TargetT::TrampolineSize;
210 uint8_t *TrampolineMem = static_cast<uint8_t *>(TrampolineBlock.base());
211 TargetT::writeTrampolines(TrampolineMem, ResolverBlock.base(),
214 for (unsigned I = 0; I < NumTrampolines; ++I)
215 this->AvailableTrampolines.push_back(
216 static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(
217 TrampolineMem + (I * TargetT::TrampolineSize))));
219 if (auto EC = sys::Memory::protectMappedMemory(
220 TrampolineBlock.getMemoryBlock(),
221 sys::Memory::MF_READ | sys::Memory::MF_EXEC))
222 return errorCodeToError(EC);
224 TrampolineBlocks.push_back(std::move(TrampolineBlock));
225 return Error::success();
228 sys::OwningMemoryBlock ResolverBlock;
229 std::vector<sys::OwningMemoryBlock> TrampolineBlocks;
232 /// Base class for managing collections of named indirect stubs.
233 class IndirectStubsManager {
235 /// Map type for initializing the manager. See init.
236 using StubInitsMap = StringMap<std::pair<JITTargetAddress, JITSymbolFlags>>;
238 virtual ~IndirectStubsManager() = default;
240 /// Create a single stub with the given name, target address and flags.
241 virtual Error createStub(StringRef StubName, JITTargetAddress StubAddr,
242 JITSymbolFlags StubFlags) = 0;
244 /// Create StubInits.size() stubs with the given names, target
245 /// addresses, and flags.
246 virtual Error createStubs(const StubInitsMap &StubInits) = 0;
248 /// Find the stub with the given name. If ExportedStubsOnly is true,
249 /// this will only return a result if the stub's flags indicate that it
251 virtual JITSymbol findStub(StringRef Name, bool ExportedStubsOnly) = 0;
253 /// Find the implementation-pointer for the stub.
254 virtual JITSymbol findPointer(StringRef Name) = 0;
256 /// Change the value of the implementation pointer for the stub.
257 virtual Error updatePointer(StringRef Name, JITTargetAddress NewAddr) = 0;
260 virtual void anchor();
263 /// IndirectStubsManager implementation for the host architecture, e.g.
264 /// OrcX86_64. (See OrcArchitectureSupport.h).
265 template <typename TargetT>
266 class LocalIndirectStubsManager : public IndirectStubsManager {
268 Error createStub(StringRef StubName, JITTargetAddress StubAddr,
269 JITSymbolFlags StubFlags) override {
270 if (auto Err = reserveStubs(1))
273 createStubInternal(StubName, StubAddr, StubFlags);
275 return Error::success();
278 Error createStubs(const StubInitsMap &StubInits) override {
279 if (auto Err = reserveStubs(StubInits.size()))
282 for (auto &Entry : StubInits)
283 createStubInternal(Entry.first(), Entry.second.first,
284 Entry.second.second);
286 return Error::success();
289 JITSymbol findStub(StringRef Name, bool ExportedStubsOnly) override {
290 auto I = StubIndexes.find(Name);
291 if (I == StubIndexes.end())
293 auto Key = I->second.first;
294 void *StubAddr = IndirectStubsInfos[Key.first].getStub(Key.second);
295 assert(StubAddr && "Missing stub address");
296 auto StubTargetAddr =
297 static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(StubAddr));
298 auto StubSymbol = JITSymbol(StubTargetAddr, I->second.second);
299 if (ExportedStubsOnly && !StubSymbol.getFlags().isExported())
304 JITSymbol findPointer(StringRef Name) override {
305 auto I = StubIndexes.find(Name);
306 if (I == StubIndexes.end())
308 auto Key = I->second.first;
309 void *PtrAddr = IndirectStubsInfos[Key.first].getPtr(Key.second);
310 assert(PtrAddr && "Missing pointer address");
312 static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(PtrAddr));
313 return JITSymbol(PtrTargetAddr, I->second.second);
316 Error updatePointer(StringRef Name, JITTargetAddress NewAddr) override {
317 auto I = StubIndexes.find(Name);
318 assert(I != StubIndexes.end() && "No stub pointer for symbol");
319 auto Key = I->second.first;
320 *IndirectStubsInfos[Key.first].getPtr(Key.second) =
321 reinterpret_cast<void *>(static_cast<uintptr_t>(NewAddr));
322 return Error::success();
326 Error reserveStubs(unsigned NumStubs) {
327 if (NumStubs <= FreeStubs.size())
328 return Error::success();
330 unsigned NewStubsRequired = NumStubs - FreeStubs.size();
331 unsigned NewBlockId = IndirectStubsInfos.size();
332 typename TargetT::IndirectStubsInfo ISI;
334 TargetT::emitIndirectStubsBlock(ISI, NewStubsRequired, nullptr))
336 for (unsigned I = 0; I < ISI.getNumStubs(); ++I)
337 FreeStubs.push_back(std::make_pair(NewBlockId, I));
338 IndirectStubsInfos.push_back(std::move(ISI));
339 return Error::success();
342 void createStubInternal(StringRef StubName, JITTargetAddress InitAddr,
343 JITSymbolFlags StubFlags) {
344 auto Key = FreeStubs.back();
345 FreeStubs.pop_back();
346 *IndirectStubsInfos[Key.first].getPtr(Key.second) =
347 reinterpret_cast<void *>(static_cast<uintptr_t>(InitAddr));
348 StubIndexes[StubName] = std::make_pair(Key, StubFlags);
351 std::vector<typename TargetT::IndirectStubsInfo> IndirectStubsInfos;
352 using StubKey = std::pair<uint16_t, uint16_t>;
353 std::vector<StubKey> FreeStubs;
354 StringMap<std::pair<StubKey, JITSymbolFlags>> StubIndexes;
357 /// Create a local compile callback manager.
359 /// The given target triple will determine the ABI, and the given
360 /// ErrorHandlerAddress will be used by the resulting compile callback
361 /// manager if a compile callback fails.
362 std::unique_ptr<JITCompileCallbackManager>
363 createLocalCompileCallbackManager(const Triple &T,
364 JITTargetAddress ErrorHandlerAddress);
366 /// Create a local indriect stubs manager builder.
368 /// The given target triple will determine the ABI.
369 std::function<std::unique_ptr<IndirectStubsManager>()>
370 createLocalIndirectStubsManagerBuilder(const Triple &T);
372 /// Build a function pointer of FunctionType with the given constant
375 /// Usage example: Turn a trampoline address into a function pointer constant
376 /// for use in a stub.
377 Constant *createIRTypedAddress(FunctionType &FT, JITTargetAddress Addr);
379 /// Create a function pointer with the given type, name, and initializer
380 /// in the given Module.
381 GlobalVariable *createImplPointer(PointerType &PT, Module &M, const Twine &Name,
382 Constant *Initializer);
384 /// Turn a function declaration into a stub function that makes an
385 /// indirect call using the given function pointer.
386 void makeStub(Function &F, Value &ImplPointer);
388 /// Raise linkage types and rename as necessary to ensure that all
389 /// symbols are accessible for other modules.
391 /// This should be called before partitioning a module to ensure that the
392 /// partitions retain access to each other's symbols.
393 void makeAllSymbolsExternallyAccessible(Module &M);
395 /// Clone a function declaration into a new module.
397 /// This function can be used as the first step towards creating a callback
398 /// stub (see makeStub), or moving a function body (see moveFunctionBody).
400 /// If the VMap argument is non-null, a mapping will be added between F and
401 /// the new declaration, and between each of F's arguments and the new
402 /// declaration's arguments. This map can then be passed in to moveFunction to
403 /// move the function body if required. Note: When moving functions between
404 /// modules with these utilities, all decls should be cloned (and added to a
405 /// single VMap) before any bodies are moved. This will ensure that references
406 /// between functions all refer to the versions in the new module.
407 Function *cloneFunctionDecl(Module &Dst, const Function &F,
408 ValueToValueMapTy *VMap = nullptr);
410 /// Move the body of function 'F' to a cloned function declaration in a
411 /// different module (See related cloneFunctionDecl).
413 /// If the target function declaration is not supplied via the NewF parameter
414 /// then it will be looked up via the VMap.
416 /// This will delete the body of function 'F' from its original parent module,
417 /// but leave its declaration.
418 void moveFunctionBody(Function &OrigF, ValueToValueMapTy &VMap,
419 ValueMaterializer *Materializer = nullptr,
420 Function *NewF = nullptr);
422 /// Clone a global variable declaration into a new module.
423 GlobalVariable *cloneGlobalVariableDecl(Module &Dst, const GlobalVariable &GV,
424 ValueToValueMapTy *VMap = nullptr);
426 /// Move global variable GV from its parent module to cloned global
427 /// declaration in a different module.
429 /// If the target global declaration is not supplied via the NewGV parameter
430 /// then it will be looked up via the VMap.
432 /// This will delete the initializer of GV from its original parent module,
433 /// but leave its declaration.
434 void moveGlobalVariableInitializer(GlobalVariable &OrigGV,
435 ValueToValueMapTy &VMap,
436 ValueMaterializer *Materializer = nullptr,
437 GlobalVariable *NewGV = nullptr);
439 /// Clone a global alias declaration into a new module.
440 GlobalAlias *cloneGlobalAliasDecl(Module &Dst, const GlobalAlias &OrigA,
441 ValueToValueMapTy &VMap);
443 /// Clone module flags metadata into the destination module.
444 void cloneModuleFlagsMetadata(Module &Dst, const Module &Src,
445 ValueToValueMapTy &VMap);
447 } // end namespace orc
449 } // end namespace llvm
451 #endif // LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H