1 //===- 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" 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" 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 36 namespace llvm { 37 38 class Constant; 39 class Function; 40 class FunctionType; 41 class GlobalAlias; 42 class GlobalVariable; 43 class Module; 44 class PointerType; 45 class Triple; 46 class Value; 47 48 namespace orc { 49 50 /// Target-independent base class for compile callback management. 51 class JITCompileCallbackManager { 52 public: 53 using CompileFunction = std::function<JITTargetAddress()>; 54 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. JITCompileCallbackManager(ExecutionSession & ES,JITTargetAddress ErrorHandlerAddress)58 JITCompileCallbackManager(ExecutionSession &ES, 59 JITTargetAddress ErrorHandlerAddress) 60 : ES(ES), CallbacksVSO(ES.createVSO("<Callbacks>")), 61 ErrorHandlerAddress(ErrorHandlerAddress) {} 62 63 virtual ~JITCompileCallbackManager() = default; 64 65 /// Reserve a compile callback. 66 Expected<JITTargetAddress> getCompileCallback(CompileFunction Compile); 67 68 /// Execute the callback for the given trampoline id. Called by the JIT 69 /// to compile functions on demand. 70 JITTargetAddress executeCompileCallback(JITTargetAddress TrampolineAddr); 71 72 protected: 73 std::vector<JITTargetAddress> AvailableTrampolines; 74 75 private: getAvailableTrampolineAddr()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(); 91 92 std::mutex CCMgrMutex; 93 ExecutionSession &ES; 94 VSO &CallbacksVSO; 95 JITTargetAddress ErrorHandlerAddress; 96 std::map<JITTargetAddress, SymbolStringPtr> AddrToSymbol; 97 size_t NextCallbackId = 0; 98 }; 99 100 /// Manage compile callbacks for in-process JITs. 101 template <typename TargetT> 102 class LocalJITCompileCallbackManager : public JITCompileCallbackManager { 103 public: 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. LocalJITCompileCallbackManager(ExecutionSession & ES,JITTargetAddress ErrorHandlerAddress)107 LocalJITCompileCallbackManager(ExecutionSession &ES, 108 JITTargetAddress ErrorHandlerAddress) 109 : JITCompileCallbackManager(ES, ErrorHandlerAddress) { 110 /// 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 126 private: reenter(void * CCMgr,void * TrampolineId)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 grow()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 172 /// Base class for managing collections of named indirect stubs. 173 class IndirectStubsManager { 174 public: 175 /// Map type for initializing the manager. See init. 176 using StubInitsMap = StringMap<std::pair<JITTargetAddress, JITSymbolFlags>>; 177 178 virtual ~IndirectStubsManager() = default; 179 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; 183 184 /// Create StubInits.size() stubs with the given names, target 185 /// addresses, and flags. 186 virtual Error createStubs(const StubInitsMap &StubInits) = 0; 187 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 190 /// is exported. 191 virtual JITEvaluatedSymbol findStub(StringRef Name, bool ExportedStubsOnly) = 0; 192 193 /// Find the implementation-pointer for the stub. 194 virtual JITEvaluatedSymbol findPointer(StringRef Name) = 0; 195 196 /// Change the value of the implementation pointer for the stub. 197 virtual Error updatePointer(StringRef Name, JITTargetAddress NewAddr) = 0; 198 199 private: 200 virtual void anchor(); 201 }; 202 203 /// IndirectStubsManager implementation for the host architecture, e.g. 204 /// OrcX86_64. (See OrcArchitectureSupport.h). 205 template <typename TargetT> 206 class LocalIndirectStubsManager : public IndirectStubsManager { 207 public: createStub(StringRef StubName,JITTargetAddress StubAddr,JITSymbolFlags StubFlags)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 createStubs(const StubInitsMap & StubInits)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 findStub(StringRef Name,bool ExportedStubsOnly)229 JITEvaluatedSymbol findStub(StringRef Name, bool ExportedStubsOnly) override { 230 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)); 238 auto StubSymbol = JITEvaluatedSymbol(StubTargetAddr, I->second.second); 239 if (ExportedStubsOnly && !StubSymbol.getFlags().isExported()) 240 return nullptr; 241 return StubSymbol; 242 } 243 findPointer(StringRef Name)244 JITEvaluatedSymbol findPointer(StringRef Name) override { 245 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)); 253 return JITEvaluatedSymbol(PtrTargetAddr, I->second.second); 254 } 255 updatePointer(StringRef Name,JITTargetAddress NewAddr)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 265 private: reserveStubs(unsigned NumStubs)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 createStubInternal(StringRef StubName,JITTargetAddress InitAddr,JITSymbolFlags StubFlags)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 297 /// Create a local compile callback manager. 298 /// 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); 305 306 /// Create a local indriect stubs manager builder. 307 /// 308 /// The given target triple will determine the ABI. 309 std::function<std::unique_ptr<IndirectStubsManager>()> 310 createLocalIndirectStubsManagerBuilder(const Triple &T); 311 312 /// Build a function pointer of FunctionType with the given constant 313 /// address. 314 /// 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); 318 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); 323 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); 327 328 /// Raise linkage types and rename as necessary to ensure that all 329 /// 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. 333 void makeAllSymbolsExternallyAccessible(Module &M); 334 335 /// Clone a function declaration into a new module. 336 /// 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. 347 Function *cloneFunctionDecl(Module &Dst, const Function &F, 348 ValueToValueMapTy *VMap = nullptr); 349 350 /// Move the body of function 'F' to a cloned function declaration in a 351 /// 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. 358 void moveFunctionBody(Function &OrigF, ValueToValueMapTy &VMap, 359 ValueMaterializer *Materializer = nullptr, 360 Function *NewF = nullptr); 361 362 /// Clone a global variable declaration into a new module. 363 GlobalVariable *cloneGlobalVariableDecl(Module &Dst, const GlobalVariable &GV, 364 ValueToValueMapTy *VMap = nullptr); 365 366 /// Move global variable GV from its parent module to cloned global 367 /// 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. 374 void moveGlobalVariableInitializer(GlobalVariable &OrigGV, 375 ValueToValueMapTy &VMap, 376 ValueMaterializer *Materializer = nullptr, 377 GlobalVariable *NewGV = nullptr); 378 379 /// Clone a global alias declaration into a new module. 380 GlobalAlias *cloneGlobalAliasDecl(Module &Dst, const GlobalAlias &OrigA, 381 ValueToValueMapTy &VMap); 382 383 /// Clone module flags metadata into the destination module. 384 void 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 392