1 //===---- OrcRemoteTargetClient.h - Orc Remote-target Client ----*- 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 // This file defines the OrcRemoteTargetClient class and helpers. This class 11 // can be used to communicate over an RPCChannel with an OrcRemoteTargetServer 12 // instance to support remote-JITing. 13 // 14 //===----------------------------------------------------------------------===// 15 16 #ifndef LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETCLIENT_H 17 #define LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETCLIENT_H 18 19 #include "IndirectionUtils.h" 20 #include "OrcRemoteTargetRPCAPI.h" 21 #include <system_error> 22 23 #define DEBUG_TYPE "orc-remote" 24 25 namespace llvm { 26 namespace orc { 27 namespace remote { 28 29 /// This class provides utilities (including memory manager, indirect stubs 30 /// manager, and compile callback manager types) that support remote JITing 31 /// in ORC. 32 /// 33 /// Each of the utility classes talks to a JIT server (an instance of the 34 /// OrcRemoteTargetServer class) via an RPC system (see RPCUtils.h) to carry out 35 /// its actions. 36 template <typename ChannelT> 37 class OrcRemoteTargetClient : public OrcRemoteTargetRPCAPI { 38 public: 39 // FIXME: Remove move/copy ops once MSVC supports synthesizing move ops. 40 41 OrcRemoteTargetClient(const OrcRemoteTargetClient &) = delete; 42 OrcRemoteTargetClient &operator=(const OrcRemoteTargetClient &) = delete; 43 OrcRemoteTargetClient(OrcRemoteTargetClient && Other)44 OrcRemoteTargetClient(OrcRemoteTargetClient &&Other) 45 : Channel(Other.Channel), ExistingError(std::move(Other.ExistingError)), 46 RemoteTargetTriple(std::move(Other.RemoteTargetTriple)), 47 RemotePointerSize(std::move(Other.RemotePointerSize)), 48 RemotePageSize(std::move(Other.RemotePageSize)), 49 RemoteTrampolineSize(std::move(Other.RemoteTrampolineSize)), 50 RemoteIndirectStubSize(std::move(Other.RemoteIndirectStubSize)), 51 AllocatorIds(std::move(Other.AllocatorIds)), 52 IndirectStubOwnerIds(std::move(Other.IndirectStubOwnerIds)) {} 53 54 OrcRemoteTargetClient &operator=(OrcRemoteTargetClient &&) = delete; 55 56 /// Remote memory manager. 57 class RCMemoryManager : public RuntimeDyld::MemoryManager { 58 public: RCMemoryManager(OrcRemoteTargetClient & Client,ResourceIdMgr::ResourceId Id)59 RCMemoryManager(OrcRemoteTargetClient &Client, ResourceIdMgr::ResourceId Id) 60 : Client(Client), Id(Id) { 61 DEBUG(dbgs() << "Created remote allocator " << Id << "\n"); 62 } 63 RCMemoryManager(RCMemoryManager && Other)64 RCMemoryManager(RCMemoryManager &&Other) 65 : Client(std::move(Other.Client)), Id(std::move(Other.Id)), 66 Unmapped(std::move(Other.Unmapped)), 67 Unfinalized(std::move(Other.Unfinalized)) {} 68 69 RCMemoryManager operator=(RCMemoryManager &&Other) { 70 Client = std::move(Other.Client); 71 Id = std::move(Other.Id); 72 Unmapped = std::move(Other.Unmapped); 73 Unfinalized = std::move(Other.Unfinalized); 74 return *this; 75 } 76 ~RCMemoryManager()77 ~RCMemoryManager() override { 78 Client.destroyRemoteAllocator(Id); 79 DEBUG(dbgs() << "Destroyed remote allocator " << Id << "\n"); 80 } 81 allocateCodeSection(uintptr_t Size,unsigned Alignment,unsigned SectionID,StringRef SectionName)82 uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, 83 unsigned SectionID, 84 StringRef SectionName) override { 85 Unmapped.back().CodeAllocs.emplace_back(Size, Alignment); 86 uint8_t *Alloc = reinterpret_cast<uint8_t *>( 87 Unmapped.back().CodeAllocs.back().getLocalAddress()); 88 DEBUG(dbgs() << "Allocator " << Id << " allocated code for " 89 << SectionName << ": " << Alloc << " (" << Size 90 << " bytes, alignment " << Alignment << ")\n"); 91 return Alloc; 92 } 93 allocateDataSection(uintptr_t Size,unsigned Alignment,unsigned SectionID,StringRef SectionName,bool IsReadOnly)94 uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, 95 unsigned SectionID, StringRef SectionName, 96 bool IsReadOnly) override { 97 if (IsReadOnly) { 98 Unmapped.back().RODataAllocs.emplace_back(Size, Alignment); 99 uint8_t *Alloc = reinterpret_cast<uint8_t *>( 100 Unmapped.back().RODataAllocs.back().getLocalAddress()); 101 DEBUG(dbgs() << "Allocator " << Id << " allocated ro-data for " 102 << SectionName << ": " << Alloc << " (" << Size 103 << " bytes, alignment " << Alignment << ")\n"); 104 return Alloc; 105 } // else... 106 107 Unmapped.back().RWDataAllocs.emplace_back(Size, Alignment); 108 uint8_t *Alloc = reinterpret_cast<uint8_t *>( 109 Unmapped.back().RWDataAllocs.back().getLocalAddress()); 110 DEBUG(dbgs() << "Allocator " << Id << " allocated rw-data for " 111 << SectionName << ": " << Alloc << " (" << Size 112 << " bytes, alignment " << Alignment << ")\n"); 113 return Alloc; 114 } 115 reserveAllocationSpace(uintptr_t CodeSize,uint32_t CodeAlign,uintptr_t RODataSize,uint32_t RODataAlign,uintptr_t RWDataSize,uint32_t RWDataAlign)116 void reserveAllocationSpace(uintptr_t CodeSize, uint32_t CodeAlign, 117 uintptr_t RODataSize, uint32_t RODataAlign, 118 uintptr_t RWDataSize, 119 uint32_t RWDataAlign) override { 120 Unmapped.push_back(ObjectAllocs()); 121 122 DEBUG(dbgs() << "Allocator " << Id << " reserved:\n"); 123 124 if (CodeSize != 0) { 125 if (auto AddrOrErr = Client.reserveMem(Id, CodeSize, CodeAlign)) 126 Unmapped.back().RemoteCodeAddr = *AddrOrErr; 127 else { 128 // FIXME; Add error to poll. 129 assert(!AddrOrErr.takeError() && "Failed reserving remote memory."); 130 } 131 132 DEBUG(dbgs() << " code: " 133 << format("0x%016x", Unmapped.back().RemoteCodeAddr) 134 << " (" << CodeSize << " bytes, alignment " << CodeAlign 135 << ")\n"); 136 } 137 138 if (RODataSize != 0) { 139 if (auto AddrOrErr = Client.reserveMem(Id, RODataSize, RODataAlign)) 140 Unmapped.back().RemoteRODataAddr = *AddrOrErr; 141 else { 142 // FIXME; Add error to poll. 143 assert(!AddrOrErr.takeError() && "Failed reserving remote memory."); 144 } 145 146 DEBUG(dbgs() << " ro-data: " 147 << format("0x%016x", Unmapped.back().RemoteRODataAddr) 148 << " (" << RODataSize << " bytes, alignment " 149 << RODataAlign << ")\n"); 150 } 151 152 if (RWDataSize != 0) { 153 if (auto AddrOrErr = Client.reserveMem(Id, RWDataSize, RWDataAlign)) 154 Unmapped.back().RemoteRWDataAddr = *AddrOrErr; 155 else { 156 // FIXME; Add error to poll. 157 assert(!AddrOrErr.takeError() && "Failed reserving remote memory."); 158 } 159 160 DEBUG(dbgs() << " rw-data: " 161 << format("0x%016x", Unmapped.back().RemoteRWDataAddr) 162 << " (" << RWDataSize << " bytes, alignment " 163 << RWDataAlign << ")\n"); 164 } 165 } 166 needsToReserveAllocationSpace()167 bool needsToReserveAllocationSpace() override { return true; } 168 registerEHFrames(uint8_t * Addr,uint64_t LoadAddr,size_t Size)169 void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr, 170 size_t Size) override { 171 UnfinalizedEHFrames.push_back( 172 std::make_pair(LoadAddr, static_cast<uint32_t>(Size))); 173 } 174 deregisterEHFrames(uint8_t * Addr,uint64_t LoadAddr,size_t Size)175 void deregisterEHFrames(uint8_t *Addr, uint64_t LoadAddr, 176 size_t Size) override { 177 auto Err = Client.deregisterEHFrames(LoadAddr, Size); 178 // FIXME: Add error poll. 179 assert(!Err && "Failed to register remote EH frames."); 180 (void)Err; 181 } 182 notifyObjectLoaded(RuntimeDyld & Dyld,const object::ObjectFile & Obj)183 void notifyObjectLoaded(RuntimeDyld &Dyld, 184 const object::ObjectFile &Obj) override { 185 DEBUG(dbgs() << "Allocator " << Id << " applied mappings:\n"); 186 for (auto &ObjAllocs : Unmapped) { 187 { 188 TargetAddress NextCodeAddr = ObjAllocs.RemoteCodeAddr; 189 for (auto &Alloc : ObjAllocs.CodeAllocs) { 190 NextCodeAddr = alignTo(NextCodeAddr, Alloc.getAlign()); 191 Dyld.mapSectionAddress(Alloc.getLocalAddress(), NextCodeAddr); 192 DEBUG(dbgs() << " code: " 193 << static_cast<void *>(Alloc.getLocalAddress()) 194 << " -> " << format("0x%016x", NextCodeAddr) << "\n"); 195 Alloc.setRemoteAddress(NextCodeAddr); 196 NextCodeAddr += Alloc.getSize(); 197 } 198 } 199 { 200 TargetAddress NextRODataAddr = ObjAllocs.RemoteRODataAddr; 201 for (auto &Alloc : ObjAllocs.RODataAllocs) { 202 NextRODataAddr = alignTo(NextRODataAddr, Alloc.getAlign()); 203 Dyld.mapSectionAddress(Alloc.getLocalAddress(), NextRODataAddr); 204 DEBUG(dbgs() << " ro-data: " 205 << static_cast<void *>(Alloc.getLocalAddress()) 206 << " -> " << format("0x%016x", NextRODataAddr) 207 << "\n"); 208 Alloc.setRemoteAddress(NextRODataAddr); 209 NextRODataAddr += Alloc.getSize(); 210 } 211 } 212 { 213 TargetAddress NextRWDataAddr = ObjAllocs.RemoteRWDataAddr; 214 for (auto &Alloc : ObjAllocs.RWDataAllocs) { 215 NextRWDataAddr = alignTo(NextRWDataAddr, Alloc.getAlign()); 216 Dyld.mapSectionAddress(Alloc.getLocalAddress(), NextRWDataAddr); 217 DEBUG(dbgs() << " rw-data: " 218 << static_cast<void *>(Alloc.getLocalAddress()) 219 << " -> " << format("0x%016x", NextRWDataAddr) 220 << "\n"); 221 Alloc.setRemoteAddress(NextRWDataAddr); 222 NextRWDataAddr += Alloc.getSize(); 223 } 224 } 225 Unfinalized.push_back(std::move(ObjAllocs)); 226 } 227 Unmapped.clear(); 228 } 229 230 bool finalizeMemory(std::string *ErrMsg = nullptr) override { 231 DEBUG(dbgs() << "Allocator " << Id << " finalizing:\n"); 232 233 for (auto &ObjAllocs : Unfinalized) { 234 235 for (auto &Alloc : ObjAllocs.CodeAllocs) { 236 DEBUG(dbgs() << " copying code: " 237 << static_cast<void *>(Alloc.getLocalAddress()) << " -> " 238 << format("0x%016x", Alloc.getRemoteAddress()) << " (" 239 << Alloc.getSize() << " bytes)\n"); 240 if (auto Err = 241 Client.writeMem(Alloc.getRemoteAddress(), 242 Alloc.getLocalAddress(), Alloc.getSize())) { 243 // FIXME: Replace this once finalizeMemory can return an Error. 244 handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) { 245 if (ErrMsg) { 246 raw_string_ostream ErrOut(*ErrMsg); 247 EIB.log(ErrOut); 248 } 249 }); 250 return true; 251 } 252 } 253 254 if (ObjAllocs.RemoteCodeAddr) { 255 DEBUG(dbgs() << " setting R-X permissions on code block: " 256 << format("0x%016x", ObjAllocs.RemoteCodeAddr) << "\n"); 257 if (auto Err = Client.setProtections(Id, ObjAllocs.RemoteCodeAddr, 258 sys::Memory::MF_READ | 259 sys::Memory::MF_EXEC)) { 260 // FIXME: Replace this once finalizeMemory can return an Error. 261 handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) { 262 if (ErrMsg) { 263 raw_string_ostream ErrOut(*ErrMsg); 264 EIB.log(ErrOut); 265 } 266 }); 267 return true; 268 } 269 } 270 271 for (auto &Alloc : ObjAllocs.RODataAllocs) { 272 DEBUG(dbgs() << " copying ro-data: " 273 << static_cast<void *>(Alloc.getLocalAddress()) << " -> " 274 << format("0x%016x", Alloc.getRemoteAddress()) << " (" 275 << Alloc.getSize() << " bytes)\n"); 276 if (auto Err = 277 Client.writeMem(Alloc.getRemoteAddress(), 278 Alloc.getLocalAddress(), Alloc.getSize())) { 279 // FIXME: Replace this once finalizeMemory can return an Error. 280 handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) { 281 if (ErrMsg) { 282 raw_string_ostream ErrOut(*ErrMsg); 283 EIB.log(ErrOut); 284 } 285 }); 286 return true; 287 } 288 } 289 290 if (ObjAllocs.RemoteRODataAddr) { 291 DEBUG(dbgs() << " setting R-- permissions on ro-data block: " 292 << format("0x%016x", ObjAllocs.RemoteRODataAddr) 293 << "\n"); 294 if (auto Err = Client.setProtections(Id, ObjAllocs.RemoteRODataAddr, 295 sys::Memory::MF_READ)) { 296 // FIXME: Replace this once finalizeMemory can return an Error. 297 handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) { 298 if (ErrMsg) { 299 raw_string_ostream ErrOut(*ErrMsg); 300 EIB.log(ErrOut); 301 } 302 }); 303 return false; 304 } 305 } 306 307 for (auto &Alloc : ObjAllocs.RWDataAllocs) { 308 DEBUG(dbgs() << " copying rw-data: " 309 << static_cast<void *>(Alloc.getLocalAddress()) << " -> " 310 << format("0x%016x", Alloc.getRemoteAddress()) << " (" 311 << Alloc.getSize() << " bytes)\n"); 312 if (auto Err = 313 Client.writeMem(Alloc.getRemoteAddress(), 314 Alloc.getLocalAddress(), Alloc.getSize())) { 315 // FIXME: Replace this once finalizeMemory can return an Error. 316 handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) { 317 if (ErrMsg) { 318 raw_string_ostream ErrOut(*ErrMsg); 319 EIB.log(ErrOut); 320 } 321 }); 322 return false; 323 } 324 } 325 326 if (ObjAllocs.RemoteRWDataAddr) { 327 DEBUG(dbgs() << " setting RW- permissions on rw-data block: " 328 << format("0x%016x", ObjAllocs.RemoteRWDataAddr) 329 << "\n"); 330 if (auto Err = Client.setProtections(Id, ObjAllocs.RemoteRWDataAddr, 331 sys::Memory::MF_READ | 332 sys::Memory::MF_WRITE)) { 333 // FIXME: Replace this once finalizeMemory can return an Error. 334 handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) { 335 if (ErrMsg) { 336 raw_string_ostream ErrOut(*ErrMsg); 337 EIB.log(ErrOut); 338 } 339 }); 340 return false; 341 } 342 } 343 } 344 Unfinalized.clear(); 345 346 for (auto &EHFrame : UnfinalizedEHFrames) { 347 if (auto Err = Client.registerEHFrames(EHFrame.first, EHFrame.second)) { 348 // FIXME: Replace this once finalizeMemory can return an Error. 349 handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) { 350 if (ErrMsg) { 351 raw_string_ostream ErrOut(*ErrMsg); 352 EIB.log(ErrOut); 353 } 354 }); 355 return false; 356 } 357 } 358 UnfinalizedEHFrames.clear(); 359 360 return false; 361 } 362 363 private: 364 class Alloc { 365 public: Alloc(uint64_t Size,unsigned Align)366 Alloc(uint64_t Size, unsigned Align) 367 : Size(Size), Align(Align), Contents(new char[Size + Align - 1]) {} 368 Alloc(Alloc && Other)369 Alloc(Alloc &&Other) 370 : Size(std::move(Other.Size)), Align(std::move(Other.Align)), 371 Contents(std::move(Other.Contents)), 372 RemoteAddr(std::move(Other.RemoteAddr)) {} 373 374 Alloc &operator=(Alloc &&Other) { 375 Size = std::move(Other.Size); 376 Align = std::move(Other.Align); 377 Contents = std::move(Other.Contents); 378 RemoteAddr = std::move(Other.RemoteAddr); 379 return *this; 380 } 381 getSize()382 uint64_t getSize() const { return Size; } 383 getAlign()384 unsigned getAlign() const { return Align; } 385 getLocalAddress()386 char *getLocalAddress() const { 387 uintptr_t LocalAddr = reinterpret_cast<uintptr_t>(Contents.get()); 388 LocalAddr = alignTo(LocalAddr, Align); 389 return reinterpret_cast<char *>(LocalAddr); 390 } 391 setRemoteAddress(TargetAddress RemoteAddr)392 void setRemoteAddress(TargetAddress RemoteAddr) { 393 this->RemoteAddr = RemoteAddr; 394 } 395 getRemoteAddress()396 TargetAddress getRemoteAddress() const { return RemoteAddr; } 397 398 private: 399 uint64_t Size; 400 unsigned Align; 401 std::unique_ptr<char[]> Contents; 402 TargetAddress RemoteAddr = 0; 403 }; 404 405 struct ObjectAllocs { 406 ObjectAllocs() = default; 407 ObjectAllocsObjectAllocs408 ObjectAllocs(ObjectAllocs &&Other) 409 : RemoteCodeAddr(std::move(Other.RemoteCodeAddr)), 410 RemoteRODataAddr(std::move(Other.RemoteRODataAddr)), 411 RemoteRWDataAddr(std::move(Other.RemoteRWDataAddr)), 412 CodeAllocs(std::move(Other.CodeAllocs)), 413 RODataAllocs(std::move(Other.RODataAllocs)), 414 RWDataAllocs(std::move(Other.RWDataAllocs)) {} 415 416 ObjectAllocs &operator=(ObjectAllocs &&Other) { 417 RemoteCodeAddr = std::move(Other.RemoteCodeAddr); 418 RemoteRODataAddr = std::move(Other.RemoteRODataAddr); 419 RemoteRWDataAddr = std::move(Other.RemoteRWDataAddr); 420 CodeAllocs = std::move(Other.CodeAllocs); 421 RODataAllocs = std::move(Other.RODataAllocs); 422 RWDataAllocs = std::move(Other.RWDataAllocs); 423 return *this; 424 } 425 426 TargetAddress RemoteCodeAddr = 0; 427 TargetAddress RemoteRODataAddr = 0; 428 TargetAddress RemoteRWDataAddr = 0; 429 std::vector<Alloc> CodeAllocs, RODataAllocs, RWDataAllocs; 430 }; 431 432 OrcRemoteTargetClient &Client; 433 ResourceIdMgr::ResourceId Id; 434 std::vector<ObjectAllocs> Unmapped; 435 std::vector<ObjectAllocs> Unfinalized; 436 std::vector<std::pair<uint64_t, uint32_t>> UnfinalizedEHFrames; 437 }; 438 439 /// Remote indirect stubs manager. 440 class RCIndirectStubsManager : public IndirectStubsManager { 441 public: RCIndirectStubsManager(OrcRemoteTargetClient & Remote,ResourceIdMgr::ResourceId Id)442 RCIndirectStubsManager(OrcRemoteTargetClient &Remote, 443 ResourceIdMgr::ResourceId Id) 444 : Remote(Remote), Id(Id) {} 445 ~RCIndirectStubsManager()446 ~RCIndirectStubsManager() override { 447 if (auto Err = Remote.destroyIndirectStubsManager(Id)) { 448 // FIXME: Thread this error back to clients. 449 consumeError(std::move(Err)); 450 } 451 } 452 createStub(StringRef StubName,TargetAddress StubAddr,JITSymbolFlags StubFlags)453 Error createStub(StringRef StubName, TargetAddress StubAddr, 454 JITSymbolFlags StubFlags) override { 455 if (auto Err = reserveStubs(1)) 456 return Err; 457 458 return createStubInternal(StubName, StubAddr, StubFlags); 459 } 460 createStubs(const StubInitsMap & StubInits)461 Error createStubs(const StubInitsMap &StubInits) override { 462 if (auto Err = reserveStubs(StubInits.size())) 463 return Err; 464 465 for (auto &Entry : StubInits) 466 if (auto Err = createStubInternal(Entry.first(), Entry.second.first, 467 Entry.second.second)) 468 return Err; 469 470 return Error::success(); 471 } 472 findStub(StringRef Name,bool ExportedStubsOnly)473 JITSymbol findStub(StringRef Name, bool ExportedStubsOnly) override { 474 auto I = StubIndexes.find(Name); 475 if (I == StubIndexes.end()) 476 return nullptr; 477 auto Key = I->second.first; 478 auto Flags = I->second.second; 479 auto StubSymbol = JITSymbol(getStubAddr(Key), Flags); 480 if (ExportedStubsOnly && !StubSymbol.isExported()) 481 return nullptr; 482 return StubSymbol; 483 } 484 findPointer(StringRef Name)485 JITSymbol findPointer(StringRef Name) override { 486 auto I = StubIndexes.find(Name); 487 if (I == StubIndexes.end()) 488 return nullptr; 489 auto Key = I->second.first; 490 auto Flags = I->second.second; 491 return JITSymbol(getPtrAddr(Key), Flags); 492 } 493 updatePointer(StringRef Name,TargetAddress NewAddr)494 Error updatePointer(StringRef Name, TargetAddress NewAddr) override { 495 auto I = StubIndexes.find(Name); 496 assert(I != StubIndexes.end() && "No stub pointer for symbol"); 497 auto Key = I->second.first; 498 return Remote.writePointer(getPtrAddr(Key), NewAddr); 499 } 500 501 private: 502 struct RemoteIndirectStubsInfo { 503 TargetAddress StubBase; 504 TargetAddress PtrBase; 505 unsigned NumStubs; 506 }; 507 508 OrcRemoteTargetClient &Remote; 509 ResourceIdMgr::ResourceId Id; 510 std::vector<RemoteIndirectStubsInfo> RemoteIndirectStubsInfos; 511 typedef std::pair<uint16_t, uint16_t> StubKey; 512 std::vector<StubKey> FreeStubs; 513 StringMap<std::pair<StubKey, JITSymbolFlags>> StubIndexes; 514 reserveStubs(unsigned NumStubs)515 Error reserveStubs(unsigned NumStubs) { 516 if (NumStubs <= FreeStubs.size()) 517 return Error::success(); 518 519 unsigned NewStubsRequired = NumStubs - FreeStubs.size(); 520 TargetAddress StubBase; 521 TargetAddress PtrBase; 522 unsigned NumStubsEmitted; 523 524 if (auto StubInfoOrErr = Remote.emitIndirectStubs(Id, NewStubsRequired)) 525 std::tie(StubBase, PtrBase, NumStubsEmitted) = *StubInfoOrErr; 526 else 527 return StubInfoOrErr.takeError(); 528 529 unsigned NewBlockId = RemoteIndirectStubsInfos.size(); 530 RemoteIndirectStubsInfos.push_back({StubBase, PtrBase, NumStubsEmitted}); 531 532 for (unsigned I = 0; I < NumStubsEmitted; ++I) 533 FreeStubs.push_back(std::make_pair(NewBlockId, I)); 534 535 return Error::success(); 536 } 537 createStubInternal(StringRef StubName,TargetAddress InitAddr,JITSymbolFlags StubFlags)538 Error createStubInternal(StringRef StubName, TargetAddress InitAddr, 539 JITSymbolFlags StubFlags) { 540 auto Key = FreeStubs.back(); 541 FreeStubs.pop_back(); 542 StubIndexes[StubName] = std::make_pair(Key, StubFlags); 543 return Remote.writePointer(getPtrAddr(Key), InitAddr); 544 } 545 getStubAddr(StubKey K)546 TargetAddress getStubAddr(StubKey K) { 547 assert(RemoteIndirectStubsInfos[K.first].StubBase != 0 && 548 "Missing stub address"); 549 return RemoteIndirectStubsInfos[K.first].StubBase + 550 K.second * Remote.getIndirectStubSize(); 551 } 552 getPtrAddr(StubKey K)553 TargetAddress getPtrAddr(StubKey K) { 554 assert(RemoteIndirectStubsInfos[K.first].PtrBase != 0 && 555 "Missing pointer address"); 556 return RemoteIndirectStubsInfos[K.first].PtrBase + 557 K.second * Remote.getPointerSize(); 558 } 559 }; 560 561 /// Remote compile callback manager. 562 class RCCompileCallbackManager : public JITCompileCallbackManager { 563 public: RCCompileCallbackManager(TargetAddress ErrorHandlerAddress,OrcRemoteTargetClient & Remote)564 RCCompileCallbackManager(TargetAddress ErrorHandlerAddress, 565 OrcRemoteTargetClient &Remote) 566 : JITCompileCallbackManager(ErrorHandlerAddress), Remote(Remote) {} 567 568 private: grow()569 void grow() override { 570 TargetAddress BlockAddr = 0; 571 uint32_t NumTrampolines = 0; 572 if (auto TrampolineInfoOrErr = Remote.emitTrampolineBlock()) 573 std::tie(BlockAddr, NumTrampolines) = *TrampolineInfoOrErr; 574 else { 575 // FIXME: Return error. 576 llvm_unreachable("Failed to create trampolines"); 577 } 578 579 uint32_t TrampolineSize = Remote.getTrampolineSize(); 580 for (unsigned I = 0; I < NumTrampolines; ++I) 581 this->AvailableTrampolines.push_back(BlockAddr + (I * TrampolineSize)); 582 } 583 584 OrcRemoteTargetClient &Remote; 585 }; 586 587 /// Create an OrcRemoteTargetClient. 588 /// Channel is the ChannelT instance to communicate on. It is assumed that 589 /// the channel is ready to be read from and written to. Create(ChannelT & Channel)590 static Expected<OrcRemoteTargetClient> Create(ChannelT &Channel) { 591 Error Err; 592 OrcRemoteTargetClient H(Channel, Err); 593 if (Err) 594 return std::move(Err); 595 return Expected<OrcRemoteTargetClient>(std::move(H)); 596 } 597 598 /// Call the int(void) function at the given address in the target and return 599 /// its result. callIntVoid(TargetAddress Addr)600 Expected<int> callIntVoid(TargetAddress Addr) { 601 DEBUG(dbgs() << "Calling int(*)(void) " << format("0x%016x", Addr) << "\n"); 602 603 auto Listen = [&](RPCChannel &C, uint32_t Id) { 604 return listenForCompileRequests(C, Id); 605 }; 606 return callSTHandling<CallIntVoid>(Channel, Listen, Addr); 607 } 608 609 /// Call the int(int, char*[]) function at the given address in the target and 610 /// return its result. callMain(TargetAddress Addr,const std::vector<std::string> & Args)611 Expected<int> callMain(TargetAddress Addr, 612 const std::vector<std::string> &Args) { 613 DEBUG(dbgs() << "Calling int(*)(int, char*[]) " << format("0x%016x", Addr) 614 << "\n"); 615 616 auto Listen = [&](RPCChannel &C, uint32_t Id) { 617 return listenForCompileRequests(C, Id); 618 }; 619 return callSTHandling<CallMain>(Channel, Listen, Addr, Args); 620 } 621 622 /// Call the void() function at the given address in the target and wait for 623 /// it to finish. callVoidVoid(TargetAddress Addr)624 Error callVoidVoid(TargetAddress Addr) { 625 DEBUG(dbgs() << "Calling void(*)(void) " << format("0x%016x", Addr) 626 << "\n"); 627 628 auto Listen = [&](RPCChannel &C, uint32_t Id) { 629 return listenForCompileRequests(C, Id); 630 }; 631 return callSTHandling<CallVoidVoid>(Channel, Listen, Addr); 632 } 633 634 /// Create an RCMemoryManager which will allocate its memory on the remote 635 /// target. createRemoteMemoryManager(std::unique_ptr<RCMemoryManager> & MM)636 Error createRemoteMemoryManager(std::unique_ptr<RCMemoryManager> &MM) { 637 assert(!MM && "MemoryManager should be null before creation."); 638 639 auto Id = AllocatorIds.getNext(); 640 if (auto Err = callST<CreateRemoteAllocator>(Channel, Id)) 641 return Err; 642 MM = llvm::make_unique<RCMemoryManager>(*this, Id); 643 return Error::success(); 644 } 645 646 /// Create an RCIndirectStubsManager that will allocate stubs on the remote 647 /// target. createIndirectStubsManager(std::unique_ptr<RCIndirectStubsManager> & I)648 Error createIndirectStubsManager(std::unique_ptr<RCIndirectStubsManager> &I) { 649 assert(!I && "Indirect stubs manager should be null before creation."); 650 auto Id = IndirectStubOwnerIds.getNext(); 651 if (auto Err = callST<CreateIndirectStubsOwner>(Channel, Id)) 652 return Err; 653 I = llvm::make_unique<RCIndirectStubsManager>(*this, Id); 654 return Error::success(); 655 } 656 657 Expected<RCCompileCallbackManager &> enableCompileCallbacks(TargetAddress ErrorHandlerAddress)658 enableCompileCallbacks(TargetAddress ErrorHandlerAddress) { 659 // Check for an 'out-of-band' error, e.g. from an MM destructor. 660 if (ExistingError) 661 return std::move(ExistingError); 662 663 // Emit the resolver block on the JIT server. 664 if (auto Err = callST<EmitResolverBlock>(Channel)) 665 return std::move(Err); 666 667 // Create the callback manager. 668 CallbackManager.emplace(ErrorHandlerAddress, *this); 669 RCCompileCallbackManager &Mgr = *CallbackManager; 670 return Mgr; 671 } 672 673 /// Search for symbols in the remote process. Note: This should be used by 674 /// symbol resolvers *after* they've searched the local symbol table in the 675 /// JIT stack. getSymbolAddress(StringRef Name)676 Expected<TargetAddress> getSymbolAddress(StringRef Name) { 677 // Check for an 'out-of-band' error, e.g. from an MM destructor. 678 if (ExistingError) 679 return std::move(ExistingError); 680 681 return callST<GetSymbolAddress>(Channel, Name); 682 } 683 684 /// Get the triple for the remote target. getTargetTriple()685 const std::string &getTargetTriple() const { return RemoteTargetTriple; } 686 terminateSession()687 Error terminateSession() { return callST<TerminateSession>(Channel); } 688 689 private: OrcRemoteTargetClient(ChannelT & Channel,Error & Err)690 OrcRemoteTargetClient(ChannelT &Channel, Error &Err) : Channel(Channel) { 691 ErrorAsOutParameter EAO(Err); 692 if (auto RIOrErr = callST<GetRemoteInfo>(Channel)) { 693 std::tie(RemoteTargetTriple, RemotePointerSize, RemotePageSize, 694 RemoteTrampolineSize, RemoteIndirectStubSize) = *RIOrErr; 695 Err = Error::success(); 696 } else { 697 Err = joinErrors(RIOrErr.takeError(), std::move(ExistingError)); 698 } 699 } 700 deregisterEHFrames(TargetAddress Addr,uint32_t Size)701 Error deregisterEHFrames(TargetAddress Addr, uint32_t Size) { 702 return callST<RegisterEHFrames>(Channel, Addr, Size); 703 } 704 destroyRemoteAllocator(ResourceIdMgr::ResourceId Id)705 void destroyRemoteAllocator(ResourceIdMgr::ResourceId Id) { 706 if (auto Err = callST<DestroyRemoteAllocator>(Channel, Id)) { 707 // FIXME: This will be triggered by a removeModuleSet call: Propagate 708 // error return up through that. 709 llvm_unreachable("Failed to destroy remote allocator."); 710 AllocatorIds.release(Id); 711 } 712 } 713 destroyIndirectStubsManager(ResourceIdMgr::ResourceId Id)714 Error destroyIndirectStubsManager(ResourceIdMgr::ResourceId Id) { 715 IndirectStubOwnerIds.release(Id); 716 return callST<DestroyIndirectStubsOwner>(Channel, Id); 717 } 718 719 Expected<std::tuple<TargetAddress, TargetAddress, uint32_t>> emitIndirectStubs(ResourceIdMgr::ResourceId Id,uint32_t NumStubsRequired)720 emitIndirectStubs(ResourceIdMgr::ResourceId Id, uint32_t NumStubsRequired) { 721 return callST<EmitIndirectStubs>(Channel, Id, NumStubsRequired); 722 } 723 emitTrampolineBlock()724 Expected<std::tuple<TargetAddress, uint32_t>> emitTrampolineBlock() { 725 // Check for an 'out-of-band' error, e.g. from an MM destructor. 726 if (ExistingError) 727 return std::move(ExistingError); 728 729 return callST<EmitTrampolineBlock>(Channel); 730 } 731 getIndirectStubSize()732 uint32_t getIndirectStubSize() const { return RemoteIndirectStubSize; } getPageSize()733 uint32_t getPageSize() const { return RemotePageSize; } getPointerSize()734 uint32_t getPointerSize() const { return RemotePointerSize; } 735 getTrampolineSize()736 uint32_t getTrampolineSize() const { return RemoteTrampolineSize; } 737 listenForCompileRequests(RPCChannel & C,uint32_t & Id)738 Error listenForCompileRequests(RPCChannel &C, uint32_t &Id) { 739 assert(CallbackManager && 740 "No calback manager. enableCompileCallbacks must be called first"); 741 742 // Check for an 'out-of-band' error, e.g. from an MM destructor. 743 if (ExistingError) 744 return std::move(ExistingError); 745 746 // FIXME: CompileCallback could be an anonymous lambda defined at the use 747 // site below, but that triggers a GCC 4.7 ICE. When we move off 748 // GCC 4.7, tidy this up. 749 auto CompileCallback = 750 [this](TargetAddress Addr) -> Expected<TargetAddress> { 751 return this->CallbackManager->executeCompileCallback(Addr); 752 }; 753 754 if (Id == RequestCompileId) { 755 if (auto Err = handle<RequestCompile>(C, CompileCallback)) 756 return Err; 757 return Error::success(); 758 } 759 // else 760 return orcError(OrcErrorCode::UnexpectedRPCCall); 761 } 762 readMem(char * Dst,TargetAddress Src,uint64_t Size)763 Expected<std::vector<char>> readMem(char *Dst, TargetAddress Src, 764 uint64_t Size) { 765 // Check for an 'out-of-band' error, e.g. from an MM destructor. 766 if (ExistingError) 767 return std::move(ExistingError); 768 769 return callST<ReadMem>(Channel, Src, Size); 770 } 771 registerEHFrames(TargetAddress & RAddr,uint32_t Size)772 Error registerEHFrames(TargetAddress &RAddr, uint32_t Size) { 773 return callST<RegisterEHFrames>(Channel, RAddr, Size); 774 } 775 reserveMem(ResourceIdMgr::ResourceId Id,uint64_t Size,uint32_t Align)776 Expected<TargetAddress> reserveMem(ResourceIdMgr::ResourceId Id, 777 uint64_t Size, uint32_t Align) { 778 779 // Check for an 'out-of-band' error, e.g. from an MM destructor. 780 if (ExistingError) 781 return std::move(ExistingError); 782 783 return callST<ReserveMem>(Channel, Id, Size, Align); 784 } 785 setProtections(ResourceIdMgr::ResourceId Id,TargetAddress RemoteSegAddr,unsigned ProtFlags)786 Error setProtections(ResourceIdMgr::ResourceId Id, 787 TargetAddress RemoteSegAddr, unsigned ProtFlags) { 788 return callST<SetProtections>(Channel, Id, RemoteSegAddr, ProtFlags); 789 } 790 writeMem(TargetAddress Addr,const char * Src,uint64_t Size)791 Error writeMem(TargetAddress Addr, const char *Src, uint64_t Size) { 792 // Check for an 'out-of-band' error, e.g. from an MM destructor. 793 if (ExistingError) 794 return std::move(ExistingError); 795 796 return callST<WriteMem>(Channel, DirectBufferWriter(Src, Addr, Size)); 797 } 798 writePointer(TargetAddress Addr,TargetAddress PtrVal)799 Error writePointer(TargetAddress Addr, TargetAddress PtrVal) { 800 // Check for an 'out-of-band' error, e.g. from an MM destructor. 801 if (ExistingError) 802 return std::move(ExistingError); 803 804 return callST<WritePtr>(Channel, Addr, PtrVal); 805 } 806 doNothing()807 static Error doNothing() { return Error::success(); } 808 809 ChannelT &Channel; 810 Error ExistingError; 811 std::string RemoteTargetTriple; 812 uint32_t RemotePointerSize = 0; 813 uint32_t RemotePageSize = 0; 814 uint32_t RemoteTrampolineSize = 0; 815 uint32_t RemoteIndirectStubSize = 0; 816 ResourceIdMgr AllocatorIds, IndirectStubOwnerIds; 817 Optional<RCCompileCallbackManager> CallbackManager; 818 }; 819 820 } // end namespace remote 821 } // end namespace orc 822 } // end namespace llvm 823 824 #undef DEBUG_TYPE 825 826 #endif // LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETCLIENT_H 827