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