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/Support/Error.h" 22 #include "llvm/Support/Memory.h" 23 #include "llvm/Support/Process.h" 24 #include "llvm/Transforms/Utils/ValueMapper.h" 25 #include <algorithm> 26 #include <cassert> 27 #include <cstdint> 28 #include <functional> 29 #include <map> 30 #include <memory> 31 #include <system_error> 32 #include <utility> 33 #include <vector> 34 35 namespace llvm { 36 37 class Constant; 38 class Function; 39 class FunctionType; 40 class GlobalAlias; 41 class GlobalVariable; 42 class Module; 43 class PointerType; 44 class Triple; 45 class Value; 46 47 namespace orc { 48 49 /// @brief Target-independent base class for compile callback management. 50 class JITCompileCallbackManager { 51 public: 52 using CompileFtor = std::function<JITTargetAddress()>; 53 54 /// @brief 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 { 58 public: 59 CompileCallbackInfo(JITTargetAddress Addr, CompileFtor &Compile) 60 : Addr(Addr), Compile(Compile) {} 61 62 JITTargetAddress getAddress() const { return Addr; } 63 void setCompileAction(CompileFtor Compile) { 64 this->Compile = std::move(Compile); 65 } 66 67 private: 68 JITTargetAddress Addr; 69 CompileFtor &Compile; 70 }; 71 72 /// @brief 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) {} 77 78 virtual ~JITCompileCallbackManager() = default; 79 80 /// @brief 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 85 // one. 86 if (I == ActiveTrampolines.end()) 87 return ErrorHandlerAddress; 88 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 93 // at 94 // least one available trampoline if the compile action triggers a request 95 // for 96 // a new one. 97 auto Compile = std::move(I->second); 98 ActiveTrampolines.erase(I); 99 AvailableTrampolines.push_back(TrampolineAddr); 100 101 if (auto Addr = Compile()) 102 return Addr; 103 104 return ErrorHandlerAddress; 105 } 106 107 /// @brief 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); 113 } else 114 return TrampolineAddrOrErr.takeError(); 115 } 116 117 /// @brief 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); 122 } 123 124 /// @brief Release a compile callback. 125 /// 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 128 /// execute. 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); 134 } 135 136 protected: 137 JITTargetAddress ErrorHandlerAddress; 138 139 using TrampolineMapT = std::map<JITTargetAddress, CompileFtor>; 140 TrampolineMapT ActiveTrampolines; 141 std::vector<JITTargetAddress> AvailableTrampolines; 142 143 private: 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; 153 } 154 155 // Create new trampolines - to be implemented in subclasses. 156 virtual Error grow() = 0; 157 158 virtual void anchor(); 159 }; 160 161 /// @brief Manage compile callbacks for in-process JITs. 162 template <typename TargetT> 163 class LocalJITCompileCallbackManager : public JITCompileCallbackManager { 164 public: 165 /// @brief 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. 171 std::error_code EC; 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"); 176 177 TargetT::writeResolverCode(static_cast<uint8_t *>(ResolverBlock.base()), 178 &reenter, this); 179 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"); 184 } 185 186 private: 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))); 193 } 194 195 Error grow() override { 196 assert(this->AvailableTrampolines.empty() && "Growing prematurely?"); 197 198 std::error_code EC; 199 auto TrampolineBlock = 200 sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory( 201 sys::Process::getPageSize(), nullptr, 202 sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC)); 203 if (EC) 204 return errorCodeToError(EC); 205 206 unsigned NumTrampolines = 207 (sys::Process::getPageSize() - TargetT::PointerSize) / 208 TargetT::TrampolineSize; 209 210 uint8_t *TrampolineMem = static_cast<uint8_t *>(TrampolineBlock.base()); 211 TargetT::writeTrampolines(TrampolineMem, ResolverBlock.base(), 212 NumTrampolines); 213 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)))); 218 219 if (auto EC = sys::Memory::protectMappedMemory( 220 TrampolineBlock.getMemoryBlock(), 221 sys::Memory::MF_READ | sys::Memory::MF_EXEC)) 222 return errorCodeToError(EC); 223 224 TrampolineBlocks.push_back(std::move(TrampolineBlock)); 225 return Error::success(); 226 } 227 228 sys::OwningMemoryBlock ResolverBlock; 229 std::vector<sys::OwningMemoryBlock> TrampolineBlocks; 230 }; 231 232 /// @brief Base class for managing collections of named indirect stubs. 233 class IndirectStubsManager { 234 public: 235 /// @brief Map type for initializing the manager. See init. 236 using StubInitsMap = StringMap<std::pair<JITTargetAddress, JITSymbolFlags>>; 237 238 virtual ~IndirectStubsManager() = default; 239 240 /// @brief Create a single stub with the given name, target address and flags. 241 virtual Error createStub(StringRef StubName, JITTargetAddress StubAddr, 242 JITSymbolFlags StubFlags) = 0; 243 244 /// @brief Create StubInits.size() stubs with the given names, target 245 /// addresses, and flags. 246 virtual Error createStubs(const StubInitsMap &StubInits) = 0; 247 248 /// @brief 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 250 /// is exported. 251 virtual JITSymbol findStub(StringRef Name, bool ExportedStubsOnly) = 0; 252 253 /// @brief Find the implementation-pointer for the stub. 254 virtual JITSymbol findPointer(StringRef Name) = 0; 255 256 /// @brief Change the value of the implementation pointer for the stub. 257 virtual Error updatePointer(StringRef Name, JITTargetAddress NewAddr) = 0; 258 259 private: 260 virtual void anchor(); 261 }; 262 263 /// @brief IndirectStubsManager implementation for the host architecture, e.g. 264 /// OrcX86_64. (See OrcArchitectureSupport.h). 265 template <typename TargetT> 266 class LocalIndirectStubsManager : public IndirectStubsManager { 267 public: 268 Error createStub(StringRef StubName, JITTargetAddress StubAddr, 269 JITSymbolFlags StubFlags) override { 270 if (auto Err = reserveStubs(1)) 271 return Err; 272 273 createStubInternal(StubName, StubAddr, StubFlags); 274 275 return Error::success(); 276 } 277 278 Error createStubs(const StubInitsMap &StubInits) override { 279 if (auto Err = reserveStubs(StubInits.size())) 280 return Err; 281 282 for (auto &Entry : StubInits) 283 createStubInternal(Entry.first(), Entry.second.first, 284 Entry.second.second); 285 286 return Error::success(); 287 } 288 289 JITSymbol findStub(StringRef Name, bool ExportedStubsOnly) override { 290 auto I = StubIndexes.find(Name); 291 if (I == StubIndexes.end()) 292 return nullptr; 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()) 300 return nullptr; 301 return StubSymbol; 302 } 303 304 JITSymbol findPointer(StringRef Name) override { 305 auto I = StubIndexes.find(Name); 306 if (I == StubIndexes.end()) 307 return nullptr; 308 auto Key = I->second.first; 309 void *PtrAddr = IndirectStubsInfos[Key.first].getPtr(Key.second); 310 assert(PtrAddr && "Missing pointer address"); 311 auto PtrTargetAddr = 312 static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(PtrAddr)); 313 return JITSymbol(PtrTargetAddr, I->second.second); 314 } 315 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(); 323 } 324 325 private: 326 Error reserveStubs(unsigned NumStubs) { 327 if (NumStubs <= FreeStubs.size()) 328 return Error::success(); 329 330 unsigned NewStubsRequired = NumStubs - FreeStubs.size(); 331 unsigned NewBlockId = IndirectStubsInfos.size(); 332 typename TargetT::IndirectStubsInfo ISI; 333 if (auto Err = 334 TargetT::emitIndirectStubsBlock(ISI, NewStubsRequired, nullptr)) 335 return Err; 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(); 340 } 341 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); 349 } 350 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; 355 }; 356 357 /// @brief Create a local compile callback manager. 358 /// 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); 365 366 /// @brief Create a local indriect stubs manager builder. 367 /// 368 /// The given target triple will determine the ABI. 369 std::function<std::unique_ptr<IndirectStubsManager>()> 370 createLocalIndirectStubsManagerBuilder(const Triple &T); 371 372 /// @brief Build a function pointer of FunctionType with the given constant 373 /// address. 374 /// 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); 378 379 /// @brief 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); 383 384 /// @brief 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); 387 388 /// @brief Raise linkage types and rename as necessary to ensure that all 389 /// symbols are accessible for other modules. 390 /// 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); 394 395 /// @brief Clone a function declaration into a new module. 396 /// 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). 399 /// 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); 409 410 /// @brief Move the body of function 'F' to a cloned function declaration in a 411 /// different module (See related cloneFunctionDecl). 412 /// 413 /// If the target function declaration is not supplied via the NewF parameter 414 /// then it will be looked up via the VMap. 415 /// 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); 421 422 /// @brief Clone a global variable declaration into a new module. 423 GlobalVariable *cloneGlobalVariableDecl(Module &Dst, const GlobalVariable &GV, 424 ValueToValueMapTy *VMap = nullptr); 425 426 /// @brief Move global variable GV from its parent module to cloned global 427 /// declaration in a different module. 428 /// 429 /// If the target global declaration is not supplied via the NewGV parameter 430 /// then it will be looked up via the VMap. 431 /// 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); 438 439 /// @brief Clone a global alias declaration into a new module. 440 GlobalAlias *cloneGlobalAliasDecl(Module &Dst, const GlobalAlias &OrigA, 441 ValueToValueMapTy &VMap); 442 443 /// @brief Clone module flags metadata into the destination module. 444 void cloneModuleFlagsMetadata(Module &Dst, const Module &Src, 445 ValueToValueMapTy &VMap); 446 447 } // end namespace orc 448 449 } // end namespace llvm 450 451 #endif // LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H 452