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 "JITSymbol.h" 18 #include "LambdaResolver.h" 19 #include "llvm/ExecutionEngine/RuntimeDyld.h" 20 #include "llvm/IR/IRBuilder.h" 21 #include "llvm/IR/Mangler.h" 22 #include "llvm/IR/Module.h" 23 #include "llvm/Support/Process.h" 24 #include "llvm/Transforms/Utils/ValueMapper.h" 25 26 namespace llvm { 27 namespace orc { 28 29 /// @brief Target-independent base class for compile callback management. 30 class JITCompileCallbackManager { 31 public: 32 typedef std::function<TargetAddress()> CompileFtor; 33 34 /// @brief Handle to a newly created compile callback. Can be used to get an 35 /// IR constant representing the address of the trampoline, and to set 36 /// the compile action for the callback. 37 class CompileCallbackInfo { 38 public: CompileCallbackInfo(TargetAddress Addr,CompileFtor & Compile)39 CompileCallbackInfo(TargetAddress Addr, CompileFtor &Compile) 40 : Addr(Addr), Compile(Compile) {} 41 getAddress()42 TargetAddress getAddress() const { return Addr; } setCompileAction(CompileFtor Compile)43 void setCompileAction(CompileFtor Compile) { 44 this->Compile = std::move(Compile); 45 } 46 47 private: 48 TargetAddress Addr; 49 CompileFtor &Compile; 50 }; 51 52 /// @brief Construct a JITCompileCallbackManager. 53 /// @param ErrorHandlerAddress The address of an error handler in the target 54 /// process to be used if a compile callback fails. JITCompileCallbackManager(TargetAddress ErrorHandlerAddress)55 JITCompileCallbackManager(TargetAddress ErrorHandlerAddress) 56 : ErrorHandlerAddress(ErrorHandlerAddress) {} 57 ~JITCompileCallbackManager()58 virtual ~JITCompileCallbackManager() {} 59 60 /// @brief Execute the callback for the given trampoline id. Called by the JIT 61 /// to compile functions on demand. executeCompileCallback(TargetAddress TrampolineAddr)62 TargetAddress executeCompileCallback(TargetAddress TrampolineAddr) { 63 auto I = ActiveTrampolines.find(TrampolineAddr); 64 // FIXME: Also raise an error in the Orc error-handler when we finally have 65 // one. 66 if (I == ActiveTrampolines.end()) 67 return ErrorHandlerAddress; 68 69 // Found a callback handler. Yank this trampoline out of the active list and 70 // put it back in the available trampolines list, then try to run the 71 // handler's compile and update actions. 72 // Moving the trampoline ID back to the available list first means there's 73 // at 74 // least one available trampoline if the compile action triggers a request 75 // for 76 // a new one. 77 auto Compile = std::move(I->second); 78 ActiveTrampolines.erase(I); 79 AvailableTrampolines.push_back(TrampolineAddr); 80 81 if (auto Addr = Compile()) 82 return Addr; 83 84 return ErrorHandlerAddress; 85 } 86 87 /// @brief Reserve a compile callback. getCompileCallback()88 CompileCallbackInfo getCompileCallback() { 89 TargetAddress TrampolineAddr = getAvailableTrampolineAddr(); 90 auto &Compile = this->ActiveTrampolines[TrampolineAddr]; 91 return CompileCallbackInfo(TrampolineAddr, Compile); 92 } 93 94 /// @brief Get a CompileCallbackInfo for an existing callback. getCompileCallbackInfo(TargetAddress TrampolineAddr)95 CompileCallbackInfo getCompileCallbackInfo(TargetAddress TrampolineAddr) { 96 auto I = ActiveTrampolines.find(TrampolineAddr); 97 assert(I != ActiveTrampolines.end() && "Not an active trampoline."); 98 return CompileCallbackInfo(I->first, I->second); 99 } 100 101 /// @brief Release a compile callback. 102 /// 103 /// Note: Callbacks are auto-released after they execute. This method should 104 /// only be called to manually release a callback that is not going to 105 /// execute. releaseCompileCallback(TargetAddress TrampolineAddr)106 void releaseCompileCallback(TargetAddress TrampolineAddr) { 107 auto I = ActiveTrampolines.find(TrampolineAddr); 108 assert(I != ActiveTrampolines.end() && "Not an active trampoline."); 109 ActiveTrampolines.erase(I); 110 AvailableTrampolines.push_back(TrampolineAddr); 111 } 112 113 protected: 114 TargetAddress ErrorHandlerAddress; 115 116 typedef std::map<TargetAddress, CompileFtor> TrampolineMapT; 117 TrampolineMapT ActiveTrampolines; 118 std::vector<TargetAddress> AvailableTrampolines; 119 120 private: getAvailableTrampolineAddr()121 TargetAddress getAvailableTrampolineAddr() { 122 if (this->AvailableTrampolines.empty()) 123 grow(); 124 assert(!this->AvailableTrampolines.empty() && 125 "Failed to grow available trampolines."); 126 TargetAddress TrampolineAddr = this->AvailableTrampolines.back(); 127 this->AvailableTrampolines.pop_back(); 128 return TrampolineAddr; 129 } 130 131 // Create new trampolines - to be implemented in subclasses. 132 virtual void grow() = 0; 133 134 virtual void anchor(); 135 }; 136 137 /// @brief Manage compile callbacks for in-process JITs. 138 template <typename TargetT> 139 class LocalJITCompileCallbackManager : public JITCompileCallbackManager { 140 public: 141 /// @brief Construct a InProcessJITCompileCallbackManager. 142 /// @param ErrorHandlerAddress The address of an error handler in the target 143 /// process to be used if a compile callback fails. LocalJITCompileCallbackManager(TargetAddress ErrorHandlerAddress)144 LocalJITCompileCallbackManager(TargetAddress ErrorHandlerAddress) 145 : JITCompileCallbackManager(ErrorHandlerAddress) { 146 147 /// Set up the resolver block. 148 std::error_code EC; 149 ResolverBlock = sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory( 150 TargetT::ResolverCodeSize, nullptr, 151 sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC)); 152 assert(!EC && "Failed to allocate resolver block"); 153 154 TargetT::writeResolverCode(static_cast<uint8_t *>(ResolverBlock.base()), 155 &reenter, this); 156 157 EC = sys::Memory::protectMappedMemory(ResolverBlock.getMemoryBlock(), 158 sys::Memory::MF_READ | 159 sys::Memory::MF_EXEC); 160 assert(!EC && "Failed to mprotect resolver block"); 161 } 162 163 private: reenter(void * CCMgr,void * TrampolineId)164 static TargetAddress reenter(void *CCMgr, void *TrampolineId) { 165 JITCompileCallbackManager *Mgr = 166 static_cast<JITCompileCallbackManager *>(CCMgr); 167 return Mgr->executeCompileCallback( 168 static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(TrampolineId))); 169 } 170 grow()171 void grow() override { 172 assert(this->AvailableTrampolines.empty() && "Growing prematurely?"); 173 174 std::error_code EC; 175 auto TrampolineBlock = 176 sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory( 177 sys::Process::getPageSize(), nullptr, 178 sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC)); 179 assert(!EC && "Failed to allocate trampoline block"); 180 181 unsigned NumTrampolines = 182 (sys::Process::getPageSize() - TargetT::PointerSize) / 183 TargetT::TrampolineSize; 184 185 uint8_t *TrampolineMem = static_cast<uint8_t *>(TrampolineBlock.base()); 186 TargetT::writeTrampolines(TrampolineMem, ResolverBlock.base(), 187 NumTrampolines); 188 189 for (unsigned I = 0; I < NumTrampolines; ++I) 190 this->AvailableTrampolines.push_back( 191 static_cast<TargetAddress>(reinterpret_cast<uintptr_t>( 192 TrampolineMem + (I * TargetT::TrampolineSize)))); 193 194 EC = sys::Memory::protectMappedMemory(TrampolineBlock.getMemoryBlock(), 195 sys::Memory::MF_READ | 196 sys::Memory::MF_EXEC); 197 assert(!EC && "Failed to mprotect trampoline block"); 198 199 TrampolineBlocks.push_back(std::move(TrampolineBlock)); 200 } 201 202 sys::OwningMemoryBlock ResolverBlock; 203 std::vector<sys::OwningMemoryBlock> TrampolineBlocks; 204 }; 205 206 /// @brief Base class for managing collections of named indirect stubs. 207 class IndirectStubsManager { 208 public: 209 /// @brief Map type for initializing the manager. See init. 210 typedef StringMap<std::pair<TargetAddress, JITSymbolFlags>> StubInitsMap; 211 ~IndirectStubsManager()212 virtual ~IndirectStubsManager() {} 213 214 /// @brief Create a single stub with the given name, target address and flags. 215 virtual Error createStub(StringRef StubName, TargetAddress StubAddr, 216 JITSymbolFlags StubFlags) = 0; 217 218 /// @brief Create StubInits.size() stubs with the given names, target 219 /// addresses, and flags. 220 virtual Error createStubs(const StubInitsMap &StubInits) = 0; 221 222 /// @brief Find the stub with the given name. If ExportedStubsOnly is true, 223 /// this will only return a result if the stub's flags indicate that it 224 /// is exported. 225 virtual JITSymbol findStub(StringRef Name, bool ExportedStubsOnly) = 0; 226 227 /// @brief Find the implementation-pointer for the stub. 228 virtual JITSymbol findPointer(StringRef Name) = 0; 229 230 /// @brief Change the value of the implementation pointer for the stub. 231 virtual Error updatePointer(StringRef Name, TargetAddress NewAddr) = 0; 232 233 private: 234 virtual void anchor(); 235 }; 236 237 /// @brief IndirectStubsManager implementation for the host architecture, e.g. 238 /// OrcX86_64. (See OrcArchitectureSupport.h). 239 template <typename TargetT> 240 class LocalIndirectStubsManager : public IndirectStubsManager { 241 public: createStub(StringRef StubName,TargetAddress StubAddr,JITSymbolFlags StubFlags)242 Error createStub(StringRef StubName, TargetAddress StubAddr, 243 JITSymbolFlags StubFlags) override { 244 if (auto Err = reserveStubs(1)) 245 return Err; 246 247 createStubInternal(StubName, StubAddr, StubFlags); 248 249 return Error::success(); 250 } 251 createStubs(const StubInitsMap & StubInits)252 Error createStubs(const StubInitsMap &StubInits) override { 253 if (auto Err = reserveStubs(StubInits.size())) 254 return Err; 255 256 for (auto &Entry : StubInits) 257 createStubInternal(Entry.first(), Entry.second.first, 258 Entry.second.second); 259 260 return Error::success(); 261 } 262 findStub(StringRef Name,bool ExportedStubsOnly)263 JITSymbol findStub(StringRef Name, bool ExportedStubsOnly) override { 264 auto I = StubIndexes.find(Name); 265 if (I == StubIndexes.end()) 266 return nullptr; 267 auto Key = I->second.first; 268 void *StubAddr = IndirectStubsInfos[Key.first].getStub(Key.second); 269 assert(StubAddr && "Missing stub address"); 270 auto StubTargetAddr = 271 static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(StubAddr)); 272 auto StubSymbol = JITSymbol(StubTargetAddr, I->second.second); 273 if (ExportedStubsOnly && !StubSymbol.isExported()) 274 return nullptr; 275 return StubSymbol; 276 } 277 findPointer(StringRef Name)278 JITSymbol findPointer(StringRef Name) override { 279 auto I = StubIndexes.find(Name); 280 if (I == StubIndexes.end()) 281 return nullptr; 282 auto Key = I->second.first; 283 void *PtrAddr = IndirectStubsInfos[Key.first].getPtr(Key.second); 284 assert(PtrAddr && "Missing pointer address"); 285 auto PtrTargetAddr = 286 static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(PtrAddr)); 287 return JITSymbol(PtrTargetAddr, I->second.second); 288 } 289 updatePointer(StringRef Name,TargetAddress NewAddr)290 Error updatePointer(StringRef Name, TargetAddress NewAddr) override { 291 auto I = StubIndexes.find(Name); 292 assert(I != StubIndexes.end() && "No stub pointer for symbol"); 293 auto Key = I->second.first; 294 *IndirectStubsInfos[Key.first].getPtr(Key.second) = 295 reinterpret_cast<void *>(static_cast<uintptr_t>(NewAddr)); 296 return Error::success(); 297 } 298 299 private: reserveStubs(unsigned NumStubs)300 Error reserveStubs(unsigned NumStubs) { 301 if (NumStubs <= FreeStubs.size()) 302 return Error::success(); 303 304 unsigned NewStubsRequired = NumStubs - FreeStubs.size(); 305 unsigned NewBlockId = IndirectStubsInfos.size(); 306 typename TargetT::IndirectStubsInfo ISI; 307 if (auto Err = 308 TargetT::emitIndirectStubsBlock(ISI, NewStubsRequired, nullptr)) 309 return Err; 310 for (unsigned I = 0; I < ISI.getNumStubs(); ++I) 311 FreeStubs.push_back(std::make_pair(NewBlockId, I)); 312 IndirectStubsInfos.push_back(std::move(ISI)); 313 return Error::success(); 314 } 315 createStubInternal(StringRef StubName,TargetAddress InitAddr,JITSymbolFlags StubFlags)316 void createStubInternal(StringRef StubName, TargetAddress InitAddr, 317 JITSymbolFlags StubFlags) { 318 auto Key = FreeStubs.back(); 319 FreeStubs.pop_back(); 320 *IndirectStubsInfos[Key.first].getPtr(Key.second) = 321 reinterpret_cast<void *>(static_cast<uintptr_t>(InitAddr)); 322 StubIndexes[StubName] = std::make_pair(Key, StubFlags); 323 } 324 325 std::vector<typename TargetT::IndirectStubsInfo> IndirectStubsInfos; 326 typedef std::pair<uint16_t, uint16_t> StubKey; 327 std::vector<StubKey> FreeStubs; 328 StringMap<std::pair<StubKey, JITSymbolFlags>> StubIndexes; 329 }; 330 331 /// @brief Create a local compile callback manager. 332 /// 333 /// The given target triple will determine the ABI, and the given 334 /// ErrorHandlerAddress will be used by the resulting compile callback 335 /// manager if a compile callback fails. 336 std::unique_ptr<JITCompileCallbackManager> 337 createLocalCompileCallbackManager(const Triple &T, 338 TargetAddress ErrorHandlerAddress); 339 340 /// @brief Create a local indriect stubs manager builder. 341 /// 342 /// The given target triple will determine the ABI. 343 std::function<std::unique_ptr<IndirectStubsManager>()> 344 createLocalIndirectStubsManagerBuilder(const Triple &T); 345 346 /// @brief Build a function pointer of FunctionType with the given constant 347 /// address. 348 /// 349 /// Usage example: Turn a trampoline address into a function pointer constant 350 /// for use in a stub. 351 Constant *createIRTypedAddress(FunctionType &FT, TargetAddress Addr); 352 353 /// @brief Create a function pointer with the given type, name, and initializer 354 /// in the given Module. 355 GlobalVariable *createImplPointer(PointerType &PT, Module &M, const Twine &Name, 356 Constant *Initializer); 357 358 /// @brief Turn a function declaration into a stub function that makes an 359 /// indirect call using the given function pointer. 360 void makeStub(Function &F, Value &ImplPointer); 361 362 /// @brief Raise linkage types and rename as necessary to ensure that all 363 /// symbols are accessible for other modules. 364 /// 365 /// This should be called before partitioning a module to ensure that the 366 /// partitions retain access to each other's symbols. 367 void makeAllSymbolsExternallyAccessible(Module &M); 368 369 /// @brief Clone a function declaration into a new module. 370 /// 371 /// This function can be used as the first step towards creating a callback 372 /// stub (see makeStub), or moving a function body (see moveFunctionBody). 373 /// 374 /// If the VMap argument is non-null, a mapping will be added between F and 375 /// the new declaration, and between each of F's arguments and the new 376 /// declaration's arguments. This map can then be passed in to moveFunction to 377 /// move the function body if required. Note: When moving functions between 378 /// modules with these utilities, all decls should be cloned (and added to a 379 /// single VMap) before any bodies are moved. This will ensure that references 380 /// between functions all refer to the versions in the new module. 381 Function *cloneFunctionDecl(Module &Dst, const Function &F, 382 ValueToValueMapTy *VMap = nullptr); 383 384 /// @brief Move the body of function 'F' to a cloned function declaration in a 385 /// different module (See related cloneFunctionDecl). 386 /// 387 /// If the target function declaration is not supplied via the NewF parameter 388 /// then it will be looked up via the VMap. 389 /// 390 /// This will delete the body of function 'F' from its original parent module, 391 /// but leave its declaration. 392 void moveFunctionBody(Function &OrigF, ValueToValueMapTy &VMap, 393 ValueMaterializer *Materializer = nullptr, 394 Function *NewF = nullptr); 395 396 /// @brief Clone a global variable declaration into a new module. 397 GlobalVariable *cloneGlobalVariableDecl(Module &Dst, const GlobalVariable &GV, 398 ValueToValueMapTy *VMap = nullptr); 399 400 /// @brief Move global variable GV from its parent module to cloned global 401 /// declaration in a different module. 402 /// 403 /// If the target global declaration is not supplied via the NewGV parameter 404 /// then it will be looked up via the VMap. 405 /// 406 /// This will delete the initializer of GV from its original parent module, 407 /// but leave its declaration. 408 void moveGlobalVariableInitializer(GlobalVariable &OrigGV, 409 ValueToValueMapTy &VMap, 410 ValueMaterializer *Materializer = nullptr, 411 GlobalVariable *NewGV = nullptr); 412 413 /// @brief Clone 414 GlobalAlias *cloneGlobalAliasDecl(Module &Dst, const GlobalAlias &OrigA, 415 ValueToValueMapTy &VMap); 416 417 } // End namespace orc. 418 } // End namespace llvm. 419 420 #endif // LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H 421