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 /// Base class for pools of compiler re-entry trampolines. 51 /// These trampolines are callable addresses that save all register state 52 /// before calling a supplied function to return the trampoline landing 53 /// address, then restore all state before jumping to that address. They 54 /// are used by various ORC APIs to support lazy compilation 55 class TrampolinePool { 56 public: ~TrampolinePool()57 virtual ~TrampolinePool() {} 58 59 /// Get an available trampoline address. 60 /// Returns an error if no trampoline can be created. 61 virtual Expected<JITTargetAddress> getTrampoline() = 0; 62 63 private: 64 virtual void anchor(); 65 }; 66 67 /// A trampoline pool for trampolines within the current process. 68 template <typename ORCABI> class LocalTrampolinePool : public TrampolinePool { 69 public: 70 using GetTrampolineLandingFunction = 71 std::function<JITTargetAddress(JITTargetAddress TrampolineAddr)>; 72 73 /// Creates a LocalTrampolinePool with the given RunCallback function. 74 /// Returns an error if this function is unable to correctly allocate, write 75 /// and protect the resolver code block. 76 static Expected<std::unique_ptr<LocalTrampolinePool>> Create(GetTrampolineLandingFunction GetTrampolineLanding)77 Create(GetTrampolineLandingFunction GetTrampolineLanding) { 78 Error Err = Error::success(); 79 80 auto LTP = std::unique_ptr<LocalTrampolinePool>( 81 new LocalTrampolinePool(std::move(GetTrampolineLanding), Err)); 82 83 if (Err) 84 return std::move(Err); 85 return std::move(LTP); 86 } 87 88 /// Get a free trampoline. Returns an error if one can not be provide (e.g. 89 /// because the pool is empty and can not be grown). getTrampoline()90 Expected<JITTargetAddress> getTrampoline() override { 91 std::lock_guard<std::mutex> Lock(LTPMutex); 92 if (AvailableTrampolines.empty()) { 93 if (auto Err = grow()) 94 return std::move(Err); 95 } 96 assert(!AvailableTrampolines.empty() && "Failed to grow trampoline pool"); 97 auto TrampolineAddr = AvailableTrampolines.back(); 98 AvailableTrampolines.pop_back(); 99 return TrampolineAddr; 100 } 101 102 /// Returns the given trampoline to the pool for re-use. releaseTrampoline(JITTargetAddress TrampolineAddr)103 void releaseTrampoline(JITTargetAddress TrampolineAddr) { 104 std::lock_guard<std::mutex> Lock(LTPMutex); 105 AvailableTrampolines.push_back(TrampolineAddr); 106 } 107 108 private: reenter(void * TrampolinePoolPtr,void * TrampolineId)109 static JITTargetAddress reenter(void *TrampolinePoolPtr, void *TrampolineId) { 110 LocalTrampolinePool<ORCABI> *TrampolinePool = 111 static_cast<LocalTrampolinePool *>(TrampolinePoolPtr); 112 return TrampolinePool->GetTrampolineLanding(static_cast<JITTargetAddress>( 113 reinterpret_cast<uintptr_t>(TrampolineId))); 114 } 115 LocalTrampolinePool(GetTrampolineLandingFunction GetTrampolineLanding,Error & Err)116 LocalTrampolinePool(GetTrampolineLandingFunction GetTrampolineLanding, 117 Error &Err) 118 : GetTrampolineLanding(std::move(GetTrampolineLanding)) { 119 120 ErrorAsOutParameter _(&Err); 121 122 /// Try to set up the resolver block. 123 std::error_code EC; 124 ResolverBlock = sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory( 125 ORCABI::ResolverCodeSize, nullptr, 126 sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC)); 127 if (EC) { 128 Err = errorCodeToError(EC); 129 return; 130 } 131 132 ORCABI::writeResolverCode(static_cast<uint8_t *>(ResolverBlock.base()), 133 &reenter, this); 134 135 EC = sys::Memory::protectMappedMemory(ResolverBlock.getMemoryBlock(), 136 sys::Memory::MF_READ | 137 sys::Memory::MF_EXEC); 138 if (EC) { 139 Err = errorCodeToError(EC); 140 return; 141 } 142 } 143 grow()144 Error grow() { 145 assert(this->AvailableTrampolines.empty() && "Growing prematurely?"); 146 147 std::error_code EC; 148 auto TrampolineBlock = 149 sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory( 150 sys::Process::getPageSize(), nullptr, 151 sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC)); 152 if (EC) 153 return errorCodeToError(EC); 154 155 unsigned NumTrampolines = 156 (sys::Process::getPageSize() - ORCABI::PointerSize) / 157 ORCABI::TrampolineSize; 158 159 uint8_t *TrampolineMem = static_cast<uint8_t *>(TrampolineBlock.base()); 160 ORCABI::writeTrampolines(TrampolineMem, ResolverBlock.base(), 161 NumTrampolines); 162 163 for (unsigned I = 0; I < NumTrampolines; ++I) 164 this->AvailableTrampolines.push_back( 165 static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>( 166 TrampolineMem + (I * ORCABI::TrampolineSize)))); 167 168 if (auto EC = sys::Memory::protectMappedMemory( 169 TrampolineBlock.getMemoryBlock(), 170 sys::Memory::MF_READ | sys::Memory::MF_EXEC)) 171 return errorCodeToError(EC); 172 173 TrampolineBlocks.push_back(std::move(TrampolineBlock)); 174 return Error::success(); 175 } 176 177 GetTrampolineLandingFunction GetTrampolineLanding; 178 179 std::mutex LTPMutex; 180 sys::OwningMemoryBlock ResolverBlock; 181 std::vector<sys::OwningMemoryBlock> TrampolineBlocks; 182 std::vector<JITTargetAddress> AvailableTrampolines; 183 }; 184 185 /// Target-independent base class for compile callback management. 186 class JITCompileCallbackManager { 187 public: 188 using CompileFunction = std::function<JITTargetAddress()>; 189 190 virtual ~JITCompileCallbackManager() = default; 191 192 /// Reserve a compile callback. 193 Expected<JITTargetAddress> getCompileCallback(CompileFunction Compile); 194 195 /// Execute the callback for the given trampoline id. Called by the JIT 196 /// to compile functions on demand. 197 JITTargetAddress executeCompileCallback(JITTargetAddress TrampolineAddr); 198 199 protected: 200 /// Construct a JITCompileCallbackManager. JITCompileCallbackManager(std::unique_ptr<TrampolinePool> TP,ExecutionSession & ES,JITTargetAddress ErrorHandlerAddress)201 JITCompileCallbackManager(std::unique_ptr<TrampolinePool> TP, 202 ExecutionSession &ES, 203 JITTargetAddress ErrorHandlerAddress) 204 : TP(std::move(TP)), ES(ES), 205 CallbacksJD(ES.createJITDylib("<Callbacks>")), 206 ErrorHandlerAddress(ErrorHandlerAddress) {} 207 setTrampolinePool(std::unique_ptr<TrampolinePool> TP)208 void setTrampolinePool(std::unique_ptr<TrampolinePool> TP) { 209 this->TP = std::move(TP); 210 } 211 212 private: 213 std::mutex CCMgrMutex; 214 std::unique_ptr<TrampolinePool> TP; 215 ExecutionSession &ES; 216 JITDylib &CallbacksJD; 217 JITTargetAddress ErrorHandlerAddress; 218 std::map<JITTargetAddress, SymbolStringPtr> AddrToSymbol; 219 size_t NextCallbackId = 0; 220 }; 221 222 /// Manage compile callbacks for in-process JITs. 223 template <typename ORCABI> 224 class LocalJITCompileCallbackManager : public JITCompileCallbackManager { 225 public: 226 /// Create a new LocalJITCompileCallbackManager. 227 static Expected<std::unique_ptr<LocalJITCompileCallbackManager>> Create(ExecutionSession & ES,JITTargetAddress ErrorHandlerAddress)228 Create(ExecutionSession &ES, JITTargetAddress ErrorHandlerAddress) { 229 Error Err = Error::success(); 230 auto CCMgr = std::unique_ptr<LocalJITCompileCallbackManager>( 231 new LocalJITCompileCallbackManager(ES, ErrorHandlerAddress, Err)); 232 if (Err) 233 return std::move(Err); 234 return std::move(CCMgr); 235 } 236 237 private: 238 /// Construct a InProcessJITCompileCallbackManager. 239 /// @param ErrorHandlerAddress The address of an error handler in the target 240 /// process to be used if a compile callback fails. LocalJITCompileCallbackManager(ExecutionSession & ES,JITTargetAddress ErrorHandlerAddress,Error & Err)241 LocalJITCompileCallbackManager(ExecutionSession &ES, 242 JITTargetAddress ErrorHandlerAddress, 243 Error &Err) 244 : JITCompileCallbackManager(nullptr, ES, ErrorHandlerAddress) { 245 ErrorAsOutParameter _(&Err); 246 auto TP = LocalTrampolinePool<ORCABI>::Create( 247 [this](JITTargetAddress TrampolineAddr) { 248 return executeCompileCallback(TrampolineAddr); 249 }); 250 251 if (!TP) { 252 Err = TP.takeError(); 253 return; 254 } 255 256 setTrampolinePool(std::move(*TP)); 257 } 258 }; 259 260 /// Base class for managing collections of named indirect stubs. 261 class IndirectStubsManager { 262 public: 263 /// Map type for initializing the manager. See init. 264 using StubInitsMap = StringMap<std::pair<JITTargetAddress, JITSymbolFlags>>; 265 266 virtual ~IndirectStubsManager() = default; 267 268 /// Create a single stub with the given name, target address and flags. 269 virtual Error createStub(StringRef StubName, JITTargetAddress StubAddr, 270 JITSymbolFlags StubFlags) = 0; 271 272 /// Create StubInits.size() stubs with the given names, target 273 /// addresses, and flags. 274 virtual Error createStubs(const StubInitsMap &StubInits) = 0; 275 276 /// Find the stub with the given name. If ExportedStubsOnly is true, 277 /// this will only return a result if the stub's flags indicate that it 278 /// is exported. 279 virtual JITEvaluatedSymbol findStub(StringRef Name, bool ExportedStubsOnly) = 0; 280 281 /// Find the implementation-pointer for the stub. 282 virtual JITEvaluatedSymbol findPointer(StringRef Name) = 0; 283 284 /// Change the value of the implementation pointer for the stub. 285 virtual Error updatePointer(StringRef Name, JITTargetAddress NewAddr) = 0; 286 287 private: 288 virtual void anchor(); 289 }; 290 291 /// IndirectStubsManager implementation for the host architecture, e.g. 292 /// OrcX86_64. (See OrcArchitectureSupport.h). 293 template <typename TargetT> 294 class LocalIndirectStubsManager : public IndirectStubsManager { 295 public: createStub(StringRef StubName,JITTargetAddress StubAddr,JITSymbolFlags StubFlags)296 Error createStub(StringRef StubName, JITTargetAddress StubAddr, 297 JITSymbolFlags StubFlags) override { 298 std::lock_guard<std::mutex> Lock(StubsMutex); 299 if (auto Err = reserveStubs(1)) 300 return Err; 301 302 createStubInternal(StubName, StubAddr, StubFlags); 303 304 return Error::success(); 305 } 306 createStubs(const StubInitsMap & StubInits)307 Error createStubs(const StubInitsMap &StubInits) override { 308 std::lock_guard<std::mutex> Lock(StubsMutex); 309 if (auto Err = reserveStubs(StubInits.size())) 310 return Err; 311 312 for (auto &Entry : StubInits) 313 createStubInternal(Entry.first(), Entry.second.first, 314 Entry.second.second); 315 316 return Error::success(); 317 } 318 findStub(StringRef Name,bool ExportedStubsOnly)319 JITEvaluatedSymbol findStub(StringRef Name, bool ExportedStubsOnly) override { 320 std::lock_guard<std::mutex> Lock(StubsMutex); 321 auto I = StubIndexes.find(Name); 322 if (I == StubIndexes.end()) 323 return nullptr; 324 auto Key = I->second.first; 325 void *StubAddr = IndirectStubsInfos[Key.first].getStub(Key.second); 326 assert(StubAddr && "Missing stub address"); 327 auto StubTargetAddr = 328 static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(StubAddr)); 329 auto StubSymbol = JITEvaluatedSymbol(StubTargetAddr, I->second.second); 330 if (ExportedStubsOnly && !StubSymbol.getFlags().isExported()) 331 return nullptr; 332 return StubSymbol; 333 } 334 findPointer(StringRef Name)335 JITEvaluatedSymbol findPointer(StringRef Name) override { 336 std::lock_guard<std::mutex> Lock(StubsMutex); 337 auto I = StubIndexes.find(Name); 338 if (I == StubIndexes.end()) 339 return nullptr; 340 auto Key = I->second.first; 341 void *PtrAddr = IndirectStubsInfos[Key.first].getPtr(Key.second); 342 assert(PtrAddr && "Missing pointer address"); 343 auto PtrTargetAddr = 344 static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(PtrAddr)); 345 return JITEvaluatedSymbol(PtrTargetAddr, I->second.second); 346 } 347 updatePointer(StringRef Name,JITTargetAddress NewAddr)348 Error updatePointer(StringRef Name, JITTargetAddress NewAddr) override { 349 using AtomicIntPtr = std::atomic<uintptr_t>; 350 351 std::lock_guard<std::mutex> Lock(StubsMutex); 352 auto I = StubIndexes.find(Name); 353 assert(I != StubIndexes.end() && "No stub pointer for symbol"); 354 auto Key = I->second.first; 355 AtomicIntPtr *AtomicStubPtr = reinterpret_cast<AtomicIntPtr *>( 356 IndirectStubsInfos[Key.first].getPtr(Key.second)); 357 *AtomicStubPtr = static_cast<uintptr_t>(NewAddr); 358 return Error::success(); 359 } 360 361 private: reserveStubs(unsigned NumStubs)362 Error reserveStubs(unsigned NumStubs) { 363 if (NumStubs <= FreeStubs.size()) 364 return Error::success(); 365 366 unsigned NewStubsRequired = NumStubs - FreeStubs.size(); 367 unsigned NewBlockId = IndirectStubsInfos.size(); 368 typename TargetT::IndirectStubsInfo ISI; 369 if (auto Err = 370 TargetT::emitIndirectStubsBlock(ISI, NewStubsRequired, nullptr)) 371 return Err; 372 for (unsigned I = 0; I < ISI.getNumStubs(); ++I) 373 FreeStubs.push_back(std::make_pair(NewBlockId, I)); 374 IndirectStubsInfos.push_back(std::move(ISI)); 375 return Error::success(); 376 } 377 createStubInternal(StringRef StubName,JITTargetAddress InitAddr,JITSymbolFlags StubFlags)378 void createStubInternal(StringRef StubName, JITTargetAddress InitAddr, 379 JITSymbolFlags StubFlags) { 380 auto Key = FreeStubs.back(); 381 FreeStubs.pop_back(); 382 *IndirectStubsInfos[Key.first].getPtr(Key.second) = 383 reinterpret_cast<void *>(static_cast<uintptr_t>(InitAddr)); 384 StubIndexes[StubName] = std::make_pair(Key, StubFlags); 385 } 386 387 std::mutex StubsMutex; 388 std::vector<typename TargetT::IndirectStubsInfo> IndirectStubsInfos; 389 using StubKey = std::pair<uint16_t, uint16_t>; 390 std::vector<StubKey> FreeStubs; 391 StringMap<std::pair<StubKey, JITSymbolFlags>> StubIndexes; 392 }; 393 394 /// Create a local compile callback manager. 395 /// 396 /// The given target triple will determine the ABI, and the given 397 /// ErrorHandlerAddress will be used by the resulting compile callback 398 /// manager if a compile callback fails. 399 Expected<std::unique_ptr<JITCompileCallbackManager>> 400 createLocalCompileCallbackManager(const Triple &T, ExecutionSession &ES, 401 JITTargetAddress ErrorHandlerAddress); 402 403 /// Create a local indriect stubs manager builder. 404 /// 405 /// The given target triple will determine the ABI. 406 std::function<std::unique_ptr<IndirectStubsManager>()> 407 createLocalIndirectStubsManagerBuilder(const Triple &T); 408 409 /// Build a function pointer of FunctionType with the given constant 410 /// address. 411 /// 412 /// Usage example: Turn a trampoline address into a function pointer constant 413 /// for use in a stub. 414 Constant *createIRTypedAddress(FunctionType &FT, JITTargetAddress Addr); 415 416 /// Create a function pointer with the given type, name, and initializer 417 /// in the given Module. 418 GlobalVariable *createImplPointer(PointerType &PT, Module &M, const Twine &Name, 419 Constant *Initializer); 420 421 /// Turn a function declaration into a stub function that makes an 422 /// indirect call using the given function pointer. 423 void makeStub(Function &F, Value &ImplPointer); 424 425 /// Promotes private symbols to global hidden, and renames to prevent clashes 426 /// with other promoted symbols. The same SymbolPromoter instance should be 427 /// used for all symbols to be added to a single JITDylib. 428 class SymbolLinkagePromoter { 429 public: 430 /// Promote symbols in the given module. Returns the set of global values 431 /// that have been renamed/promoted. 432 std::vector<GlobalValue *> operator()(Module &M); 433 434 private: 435 unsigned NextId = 0; 436 }; 437 438 /// Clone a function declaration into a new module. 439 /// 440 /// This function can be used as the first step towards creating a callback 441 /// stub (see makeStub), or moving a function body (see moveFunctionBody). 442 /// 443 /// If the VMap argument is non-null, a mapping will be added between F and 444 /// the new declaration, and between each of F's arguments and the new 445 /// declaration's arguments. This map can then be passed in to moveFunction to 446 /// move the function body if required. Note: When moving functions between 447 /// modules with these utilities, all decls should be cloned (and added to a 448 /// single VMap) before any bodies are moved. This will ensure that references 449 /// between functions all refer to the versions in the new module. 450 Function *cloneFunctionDecl(Module &Dst, const Function &F, 451 ValueToValueMapTy *VMap = nullptr); 452 453 /// Move the body of function 'F' to a cloned function declaration in a 454 /// different module (See related cloneFunctionDecl). 455 /// 456 /// If the target function declaration is not supplied via the NewF parameter 457 /// then it will be looked up via the VMap. 458 /// 459 /// This will delete the body of function 'F' from its original parent module, 460 /// but leave its declaration. 461 void moveFunctionBody(Function &OrigF, ValueToValueMapTy &VMap, 462 ValueMaterializer *Materializer = nullptr, 463 Function *NewF = nullptr); 464 465 /// Clone a global variable declaration into a new module. 466 GlobalVariable *cloneGlobalVariableDecl(Module &Dst, const GlobalVariable &GV, 467 ValueToValueMapTy *VMap = nullptr); 468 469 /// Move global variable GV from its parent module to cloned global 470 /// declaration in a different module. 471 /// 472 /// If the target global declaration is not supplied via the NewGV parameter 473 /// then it will be looked up via the VMap. 474 /// 475 /// This will delete the initializer of GV from its original parent module, 476 /// but leave its declaration. 477 void moveGlobalVariableInitializer(GlobalVariable &OrigGV, 478 ValueToValueMapTy &VMap, 479 ValueMaterializer *Materializer = nullptr, 480 GlobalVariable *NewGV = nullptr); 481 482 /// Clone a global alias declaration into a new module. 483 GlobalAlias *cloneGlobalAliasDecl(Module &Dst, const GlobalAlias &OrigA, 484 ValueToValueMapTy &VMap); 485 486 /// Clone module flags metadata into the destination module. 487 void cloneModuleFlagsMetadata(Module &Dst, const Module &Src, 488 ValueToValueMapTy &VMap); 489 490 } // end namespace orc 491 492 } // end namespace llvm 493 494 #endif // LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H 495